about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_ty/src/builder.rs4
-rw-r--r--crates/hir_ty/src/consteval.rs23
-rw-r--r--crates/hir_ty/src/infer/expr.rs3
-rw-r--r--crates/hir_ty/src/lib.rs29
-rw-r--r--crates/hir_ty/src/lower.rs51
-rw-r--r--crates/ide_diagnostics/src/handlers/type_mismatch.rs32
6 files changed, 86 insertions, 56 deletions
diff --git a/crates/hir_ty/src/builder.rs b/crates/hir_ty/src/builder.rs
index 5c77c0cdf8b..8c47e9ce1cb 100644
--- a/crates/hir_ty/src/builder.rs
+++ b/crates/hir_ty/src/builder.rs
@@ -154,6 +154,10 @@ impl TyBuilder<()> {
         TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner)
     }
 
+    pub fn usize() -> Ty {
+        TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(Interner)
+    }
+
     pub fn fn_ptr(sig: CallableSig) -> Ty {
         TyKind::Function(sig.to_fn_ptr()).intern(Interner)
     }
diff --git a/crates/hir_ty/src/consteval.rs b/crates/hir_ty/src/consteval.rs
index 009ea008fcb..4b58262dace 100644
--- a/crates/hir_ty/src/consteval.rs
+++ b/crates/hir_ty/src/consteval.rs
@@ -20,7 +20,7 @@ use stdx::never;
 use crate::{
     db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode, to_placeholder_idx,
     utils::Generics, Const, ConstData, ConstValue, GenericArg, InferenceResult, Interner, Ty,
-    TyKind,
+    TyBuilder, TyKind,
 };
 
 /// Extension trait for [`Const`]
@@ -401,23 +401,22 @@ pub fn unknown_const(ty: Ty) -> Const {
     .intern(Interner)
 }
 
-pub fn unknown_const_usize() -> Const {
-    unknown_const(TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(Interner))
-}
-
 pub fn unknown_const_as_generic(ty: Ty) -> GenericArg {
     GenericArgData::Const(unknown_const(ty)).intern(Interner)
 }
 
+/// Interns a constant scalar with the given type
+pub fn intern_scalar_const(value: ConstScalar, ty: Ty) -> Const {
+    ConstData { ty, value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: value }) }
+        .intern(Interner)
+}
+
 /// Interns a possibly-unknown target usize
 pub fn usize_const(value: Option<u64>) -> Const {
-    ConstData {
-        ty: TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(Interner),
-        value: ConstValue::Concrete(chalk_ir::ConcreteConst {
-            interned: value.map(ConstScalar::Usize).unwrap_or(ConstScalar::Unknown),
-        }),
-    }
-    .intern(Interner)
+    intern_scalar_const(
+        value.map(ConstScalar::Usize).unwrap_or(ConstScalar::Unknown),
+        TyBuilder::usize(),
+    )
 }
 
 pub(crate) fn const_eval_recover(
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index fc88e97d6ab..7426a22e6af 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -1129,10 +1129,11 @@ impl<'a> InferenceContext<'a> {
                     arg,
                     self,
                     |this, type_ref| this.make_ty(type_ref),
-                    |this, c| {
+                    |this, c, ty| {
                         const_or_path_to_chalk(
                             this.db,
                             &this.resolver,
+                            ty,
                             c,
                             ParamLoweringMode::Placeholder,
                             || generics(this.db.upcast(), (&this.resolver).generic_def().unwrap()),
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 225bcdd25e1..85d8ccc0772 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -35,17 +35,13 @@ use std::sync::Arc;
 use chalk_ir::{
     fold::{Fold, Shift},
     interner::HasInterner,
-    NoSolution, UintTy,
-};
-use hir_def::{
-    expr::ExprId,
-    type_ref::{ConstScalar, Rawness},
-    TypeOrConstParamId,
+    NoSolution,
 };
+use hir_def::{expr::ExprId, type_ref::Rawness, TypeOrConstParamId};
 use itertools::Either;
 use utils::Generics;
 
-use crate::{db::HirDatabase, utils::generics};
+use crate::{consteval::unknown_const, db::HirDatabase, utils::generics};
 
 pub use autoderef::autoderef;
 pub use builder::{ParamKind, TyBuilder};
@@ -303,17 +299,6 @@ pub fn static_lifetime() -> Lifetime {
     LifetimeData::Static.intern(Interner)
 }
 
-pub fn dummy_usize_const() -> Const {
-    let usize_ty = chalk_ir::TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner);
-    chalk_ir::ConstData {
-        ty: usize_ty,
-        value: chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
-            interned: ConstScalar::Unknown,
-        }),
-    }
-    .intern(Interner)
-}
-
 pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + Fold<Interner>>(
     t: T,
     for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
@@ -476,27 +461,27 @@ where
 
         fn fold_inference_const(
             &mut self,
-            _ty: Ty,
+            ty: Ty,
             _var: InferenceVar,
             _outer_binder: DebruijnIndex,
         ) -> Fallible<Const> {
             if cfg!(debug_assertions) {
                 Err(NoSolution)
             } else {
-                Ok(dummy_usize_const())
+                Ok(unknown_const(ty))
             }
         }
 
         fn fold_free_var_const(
             &mut self,
-            _ty: Ty,
+            ty: Ty,
             _bound_var: BoundVar,
             _outer_binder: DebruijnIndex,
         ) -> Fallible<Const> {
             if cfg!(debug_assertions) {
                 Err(NoSolution)
             } else {
-                Ok(dummy_usize_const())
+                Ok(unknown_const(ty))
             }
         }
 
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 373196969a3..ca6241c5d1a 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -37,11 +37,12 @@ use smallvec::SmallVec;
 use stdx::{impl_from, never};
 use syntax::{ast, SmolStr};
 
-use crate::consteval::{path_to_const, unknown_const_as_generic, unknown_const_usize, usize_const};
+use crate::consteval::{
+    intern_scalar_const, path_to_const, unknown_const, unknown_const_as_generic,
+};
 use crate::utils::Generics;
 use crate::{all_super_traits, make_binders, Const, GenericArgData, ParamKind};
 use crate::{
-    consteval,
     db::HirDatabase,
     mapping::ToChalk,
     static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
@@ -202,6 +203,7 @@ impl<'a> TyLoweringContext<'a> {
                 let const_len = const_or_path_to_chalk(
                     self.db,
                     self.resolver,
+                    TyBuilder::usize(),
                     len,
                     self.type_param_mode,
                     || self.generics(),
@@ -677,12 +679,13 @@ impl<'a> TyLoweringContext<'a> {
             parent_params + self_params + type_params + const_params + impl_trait_params;
 
         let ty_error = GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner);
-        let const_error = GenericArgData::Const(consteval::usize_const(None)).intern(Interner);
 
-        for (_, data) in def_generics.iter().take(parent_params) {
-            match data {
-                TypeOrConstParamData::TypeParamData(_) => substs.push(ty_error.clone()),
-                TypeOrConstParamData::ConstParamData(_) => substs.push(const_error.clone()),
+        for eid in def_generics.iter_id().take(parent_params) {
+            match eid {
+                Either::Left(_) => substs.push(ty_error.clone()),
+                Either::Right(x) => {
+                    substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
+                }
             }
         }
 
@@ -722,10 +725,11 @@ impl<'a> TyLoweringContext<'a> {
                     arg,
                     &mut (),
                     |_, type_ref| self.lower_ty(type_ref),
-                    |_, c| {
+                    |_, c, ty| {
                         const_or_path_to_chalk(
                             self.db,
                             &self.resolver,
+                            ty,
                             c,
                             self.type_param_mode,
                             || self.generics(),
@@ -759,10 +763,12 @@ impl<'a> TyLoweringContext<'a> {
 
         // add placeholders for args that were not provided
         // FIXME: emit diagnostics in contexts where this is not allowed
-        for (_, data) in def_generics.iter().skip(substs.len()) {
-            match data {
-                TypeOrConstParamData::TypeParamData(_) => substs.push(ty_error.clone()),
-                TypeOrConstParamData::ConstParamData(_) => substs.push(const_error.clone()),
+        for eid in def_generics.iter_id().skip(substs.len()) {
+            match eid {
+                Either::Left(_) => substs.push(ty_error.clone()),
+                Either::Right(x) => {
+                    substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
+                }
             }
         }
         assert_eq!(substs.len(), total_len);
@@ -1642,7 +1648,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
     arg: &'a GenericArg,
     this: &mut T,
     for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a,
-    for_const: impl FnOnce(&mut T, &ConstScalarOrPath) -> Const + 'a,
+    for_const: impl FnOnce(&mut T, &ConstScalarOrPath, Ty) -> Const + 'a,
 ) -> Option<crate::GenericArg> {
     let kind = match kind_id {
         Either::Left(_) => ParamKind::Type,
@@ -1656,13 +1662,13 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
             let ty = for_type(this, type_ref);
             GenericArgData::Ty(ty).intern(Interner)
         }
-        (GenericArg::Const(c), ParamKind::Const(_)) => {
-            GenericArgData::Const(for_const(this, c)).intern(Interner)
+        (GenericArg::Const(c), ParamKind::Const(c_ty)) => {
+            GenericArgData::Const(for_const(this, c, c_ty)).intern(Interner)
         }
         (GenericArg::Const(_), ParamKind::Type) => {
             GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
         }
-        (GenericArg::Type(t), ParamKind::Const(ty)) => {
+        (GenericArg::Type(t), ParamKind::Const(c_ty)) => {
             // We want to recover simple idents, which parser detects them
             // as types. Maybe here is not the best place to do it, but
             // it works.
@@ -1671,11 +1677,13 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
                 if p.kind == PathKind::Plain {
                     if let [n] = p.segments() {
                         let c = ConstScalarOrPath::Path(n.clone());
-                        return Some(GenericArgData::Const(for_const(this, &c)).intern(Interner));
+                        return Some(
+                            GenericArgData::Const(for_const(this, &c, c_ty)).intern(Interner),
+                        );
                     }
                 }
             }
-            unknown_const_as_generic(ty)
+            unknown_const_as_generic(c_ty)
         }
         (GenericArg::Lifetime(_), _) => return None,
     })
@@ -1684,17 +1692,18 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
 pub(crate) fn const_or_path_to_chalk(
     db: &dyn HirDatabase,
     resolver: &Resolver,
+    expected_ty: Ty,
     value: &ConstScalarOrPath,
     mode: ParamLoweringMode,
     args: impl FnOnce() -> Generics,
     debruijn: DebruijnIndex,
 ) -> Const {
     match value {
-        ConstScalarOrPath::Scalar(s) => usize_const(s.as_usize()),
+        ConstScalarOrPath::Scalar(s) => intern_scalar_const(s.clone(), expected_ty),
         ConstScalarOrPath::Path(n) => {
             let path = ModPath::from_segments(PathKind::Plain, Some(n.clone()));
             path_to_const(db, resolver, &path, mode, args, debruijn)
-                .unwrap_or_else(|| unknown_const_usize())
+                .unwrap_or_else(|| unknown_const(expected_ty))
         }
     }
 }
@@ -1716,7 +1725,7 @@ fn fallback_bound_vars<T: Fold<Interner> + HasInterner<Interner = Interner>>(
         },
         |ty, bound, binders| {
             if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
-                consteval::unknown_const(ty.clone())
+                unknown_const(ty.clone())
             } else {
                 bound.shifted_in_from(binders).to_const(Interner, ty)
             }
diff --git a/crates/ide_diagnostics/src/handlers/type_mismatch.rs b/crates/ide_diagnostics/src/handlers/type_mismatch.rs
index 1b275f7e6cb..442268d1352 100644
--- a/crates/ide_diagnostics/src/handlers/type_mismatch.rs
+++ b/crates/ide_diagnostics/src/handlers/type_mismatch.rs
@@ -317,6 +317,38 @@ fn div(x: i32, y: i32) -> Option<i32> {
     }
 
     #[test]
+    fn const_generic_type_mismatch() {
+        check_diagnostics(
+            r#"
+            pub struct Rate<const N: u32>;
+            fn f<const N: u64>() -> Rate<N> { // FIXME: add some error
+                loop {}
+            }
+            fn run(t: Rate<5>) {
+            }
+            fn main() {
+                run(f()) // FIXME: remove this error
+                  //^^^ error: expected Rate<5>, found Rate<_>
+            }
+"#,
+        );
+    }
+
+    #[test]
+    fn const_generic_unknown() {
+        check_diagnostics(
+            r#"
+            pub struct Rate<T, const NOM: u32, const DENOM: u32>(T);
+            fn run(t: Rate<u32, 1, 1>) {
+            }
+            fn main() {
+                run(Rate::<_, _, _>(5));
+            }
+"#,
+        );
+    }
+
+    #[test]
     fn test_wrap_return_type_option_tails() {
         check_fix(
             r#"