diff --git a/lang/driver/src/database.rs b/lang/driver/src/database.rs index 460762f94e..b928d14dcd 100644 --- a/lang/driver/src/database.rs +++ b/lang/driver/src/database.rs @@ -228,7 +228,7 @@ impl Database { let ust = self.ust(uri).map(|x| (*x).clone())?; let ast = elaborator::typechecker::check_with_lookup_table(Rc::new(ust), &info_table) .map(Arc::new) - .map_err(Error::Type); + .map_err(|arg| Error::Type(Box::new(arg))); self.ast.insert(uri.clone(), ast.clone()); ast } @@ -370,8 +370,8 @@ impl Database { match main { Some(exp) => { - let nf = exp.normalize_in_empty_env(&ast)?; - Ok(Some(nf)) + let nf = exp.normalize_in_empty_env(&ast); + nf.map(Some).map_err(|err| Error::Type(Box::new(err))) } None => Ok(None), } diff --git a/lang/driver/src/result.rs b/lang/driver/src/result.rs index ac58f9e02c..55ad0a8ffb 100644 --- a/lang/driver/src/result.rs +++ b/lang/driver/src/result.rs @@ -10,7 +10,7 @@ use url::Url; pub enum Error { Parser(#[from] parser::ParseError), Lowering(#[from] lowering::LoweringError), - Type(#[from] elaborator::result::TypeError), + Type(#[from] Box), Xfunc(#[from] transformations::result::XfuncError), Driver(#[from] DriverError), } diff --git a/lang/elaborator/src/result.rs b/lang/elaborator/src/result.rs index f5d33ef4fc..c2e083458d 100644 --- a/lang/elaborator/src/result.rs +++ b/lang/elaborator/src/result.rs @@ -35,6 +35,8 @@ pub enum TypeError { lhs_span: Option, #[label("Source of (2)")] rhs_span: Option, + #[label("Originating from")] + reason_span: Option, }, #[error("Cannot match on codata type {name}")] #[diagnostic(code("T-003"))] @@ -157,12 +159,13 @@ pub enum TypeError { } impl TypeError { - pub fn not_eq(lhs: &Exp, rhs: &Exp) -> Self { + pub fn not_eq(reason: &Option, lhs: &Exp, rhs: &Exp) -> Self { Self::NotEq { lhs: lhs.print_to_string(None), rhs: rhs.print_to_string(None), lhs_span: lhs.span().to_miette(), rhs_span: rhs.span().to_miette(), + reason_span: reason.to_miette(), } } diff --git a/lang/elaborator/src/typechecker/exprs/anno.rs b/lang/elaborator/src/typechecker/exprs/anno.rs index 7e8e720025..047dee32bc 100644 --- a/lang/elaborator/src/typechecker/exprs/anno.rs +++ b/lang/elaborator/src/typechecker/exprs/anno.rs @@ -16,7 +16,7 @@ impl CheckInfer for Anno { message: "Expected inferred type".to_owned(), span: None, })?; - convert(ctx.levels(), &mut ctx.meta_vars, inferred_typ, t)?; + convert(&self.span(), ctx.levels(), &mut ctx.meta_vars, inferred_typ, t)?; Ok(inferred_term) } diff --git a/lang/elaborator/src/typechecker/exprs/call.rs b/lang/elaborator/src/typechecker/exprs/call.rs index a6b68fc098..333ce9710f 100644 --- a/lang/elaborator/src/typechecker/exprs/call.rs +++ b/lang/elaborator/src/typechecker/exprs/call.rs @@ -25,7 +25,7 @@ impl CheckInfer for Call { message: "Expected inferred type".to_owned(), span: None, })?; - convert(ctx.levels(), &mut ctx.meta_vars, inferred_typ, t)?; + convert(&self.span(), ctx.levels(), &mut ctx.meta_vars, inferred_typ, t)?; Ok(inferred_term) } /// The *inference* rule for calls is: diff --git a/lang/elaborator/src/typechecker/exprs/dot_call.rs b/lang/elaborator/src/typechecker/exprs/dot_call.rs index 291a3ee058..ee7d383c47 100644 --- a/lang/elaborator/src/typechecker/exprs/dot_call.rs +++ b/lang/elaborator/src/typechecker/exprs/dot_call.rs @@ -24,7 +24,7 @@ impl CheckInfer for DotCall { message: "Expected inferred type".to_owned(), span: None, })?; - convert(ctx.levels(), &mut ctx.meta_vars, inferred_typ, t)?; + convert(&self.span(), ctx.levels(), &mut ctx.meta_vars, inferred_typ, t)?; Ok(inferred_term) } diff --git a/lang/elaborator/src/typechecker/exprs/local_match.rs b/lang/elaborator/src/typechecker/exprs/local_match.rs index a7d8f1e395..a12cce05ca 100644 --- a/lang/elaborator/src/typechecker/exprs/local_match.rs +++ b/lang/elaborator/src/typechecker/exprs/local_match.rs @@ -58,7 +58,7 @@ impl CheckInfer for LocalMatch { let mut motive_t = ret_typ.subst(&mut subst_ctx, &subst); motive_t.shift((-1, 0)); let motive_t_nf = motive_t.normalize(&ctx.module, &mut ctx.env())?; - convert(subst_ctx, &mut ctx.meta_vars, motive_t_nf, t)?; + convert(span, subst_ctx, &mut ctx.meta_vars, motive_t_nf, t)?; body_t = ctx.bind_single(&self_binder, |ctx| { ret_typ.normalize(&ctx.module, &mut ctx.env()) diff --git a/lang/elaborator/src/typechecker/exprs/typ_ctor.rs b/lang/elaborator/src/typechecker/exprs/typ_ctor.rs index ff1184079d..6dd9c929b2 100644 --- a/lang/elaborator/src/typechecker/exprs/typ_ctor.rs +++ b/lang/elaborator/src/typechecker/exprs/typ_ctor.rs @@ -22,7 +22,7 @@ impl CheckInfer for TypCtor { message: "Expected inferred type".to_owned(), span: None, })?; - convert(ctx.levels(), &mut ctx.meta_vars, inferred_typ, t)?; + convert(&self.span(), ctx.levels(), &mut ctx.meta_vars, inferred_typ, t)?; Ok(inferred_term) } diff --git a/lang/elaborator/src/typechecker/exprs/type_univ.rs b/lang/elaborator/src/typechecker/exprs/type_univ.rs index 1dfd4824d8..4dc2b915e2 100644 --- a/lang/elaborator/src/typechecker/exprs/type_univ.rs +++ b/lang/elaborator/src/typechecker/exprs/type_univ.rs @@ -19,7 +19,13 @@ impl CheckInfer for TypeUniv { /// P, Γ ⊢ Type ⇐ τ /// ``` fn check(&self, ctx: &mut Ctx, t: &Exp) -> Result { - convert(ctx.levels(), &mut ctx.meta_vars, Box::new(TypeUniv::new().into()), t)?; + convert( + &self.span(), + ctx.levels(), + &mut ctx.meta_vars, + Box::new(TypeUniv::new().into()), + t, + )?; Ok(self.clone()) } diff --git a/lang/elaborator/src/typechecker/exprs/variable.rs b/lang/elaborator/src/typechecker/exprs/variable.rs index 6b992b1547..f26e9a10cd 100644 --- a/lang/elaborator/src/typechecker/exprs/variable.rs +++ b/lang/elaborator/src/typechecker/exprs/variable.rs @@ -21,7 +21,7 @@ impl CheckInfer for Variable { message: "Expected inferred type".to_owned(), span: None, })?; - convert(ctx.levels(), &mut ctx.meta_vars, inferred_typ, t)?; + convert(&self.span(), ctx.levels(), &mut ctx.meta_vars, inferred_typ, t)?; Ok(inferred_term) } diff --git a/lang/elaborator/src/typechecker/util.rs b/lang/elaborator/src/typechecker/util.rs index 1be4ceeb72..4f92d7fbd2 100644 --- a/lang/elaborator/src/typechecker/util.rs +++ b/lang/elaborator/src/typechecker/util.rs @@ -1,3 +1,4 @@ +use codespan::Span; use log::trace; use ast::ctx::LevelCtx; @@ -20,6 +21,7 @@ pub fn uses_self(codata: &Codata) -> Result { } pub fn convert( + reason: &Option, ctx: LevelCtx, meta_vars: &mut HashMap, this: Box, @@ -32,7 +34,7 @@ pub fn convert( let res = unify(ctx, meta_vars, constraint, true)?; match res { crate::unifier::dec::Dec::Yes(_) => Ok(()), - crate::unifier::dec::Dec::No(_) => Err(TypeError::not_eq(&this, other)), + crate::unifier::dec::Dec::No(_) => Err(TypeError::not_eq(reason, &this, other)), } } diff --git a/test/test-runner/src/phases.rs b/test/test-runner/src/phases.rs index 6dad5adf2a..e3d9cafc17 100644 --- a/test/test-runner/src/phases.rs +++ b/test/test-runner/src/phases.rs @@ -363,10 +363,10 @@ impl Phase for Xfunc { let new_source = db.edited(uri, xfunc_out.edits); db.write_source(&new_uri, &new_source.to_string())?; db.ast(&new_uri).map_err(|err| { - driver::Error::Type(elaborator::result::TypeError::Impossible { + driver::Error::Type(Box::new(elaborator::result::TypeError::Impossible { message: format!("Failed to xfunc {type_name}: {err}"), span: None, - }) + })) })?; }