pub fn check_case<'file>(
    context: &Context,
    metas: &mut meta::Env,
    span: FileSpan,
    scrutinee: &Term<'file>,
    clauses: Vec<CaseClause<'file>>,
    expected_ty: &Rc<domain::Type>,
) -> Result<Rc<syntax::Term>, Diagnostic<FileSpan>> {
    // TODO: Merge with `check_clause`
    // TODO: Zero or more scrutinees
    // TODO: One-or-more patterns per case clause

    match clauses.split_last() {
        None => Err(Diagnostic::new_error("non-exhaustive patterns").with_label(
            DiagnosticLabel::new_primary(span).with_message("empty patterns are not yet supported"),
        )),
        Some((default_clause, literal_clauses)) => {
            let mut context = context.clone();

            let (checked_scrutinee, (param_level, param_ty)) = {
                let scrutinee_level = context.values().size().next_level();
                let (scrutinee_term, scrutinee_ty) =
                    synth_term(MetaInsertion::Yes, &context, metas, scrutinee)?;
                let scrutinee_value =
                    context.eval_term(metas, scrutinee.span(), &scrutinee_term)?;
                context.add_fresh_defn(scrutinee_value, scrutinee_ty.clone());

                ((scrutinee_term, None), (scrutinee_level, scrutinee_ty))
            };

            let mut literal_branches =
                Vec::<(LiteralIntro, Rc<syntax::Term>)>::with_capacity(literal_clauses.len());

            for literal_clause in literal_clauses {
                match literal_clause.pattern {
                    Pattern::LiteralIntro(kind, literal) => {
                        let literal_intro =
                            literal::check(&context, metas, *kind, literal, &param_ty)?;
                        let body = check_term(&context, metas, &literal_clause.body, expected_ty)?;

                        match literal_branches
                            .binary_search_by(|(l, _)| l.partial_cmp(&literal_intro).unwrap()) // NaN?
                        {
                            Ok(_) => {}, // TODO: Warn about duplicated patterns?
                            Err(index) => literal_branches.insert(index, (literal_intro, body)),
                        }
                    },
                    _ => {
                        return Err(
                            Diagnostic::new_error("variable literal pattern").with_label(
                                DiagnosticLabel::new_primary(literal_clause.pattern.span())
                                    .with_message("literal pattern expected here"),
                            ),
                        );
                    },
                }
            }

            let default_body = match default_clause.pattern {
                Pattern::Var(name) => {
                    let mut context = context.clone();
                    context.add_name(name, param_level);
                    check_term(&context, metas, &default_clause.body, expected_ty)?
                },
                _ => {
                    return Err(
                        Diagnostic::new_error("expected variable pattern").with_label(
                            DiagnosticLabel::new_primary(default_clause.pattern.span())
                                .with_message("default case expected here"),
                        ),
                    );
                },
            };

            let body = Rc::from(syntax::Term::LiteralElim(
                Rc::from(syntax::Term::var(
                    context.values().size().index(param_level),
                )),
                Rc::from(literal_branches),
                default_body,
            ));

            Ok(done(vec![checked_scrutinee], Vec::new(), body))
        },
    }
}
/// Check that the given case clauses conform to the expected type, and
/// elaborate them into a case tree.
Check that the given case clauses conform to the expected type, and
elaborate them into a case tree.
Check that the given case clauses conform to the expected type and elaborate them into a case tree .
pub fn check_case<'file>(
    context: &Context,
    metas: &mut meta::Env,
    span: FileSpan,
    scrutinee: &Term<'file>,
    clauses: Vec<CaseClause<'file>>,
    expected_ty: &Rc<domain::Type>,
) -> Result<Rc<syntax::Term>, Diagnostic<FileSpan>> {
    // TODO: Merge with `check_clause`
    // TODO: Zero or more scrutinees
    // TODO: One-or-more patterns per case clause
    match clauses.split_last() {
        None => Err(Diagnostic::new_error("non-exhaustive patterns").with_label(
            DiagnosticLabel::new_primary(span).with_message("empty patterns are not yet supported"),
        )),
        Some((default_clause, literal_clauses)) => {
            let mut context = context.clone();
            let (checked_scrutinee, (param_level, param_ty)) = {
                let scrutinee_level = context.values().size().next_level();
                let (scrutinee_term, scrutinee_ty) =
                    synth_term(MetaInsertion::Yes, &context, metas, scrutinee)?;
                let scrutinee_value =
                    context.eval_term(metas, scrutinee.span(), &scrutinee_term)?;
                context.add_fresh_defn(scrutinee_value, scrutinee_ty.clone());
                ((scrutinee_term, None), (scrutinee_level, scrutinee_ty))
            };
            let mut literal_branches =
                Vec::<(LiteralIntro, Rc<syntax::Term>)>::with_capacity(literal_clauses.len());
            for literal_clause in literal_clauses {
                match literal_clause.pattern {
                    Pattern::LiteralIntro(kind, literal) => {
                        let literal_intro =
                            literal::check(&context, metas, *kind, literal, &param_ty)?;
                        let body = check_term(&context, metas, &literal_clause.body, expected_ty)?;
                        match literal_branches
                            .binary_search_by(|(l, _)| l.partial_cmp(&literal_intro).unwrap()) // NaN?
                        {
                            Ok(_) => {}, // TODO: Warn about duplicated patterns?
                            Err(index) => literal_branches.insert(index, (literal_intro, body)),
                        }
                    },
                    _ => {
                        return Err(
                            Diagnostic::new_error("variable literal pattern").with_label(
                                DiagnosticLabel::new_primary(literal_clause.pattern.span())
                                    .with_message("literal pattern expected here"),
                            ),
                        );
                    },
                }
            }
            let default_body = match default_clause.pattern {
                Pattern::Var(name) => {
                    let mut context = context.clone();
                    context.add_name(name, param_level);
                    check_term(&context, metas, &default_clause.body, expected_ty)?
                },
                _ => {
                    return Err(
                        Diagnostic::new_error("expected variable pattern").with_label(
                            DiagnosticLabel::new_primary(default_clause.pattern.span())
                                .with_message("default case expected here"),
                        ),
                    );
                },
            };
            let body = Rc::from(syntax::Term::LiteralElim(
                Rc::from(syntax::Term::var(
                    context.values().size().index(param_level),
                )),
                Rc::from(literal_branches),
                default_body,
            ));
            Ok(done(vec![checked_scrutinee], Vec::new(), body))
        },
    }
}
pub fn check_case < ' file > ( context : & Context , metas : & mut meta :: Env , span : FileSpan , scrutinee : & Term < ' file > , clauses : Vec < CaseClause < ' file > > , expected_ty : & Rc < domain :: Type > , ) -> Result < Rc < syntax :: Term > , Diagnostic < FileSpan > > { // TODO: Merge with `check_clause` // TODO: Zero or more scrutinees // TODO: One-or-more patterns per case clause match clauses . split_last ( ) { None => Err ( Diagnostic :: new_error ( " " ) . with_label ( DiagnosticLabel :: new_primary ( span ) . with_message ( " " ) , ) ) , Some ( ( default_clause , literal_clauses ) ) => { let mut context = context . clone ( ) ; let ( checked_scrutinee , ( param_level , param_ty ) ) = { let scrutinee_level = context . values ( ) . size ( ) . next_level ( ) ; let ( scrutinee_term , scrutinee_ty ) = synth_term ( MetaInsertion :: Yes , & context , metas , scrutinee ) ? ; let scrutinee_value = context . eval_term ( metas , scrutinee . span ( ) , & scrutinee_term ) ? ; context . add_fresh_defn ( scrutinee_value , scrutinee_ty . clone ( ) ) ; ( ( scrutinee_term , None ) , ( scrutinee_level , scrutinee_ty ) ) } ; let mut literal_branches = Vec :: < ( LiteralIntro , Rc < syntax :: Term > ) > :: with_capacity ( literal_clauses . len ( ) ) ; for literal_clause in literal_clauses { match literal_clause . pattern { Pattern :: LiteralIntro ( kind , literal ) => { let literal_intro = literal :: check ( & context , metas , * kind , literal , & param_ty ) ? ; let body = check_term ( & context , metas , & literal_clause . body , expected_ty ) ? ; match literal_branches . binary_search_by ( | ( l , _ ) | l . partial_cmp ( & literal_intro ) . unwrap ( ) ) // NaN? { Ok ( _ ) => { } , // TODO: Warn about duplicated patterns? Err ( index ) => literal_branches . insert ( index , ( literal_intro , body ) ) , } } , _ => { return Err ( Diagnostic :: new_error ( " " ) . with_label ( DiagnosticLabel :: new_primary ( literal_clause . pattern . span ( ) ) . with_message ( " " ) , ) , ) ; } , } } let default_body = match default_clause . pattern { Pattern :: Var ( name ) => { let mut context = context . clone ( ) ; context . add_name ( name , param_level ) ; check_term ( & context , metas , & default_clause . body , expected_ty ) ? } , _ => { return Err ( Diagnostic :: new_error ( " " ) . with_label ( DiagnosticLabel :: new_primary ( default_clause . pattern . span ( ) ) . with_message ( " " ) , ) , ) ; } , } ; let body = Rc :: from ( syntax :: Term :: LiteralElim ( Rc :: from ( syntax :: Term :: var ( context . values ( ) . size ( ) . index ( param_level ) , ) ) , Rc :: from ( literal_branches ) , default_body , ) ) ; Ok ( done ( vec ! [ checked_scrutinee ] , Vec :: new ( ) , body ) ) } , } }
Check that the given case clauses conform to the expected type, and
elaborate them into a case tree.
Check that the given case clauses conform to the expected type and elaborate them into a case tree .
context
&Context
metas
&mut meta::Env
span
FileSpan
scrutinee
&Term<'file>
clauses
Vec<CaseClause<'file>>
expected_ty
&Rc<domain::Type>
context
&Context
metas
&mut meta::Env
span
FileSpan
scrutinee
&Term<'file>
clauses
Vec<CaseClause<'file>>
expected_ty
&Rc<domain::Type>