Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/lower.rs')
| -rw-r--r-- | crates/hir-ty/src/lower.rs | 271 |
1 files changed, 143 insertions, 128 deletions
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 25ccc84c13..4d0516ead6 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -15,7 +15,10 @@ use base_db::{ CrateId, }; use chalk_ir::{ - cast::Cast, fold::Shift, fold::TypeFoldable, interner::HasInterner, Mutability, Safety, + cast::Cast, + fold::{Shift, TypeFoldable}, + interner::HasInterner, + Mutability, Safety, TypeOutlives, }; use either::Either; @@ -59,14 +62,14 @@ use crate::{ mapping::{from_chalk_trait_id, lt_to_placeholder_idx, ToChalk}, static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, utils::{ - all_super_trait_refs, associated_type_by_name_including_super_traits, generics, Generics, - InTypeConstIdMetadata, + self, all_super_trait_refs, associated_type_by_name_including_super_traits, generics, + Generics, InTypeConstIdMetadata, }, AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy, FnAbi, FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, - LifetimeData, ParamKind, PolyFnSig, ProjectionTy, QuantifiedWhereClause, - QuantifiedWhereClauses, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, - TyKind, WhereClause, + LifetimeData, LifetimeOutlives, ParamKind, PolyFnSig, ProgramClause, ProjectionTy, + QuantifiedWhereClause, QuantifiedWhereClauses, Substitution, TraitEnvironment, TraitRef, + TraitRefExt, Ty, TyBuilder, TyKind, WhereClause, }; #[derive(Debug)] @@ -242,13 +245,8 @@ impl<'a> TyLoweringContext<'a> { ) } - fn generics(&self) -> Generics { - generics( - self.db.upcast(), - self.resolver - .generic_def() - .expect("there should be generics if there's a generic param"), - ) + fn generics(&self) -> Option<Generics> { + Some(generics(self.db.upcast(), self.resolver.generic_def()?)) } pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) { @@ -282,7 +280,7 @@ impl<'a> TyLoweringContext<'a> { let inner_ty = self.lower_ty(inner); // FIXME: It should infer the eldided lifetimes instead of stubbing with static let lifetime = - lifetime.as_ref().map_or_else(static_lifetime, |lr| self.lower_lifetime(lr)); + lifetime.as_ref().map_or_else(error_lifetime, |lr| self.lower_lifetime(lr)); TyKind::Ref(lower_to_chalk_mutability(*mutability), lifetime, inner_ty) .intern(Interner) } @@ -318,7 +316,7 @@ impl<'a> TyLoweringContext<'a> { // place even if we encounter more opaque types while // lowering the bounds let idx = opaque_type_data.borrow_mut().alloc(ImplTrait { - bounds: crate::make_single_type_binders(Vec::new()), + bounds: crate::make_single_type_binders(Vec::default()), }); // We don't want to lower the bounds inside the binders // we're currently in, because they don't end up inside @@ -349,8 +347,7 @@ impl<'a> TyLoweringContext<'a> { let idx = counter.get(); // FIXME we're probably doing something wrong here counter.set(idx + count_impl_traits(type_ref) as u16); - if let Some(def) = self.resolver.generic_def() { - let generics = generics(self.db.upcast(), def); + if let Some(generics) = self.generics() { let param = generics .iter() .filter(|(_, data)| { @@ -385,8 +382,7 @@ impl<'a> TyLoweringContext<'a> { const_params, _impl_trait_params, _lifetime_params, - ) = if let Some(def) = self.resolver.generic_def() { - let generics = generics(self.db.upcast(), def); + ) = if let Some(generics) = self.generics() { generics.provenance_split() } else { (0, 0, 0, 0, 0, 0) @@ -574,44 +570,40 @@ impl<'a> TyLoweringContext<'a> { // FIXME(trait_alias): Implement trait alias. return (TyKind::Error.intern(Interner), None); } - TypeNs::GenericParam(param_id) => { - let generics = generics( - self.db.upcast(), - self.resolver.generic_def().expect("generics in scope"), - ); - match self.type_param_mode { - ParamLoweringMode::Placeholder => { - TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into())) - } - ParamLoweringMode::Variable => { - let idx = match generics.param_idx(param_id.into()) { - None => { - never!("no matching generics"); - return (TyKind::Error.intern(Interner), None); - } - Some(idx) => idx, - }; + TypeNs::GenericParam(param_id) => match self.type_param_mode { + ParamLoweringMode::Placeholder => { + TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into())) + } + ParamLoweringMode::Variable => { + let idx = match self + .generics() + .expect("generics in scope") + .type_or_const_param_idx(param_id.into()) + { + None => { + never!("no matching generics"); + return (TyKind::Error.intern(Interner), None); + } + Some(idx) => idx, + }; - TyKind::BoundVar(BoundVar::new(self.in_binders, idx)) - } + TyKind::BoundVar(BoundVar::new(self.in_binders, idx)) } - .intern(Interner) } + .intern(Interner), TypeNs::SelfType(impl_id) => { - let def = - self.resolver.generic_def().expect("impl should have generic param scope"); - let generics = generics(self.db.upcast(), def); + let generics = self.generics().expect("impl should have generic param scope"); match self.type_param_mode { ParamLoweringMode::Placeholder => { // `def` can be either impl itself or item within, and we need impl itself // now. - let generics = generics.parent_generics().unwrap_or(&generics); + let generics = generics.parent_or_self(); let subst = generics.placeholder_subst(self.db); self.db.impl_self_ty(impl_id).substitute(Interner, &subst) } ParamLoweringMode::Variable => { - let starting_from = match def { + let starting_from = match generics.def() { GenericDefId::ImplId(_) => 0, // `def` is an item within impl. We need to substitute `BoundVar`s but // remember that they are for parent (i.e. impl) generic params so they @@ -679,12 +671,12 @@ impl<'a> TyLoweringContext<'a> { } fn select_associated_type(&self, res: Option<TypeNs>, segment: PathSegment<'_>) -> Ty { - let Some((def, res)) = self.resolver.generic_def().zip(res) else { + let Some((generics, res)) = self.generics().zip(res) else { return TyKind::Error.intern(Interner); }; let ty = named_associated_type_shorthand_candidates( self.db, - def, + generics.def(), res, Some(segment.name.clone()), move |name, t, associated_ty| { @@ -696,7 +688,6 @@ impl<'a> TyLoweringContext<'a> { let parent_subst = match self.type_param_mode { ParamLoweringMode::Placeholder => { // if we're lowering to placeholders, we have to put them in now. - let generics = generics(self.db.upcast(), def); let s = generics.placeholder_subst(self.db); s.apply(parent_subst, Interner) } @@ -718,7 +709,7 @@ impl<'a> TyLoweringContext<'a> { None, ); - let len_self = generics(self.db.upcast(), associated_ty.into()).len_self(); + let len_self = utils::generics(self.db.upcast(), associated_ty.into()).len_self(); let substs = Substitution::from_iter( Interner, @@ -1016,40 +1007,43 @@ impl<'a> TyLoweringContext<'a> { self.substs_from_path_segment(segment, Some(resolved.into()), false, explicit_self_ty) } - pub(crate) fn lower_where_predicate( - &self, - where_predicate: &WherePredicate, + pub(crate) fn lower_where_predicate<'b>( + &'b self, + where_predicate: &'b WherePredicate, ignore_bindings: bool, - ) -> impl Iterator<Item = QuantifiedWhereClause> { + ) -> impl Iterator<Item = QuantifiedWhereClause> + 'b { match where_predicate { WherePredicate::ForLifetime { target, bound, .. } | WherePredicate::TypeBound { target, bound } => { let self_ty = match target { WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref), - WherePredicateTypeTarget::TypeOrConstParam(param_id) => { - let generic_def = self.resolver.generic_def().expect("generics in scope"); - let generics = generics(self.db.upcast(), generic_def); - let param_id = hir_def::TypeOrConstParamId { - parent: generic_def, - local_id: *param_id, - }; - let placeholder = to_placeholder_idx(self.db, param_id); + &WherePredicateTypeTarget::TypeOrConstParam(local_id) => { + let def = self.resolver.generic_def().expect("generics in scope"); + let param_id = hir_def::TypeOrConstParamId { parent: def, local_id }; match self.type_param_mode { - ParamLoweringMode::Placeholder => TyKind::Placeholder(placeholder), + ParamLoweringMode::Placeholder => { + TyKind::Placeholder(to_placeholder_idx(self.db, param_id)) + } ParamLoweringMode::Variable => { - let idx = generics.param_idx(param_id).expect("matching generics"); + let idx = generics(self.db.upcast(), def) + .type_or_const_param_idx(param_id) + .expect("matching generics"); TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, idx)) } } .intern(Interner) } }; - self.lower_type_bound(bound, self_ty, ignore_bindings) - .collect::<Vec<_>>() - .into_iter() + Either::Left(self.lower_type_bound(bound, self_ty, ignore_bindings)) } - WherePredicate::Lifetime { .. } => vec![].into_iter(), + WherePredicate::Lifetime { bound, target } => Either::Right(iter::once( + crate::wrap_empty_binders(WhereClause::LifetimeOutlives(LifetimeOutlives { + a: self.lower_lifetime(bound), + b: self.lower_lifetime(target), + })), + )), } + .into_iter() } pub(crate) fn lower_type_bound( @@ -1058,11 +1052,11 @@ impl<'a> TyLoweringContext<'a> { self_ty: Ty, ignore_bindings: bool, ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a { - let mut bindings = None; - let trait_ref = match bound.as_ref() { + let mut trait_ref = None; + let clause = match bound.as_ref() { TypeBound::Path(path, TraitBoundModifier::None) => { - bindings = self.lower_trait_ref_from_path(path, Some(self_ty)); - bindings + trait_ref = self.lower_trait_ref_from_path(path, Some(self_ty)); + trait_ref .clone() .filter(|tr| { // ignore `T: Drop` or `T: Destruct` bounds. @@ -1098,14 +1092,20 @@ impl<'a> TyLoweringContext<'a> { } TypeBound::ForLifetime(_, path) => { // FIXME Don't silently drop the hrtb lifetimes here - bindings = self.lower_trait_ref_from_path(path, Some(self_ty)); - bindings.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders) + trait_ref = self.lower_trait_ref_from_path(path, Some(self_ty)); + trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders) + } + TypeBound::Lifetime(l) => { + let lifetime = self.lower_lifetime(l); + Some(crate::wrap_empty_binders(WhereClause::TypeOutlives(TypeOutlives { + ty: self_ty, + lifetime, + }))) } - TypeBound::Lifetime(_) => None, TypeBound::Error => None, }; - trait_ref.into_iter().chain( - bindings + clause.into_iter().chain( + trait_ref .into_iter() .filter(move |_| !ignore_bindings) .flat_map(move |tr| self.assoc_type_bindings_from_type_bound(bound, tr)), @@ -1203,8 +1203,8 @@ impl<'a> TyLoweringContext<'a> { }); if let Some(target_param_idx) = target_param_idx { let mut counter = 0; - for (idx, data) in self.generics().params.type_or_consts.iter() - { + let generics = self.generics().expect("generics in scope"); + for (idx, data) in generics.params.type_or_consts.iter() { // Count the number of `impl Trait` things that appear before // the target of our `bound`. // Our counter within `impl_trait_mode` should be that number @@ -1264,10 +1264,19 @@ impl<'a> TyLoweringContext<'a> { // bounds in the input. // INVARIANT: If this function returns `DynTy`, there should be at least one trait bound. // These invariants are utilized by `TyExt::dyn_trait()` and chalk. + let mut lifetime = None; let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { let mut bounds: Vec<_> = bounds .iter() .flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)) + .filter(|b| match b.skip_binders() { + WhereClause::Implemented(_) | WhereClause::AliasEq(_) => true, + WhereClause::LifetimeOutlives(_) => false, + WhereClause::TypeOutlives(t) => { + lifetime = Some(t.lifetime.clone()); + false + } + }) .collect(); let mut multiple_regular_traits = false; @@ -1305,7 +1314,7 @@ impl<'a> TyLoweringContext<'a> { _ => unreachable!(), } } - // We don't produce `WhereClause::{TypeOutlives, LifetimeOutlives}` yet. + // `WhereClause::{TypeOutlives, LifetimeOutlives}` have been filtered out _ => unreachable!(), } }); @@ -1325,7 +1334,21 @@ impl<'a> TyLoweringContext<'a> { if let Some(bounds) = bounds { let bounds = crate::make_single_type_binders(bounds); - TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner) + TyKind::Dyn(DynTy { + bounds, + lifetime: match lifetime { + Some(it) => match it.bound_var(Interner) { + Some(bound_var) => LifetimeData::BoundVar(BoundVar::new( + DebruijnIndex::INNERMOST, + bound_var.index, + )) + .intern(Interner), + None => it, + }, + None => static_lifetime(), + }, + }) + .intern(Interner) } else { // FIXME: report error // (additional non-auto traits, associated type rebound, or no resolved trait) @@ -1355,8 +1378,8 @@ impl<'a> TyLoweringContext<'a> { crate::wrap_empty_binders(clause) }); predicates.extend(sized_clause); - predicates.shrink_to_fit(); } + predicates.shrink_to_fit(); predicates }); ImplTrait { bounds: crate::make_single_type_binders(predicates) } @@ -1371,10 +1394,7 @@ impl<'a> TyLoweringContext<'a> { LifetimeData::Placeholder(lt_to_placeholder_idx(self.db, id)) } ParamLoweringMode::Variable => { - let generics = generics( - self.db.upcast(), - self.resolver.generic_def().expect("generics in scope"), - ); + let generics = self.generics().expect("generics in scope"); let idx = match generics.lifetime_idx(id) { None => return error_lifetime(), Some(idx) => idx, @@ -1485,7 +1505,7 @@ fn named_associated_type_shorthand_candidates<R>( // Handle `Self::Type` referring to own associated type in trait definitions if let GenericDefId::TraitId(trait_id) = param_id.parent() { let trait_generics = generics(db.upcast(), trait_id.into()); - if trait_generics.params.type_or_consts[param_id.local_id()].is_trait_self() { + if trait_generics.params[param_id.local_id()].is_trait_self() { let def_generics = generics(db.upcast(), def); let starting_idx = match def { GenericDefId::TraitId(_) => 0, @@ -1604,10 +1624,14 @@ pub(crate) fn generic_predicates_for_param_query( let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); let explicitly_unsized_tys = ctx.unsized_types.into_inner(); - let implicitly_sized_predicates = + if let Some(implicitly_sized_predicates) = implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &subst, &resolver) - .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))); - predicates.extend(implicitly_sized_predicates); + { + predicates.extend( + implicitly_sized_predicates + .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))), + ); + } predicates.into() } @@ -1657,18 +1681,7 @@ pub(crate) fn trait_environment_query( } } - let container: Option<ItemContainerId> = match def { - // FIXME: is there a function for this? - GenericDefId::FunctionId(f) => Some(f.lookup(db.upcast()).container), - GenericDefId::AdtId(_) => None, - GenericDefId::TraitId(_) => None, - GenericDefId::TraitAliasId(_) => None, - GenericDefId::TypeAliasId(t) => Some(t.lookup(db.upcast()).container), - GenericDefId::ImplId(_) => None, - GenericDefId::EnumVariantId(_) => None, - GenericDefId::ConstId(c) => Some(c.lookup(db.upcast()).container), - }; - if let Some(ItemContainerId::TraitId(trait_id)) = container { + if let Some(trait_id) = def.assoc_trait_container(db.upcast()) { // add `Self: Trait<T1, T2, ...>` to the environment in trait // function default implementations (and speculative code // inside consts or type aliases) @@ -1676,24 +1689,23 @@ pub(crate) fn trait_environment_query( let substs = TyBuilder::placeholder_subst(db, trait_id); let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs }; let pred = WhereClause::Implemented(trait_ref); - let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner); - clauses.push(program_clause.into_from_env_clause(Interner)); + clauses.push(pred.cast::<ProgramClause>(Interner).into_from_env_clause(Interner)); } let subst = generics(db.upcast(), def).placeholder_subst(db); let explicitly_unsized_tys = ctx.unsized_types.into_inner(); - let implicitly_sized_clauses = - implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver).map(|pred| { - let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner); - program_clause.into_from_env_clause(Interner) - }); - clauses.extend(implicitly_sized_clauses); - - let krate = def.module(db.upcast()).krate(); + if let Some(implicitly_sized_clauses) = + implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver) + { + clauses.extend( + implicitly_sized_clauses + .map(|pred| pred.cast::<ProgramClause>(Interner).into_from_env_clause(Interner)), + ); + } let env = chalk_ir::Environment::new(Interner).add_clauses(Interner, clauses); - TraitEnvironment::new(krate, None, traits_in_scope.into_boxed_slice(), env) + TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env) } /// Resolve the where clause(s) of an item with generics. @@ -1721,10 +1733,14 @@ pub(crate) fn generic_predicates_query( let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); let explicitly_unsized_tys = ctx.unsized_types.into_inner(); - let implicitly_sized_predicates = + if let Some(implicitly_sized_predicates) = implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver) - .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))); - predicates.extend(implicitly_sized_predicates); + { + predicates.extend( + implicitly_sized_predicates + .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))), + ); + } predicates.into() } @@ -1736,24 +1752,24 @@ fn implicitly_sized_clauses<'a>( explicitly_unsized_tys: &'a FxHashSet<Ty>, substitution: &'a Substitution, resolver: &Resolver, -) -> impl Iterator<Item = WhereClause> + 'a { +) -> Option<impl Iterator<Item = WhereClause> + 'a> { let is_trait_def = matches!(def, GenericDefId::TraitId(..)); let generic_args = &substitution.as_slice(Interner)[is_trait_def as usize..]; let sized_trait = db .lang_item(resolver.krate(), LangItem::Sized) .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id)); - sized_trait.into_iter().flat_map(move |sized_trait| { - let implicitly_sized_tys = generic_args + sized_trait.map(move |sized_trait| { + generic_args .iter() .filter_map(|generic_arg| generic_arg.ty(Interner)) - .filter(move |&self_ty| !explicitly_unsized_tys.contains(self_ty)); - implicitly_sized_tys.map(move |self_ty| { - WhereClause::Implemented(TraitRef { - trait_id: sized_trait, - substitution: Substitution::from1(Interner, self_ty.clone()), + .filter(move |&self_ty| !explicitly_unsized_tys.contains(self_ty)) + .map(move |self_ty| { + WhereClause::Implemented(TraitRef { + trait_id: sized_trait, + substitution: Substitution::from1(Interner, self_ty.clone()), + }) }) - }) }) } @@ -1796,8 +1812,7 @@ pub(crate) fn generic_defaults_query( make_binders(db, &generic_params, val) } GenericParamDataRef::LifetimeParamData(_) => { - // using static because it requires defaults - make_binders(db, &generic_params, static_lifetime().cast(Interner)) + make_binders(db, &generic_params, error_lifetime().cast(Interner)) } } })); @@ -1817,7 +1832,7 @@ pub(crate) fn generic_defaults_recover( let val = match id { GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner), GenericParamId::ConstParamId(id) => unknown_const_as_generic(db.const_param_ty(id)), - GenericParamId::LifetimeParamId(_) => static_lifetime().cast(Interner), + GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner), }; crate::make_binders(db, &generic_params, val) })); @@ -2232,7 +2247,7 @@ pub(crate) fn const_or_path_to_chalk( expected_ty: Ty, value: &ConstRef, mode: ParamLoweringMode, - args: impl FnOnce() -> Generics, + args: impl FnOnce() -> Option<Generics>, debruijn: DebruijnIndex, ) -> Const { match value { @@ -2251,7 +2266,7 @@ pub(crate) fn const_or_path_to_chalk( .unwrap_or_else(|| unknown_const(expected_ty)) } &ConstRef::Complex(it) => { - let crate_data = &db.crate_graph()[owner.module(db.upcast()).krate()]; + let crate_data = &db.crate_graph()[resolver.krate()]; if crate_data.env.get("__ra_is_test_fixture").is_none() && crate_data.origin.is_local() { // FIXME: current `InTypeConstId` is very unstable, so we only use it in non local crate |