From 204a1561b2363f7583868f10939ed9427befdef9 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Thu, 7 Apr 2022 05:30:33 +0430 Subject: [PATCH] consider types of const generics --- crates/hir_ty/src/builder.rs | 4 ++ crates/hir_ty/src/consteval.rs | 23 ++++----- crates/hir_ty/src/infer/expr.rs | 3 +- crates/hir_ty/src/lib.rs | 29 +++-------- crates/hir_ty/src/lower.rs | 51 +++++++++++-------- .../src/handlers/type_mismatch.rs | 32 ++++++++++++ 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) -> 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 8729b52ae8b..923b30c34d1 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 + Fold>( 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 { 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 { 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 81134f666b5..6f624ce7fbc 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 { 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 + HasInterner>( }, |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 @@ -316,6 +316,38 @@ fn div(x: i32, y: i32) -> Option { ); } + #[test] + fn const_generic_type_mismatch() { + check_diagnostics( + r#" + pub struct Rate; + fn f() -> Rate { // 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); + fn run(t: Rate) { + } + fn main() { + run(Rate::<_, _, _>(5)); + } +"#, + ); + } + #[test] fn test_wrap_return_type_option_tails() { check_fix(