diff options
| author | hkalbasi <hamidrezakalbasi@protonmail.com> | 2023-05-25 19:37:04 +0330 |
|---|---|---|
| committer | hkalbasi <hamidrezakalbasi@protonmail.com> | 2023-05-25 19:37:20 +0330 |
| commit | 7ef185d65ea8da681f0f89ab4785c45f25cfaf91 (patch) | |
| tree | 5cddf702253015b6af603e5546efa96ac4a0f93a | |
| parent | efd3094aba281de248f48e67b5b93bf2c557e16c (diff) | |
| download | rust-7ef185d65ea8da681f0f89ab4785c45f25cfaf91.tar.gz rust-7ef185d65ea8da681f0f89ab4785c45f25cfaf91.zip | |
evaluate `UnevaluatedConst` in unify
| -rw-r--r-- | crates/hir-ty/src/infer/expr.rs | 3 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/unify.rs | 10 | ||||
| -rw-r--r-- | crates/hir-ty/src/tests/regression.rs | 55 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/type_mismatch.rs | 22 |
4 files changed, 89 insertions, 1 deletions
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 @@ impl<'a> InferenceContext<'a> { 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 @@ impl<'a> InferenceTable<'a> { 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<T>(); + +pub struct Outer { + pub inner: Inner<Ty>, +} + +fn main() { + _ = Outer { + inner: Inner::<i32>(), + }; +} + "#, + ); + check_no_mismatches( + r#" +pub const ONE: usize = 1; + +pub struct Inner<const P: usize>(); + +pub struct Outer { + pub inner: Inner<ONE>, +} + +fn main() { + _ = Outer { + inner: Inner::<1>(), + }; +} + "#, + ); + check_no_mismatches( + r#" +pub const ONE: usize = unknown(); + +pub struct Inner<const P: usize>(); + +pub struct Outer { + pub inner: Inner<ONE>, +} + +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 @@ -645,6 +645,28 @@ fn h() { } #[test] + fn evaluate_const_generics_in_types() { + check_diagnostics( + r#" +pub const ONE: usize = 1; + +pub struct Inner<const P: usize>(); + +pub struct Outer { + pub inner: Inner<ONE>, +} + +fn main() { + _ = Outer { + inner: Inner::<2>(), + //^^^^^^^^^^^^ error: expected Inner<1>, found Inner<2> + }; +} +"#, + ); + } + + #[test] fn type_mismatch_pat_smoke_test() { check_diagnostics( r#" |
