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 | 292 |
1 files changed, 216 insertions, 76 deletions
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 073a584d8d..eecca32240 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -25,8 +25,8 @@ use chalk_ir::{ use either::Either; use hir_def::{ AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, - FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, - StructId, TypeAliasId, TypeOrConstParamId, UnionId, VariantId, + FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LocalFieldId, + Lookup, StaticId, StructId, TypeAliasId, TypeOrConstParamId, UnionId, VariantId, builtin_type::BuiltinType, expr_store::{ExpressionStore, path::Path}, hir::generics::{ @@ -35,7 +35,7 @@ use hir_def::{ item_tree::FieldsShape, lang_item::LangItem, resolver::{HasResolver, LifetimeNs, Resolver, TypeNs}, - signatures::{TraitFlags, TypeAliasFlags}, + signatures::{FunctionSignature, TraitFlags, TypeAliasFlags}, type_ref::{ ConstRef, LifetimeRef, LiteralConstRef, PathId, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId, @@ -86,21 +86,70 @@ impl ImplTraitLoweringState { pub(crate) struct PathDiagnosticCallbackData(TypeRefId); -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum GenericArgsPosition { - Type, - /// E.g. functions. - Value, - MethodCall, - // FIXME: This is a temporary variant we need to work around the lack of lifetime elision. - // The reason for its existence is that in `check_generic_args_len()`, without this, we will - // not infer elide lifetimes. - // They indeed should not be inferred - they should be elided - but we won't elide them either, - // emitting an error instead. rustc elides them in late resolve, and the generics it passes - // to lowering already include them. We probably can't do that, but we will still need to - // account for them when we properly implement lifetime elision. - FnSignature, - OtherSignature, +#[derive(Debug, Clone)] +pub enum LifetimeElisionKind { + /// Create a new anonymous lifetime parameter and reference it. + /// + /// If `report_in_path`, report an error when encountering lifetime elision in a path: + /// ```compile_fail + /// struct Foo<'a> { x: &'a () } + /// async fn foo(x: Foo) {} + /// ``` + /// + /// Note: the error should not trigger when the elided lifetime is in a pattern or + /// expression-position path: + /// ``` + /// struct Foo<'a> { x: &'a () } + /// async fn foo(Foo { x: _ }: Foo<'_>) {} + /// ``` + AnonymousCreateParameter { report_in_path: bool }, + + /// Replace all anonymous lifetimes by provided lifetime. + Elided(Lifetime), + + /// Give a hard error when either `&` or `'_` is written. Used to + /// rule out things like `where T: Foo<'_>`. Does not imply an + /// error on default object bounds (e.g., `Box<dyn Foo>`). + AnonymousReportError, + + /// Resolves elided lifetimes to `'static` if there are no other lifetimes in scope, + /// otherwise give a warning that the previous behavior of introducing a new early-bound + /// lifetime is a bug and will be removed (if `only_lint` is enabled). + StaticIfNoLifetimeInScope { only_lint: bool }, + + /// Signal we cannot find which should be the anonymous lifetime. + ElisionFailure, + + /// Infer all elided lifetimes. + Infer, +} + +impl LifetimeElisionKind { + #[inline] + pub(crate) fn for_const(const_parent: ItemContainerId) -> LifetimeElisionKind { + match const_parent { + ItemContainerId::ExternBlockId(_) | ItemContainerId::ModuleId(_) => { + LifetimeElisionKind::Elided(static_lifetime()) + } + ItemContainerId::ImplId(_) => { + LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: true } + } + ItemContainerId::TraitId(_) => { + LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: false } + } + } + } + + #[inline] + pub(crate) fn for_fn_params(data: &FunctionSignature) -> LifetimeElisionKind { + LifetimeElisionKind::AnonymousCreateParameter { report_in_path: data.is_async() } + } + + #[inline] + pub(crate) fn for_fn_ret() -> LifetimeElisionKind { + // FIXME: We should use the elided lifetime here, or `ElisionFailure`. + LifetimeElisionKind::Elided(error_lifetime()) + } } #[derive(Debug)] @@ -120,7 +169,7 @@ pub struct TyLoweringContext<'a> { /// Tracks types with explicit `?Sized` bounds. pub(crate) unsized_types: FxHashSet<Ty>, pub(crate) diagnostics: Vec<TyLoweringDiagnostic>, - pub(crate) in_fn_signature: bool, + lifetime_elision: LifetimeElisionKind, } impl<'a> TyLoweringContext<'a> { @@ -129,6 +178,7 @@ impl<'a> TyLoweringContext<'a> { resolver: &'a Resolver, store: &'a ExpressionStore, def: GenericDefId, + lifetime_elision: LifetimeElisionKind, ) -> Self { let impl_trait_mode = ImplTraitLoweringState::new(ImplTraitLoweringMode::Disallowed); let type_param_mode = ParamLoweringMode::Placeholder; @@ -144,7 +194,7 @@ impl<'a> TyLoweringContext<'a> { type_param_mode, unsized_types: FxHashSet::default(), diagnostics: Vec::new(), - in_fn_signature: false, + lifetime_elision, } } @@ -167,6 +217,17 @@ impl<'a> TyLoweringContext<'a> { self.with_debruijn(self.in_binders.shifted_in_from(debruijn), f) } + fn with_lifetime_elision<T>( + &mut self, + lifetime_elision: LifetimeElisionKind, + f: impl FnOnce(&mut TyLoweringContext<'_>) -> T, + ) -> T { + let old_lifetime_elision = mem::replace(&mut self.lifetime_elision, lifetime_elision); + let result = f(self); + self.lifetime_elision = old_lifetime_elision; + result + } + pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self { Self { impl_trait_mode: ImplTraitLoweringState::new(impl_trait_mode), ..self } } @@ -318,10 +379,18 @@ impl<'a> TyLoweringContext<'a> { TypeRef::Placeholder => TyKind::Error.intern(Interner), TypeRef::Fn(fn_) => { let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { - Substitution::from_iter( - Interner, - fn_.params.iter().map(|&(_, tr)| ctx.lower_ty(tr)), - ) + let (params, ret) = fn_.split_params_and_ret(); + let mut subst = Vec::with_capacity(fn_.params.len()); + ctx.with_lifetime_elision( + LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false }, + |ctx| { + subst.extend(params.iter().map(|&(_, tr)| ctx.lower_ty(tr))); + }, + ); + ctx.with_lifetime_elision(LifetimeElisionKind::for_fn_ret(), |ctx| { + subst.push(ctx.lower_ty(ret)); + }); + Substitution::from_iter(Interner, subst) }); TyKind::Function(FnPointer { num_binders: 0, // FIXME lower `for<'a> fn()` correctly @@ -431,11 +500,6 @@ impl<'a> TyLoweringContext<'a> { self, Self::on_path_diagnostic_callback(path_id.type_ref()), &self.store[path_id], - if self.in_fn_signature { - GenericArgsPosition::FnSignature - } else { - GenericArgsPosition::Type - }, ) } @@ -855,8 +919,14 @@ pub(crate) fn field_types_with_diagnostics_query( }; let generics = generics(db, def); let mut res = ArenaMap::default(); - let mut ctx = TyLoweringContext::new(db, &resolver, &var_data.store, def) - .with_type_param_mode(ParamLoweringMode::Variable); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &var_data.store, + def, + LifetimeElisionKind::AnonymousReportError, + ) + .with_type_param_mode(ParamLoweringMode::Variable); for (field_id, field_data) in var_data.fields().iter() { res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(field_data.type_ref))); } @@ -879,8 +949,14 @@ pub(crate) fn generic_predicates_for_param_query( ) -> GenericPredicates { let generics = generics(db, def); let resolver = def.resolver(db); - let mut ctx = TyLoweringContext::new(db, &resolver, generics.store(), def) - .with_type_param_mode(ParamLoweringMode::Variable); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + generics.store(), + def, + LifetimeElisionKind::AnonymousReportError, + ) + .with_type_param_mode(ParamLoweringMode::Variable); // we have to filter out all other predicates *first*, before attempting to lower them let predicate = |pred: &_, generics: &Generics, ctx: &mut TyLoweringContext<'_>| match pred { @@ -987,8 +1063,14 @@ pub(crate) fn trait_environment_query( ) -> Arc<TraitEnvironment> { let generics = generics(db, def); let resolver = def.resolver(db); - let mut ctx = TyLoweringContext::new(db, &resolver, generics.store(), def) - .with_type_param_mode(ParamLoweringMode::Placeholder); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + generics.store(), + def, + LifetimeElisionKind::AnonymousReportError, + ) + .with_type_param_mode(ParamLoweringMode::Placeholder); let mut traits_in_scope = Vec::new(); let mut clauses = Vec::new(); for maybe_parent_generics in @@ -1086,8 +1168,14 @@ where { let generics = generics(db, def); let resolver = def.resolver(db); - let mut ctx = TyLoweringContext::new(db, &resolver, generics.store(), def) - .with_type_param_mode(ParamLoweringMode::Variable); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + generics.store(), + def, + LifetimeElisionKind::AnonymousReportError, + ) + .with_type_param_mode(ParamLoweringMode::Variable); let mut predicates = Vec::new(); for maybe_parent_generics in @@ -1188,9 +1276,15 @@ pub(crate) fn generic_defaults_with_diagnostics_query( } let resolver = def.resolver(db); - let mut ctx = TyLoweringContext::new(db, &resolver, generic_params.store(), def) - .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed) - .with_type_param_mode(ParamLoweringMode::Variable); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + generic_params.store(), + def, + LifetimeElisionKind::AnonymousReportError, + ) + .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed) + .with_type_param_mode(ParamLoweringMode::Variable); let mut idx = 0; let mut has_any_default = false; let mut defaults = generic_params @@ -1273,17 +1367,27 @@ pub(crate) fn generic_defaults_with_diagnostics_cycle_result( fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { let data = db.function_signature(def); let resolver = def.resolver(db); - let mut ctx_params = TyLoweringContext::new(db, &resolver, &data.store, def.into()) - .with_type_param_mode(ParamLoweringMode::Variable); - ctx_params.in_fn_signature = true; + let mut ctx_params = TyLoweringContext::new( + db, + &resolver, + &data.store, + def.into(), + LifetimeElisionKind::for_fn_params(&data), + ) + .with_type_param_mode(ParamLoweringMode::Variable); let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr)); let ret = match data.ret_type { Some(ret_type) => { - let mut ctx_ret = TyLoweringContext::new(db, &resolver, &data.store, def.into()) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) - .with_type_param_mode(ParamLoweringMode::Variable); - ctx_ret.in_fn_signature = true; + let mut ctx_ret = TyLoweringContext::new( + db, + &resolver, + &data.store, + def.into(), + LifetimeElisionKind::for_fn_ret(), + ) + .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) + .with_type_param_mode(ParamLoweringMode::Variable); ctx_ret.lower_ty(ret_type) } None => TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner), @@ -1316,8 +1420,15 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> { let data = db.const_signature(def); let generics = generics(db, def.into()); let resolver = def.resolver(db); - let mut ctx = TyLoweringContext::new(db, &resolver, &data.store, def.into()) - .with_type_param_mode(ParamLoweringMode::Variable); + let parent = def.loc(db).container; + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &data.store, + def.into(), + LifetimeElisionKind::for_const(parent), + ) + .with_type_param_mode(ParamLoweringMode::Variable); make_binders(db, &generics, ctx.lower_ty(data.type_ref)) } @@ -1326,18 +1437,20 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> { fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders<Ty> { let data = db.static_signature(def); let resolver = def.resolver(db); - let mut ctx = TyLoweringContext::new(db, &resolver, &data.store, def.into()); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &data.store, + def.into(), + LifetimeElisionKind::Elided(static_lifetime()), + ); Binders::empty(Interner, ctx.lower_ty(data.type_ref)) } fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig { - let struct_data = db.variant_fields(def.into()); - let fields = struct_data.fields(); - let resolver = def.resolver(db); - let mut ctx = TyLoweringContext::new(db, &resolver, &struct_data.store, def.into()) - .with_type_param_mode(ParamLoweringMode::Variable); - let params = fields.iter().map(|(_, field)| ctx.lower_ty(field.type_ref)); + let field_tys = db.field_types(def.into()); + let params = field_tys.iter().map(|(_, ty)| ty.skip_binders().clone()); let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders(); Binders::new( binders, @@ -1364,13 +1477,9 @@ fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Option<Bi } fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> PolyFnSig { - let var_data = db.variant_fields(def.into()); - let fields = var_data.fields(); - let resolver = def.resolver(db); + let field_tys = db.field_types(def.into()); + let params = field_tys.iter().map(|(_, ty)| ty.skip_binders().clone()); let parent = def.lookup(db).parent; - let mut ctx = TyLoweringContext::new(db, &resolver, &var_data.store, parent.into()) - .with_type_param_mode(ParamLoweringMode::Variable); - let params = fields.iter().map(|(_, field)| ctx.lower_ty(field.type_ref)); let (ret, binders) = type_for_adt(db, parent.into()).into_value_and_skipped_binders(); Binders::new( binders, @@ -1429,9 +1538,15 @@ pub(crate) fn type_for_type_alias_with_diagnostics_query( } else { let resolver = t.resolver(db); let alias = db.type_alias_signature(t); - let mut ctx = TyLoweringContext::new(db, &resolver, &alias.store, t.into()) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) - .with_type_param_mode(ParamLoweringMode::Variable); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &alias.store, + t.into(), + LifetimeElisionKind::AnonymousReportError, + ) + .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) + .with_type_param_mode(ParamLoweringMode::Variable); let res = alias .ty .map(|type_ref| ctx.lower_ty(type_ref)) @@ -1517,8 +1632,14 @@ pub(crate) fn impl_self_ty_with_diagnostics_query( let impl_data = db.impl_signature(impl_id); let resolver = impl_id.resolver(db); let generics = generics(db, impl_id.into()); - let mut ctx = TyLoweringContext::new(db, &resolver, &impl_data.store, impl_id.into()) - .with_type_param_mode(ParamLoweringMode::Variable); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &impl_data.store, + impl_id.into(), + LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, + ) + .with_type_param_mode(ParamLoweringMode::Variable); ( make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty)), create_diagnostics(ctx.diagnostics), @@ -1537,7 +1658,13 @@ pub(crate) fn const_param_ty_with_diagnostics_query( let (parent_data, store) = db.generic_params_and_store(def.parent()); let data = &parent_data[def.local_id()]; let resolver = def.parent().resolver(db); - let mut ctx = TyLoweringContext::new(db, &resolver, &store, def.parent()); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &store, + def.parent(), + LifetimeElisionKind::AnonymousReportError, + ); let ty = match data { TypeOrConstParamData::TypeParamData(_) => { never!(); @@ -1566,8 +1693,14 @@ pub(crate) fn impl_trait_with_diagnostics_query( ) -> Option<(Binders<TraitRef>, Diagnostics)> { let impl_data = db.impl_signature(impl_id); let resolver = impl_id.resolver(db); - let mut ctx = TyLoweringContext::new(db, &resolver, &impl_data.store, impl_id.into()) - .with_type_param_mode(ParamLoweringMode::Variable); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &impl_data.store, + impl_id.into(), + LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, + ) + .with_type_param_mode(ParamLoweringMode::Variable); let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders(); let target_trait = impl_data.target_trait.as_ref()?; let trait_ref = Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?); @@ -1581,9 +1714,10 @@ pub(crate) fn return_type_impl_traits( // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe let data = db.function_signature(def); let resolver = def.resolver(db); - let mut ctx_ret = TyLoweringContext::new(db, &resolver, &data.store, def.into()) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) - .with_type_param_mode(ParamLoweringMode::Variable); + let mut ctx_ret = + TyLoweringContext::new(db, &resolver, &data.store, def.into(), LifetimeElisionKind::Infer) + .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) + .with_type_param_mode(ParamLoweringMode::Variable); if let Some(ret_type) = data.ret_type { let _ret = ctx_ret.lower_ty(ret_type); } @@ -1603,9 +1737,15 @@ pub(crate) fn type_alias_impl_traits( ) -> Option<Arc<Binders<ImplTraits>>> { let data = db.type_alias_signature(def); let resolver = def.resolver(db); - let mut ctx = TyLoweringContext::new(db, &resolver, &data.store, def.into()) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) - .with_type_param_mode(ParamLoweringMode::Variable); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &data.store, + def.into(), + LifetimeElisionKind::AnonymousReportError, + ) + .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) + .with_type_param_mode(ParamLoweringMode::Variable); if let Some(type_ref) = data.ty { let _ty = ctx.lower_ty(type_ref); } |