diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs index b2ab0c30e0..5a0aa19338 100644 --- a/crates/hir-def/src/generics.rs +++ b/crates/hir-def/src/generics.rs @@ -207,12 +207,10 @@ impl GenericParams { pub(crate) fn fill_bounds( &mut self, lower_ctx: &LowerCtx<'_>, - node: &dyn ast::HasTypeBounds, + type_bounds: Option, target: Either, ) { - for bound in - node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) - { + for bound in type_bounds.iter().flat_map(|type_bound_list| type_bound_list.bounds()) { self.add_where_predicate_from_bound(lower_ctx, bound, None, target.clone()); } } @@ -233,7 +231,11 @@ impl GenericParams { }; self.type_or_consts.alloc(param.into()); let type_ref = TypeRef::Path(name.into()); - self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref)); + self.fill_bounds( + lower_ctx, + type_param.type_bound_list(), + Either::Left(type_ref), + ); } ast::TypeOrConstParam::Const(const_param) => { let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); @@ -255,7 +257,11 @@ impl GenericParams { let param = LifetimeParamData { name: name.clone() }; self.lifetimes.alloc(param); let lifetime_ref = LifetimeRef::new_name(name); - self.fill_bounds(lower_ctx, &lifetime_param, Either::Right(lifetime_ref)); + self.fill_bounds( + lower_ctx, + lifetime_param.type_bound_list(), + Either::Right(lifetime_ref), + ); } } diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index bd7c556ae6..b64b4d11e3 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -3,7 +3,7 @@ use std::{collections::hash_map::Entry, sync::Arc}; use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId}; -use syntax::ast::{self, HasModuleItem}; +use syntax::ast::{self, HasModuleItem, HasTypeBounds}; use crate::{ generics::{GenericParams, TypeParamData, TypeParamProvenance}, @@ -148,7 +148,7 @@ impl<'a> Ctx<'a> { fn lower_struct(&mut self, strukt: &ast::Struct) -> Option> { let visibility = self.lower_visibility(strukt); let name = strukt.name()?.as_name(); - let generic_params = self.lower_generic_params(GenericsOwner::Struct, strukt); + let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt); let fields = self.lower_fields(&strukt.kind()); let ast_id = self.source_ast_id_map.ast_id(strukt); let res = Struct { name, visibility, generic_params, fields, ast_id }; @@ -212,7 +212,7 @@ impl<'a> Ctx<'a> { fn lower_union(&mut self, union: &ast::Union) -> Option> { let visibility = self.lower_visibility(union); let name = union.name()?.as_name(); - let generic_params = self.lower_generic_params(GenericsOwner::Union, union); + let generic_params = self.lower_generic_params(HasImplicitSelf::No, union); let fields = match union.record_field_list() { Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)), None => Fields::Record(IdxRange::new(self.next_field_idx()..self.next_field_idx())), @@ -225,7 +225,7 @@ impl<'a> Ctx<'a> { fn lower_enum(&mut self, enum_: &ast::Enum) -> Option> { let visibility = self.lower_visibility(enum_); let name = enum_.name()?.as_name(); - let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_); + let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_); let variants = match &enum_.variant_list() { Some(variant_list) => self.lower_variants(variant_list), None => IdxRange::new(self.next_variant_idx()..self.next_variant_idx()), @@ -373,8 +373,7 @@ impl<'a> Ctx<'a> { ast_id, flags, }; - res.explicit_generic_params = - self.lower_generic_params(GenericsOwner::Function(&res), func); + res.explicit_generic_params = self.lower_generic_params(HasImplicitSelf::No, func); Some(id(self.data().functions.alloc(res))) } @@ -387,7 +386,7 @@ impl<'a> Ctx<'a> { let type_ref = type_alias.ty().map(|it| self.lower_type_ref(&it)); let visibility = self.lower_visibility(type_alias); let bounds = self.lower_type_bounds(type_alias); - let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias); + let generic_params = self.lower_generic_params(HasImplicitSelf::No, type_alias); let ast_id = self.source_ast_id_map.ast_id(type_alias); let res = TypeAlias { name, @@ -443,7 +442,8 @@ impl<'a> Ctx<'a> { fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option> { let name = trait_def.name()?.as_name(); let visibility = self.lower_visibility(trait_def); - let generic_params = self.lower_generic_params(GenericsOwner::Trait(trait_def), trait_def); + let generic_params = + self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def); let is_auto = trait_def.auto_token().is_some(); let is_unsafe = trait_def.unsafe_token().is_some(); let items = trait_def.assoc_item_list().map(|list| { @@ -463,7 +463,9 @@ impl<'a> Ctx<'a> { } fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option> { - let generic_params = self.lower_generic_params(GenericsOwner::Impl, impl_def); + // Note that trait impls don't get implicit `Self` unlike traits, because here they are a + // type alias rather than a type parameter, so this is handled by the resolver. + let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def); // FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl // as if it was an non-trait impl. Ideally we want to create a unique missing ref that only // equals itself. @@ -567,42 +569,29 @@ impl<'a> Ctx<'a> { fn lower_generic_params( &mut self, - owner: GenericsOwner<'_>, + has_implicit_self: HasImplicitSelf, node: &dyn ast::HasGenericParams, ) -> Interned { let mut generics = GenericParams::default(); - match owner { - GenericsOwner::Function(_) - | GenericsOwner::Struct - | GenericsOwner::Enum - | GenericsOwner::Union - | GenericsOwner::TypeAlias => { - generics.fill(&self.body_ctx, node); - } - GenericsOwner::Trait(trait_def) => { - // traits get the Self type as an implicit first type parameter - generics.type_or_consts.alloc( - TypeParamData { - name: Some(name![Self]), - default: None, - provenance: TypeParamProvenance::TraitSelf, - } - .into(), - ); - // add super traits as bounds on Self - // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar - let self_param = TypeRef::Path(name![Self].into()); - generics.fill_bounds(&self.body_ctx, trait_def, Either::Left(self_param)); - generics.fill(&self.body_ctx, node); - } - GenericsOwner::Impl => { - // Note that we don't add `Self` here: in `impl`s, `Self` is not a - // type-parameter, but rather is a type-alias for impl's target - // type, so this is handled by the resolver. - generics.fill(&self.body_ctx, node); - } + + if let HasImplicitSelf::Yes(bounds) = has_implicit_self { + // Traits and trait aliases get the Self type as an implicit first type parameter. + generics.type_or_consts.alloc( + TypeParamData { + name: Some(name![Self]), + default: None, + provenance: TypeParamProvenance::TraitSelf, + } + .into(), + ); + // add super traits as bounds on Self + // i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar` + let self_param = TypeRef::Path(name![Self].into()); + generics.fill_bounds(&self.body_ctx, bounds, Either::Left(self_param)); } + generics.fill(&self.body_ctx, node); + generics.shrink_to_fit(); Interned::new(generics) } @@ -674,17 +663,10 @@ fn desugar_future_path(orig: TypeRef) -> Path { Path::from_known_path(path, generic_args) } -enum GenericsOwner<'a> { - /// We need access to the partially-lowered `Function` for lowering `impl Trait` in argument - /// position. - Function(&'a Function), - Struct, - Enum, - Union, - /// The `TraitDef` is needed to fill the source map for the implicit `Self` parameter. - Trait(&'a ast::Trait), - TypeAlias, - Impl, +enum HasImplicitSelf { + /// Inner list is a type bound list for the implicit `Self`. + Yes(Option), + No, } fn lower_abi(abi: ast::Abi) -> Interned {