Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/lower_nextsolver.rs')
| -rw-r--r-- | crates/hir-ty/src/lower_nextsolver.rs | 201 |
1 files changed, 173 insertions, 28 deletions
diff --git a/crates/hir-ty/src/lower_nextsolver.rs b/crates/hir-ty/src/lower_nextsolver.rs index 84cd216b81..abca6b6bb9 100644 --- a/crates/hir-ty/src/lower_nextsolver.rs +++ b/crates/hir-ty/src/lower_nextsolver.rs @@ -17,6 +17,7 @@ use std::{ use base_db::Crate; use either::Either; +use hir_def::hir::generics::GenericParamDataRef; use hir_def::item_tree::FieldsShape; use hir_def::{ AdtId, AssocItemId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, @@ -35,11 +36,11 @@ use hir_def::{ TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId, }, }; -use hir_def::{ConstId, StaticId}; +use hir_def::{ConstId, LifetimeParamId, StaticId, TypeParamId}; use hir_expand::name::Name; -use intern::sym; +use intern::{Symbol, sym}; use la_arena::{Arena, ArenaMap, Idx}; -use path::{PathDiagnosticCallback, PathLoweringContext, builtin}; +use path::{PathDiagnosticCallback, PathLoweringContext}; use rustc_ast_ir::Mutability; use rustc_hash::FxHashSet; use rustc_pattern_analysis::Captures; @@ -50,16 +51,18 @@ use rustc_type_ir::{ TypeVisitableExt, inherent::{GenericArg as _, GenericArgs as _, IntoKind as _, Region as _, SliceLike, Ty as _}, }; +use rustc_type_ir::{TypeFoldable, TypeFolder, Upcast}; use salsa::plumbing::AsId; use smallvec::{SmallVec, smallvec}; use stdx::never; use triomphe::Arc; use crate::ValueTyDefId; +use crate::next_solver::ParamConst; use crate::{ FnAbi, ImplTraitId, Interner, ParamKind, TraitEnvironment, TyDefId, TyLoweringDiagnostic, TyLoweringDiagnosticKind, - consteval_nextsolver::{intern_const_ref, path_to_const, unknown_const_as_generic}, + consteval::{intern_const_ref, path_to_const, unknown_const_as_generic}, db::HirDatabase, generics::{Generics, generics, trait_self_param_idx}, lower::{Diagnostics, PathDiagnosticCallbackData, create_diagnostics}, @@ -79,11 +82,11 @@ pub struct ImplTraits<'db> { } #[derive(PartialEq, Eq, Debug, Hash)] -pub(crate) struct ImplTrait<'db> { +pub struct ImplTrait<'db> { pub(crate) predicates: Vec<Clause<'db>>, } -pub(crate) type ImplTraitIdx<'db> = Idx<ImplTrait<'db>>; +pub type ImplTraitIdx<'db> = Idx<ImplTrait<'db>>; #[derive(Debug, Default)] struct ImplTraitLoweringState<'db> { @@ -102,7 +105,7 @@ impl<'db> ImplTraitLoweringState<'db> { } #[derive(Debug, Clone)] -pub(crate) enum LifetimeElisionKind<'db> { +pub enum LifetimeElisionKind<'db> { /// Create a new anonymous lifetime parameter and reference it. /// /// If `report_in_path`, report an error when encountering lifetime elision in a path: @@ -171,7 +174,7 @@ impl<'db> LifetimeElisionKind<'db> { } #[derive(Debug)] -pub(crate) struct TyLoweringContext<'db, 'a> { +pub struct TyLoweringContext<'db, 'a> { pub db: &'db dyn HirDatabase, interner: DbInterner<'db>, resolver: &'a Resolver<'db>, @@ -184,10 +187,12 @@ pub(crate) struct TyLoweringContext<'db, 'a> { pub(crate) unsized_types: FxHashSet<Ty<'db>>, pub(crate) diagnostics: Vec<TyLoweringDiagnostic>, lifetime_elision: LifetimeElisionKind<'db>, + /// We disallow referencing generic parameters that have an index greater than or equal to this number. + disallow_params_after: u32, } impl<'db, 'a> TyLoweringContext<'db, 'a> { - pub(crate) fn new( + pub fn new( db: &'db dyn HirDatabase, resolver: &'a Resolver<'db>, store: &'a ExpressionStore, @@ -208,6 +213,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { unsized_types: FxHashSet::default(), diagnostics: Vec::new(), lifetime_elision, + disallow_params_after: u32::MAX, } } @@ -243,6 +249,10 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { self } + pub(crate) fn disallow_params_after(&mut self, after: u32) { + self.disallow_params_after = after; + } + pub(crate) fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) { self.diagnostics.push(TyLoweringDiagnostic { source: type_ref, kind }); } @@ -261,11 +271,11 @@ pub(crate) enum ImplTraitLoweringMode { } impl<'db, 'a> TyLoweringContext<'db, 'a> { - pub(crate) fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> { + pub fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> { self.lower_ty_ext(type_ref).0 } - pub(crate) fn lower_const(&mut self, const_ref: &ConstRef, const_type: Ty<'db>) -> Const<'db> { + pub(crate) fn lower_const(&mut self, const_ref: ConstRef, const_type: Ty<'db>) -> Const<'db> { let const_ref = &self.store[const_ref.expr]; match const_ref { hir_def::hir::Expr::Path(path) => { @@ -323,8 +333,35 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { self.generics.get_or_init(|| generics(self.db, self.def)) } + fn type_param(&mut self, id: TypeParamId, index: u32, name: Symbol) -> Ty<'db> { + if index >= self.disallow_params_after { + // FIXME: Report an error. + Ty::new_error(self.interner, ErrorGuaranteed) + } else { + Ty::new_param(self.interner, id, index, name) + } + } + + fn const_param(&mut self, id: ConstParamId, index: u32) -> Const<'db> { + if index >= self.disallow_params_after { + // FIXME: Report an error. + Const::error(self.interner) + } else { + Const::new_param(self.interner, ParamConst { id, index }) + } + } + + fn region_param(&mut self, id: LifetimeParamId, index: u32) -> Region<'db> { + if index >= self.disallow_params_after { + // FIXME: Report an error. + Region::error(self.interner) + } else { + Region::new_early_param(self.interner, EarlyParamRegion { id, index }) + } + } + #[tracing::instrument(skip(self), ret)] - pub(crate) fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty<'db>, Option<TypeNs>) { + pub fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty<'db>, Option<TypeNs>) { let interner = self.interner; let mut res = None; let type_ref = &self.store[type_ref_id]; @@ -351,8 +388,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { TypeOrConstParamData::TypeParamData(ty) => ty, _ => unreachable!(), }; - Ty::new_param( - self.interner, + self.type_param( type_param_id, idx as u32, type_data @@ -367,7 +403,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } TypeRef::Array(array) => { let inner_ty = self.lower_ty(array.ty); - let const_len = self.lower_const(&array.len, Ty::new_usize(interner)); + let const_len = self.lower_const(array.len, Ty::new_usize(interner)); Ty::new_array_with_const_len(interner, inner_ty, const_len) } &TypeRef::Slice(inner) => { @@ -491,7 +527,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } #[inline] - fn on_path_diagnostic_callback(type_ref: TypeRefId) -> PathDiagnosticCallback<'static, 'db> { + fn on_path_diagnostic_callback<'b>(type_ref: TypeRefId) -> PathDiagnosticCallback<'b, 'db> { PathDiagnosticCallback { data: Either::Left(PathDiagnosticCallbackData(type_ref)), callback: |data, this, diag| { @@ -515,7 +551,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { if let Some(type_ref) = path.type_anchor() { let (ty, res) = self.lower_ty_ext(type_ref); let mut ctx = self.at_path(path_id); - return ctx.lower_ty_relative_path(ty, res); + return ctx.lower_ty_relative_path(ty, res, false); } let mut ctx = self.at_path(path_id); @@ -545,7 +581,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { TypeNs::TraitId(tr) => tr, _ => return None, }; - Some((ctx.lower_trait_ref_from_resolved_path(resolved, explicit_self_ty), ctx)) + Some((ctx.lower_trait_ref_from_resolved_path(resolved, explicit_self_ty, false), ctx)) } fn lower_trait_ref( @@ -869,7 +905,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { ImplTrait { predicates } } - pub(crate) fn lower_lifetime(&self, lifetime: LifetimeRefId) -> Region<'db> { + pub(crate) fn lower_lifetime(&mut self, lifetime: LifetimeRefId) -> Region<'db> { match self.resolver.resolve_lifetime(&self.store[lifetime]) { Some(resolution) => match resolution { LifetimeNs::Static => Region::new_static(self.interner), @@ -878,10 +914,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { None => return Region::error(self.interner), Some(idx) => idx, }; - Region::new_early_param( - self.interner, - EarlyParamRegion { index: idx as u32, id }, - ) + self.region_param(id, idx as u32) } }, None => Region::error(self.interner), @@ -980,10 +1013,10 @@ pub(crate) fn type_alias_impl_traits<'db>( pub(crate) fn ty_query<'db>(db: &'db dyn HirDatabase, def: TyDefId) -> EarlyBinder<'db, Ty<'db>> { let interner = DbInterner::new_with(db, None, None); match def { - TyDefId::BuiltinType(it) => EarlyBinder::bind(builtin(interner, it)), + TyDefId::BuiltinType(it) => EarlyBinder::bind(Ty::from_builtin_type(interner, it)), TyDefId::AdtId(it) => EarlyBinder::bind(Ty::new_adt( interner, - AdtDef::new(it, interner), + it, GenericArgs::identity_for_item(interner, it.into()), )), TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0, @@ -1368,6 +1401,7 @@ pub(crate) fn generic_predicates_for_param_cycle_result( pub struct GenericPredicates<'db>(Option<Arc<[Clause<'db>]>>); impl<'db> GenericPredicates<'db> { + #[inline] pub fn instantiate( &self, interner: DbInterner<'db>, @@ -1377,6 +1411,11 @@ impl<'db> GenericPredicates<'db> { .as_ref() .map(|it| EarlyBinder::bind(it.iter().copied()).iter_instantiated(interner, args)) } + + #[inline] + pub fn instantiate_identity(&self) -> Option<impl Iterator<Item = Clause<'db>>> { + self.0.as_ref().map(|it| it.iter().copied()) + } } impl<'db> ops::Deref for GenericPredicates<'db> { @@ -1425,8 +1464,7 @@ pub(crate) fn trait_environment_query<'db>( for pred in maybe_parent_generics.where_predicates() { for pred in ctx.lower_where_predicate(pred, false, &generics, PredicateFilter::All) { if let rustc_type_ir::ClauseKind::Trait(tr) = pred.kind().skip_binder() { - traits_in_scope - .push((convert_ty_for_result(interner, tr.self_ty()), tr.def_id().0)); + traits_in_scope.push((tr.self_ty(), tr.def_id().0)); } clauses.push(pred); } @@ -1748,6 +1786,113 @@ pub(crate) fn lower_generic_arg<'a, 'db, T>( } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct GenericDefaults<'db>( + Option<Arc<[Option<EarlyBinder<'db, crate::next_solver::GenericArg<'db>>>]>>, +); + +impl<'db> GenericDefaults<'db> { + #[inline] + pub fn get(&self, idx: usize) -> Option<EarlyBinder<'db, crate::next_solver::GenericArg<'db>>> { + self.0.as_ref()?[idx] + } +} + +pub(crate) fn generic_defaults_query( + db: &dyn HirDatabase, + def: GenericDefId, +) -> GenericDefaults<'_> { + db.generic_defaults_ns_with_diagnostics(def).0 +} + +/// Resolve the default type params from generics. +/// +/// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents). +pub(crate) fn generic_defaults_with_diagnostics_query( + db: &dyn HirDatabase, + def: GenericDefId, +) -> (GenericDefaults<'_>, Diagnostics) { + let generic_params = generics(db, def); + if generic_params.is_empty() { + return (GenericDefaults(None), None); + } + let resolver = def.resolver(db); + + let mut ctx = TyLoweringContext::new( + db, + &resolver, + generic_params.store(), + def, + LifetimeElisionKind::AnonymousReportError, + ) + .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed); + let mut idx = 0; + let mut has_any_default = false; + let mut defaults = generic_params + .iter_parents_with_store() + .map(|((id, p), store)| { + ctx.store = store; + let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params); + has_any_default |= has_default; + idx += 1; + result + }) + .collect::<Vec<_>>(); + ctx.diagnostics.clear(); // Don't include diagnostics from the parent. + defaults.extend(generic_params.iter_self().map(|(id, p)| { + let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params); + has_any_default |= has_default; + idx += 1; + result + })); + let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics)); + let defaults = if has_any_default { + GenericDefaults(Some(Arc::from_iter(defaults))) + } else { + GenericDefaults(None) + }; + return (defaults, diagnostics); + + fn handle_generic_param<'db>( + ctx: &mut TyLoweringContext<'db, '_>, + idx: usize, + id: GenericParamId, + p: GenericParamDataRef<'_>, + generic_params: &Generics, + ) -> (Option<EarlyBinder<'db, crate::next_solver::GenericArg<'db>>>, bool) { + // Each default can only refer to previous parameters. + // Type variable default referring to parameter coming + // after it is forbidden. + ctx.disallow_params_after(idx as u32); + match p { + GenericParamDataRef::TypeParamData(p) => { + let ty = p.default.map(|ty| ctx.lower_ty(ty)); + (ty.map(|ty| EarlyBinder::bind(ty.into())), p.default.is_some()) + } + GenericParamDataRef::ConstParamData(p) => { + let GenericParamId::ConstParamId(id) = id else { + unreachable!("Unexpected lifetime or type argument") + }; + + let mut val = p.default.map(|c| { + let param_ty = ctx.lower_ty(p.ty); + let c = ctx.lower_const(c, param_ty); + c.into() + }); + (val.map(EarlyBinder::bind), p.default.is_some()) + } + GenericParamDataRef::LifetimeParamData(_) => (None, false), + } + } +} + +pub(crate) fn generic_defaults_with_diagnostics_cycle_result( + _db: &dyn HirDatabase, + _def: GenericDefId, +) -> (GenericDefaults<'_>, Diagnostics) { + (GenericDefaults(None), None) +} + /// Build the signature of a callable item (function, struct or enum variant). pub(crate) fn callable_item_signature_query<'db>( db: &'db dyn HirDatabase, @@ -1804,7 +1949,7 @@ fn fn_sig_for_fn<'db>( fn type_for_adt<'db>(db: &'db dyn HirDatabase, adt: AdtId) -> EarlyBinder<'db, Ty<'db>> { let interner = DbInterner::new_with(db, None, None); let args = GenericArgs::identity_for_item(interner, adt.into()); - let ty = Ty::new_adt(interner, AdtDef::new(adt, interner), args); + let ty = Ty::new_adt(interner, adt, args); EarlyBinder::bind(ty) } |