Refactor generic parameter lowering

Since we moved impl trait handling to other place, there are only two
cases now: those that introduce implicit `Self` parameter and those that
don't.
This commit is contained in:
Ryo Yoshida 2023-03-04 00:24:05 +09:00
parent 356d12eae4
commit e2ec3a6561
No known key found for this signature in database
GPG key ID: E25698A930586171
2 changed files with 45 additions and 57 deletions

View file

@ -207,12 +207,10 @@ impl GenericParams {
pub(crate) fn fill_bounds( pub(crate) fn fill_bounds(
&mut self, &mut self,
lower_ctx: &LowerCtx<'_>, lower_ctx: &LowerCtx<'_>,
node: &dyn ast::HasTypeBounds, type_bounds: Option<ast::TypeBoundList>,
target: Either<TypeRef, LifetimeRef>, target: Either<TypeRef, LifetimeRef>,
) { ) {
for bound in for bound in type_bounds.iter().flat_map(|type_bound_list| type_bound_list.bounds()) {
node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds())
{
self.add_where_predicate_from_bound(lower_ctx, bound, None, target.clone()); 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()); self.type_or_consts.alloc(param.into());
let type_ref = TypeRef::Path(name.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) => { ast::TypeOrConstParam::Const(const_param) => {
let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); 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() }; let param = LifetimeParamData { name: name.clone() };
self.lifetimes.alloc(param); self.lifetimes.alloc(param);
let lifetime_ref = LifetimeRef::new_name(name); 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),
);
} }
} }

View file

@ -3,7 +3,7 @@
use std::{collections::hash_map::Entry, sync::Arc}; use std::{collections::hash_map::Entry, sync::Arc};
use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId}; use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId};
use syntax::ast::{self, HasModuleItem}; use syntax::ast::{self, HasModuleItem, HasTypeBounds};
use crate::{ use crate::{
generics::{GenericParams, TypeParamData, TypeParamProvenance}, generics::{GenericParams, TypeParamData, TypeParamProvenance},
@ -148,7 +148,7 @@ impl<'a> Ctx<'a> {
fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> { fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> {
let visibility = self.lower_visibility(strukt); let visibility = self.lower_visibility(strukt);
let name = strukt.name()?.as_name(); 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 fields = self.lower_fields(&strukt.kind());
let ast_id = self.source_ast_id_map.ast_id(strukt); let ast_id = self.source_ast_id_map.ast_id(strukt);
let res = Struct { name, visibility, generic_params, fields, ast_id }; 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<FileItemTreeId<Union>> { fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
let visibility = self.lower_visibility(union); let visibility = self.lower_visibility(union);
let name = union.name()?.as_name(); 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() { let fields = match union.record_field_list() {
Some(record_field_list) => self.lower_fields(&StructKind::Record(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())), 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<FileItemTreeId<Enum>> { fn lower_enum(&mut self, enum_: &ast::Enum) -> Option<FileItemTreeId<Enum>> {
let visibility = self.lower_visibility(enum_); let visibility = self.lower_visibility(enum_);
let name = enum_.name()?.as_name(); 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() { let variants = match &enum_.variant_list() {
Some(variant_list) => self.lower_variants(variant_list), Some(variant_list) => self.lower_variants(variant_list),
None => IdxRange::new(self.next_variant_idx()..self.next_variant_idx()), None => IdxRange::new(self.next_variant_idx()..self.next_variant_idx()),
@ -373,8 +373,7 @@ impl<'a> Ctx<'a> {
ast_id, ast_id,
flags, flags,
}; };
res.explicit_generic_params = res.explicit_generic_params = self.lower_generic_params(HasImplicitSelf::No, func);
self.lower_generic_params(GenericsOwner::Function(&res), func);
Some(id(self.data().functions.alloc(res))) 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 type_ref = type_alias.ty().map(|it| self.lower_type_ref(&it));
let visibility = self.lower_visibility(type_alias); let visibility = self.lower_visibility(type_alias);
let bounds = self.lower_type_bounds(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 ast_id = self.source_ast_id_map.ast_id(type_alias);
let res = TypeAlias { let res = TypeAlias {
name, name,
@ -443,7 +442,8 @@ impl<'a> Ctx<'a> {
fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option<FileItemTreeId<Trait>> { fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option<FileItemTreeId<Trait>> {
let name = trait_def.name()?.as_name(); let name = trait_def.name()?.as_name();
let visibility = self.lower_visibility(trait_def); 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_auto = trait_def.auto_token().is_some();
let is_unsafe = trait_def.unsafe_token().is_some(); let is_unsafe = trait_def.unsafe_token().is_some();
let items = trait_def.assoc_item_list().map(|list| { 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<FileItemTreeId<Impl>> { fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> {
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 // 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 // as if it was an non-trait impl. Ideally we want to create a unique missing ref that only
// equals itself. // equals itself.
@ -567,42 +569,29 @@ impl<'a> Ctx<'a> {
fn lower_generic_params( fn lower_generic_params(
&mut self, &mut self,
owner: GenericsOwner<'_>, has_implicit_self: HasImplicitSelf,
node: &dyn ast::HasGenericParams, node: &dyn ast::HasGenericParams,
) -> Interned<GenericParams> { ) -> Interned<GenericParams> {
let mut generics = GenericParams::default(); let mut generics = GenericParams::default();
match owner {
GenericsOwner::Function(_) if let HasImplicitSelf::Yes(bounds) = has_implicit_self {
| GenericsOwner::Struct // Traits and trait aliases get the Self type as an implicit first type parameter.
| GenericsOwner::Enum generics.type_or_consts.alloc(
| GenericsOwner::Union TypeParamData {
| GenericsOwner::TypeAlias => { name: Some(name![Self]),
generics.fill(&self.body_ctx, node); default: None,
} provenance: TypeParamProvenance::TraitSelf,
GenericsOwner::Trait(trait_def) => { }
// traits get the Self type as an implicit first type parameter .into(),
generics.type_or_consts.alloc( );
TypeParamData { // add super traits as bounds on Self
name: Some(name![Self]), // i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar`
default: None, let self_param = TypeRef::Path(name![Self].into());
provenance: TypeParamProvenance::TraitSelf, generics.fill_bounds(&self.body_ctx, bounds, Either::Left(self_param));
}
.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);
}
} }
generics.fill(&self.body_ctx, node);
generics.shrink_to_fit(); generics.shrink_to_fit();
Interned::new(generics) Interned::new(generics)
} }
@ -674,17 +663,10 @@ fn desugar_future_path(orig: TypeRef) -> Path {
Path::from_known_path(path, generic_args) Path::from_known_path(path, generic_args)
} }
enum GenericsOwner<'a> { enum HasImplicitSelf {
/// We need access to the partially-lowered `Function` for lowering `impl Trait` in argument /// Inner list is a type bound list for the implicit `Self`.
/// position. Yes(Option<ast::TypeBoundList>),
Function(&'a Function), No,
Struct,
Enum,
Union,
/// The `TraitDef` is needed to fill the source map for the implicit `Self` parameter.
Trait(&'a ast::Trait),
TypeAlias,
Impl,
} }
fn lower_abi(abi: ast::Abi) -> Interned<str> { fn lower_abi(abi: ast::Abi) -> Interned<str> {