pub fn synth_term(context: &Context, term: &RcTerm) -> Result<RcType, TypeError> {
    use std::cmp;

    log::trace!("synthesizing term:\t\t{}", term);

    match term.as_ref() {
        Term::Var(index) => match context.tys().lookup_entry(*index) {
            None => Err(TypeError::UnboundVariable),
            Some(ann) => Ok(ann.clone()),
        },
        Term::PrimitiveAbort(ty, _) => {
            synth_universe(context, ty)?;
            let ty = context.eval(ty)?;
            Ok(ty)
        },
        Term::Let(def, body) => {
            let mut body_context = context.clone();
            let def_ty = synth_term(context, def)?;
            body_context.local_define(context.eval(def)?, def_ty);

            synth_term(&body_context, body)
        },

        Term::LiteralType(_) => Ok(RcValue::from(Value::Universe(UniverseLevel(0)))),
        Term::LiteralIntro(literal_intro) => Ok(synth_literal(literal_intro)),
        Term::LiteralElim(_, _, _) => Err(TypeError::AmbiguousTerm(term.clone())),

        Term::FunType(_app_mode, param_ty, body_ty) => {
            let param_level = synth_universe(context, param_ty)?;
            let param_ty_value = context.eval(param_ty)?;

            let mut body_ty_context = context.clone();
            body_ty_context.local_bind(param_ty_value);

            let body_level = synth_universe(&body_ty_context, body_ty)?;

            Ok(RcValue::from(Value::Universe(cmp::max(
                param_level,
                body_level,
            ))))
        },
        Term::FunIntro(_, _) => Err(TypeError::AmbiguousTerm(term.clone())),

        Term::FunElim(fun, arg_app_mode, arg) => {
            let fun_ty = synth_term(context, fun)?;
            match fun_ty.as_ref() {
                Value::FunType(ty_app_mode, arg_ty, body_ty) if arg_app_mode == ty_app_mode => {
                    check_term(context, arg, arg_ty)?;
                    let arg_value = context.eval(arg)?;
                    Ok(nbe::do_closure_app(body_ty, arg_value)?)
                },
                Value::FunType(ty_app_mode, _, _) => Err(TypeError::UnexpectedAppMode {
                    found: arg_app_mode.clone(),
                    expected: ty_app_mode.clone(),
                }),
                _ => Err(TypeError::ExpectedFunType {
                    found: fun_ty.clone(),
                }),
            }
        },

        Term::RecordType(ty_fields) => {
            let mut context = context.clone();
            let mut max_level = UniverseLevel(0);

            for (_, _, ty) in ty_fields {
                let ty_level = synth_universe(&context, &ty)?;
                context.local_bind(context.eval(&ty)?);
                max_level = cmp::max(max_level, ty_level);
            }

            Ok(RcValue::from(Value::Universe(max_level)))
        },
        Term::RecordIntro(intro_fields) => {
            if intro_fields.is_empty() {
                Ok(RcValue::from(Value::RecordTypeEmpty))
            } else {
                Err(TypeError::AmbiguousTerm(term.clone()))
            }
        },
        Term::RecordElim(record, label) => {
            let mut record_ty = synth_term(context, record)?;

            while let Value::RecordTypeExtend(_, current_label, current_ty, rest) =
                record_ty.as_ref()
            {
                if label == current_label {
                    return Ok(current_ty.clone());
                } else {
                    let label = current_label.clone();
                    let expr = RcTerm::from(Term::RecordElim(record.clone(), label));
                    record_ty = nbe::do_closure_app(rest, context.eval(&expr)?)?;
                }
            }

            Err(TypeError::NoFieldInType(label.clone()))
        },

        Term::Universe(level) => Ok(RcValue::from(Value::Universe(*level + 1))),
    }
}
/// Synthesize the type of the term.
Synthesize the type of the term.
Synthesize the type of the term .
pub fn synth_term(context: &Context, term: &RcTerm) -> Result<RcType, TypeError> {
    use std::cmp;
    log::trace!("synthesizing term:\t\t{}", term);
    match term.as_ref() {
        Term::Var(index) => match context.tys().lookup_entry(*index) {
            None => Err(TypeError::UnboundVariable),
            Some(ann) => Ok(ann.clone()),
        },
        Term::PrimitiveAbort(ty, _) => {
            synth_universe(context, ty)?;
            let ty = context.eval(ty)?;
            Ok(ty)
        },
        Term::Let(def, body) => {
            let mut body_context = context.clone();
            let def_ty = synth_term(context, def)?;
            body_context.local_define(context.eval(def)?, def_ty);
            synth_term(&body_context, body)
        },
        Term::LiteralType(_) => Ok(RcValue::from(Value::Universe(UniverseLevel(0)))),
        Term::LiteralIntro(literal_intro) => Ok(synth_literal(literal_intro)),
        Term::LiteralElim(_, _, _) => Err(TypeError::AmbiguousTerm(term.clone())),
        Term::FunType(_app_mode, param_ty, body_ty) => {
            let param_level = synth_universe(context, param_ty)?;
            let param_ty_value = context.eval(param_ty)?;
            let mut body_ty_context = context.clone();
            body_ty_context.local_bind(param_ty_value);
            let body_level = synth_universe(&body_ty_context, body_ty)?;
            Ok(RcValue::from(Value::Universe(cmp::max(
                param_level,
                body_level,
            ))))
        },
        Term::FunIntro(_, _) => Err(TypeError::AmbiguousTerm(term.clone())),
        Term::FunElim(fun, arg_app_mode, arg) => {
            let fun_ty = synth_term(context, fun)?;
            match fun_ty.as_ref() {
                Value::FunType(ty_app_mode, arg_ty, body_ty) if arg_app_mode == ty_app_mode => {
                    check_term(context, arg, arg_ty)?;
                    let arg_value = context.eval(arg)?;
                    Ok(nbe::do_closure_app(body_ty, arg_value)?)
                },
                Value::FunType(ty_app_mode, _, _) => Err(TypeError::UnexpectedAppMode {
                    found: arg_app_mode.clone(),
                    expected: ty_app_mode.clone(),
                }),
                _ => Err(TypeError::ExpectedFunType {
                    found: fun_ty.clone(),
                }),
            }
        },
        Term::RecordType(ty_fields) => {
            let mut context = context.clone();
            let mut max_level = UniverseLevel(0);
            for (_, _, ty) in ty_fields {
                let ty_level = synth_universe(&context, &ty)?;
                context.local_bind(context.eval(&ty)?);
                max_level = cmp::max(max_level, ty_level);
            }
            Ok(RcValue::from(Value::Universe(max_level)))
        },
        Term::RecordIntro(intro_fields) => {
            if intro_fields.is_empty() {
                Ok(RcValue::from(Value::RecordTypeEmpty))
            } else {
                Err(TypeError::AmbiguousTerm(term.clone()))
            }
        },
        Term::RecordElim(record, label) => {
            let mut record_ty = synth_term(context, record)?;
            while let Value::RecordTypeExtend(_, current_label, current_ty, rest) =
                record_ty.as_ref()
            {
                if label == current_label {
                    return Ok(current_ty.clone());
                } else {
                    let label = current_label.clone();
                    let expr = RcTerm::from(Term::RecordElim(record.clone(), label));
                    record_ty = nbe::do_closure_app(rest, context.eval(&expr)?)?;
                }
            }
            Err(TypeError::NoFieldInType(label.clone()))
        },
        Term::Universe(level) => Ok(RcValue::from(Value::Universe(*level + 1))),
    }
}
pub fn synth_term ( context : & Context , term : & RcTerm ) -> Result < RcType , TypeError > { use std :: cmp ; log :: trace ! ( " \t \t " term ) ; match term . as_ref ( ) { Term :: Var ( index ) => match context . tys ( ) . lookup_entry ( * index ) { None => Err ( TypeError :: UnboundVariable ) , Some ( ann ) => Ok ( ann . clone ( ) ) , } , Term :: PrimitiveAbort ( ty , _ ) => { synth_universe ( context , ty ) ? ; let ty = context . eval ( ty ) ? ; Ok ( ty ) } , Term :: Let ( def , body ) => { let mut body_context = context . clone ( ) ; let def_ty = synth_term ( context , def ) ? ; body_context . local_define ( context . eval ( def ) ? , def_ty ) ; synth_term ( & body_context , body ) } , Term :: LiteralType ( _ ) => Ok ( RcValue :: from ( Value :: Universe ( UniverseLevel ( 0 ) ) ) ) , Term :: LiteralIntro ( literal_intro ) => Ok ( synth_literal ( literal_intro ) ) , Term :: LiteralElim ( _ , _ , _ ) => Err ( TypeError :: AmbiguousTerm ( term . clone ( ) ) ) , Term :: FunType ( _app_mode , param_ty , body_ty ) => { let param_level = synth_universe ( context , param_ty ) ? ; let param_ty_value = context . eval ( param_ty ) ? ; let mut body_ty_context = context . clone ( ) ; body_ty_context . local_bind ( param_ty_value ) ; let body_level = synth_universe ( & body_ty_context , body_ty ) ? ; Ok ( RcValue :: from ( Value :: Universe ( cmp :: max ( param_level , body_level , ) ) ) ) } , Term :: FunIntro ( _ , _ ) => Err ( TypeError :: AmbiguousTerm ( term . clone ( ) ) ) , Term :: FunElim ( fun , arg_app_mode , arg ) => { let fun_ty = synth_term ( context , fun ) ? ; match fun_ty . as_ref ( ) { Value :: FunType ( ty_app_mode , arg_ty , body_ty ) if arg_app_mode == ty_app_mode => { check_term ( context , arg , arg_ty ) ? ; let arg_value = context . eval ( arg ) ? ; Ok ( nbe :: do_closure_app ( body_ty , arg_value ) ? ) } , Value :: FunType ( ty_app_mode , _ , _ ) => Err ( TypeError :: UnexpectedAppMode { found : arg_app_mode . clone ( ) , expected : ty_app_mode . clone ( ) , } ) , _ => Err ( TypeError :: ExpectedFunType { found : fun_ty . clone ( ) , } ) , } } , Term :: RecordType ( ty_fields ) => { let mut context = context . clone ( ) ; let mut max_level = UniverseLevel ( 0 ) ; for ( _ , _ , ty ) in ty_fields { let ty_level = synth_universe ( & context , & ty ) ? ; context . local_bind ( context . eval ( & ty ) ? ) ; max_level = cmp :: max ( max_level , ty_level ) ; } Ok ( RcValue :: from ( Value :: Universe ( max_level ) ) ) } , Term :: RecordIntro ( intro_fields ) => { if intro_fields . is_empty ( ) { Ok ( RcValue :: from ( Value :: RecordTypeEmpty ) ) } else { Err ( TypeError :: AmbiguousTerm ( term . clone ( ) ) ) } } , Term :: RecordElim ( record , label ) => { let mut record_ty = synth_term ( context , record ) ? ; while let Value :: RecordTypeExtend ( _ , current_label , current_ty , rest ) = record_ty . as_ref ( ) { if label == current_label { return Ok ( current_ty . clone ( ) ) ; } else { let label = current_label . clone ( ) ; let expr = RcTerm :: from ( Term :: RecordElim ( record . clone ( ) , label ) ) ; record_ty = nbe :: do_closure_app ( rest , context . eval ( & expr ) ? ) ? ; } } Err ( TypeError :: NoFieldInType ( label . clone ( ) ) ) } , Term :: Universe ( level ) => Ok ( RcValue :: from ( Value :: Universe ( * level + 1 ) ) ) , } }
Synthesize the type of the term.
Synthesize the type of the term .
context
&Context
term
&RcTerm