diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index b800c2e32a9..7772fab796c 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -575,6 +575,9 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { let field_ty = field_def.map_or(self.err_ty(), |it| { field_types[it.local_id].clone().substitute(Interner, &substs) }); + // Field type might have some unknown types + // FIXME: we may want to emit a single type variable for all instance of type fields? + let field_ty = self.insert_type_vars(field_ty); self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty)); } if let Some(expr) = spread { diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index 21b962a48f2..38eae475b55 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -781,8 +781,16 @@ pub(super) fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { pub(super) fn insert_const_vars_shallow(&mut self, c: Const) -> Const { let data = c.data(Interner); match &data.value { - ConstValue::Concrete(cc) => match cc.interned { + ConstValue::Concrete(cc) => match &cc.interned { crate::ConstScalar::Unknown => self.new_const_var(data.ty.clone()), + // try to evaluate unevaluated const. Replace with new var if const eval failed. + crate::ConstScalar::UnevaluatedConst(id, subst) => { + if let Ok(eval) = self.db.const_eval(*id, subst.clone()) { + eval + } else { + self.new_const_var(data.ty.clone()) + } + } _ => c, }, _ => c, diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index 9f5f1ea3255..259f43e7e20 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -1837,3 +1837,58 @@ fn foo() { }", ); } + +#[test] +fn regression_14844() { + check_no_mismatches( + r#" +pub type Ty = Unknown; + +pub struct Inner(); + +pub struct Outer { + pub inner: Inner, +} + +fn main() { + _ = Outer { + inner: Inner::(), + }; +} + "#, + ); + check_no_mismatches( + r#" +pub const ONE: usize = 1; + +pub struct Inner(); + +pub struct Outer { + pub inner: Inner, +} + +fn main() { + _ = Outer { + inner: Inner::<1>(), + }; +} + "#, + ); + check_no_mismatches( + r#" +pub const ONE: usize = unknown(); + +pub struct Inner(); + +pub struct Outer { + pub inner: Inner, +} + +fn main() { + _ = Outer { + inner: Inner::<1>(), + }; +} + "#, + ); +} diff --git a/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/crates/ide-diagnostics/src/handlers/type_mismatch.rs index a5359741ac9..cc282bf9348 100644 --- a/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -644,6 +644,28 @@ fn h() { ); } + #[test] + fn evaluate_const_generics_in_types() { + check_diagnostics( + r#" +pub const ONE: usize = 1; + +pub struct Inner(); + +pub struct Outer { + pub inner: Inner, +} + +fn main() { + _ = Outer { + inner: Inner::<2>(), + //^^^^^^^^^^^^ error: expected Inner<1>, found Inner<2> + }; +} +"#, + ); + } + #[test] fn type_mismatch_pat_smoke_test() { check_diagnostics(