pub fn check_term(context: &Context, term: &RcTerm, expected_ty: &RcType) -> Result<(), TypeError> {
    log::trace!("checking term:\t\t{}", term);

    match term.as_ref() {
        Term::Let(def, body) => {
            let mut body_context = context.clone();
            body_context.local_define(context.eval(def)?, synth_term(context, def)?);

            check_term(&body_context, body, expected_ty)
        },

        Term::LiteralElim(scrutinee, clauses, default_body) => {
            let scrutinee_ty = synth_term(context, scrutinee)?;

            // TODO: check that clauses are sorted by patterns
            // TODO: check that patterns aren't duplicated

            for (literal_intro, body) in clauses.iter() {
                check_literal(context, literal_intro, &scrutinee_ty)?;
                check_term(context, body, &expected_ty)?;
            }

            let mut default_body_context = context.clone();
            default_body_context.local_bind(scrutinee_ty.clone());
            check_term(&default_body_context, default_body, expected_ty)
        },

        Term::FunIntro(intro_app_mode, body) => match expected_ty.as_ref() {
            Value::FunType(ty_app_mode, param_ty, body_ty) if intro_app_mode == ty_app_mode => {
                let mut body_context = context.clone();
                let param = body_context.local_bind(param_ty.clone());
                let body_ty = nbe::do_closure_app(body_ty, param)?;

                check_term(&body_context, body, &body_ty)
            },
            Value::FunType(ty_app_mode, _, _) => Err(TypeError::UnexpectedAppMode {
                found: intro_app_mode.clone(),
                expected: ty_app_mode.clone(),
            }),
            _ => Err(TypeError::ExpectedFunType {
                found: expected_ty.clone(),
            }),
        },

        Term::RecordIntro(intro_fields) => {
            let mut context = context.clone();
            let mut expected_ty = expected_ty.clone();

            for (label, term) in intro_fields {
                if let Value::RecordTypeExtend(_, expected_label, expected_term_ty, rest) =
                    expected_ty.as_ref()
                {
                    if label != expected_label {
                        return Err(TypeError::UnexpectedField {
                            found: label.clone(),
                            expected: expected_label.clone(),
                        });
                    }

                    check_term(&context, term, expected_term_ty)?;
                    let term_value = context.eval(term)?;

                    context.local_define(term_value.clone(), expected_term_ty.clone());
                    expected_ty = nbe::do_closure_app(&rest, term_value)?;
                } else {
                    return Err(TypeError::TooManyFieldsFound);
                }
            }

            if let Value::RecordTypeEmpty = expected_ty.as_ref() {
                Ok(())
            } else {
                Err(TypeError::NotEnoughFieldsProvided)
            }
        },

        _ => context.expect_subtype(&synth_term(context, term)?, expected_ty),
    }
}
/// Check that a term conforms to a given type.
Check that a term conforms to a given type.
Check that a term conforms to a given type .
pub fn check_term(context: &Context, term: &RcTerm, expected_ty: &RcType) -> Result<(), TypeError> {
    log::trace!("checking term:\t\t{}", term);
    match term.as_ref() {
        Term::Let(def, body) => {
            let mut body_context = context.clone();
            body_context.local_define(context.eval(def)?, synth_term(context, def)?);
            check_term(&body_context, body, expected_ty)
        },
        Term::LiteralElim(scrutinee, clauses, default_body) => {
            let scrutinee_ty = synth_term(context, scrutinee)?;
            // TODO: check that clauses are sorted by patterns
            // TODO: check that patterns aren't duplicated
            for (literal_intro, body) in clauses.iter() {
                check_literal(context, literal_intro, &scrutinee_ty)?;
                check_term(context, body, &expected_ty)?;
            }
            let mut default_body_context = context.clone();
            default_body_context.local_bind(scrutinee_ty.clone());
            check_term(&default_body_context, default_body, expected_ty)
        },
        Term::FunIntro(intro_app_mode, body) => match expected_ty.as_ref() {
            Value::FunType(ty_app_mode, param_ty, body_ty) if intro_app_mode == ty_app_mode => {
                let mut body_context = context.clone();
                let param = body_context.local_bind(param_ty.clone());
                let body_ty = nbe::do_closure_app(body_ty, param)?;
                check_term(&body_context, body, &body_ty)
            },
            Value::FunType(ty_app_mode, _, _) => Err(TypeError::UnexpectedAppMode {
                found: intro_app_mode.clone(),
                expected: ty_app_mode.clone(),
            }),
            _ => Err(TypeError::ExpectedFunType {
                found: expected_ty.clone(),
            }),
        },
        Term::RecordIntro(intro_fields) => {
            let mut context = context.clone();
            let mut expected_ty = expected_ty.clone();
            for (label, term) in intro_fields {
                if let Value::RecordTypeExtend(_, expected_label, expected_term_ty, rest) =
                    expected_ty.as_ref()
                {
                    if label != expected_label {
                        return Err(TypeError::UnexpectedField {
                            found: label.clone(),
                            expected: expected_label.clone(),
                        });
                    }
                    check_term(&context, term, expected_term_ty)?;
                    let term_value = context.eval(term)?;
                    context.local_define(term_value.clone(), expected_term_ty.clone());
                    expected_ty = nbe::do_closure_app(&rest, term_value)?;
                } else {
                    return Err(TypeError::TooManyFieldsFound);
                }
            }
            if let Value::RecordTypeEmpty = expected_ty.as_ref() {
                Ok(())
            } else {
                Err(TypeError::NotEnoughFieldsProvided)
            }
        },
        _ => context.expect_subtype(&synth_term(context, term)?, expected_ty),
    }
}
pub fn check_term ( context : & Context , term : & RcTerm , expected_ty : & RcType ) -> Result < ( ) , TypeError > { log :: trace ! ( " \t \t " term ) ; match term . as_ref ( ) { Term :: Let ( def , body ) => { let mut body_context = context . clone ( ) ; body_context . local_define ( context . eval ( def ) ? , synth_term ( context , def ) ? ) ; check_term ( & body_context , body , expected_ty ) } , Term :: LiteralElim ( scrutinee , clauses , default_body ) => { let scrutinee_ty = synth_term ( context , scrutinee ) ? ; // TODO: check that clauses are sorted by patterns // TODO: check that patterns aren't duplicated for ( literal_intro , body ) in clauses . iter ( ) { check_literal ( context , literal_intro , & scrutinee_ty ) ? ; check_term ( context , body , & expected_ty ) ? ; } let mut default_body_context = context . clone ( ) ; default_body_context . local_bind ( scrutinee_ty . clone ( ) ) ; check_term ( & default_body_context , default_body , expected_ty ) } , Term :: FunIntro ( intro_app_mode , body ) => match expected_ty . as_ref ( ) { Value :: FunType ( ty_app_mode , param_ty , body_ty ) if intro_app_mode == ty_app_mode => { let mut body_context = context . clone ( ) ; let param = body_context . local_bind ( param_ty . clone ( ) ) ; let body_ty = nbe :: do_closure_app ( body_ty , param ) ? ; check_term ( & body_context , body , & body_ty ) } , Value :: FunType ( ty_app_mode , _ , _ ) => Err ( TypeError :: UnexpectedAppMode { found : intro_app_mode . clone ( ) , expected : ty_app_mode . clone ( ) , } ) , _ => Err ( TypeError :: ExpectedFunType { found : expected_ty . clone ( ) , } ) , } , Term :: RecordIntro ( intro_fields ) => { let mut context = context . clone ( ) ; let mut expected_ty = expected_ty . clone ( ) ; for ( label , term ) in intro_fields { if let Value :: RecordTypeExtend ( _ , expected_label , expected_term_ty , rest ) = expected_ty . as_ref ( ) { if label != expected_label { return Err ( TypeError :: UnexpectedField { found : label . clone ( ) , expected : expected_label . clone ( ) , } ) ; } check_term ( & context , term , expected_term_ty ) ? ; let term_value = context . eval ( term ) ? ; context . local_define ( term_value . clone ( ) , expected_term_ty . clone ( ) ) ; expected_ty = nbe :: do_closure_app ( & rest , term_value ) ? ; } else { return Err ( TypeError :: TooManyFieldsFound ) ; } } if let Value :: RecordTypeEmpty = expected_ty . as_ref ( ) { Ok ( ( ) ) } else { Err ( TypeError :: NotEnoughFieldsProvided ) } } , _ => context . expect_subtype ( & synth_term ( context , term ) ? , expected_ty ) , } }
Check that a term conforms to a given type.
Check that a term conforms to a given type .
context
&Context
term
&RcTerm
expected_ty
&RcType