Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/generics.rs')
-rw-r--r--crates/hir-def/src/generics.rs341
1 files changed, 281 insertions, 60 deletions
diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs
index 6c34ee086a..6b79850e9c 100644
--- a/crates/hir-def/src/generics.rs
+++ b/crates/hir-def/src/generics.rs
@@ -3,16 +3,18 @@
//! generic parameters. See also the `Generics` type and the `generics_of` query
//! in rustc.
-use std::ops;
+use std::{ops, sync::LazyLock};
use either::Either;
use hir_expand::{
name::{AsName, Name},
ExpandResult,
};
-use intern::Interned;
use la_arena::{Arena, RawIdx};
-use stdx::impl_from;
+use stdx::{
+ impl_from,
+ thin_vec::{EmptyOptimizedThinVec, ThinVec},
+};
use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
use triomphe::Arc;
@@ -22,7 +24,11 @@ use crate::{
item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree},
lower::LowerCtx,
nameres::{DefMap, MacroSubNs},
- type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
+ path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path},
+ type_ref::{
+ ArrayType, ConstRef, FnType, LifetimeRef, RefType, TypeBound, TypeRef, TypeRefId, TypesMap,
+ TypesSourceMap,
+ },
AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LifetimeParamId,
LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
};
@@ -37,7 +43,7 @@ pub struct TypeParamData {
/// [`None`] only if the type ref is an [`TypeRef::ImplTrait`]. FIXME: Might be better to just
/// make it always be a value, giving impl trait a special name.
pub name: Option<Name>,
- pub default: Option<Interned<TypeRef>>,
+ pub default: Option<TypeRefId>,
pub provenance: TypeParamProvenance,
}
@@ -51,7 +57,7 @@ pub struct LifetimeParamData {
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct ConstParamData {
pub name: Name,
- pub ty: Interned<TypeRef>,
+ pub ty: TypeRefId,
pub default: Option<ConstRef>,
}
@@ -161,6 +167,7 @@ pub struct GenericParams {
type_or_consts: Arena<TypeOrConstParamData>,
lifetimes: Arena<LifetimeParamData>,
where_predicates: Box<[WherePredicate]>,
+ pub types_map: TypesMap,
}
impl ops::Index<LocalTypeOrConstParamId> for GenericParams {
@@ -183,24 +190,14 @@ impl ops::Index<LocalLifetimeParamId> for GenericParams {
/// associated type bindings like `Iterator<Item = u32>`.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum WherePredicate {
- TypeBound {
- target: WherePredicateTypeTarget,
- bound: Interned<TypeBound>,
- },
- Lifetime {
- target: LifetimeRef,
- bound: LifetimeRef,
- },
- ForLifetime {
- lifetimes: Box<[Name]>,
- target: WherePredicateTypeTarget,
- bound: Interned<TypeBound>,
- },
+ TypeBound { target: WherePredicateTypeTarget, bound: TypeBound },
+ Lifetime { target: LifetimeRef, bound: LifetimeRef },
+ ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound },
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum WherePredicateTypeTarget {
- TypeRef(Interned<TypeRef>),
+ TypeRef(TypeRefId),
/// For desugared where predicates that can directly refer to a type param.
TypeOrConstParam(LocalTypeOrConstParamId),
}
@@ -300,7 +297,14 @@ impl GenericParams {
pub(crate) fn generic_params_query(
db: &dyn DefDatabase,
def: GenericDefId,
- ) -> Interned<GenericParams> {
+ ) -> Arc<GenericParams> {
+ db.generic_params_with_source_map(def).0
+ }
+
+ pub(crate) fn generic_params_with_source_map_query(
+ db: &dyn DefDatabase,
+ def: GenericDefId,
+ ) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>) {
let _p = tracing::info_span!("generic_params_query").entered();
let krate = def.krate(db);
@@ -309,7 +313,7 @@ impl GenericParams {
// Returns the generic parameters that are enabled under the current `#[cfg]` options
let enabled_params =
- |params: &Interned<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
+ |params: &Arc<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param);
let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param);
@@ -325,7 +329,7 @@ impl GenericParams {
if all_type_or_consts_enabled && all_lifetimes_enabled {
params.clone()
} else {
- Interned::new(GenericParams {
+ Arc::new(GenericParams {
type_or_consts: all_type_or_consts_enabled
.then(|| params.type_or_consts.clone())
.unwrap_or_else(|| {
@@ -347,6 +351,7 @@ impl GenericParams {
.collect()
}),
where_predicates: params.where_predicates.clone(),
+ types_map: params.types_map.clone(),
})
}
};
@@ -357,18 +362,18 @@ impl GenericParams {
Data = impl ItemTreeLoc<Id = Id>,
>,
enabled_params: impl Fn(
- &Interned<GenericParams>,
+ &Arc<GenericParams>,
&ItemTree,
GenericModItem,
- ) -> Interned<GenericParams>,
- ) -> Interned<GenericParams>
+ ) -> Arc<GenericParams>,
+ ) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>)
where
FileItemTreeId<Id>: Into<GenericModItem>,
{
let id = id.lookup(db).item_tree_id();
let tree = id.item_tree(db);
let item = &tree[id.value];
- enabled_params(item.generic_params(), &tree, id.value.into())
+ (enabled_params(item.generic_params(), &tree, id.value.into()), None)
}
match def {
@@ -383,28 +388,37 @@ impl GenericParams {
let module = loc.container.module(db);
let func_data = db.function_data(id);
if func_data.params.is_empty() {
- enabled_params
+ (enabled_params, None)
} else {
+ let source_maps = loc.id.item_tree_with_source_map(db).1;
+ let item_source_maps = source_maps.function(loc.id.value);
let mut generic_params = GenericParamsCollector {
type_or_consts: enabled_params.type_or_consts.clone(),
lifetimes: enabled_params.lifetimes.clone(),
where_predicates: enabled_params.where_predicates.clone().into(),
};
+ let (mut types_map, mut types_source_maps) =
+ (enabled_params.types_map.clone(), item_source_maps.generics().clone());
// Don't create an `Expander` if not needed since this
// could cause a reparse after the `ItemTree` has been created due to the spanmap.
let mut expander = None;
- for param in func_data.params.iter() {
+ for &param in func_data.params.iter() {
generic_params.fill_implicit_impl_trait_args(
db,
+ &mut types_map,
+ &mut types_source_maps,
&mut expander,
&mut || {
(module.def_map(db), Expander::new(db, loc.id.file_id(), module))
},
param,
+ &item.types_map,
+ item_source_maps.item(),
);
}
- Interned::new(generic_params.finish())
+ let generics = generic_params.finish(types_map, &mut types_source_maps);
+ (generics, Some(Arc::new(types_source_maps)))
}
}
GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics(db, id, enabled_params),
@@ -414,11 +428,15 @@ impl GenericParams {
GenericDefId::TraitAliasId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::TypeAliasId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::ImplId(id) => id_to_generics(db, id, enabled_params),
- GenericDefId::ConstId(_) => Interned::new(GenericParams {
- type_or_consts: Default::default(),
- lifetimes: Default::default(),
- where_predicates: Default::default(),
- }),
+ GenericDefId::ConstId(_) => (
+ Arc::new(GenericParams {
+ type_or_consts: Default::default(),
+ lifetimes: Default::default(),
+ where_predicates: Default::default(),
+ types_map: Default::default(),
+ }),
+ None,
+ ),
}
}
}
@@ -452,7 +470,7 @@ impl GenericParamsCollector {
&mut self,
lower_ctx: &LowerCtx<'_>,
type_bounds: Option<ast::TypeBoundList>,
- target: Either<TypeRef, LifetimeRef>,
+ target: Either<TypeRefId, LifetimeRef>,
) {
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());
@@ -473,16 +491,15 @@ impl GenericParamsCollector {
ast::TypeOrConstParam::Type(type_param) => {
let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
// FIXME: Use `Path::from_src`
- let default = type_param
- .default_type()
- .map(|it| Interned::new(TypeRef::from_ast(lower_ctx, it)));
+ let default =
+ type_param.default_type().map(|it| TypeRef::from_ast(lower_ctx, it));
let param = TypeParamData {
name: Some(name.clone()),
default,
provenance: TypeParamProvenance::TypeParamList,
};
let idx = self.type_or_consts.alloc(param.into());
- let type_ref = TypeRef::Path(name.into());
+ let type_ref = lower_ctx.alloc_type_ref_desugared(TypeRef::Path(name.into()));
self.fill_bounds(
lower_ctx,
type_param.type_bound_list(),
@@ -492,12 +509,10 @@ impl GenericParamsCollector {
}
ast::TypeOrConstParam::Const(const_param) => {
let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
- let ty = const_param
- .ty()
- .map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
+ let ty = TypeRef::from_ast_opt(lower_ctx, const_param.ty());
let param = ConstParamData {
name,
- ty: Interned::new(ty),
+ ty,
default: ConstRef::from_const_param(lower_ctx, &const_param),
};
let idx = self.type_or_consts.alloc(param.into());
@@ -557,7 +572,7 @@ impl GenericParamsCollector {
lower_ctx: &LowerCtx<'_>,
bound: ast::TypeBound,
hrtb_lifetimes: Option<&[Name]>,
- target: Either<TypeRef, LifetimeRef>,
+ target: Either<TypeRefId, LifetimeRef>,
) {
let bound = TypeBound::from_ast(lower_ctx, bound);
self.fill_impl_trait_bounds(lower_ctx.take_impl_traits_bounds());
@@ -565,12 +580,12 @@ impl GenericParamsCollector {
(Either::Left(type_ref), bound) => match hrtb_lifetimes {
Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
lifetimes: hrtb_lifetimes.to_vec().into_boxed_slice(),
- target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
- bound: Interned::new(bound),
+ target: WherePredicateTypeTarget::TypeRef(type_ref),
+ bound,
},
None => WherePredicate::TypeBound {
- target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
- bound: Interned::new(bound),
+ target: WherePredicateTypeTarget::TypeRef(type_ref),
+ bound,
},
},
(Either::Right(lifetime), TypeBound::Lifetime(bound)) => {
@@ -581,7 +596,7 @@ impl GenericParamsCollector {
self.where_predicates.push(predicate);
}
- fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<Vec<Interned<TypeBound>>>) {
+ fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<ThinVec<TypeBound>>) {
for bounds in impl_bounds {
let param = TypeParamData {
name: None,
@@ -589,10 +604,10 @@ impl GenericParamsCollector {
provenance: TypeParamProvenance::ArgumentImplTrait,
};
let param_id = self.type_or_consts.alloc(param.into());
- for bound in bounds {
+ for bound in &bounds {
self.where_predicates.push(WherePredicate::TypeBound {
target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
- bound,
+ bound: bound.clone(),
});
}
}
@@ -601,12 +616,16 @@ impl GenericParamsCollector {
fn fill_implicit_impl_trait_args(
&mut self,
db: &dyn DefDatabase,
+ generics_types_map: &mut TypesMap,
+ generics_types_source_map: &mut TypesSourceMap,
// FIXME: Change this back to `LazyCell` if https://github.com/rust-lang/libs-team/issues/429 is accepted.
exp: &mut Option<(Arc<DefMap>, Expander)>,
exp_fill: &mut dyn FnMut() -> (Arc<DefMap>, Expander),
- type_ref: &TypeRef,
+ type_ref: TypeRefId,
+ types_map: &TypesMap,
+ types_source_map: &TypesSourceMap,
) {
- type_ref.walk(&mut |type_ref| {
+ TypeRef::walk(type_ref, types_map, &mut |type_ref| {
if let TypeRef::ImplTrait(bounds) = type_ref {
let param = TypeParamData {
name: None,
@@ -615,12 +634,20 @@ impl GenericParamsCollector {
};
let param_id = self.type_or_consts.alloc(param.into());
for bound in bounds {
+ let bound = copy_type_bound(
+ bound,
+ types_map,
+ types_source_map,
+ generics_types_map,
+ generics_types_source_map,
+ );
self.where_predicates.push(WherePredicate::TypeBound {
target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
- bound: bound.clone(),
+ bound,
});
}
}
+
if let TypeRef::Macro(mc) = type_ref {
let macro_call = mc.to_node(db.upcast());
let (def_map, expander) = exp.get_or_insert_with(&mut *exp_fill);
@@ -641,23 +668,217 @@ impl GenericParamsCollector {
if let Ok(ExpandResult { value: Some((mark, expanded)), .. }) =
expander.enter_expand(db, macro_call, resolver)
{
- let ctx = expander.ctx(db);
+ let (mut macro_types_map, mut macro_types_source_map) =
+ (TypesMap::default(), TypesSourceMap::default());
+ let ctx = expander.ctx(db, &mut macro_types_map, &mut macro_types_source_map);
let type_ref = TypeRef::from_ast(&ctx, expanded.tree());
- self.fill_implicit_impl_trait_args(db, &mut *exp, exp_fill, &type_ref);
+ self.fill_implicit_impl_trait_args(
+ db,
+ generics_types_map,
+ generics_types_source_map,
+ &mut *exp,
+ exp_fill,
+ type_ref,
+ &macro_types_map,
+ &macro_types_source_map,
+ );
exp.get_or_insert_with(&mut *exp_fill).1.exit(mark);
}
}
});
}
- pub(crate) fn finish(self) -> GenericParams {
- let Self { mut lifetimes, mut type_or_consts, where_predicates } = self;
+ pub(crate) fn finish(
+ self,
+ mut generics_types_map: TypesMap,
+ generics_types_source_map: &mut TypesSourceMap,
+ ) -> Arc<GenericParams> {
+ let Self { mut lifetimes, mut type_or_consts, mut where_predicates } = self;
+
+ if lifetimes.is_empty() && type_or_consts.is_empty() && where_predicates.is_empty() {
+ static EMPTY: LazyLock<Arc<GenericParams>> = LazyLock::new(|| {
+ Arc::new(GenericParams {
+ lifetimes: Arena::new(),
+ type_or_consts: Arena::new(),
+ where_predicates: Box::default(),
+ types_map: TypesMap::default(),
+ })
+ });
+ return Arc::clone(&EMPTY);
+ }
+
lifetimes.shrink_to_fit();
type_or_consts.shrink_to_fit();
- GenericParams {
+ where_predicates.shrink_to_fit();
+ generics_types_map.shrink_to_fit();
+ generics_types_source_map.shrink_to_fit();
+ Arc::new(GenericParams {
type_or_consts,
lifetimes,
where_predicates: where_predicates.into_boxed_slice(),
+ types_map: generics_types_map,
+ })
+ }
+}
+
+/// Copies a `TypeRef` from a `TypesMap` (accompanied with `TypesSourceMap`) into another `TypesMap`
+/// (and `TypesSourceMap`).
+fn copy_type_ref(
+ type_ref: TypeRefId,
+ from: &TypesMap,
+ from_source_map: &TypesSourceMap,
+ to: &mut TypesMap,
+ to_source_map: &mut TypesSourceMap,
+) -> TypeRefId {
+ let result = match &from[type_ref] {
+ TypeRef::Fn(fn_) => {
+ let params = fn_.params().iter().map(|(name, param_type)| {
+ (name.clone(), copy_type_ref(*param_type, from, from_source_map, to, to_source_map))
+ });
+ TypeRef::Fn(FnType::new(fn_.is_varargs(), fn_.is_unsafe(), fn_.abi().clone(), params))
}
+ TypeRef::Tuple(types) => TypeRef::Tuple(EmptyOptimizedThinVec::from_iter(
+ types.iter().map(|&t| copy_type_ref(t, from, from_source_map, to, to_source_map)),
+ )),
+ &TypeRef::RawPtr(type_ref, mutbl) => TypeRef::RawPtr(
+ copy_type_ref(type_ref, from, from_source_map, to, to_source_map),
+ mutbl,
+ ),
+ TypeRef::Reference(ref_) => TypeRef::Reference(Box::new(RefType {
+ ty: copy_type_ref(ref_.ty, from, from_source_map, to, to_source_map),
+ lifetime: ref_.lifetime.clone(),
+ mutability: ref_.mutability,
+ })),
+ TypeRef::Array(array) => TypeRef::Array(Box::new(ArrayType {
+ ty: copy_type_ref(array.ty, from, from_source_map, to, to_source_map),
+ len: array.len.clone(),
+ })),
+ &TypeRef::Slice(type_ref) => {
+ TypeRef::Slice(copy_type_ref(type_ref, from, from_source_map, to, to_source_map))
+ }
+ TypeRef::ImplTrait(bounds) => TypeRef::ImplTrait(ThinVec::from_iter(copy_type_bounds(
+ bounds,
+ from,
+ from_source_map,
+ to,
+ to_source_map,
+ ))),
+ TypeRef::DynTrait(bounds) => TypeRef::DynTrait(ThinVec::from_iter(copy_type_bounds(
+ bounds,
+ from,
+ from_source_map,
+ to,
+ to_source_map,
+ ))),
+ TypeRef::Path(path) => {
+ TypeRef::Path(copy_path(path, from, from_source_map, to, to_source_map))
+ }
+ TypeRef::Never => TypeRef::Never,
+ TypeRef::Placeholder => TypeRef::Placeholder,
+ TypeRef::Macro(macro_call) => TypeRef::Macro(*macro_call),
+ TypeRef::Error => TypeRef::Error,
+ };
+ let id = to.types.alloc(result);
+ if let Some(&ptr) = from_source_map.types_map_back.get(id) {
+ to_source_map.types_map_back.insert(id, ptr);
+ }
+ id
+}
+
+fn copy_path(
+ path: &Path,
+ from: &TypesMap,
+ from_source_map: &TypesSourceMap,
+ to: &mut TypesMap,
+ to_source_map: &mut TypesSourceMap,
+) -> Path {
+ match path {
+ Path::BarePath(mod_path) => Path::BarePath(mod_path.clone()),
+ Path::Normal(path) => {
+ let type_anchor = path
+ .type_anchor()
+ .map(|type_ref| copy_type_ref(type_ref, from, from_source_map, to, to_source_map));
+ let mod_path = path.mod_path().clone();
+ let generic_args = path.generic_args().iter().map(|generic_args| {
+ copy_generic_args(generic_args, from, from_source_map, to, to_source_map)
+ });
+ Path::Normal(NormalPath::new(type_anchor, mod_path, generic_args))
+ }
+ Path::LangItem(lang_item, name) => Path::LangItem(*lang_item, name.clone()),
+ }
+}
+
+fn copy_generic_args(
+ generic_args: &Option<GenericArgs>,
+ from: &TypesMap,
+ from_source_map: &TypesSourceMap,
+ to: &mut TypesMap,
+ to_source_map: &mut TypesSourceMap,
+) -> Option<GenericArgs> {
+ generic_args.as_ref().map(|generic_args| {
+ let args = generic_args
+ .args
+ .iter()
+ .map(|arg| match arg {
+ &GenericArg::Type(ty) => {
+ GenericArg::Type(copy_type_ref(ty, from, from_source_map, to, to_source_map))
+ }
+ GenericArg::Lifetime(lifetime) => GenericArg::Lifetime(lifetime.clone()),
+ GenericArg::Const(konst) => GenericArg::Const(konst.clone()),
+ })
+ .collect();
+ let bindings = generic_args
+ .bindings
+ .iter()
+ .map(|binding| {
+ let name = binding.name.clone();
+ let args =
+ copy_generic_args(&binding.args, from, from_source_map, to, to_source_map);
+ let type_ref = binding.type_ref.map(|type_ref| {
+ copy_type_ref(type_ref, from, from_source_map, to, to_source_map)
+ });
+ let bounds =
+ copy_type_bounds(&binding.bounds, from, from_source_map, to, to_source_map)
+ .collect();
+ AssociatedTypeBinding { name, args, type_ref, bounds }
+ })
+ .collect();
+ GenericArgs {
+ args,
+ has_self_type: generic_args.has_self_type,
+ bindings,
+ desugared_from_fn: generic_args.desugared_from_fn,
+ }
+ })
+}
+
+fn copy_type_bounds<'a>(
+ bounds: &'a [TypeBound],
+ from: &'a TypesMap,
+ from_source_map: &'a TypesSourceMap,
+ to: &'a mut TypesMap,
+ to_source_map: &'a mut TypesSourceMap,
+) -> impl stdx::thin_vec::TrustedLen<Item = TypeBound> + 'a {
+ bounds.iter().map(|bound| copy_type_bound(bound, from, from_source_map, to, to_source_map))
+}
+
+fn copy_type_bound(
+ bound: &TypeBound,
+ from: &TypesMap,
+ from_source_map: &TypesSourceMap,
+ to: &mut TypesMap,
+ to_source_map: &mut TypesSourceMap,
+) -> TypeBound {
+ match bound {
+ TypeBound::Path(path, modifier) => {
+ TypeBound::Path(copy_path(path, from, from_source_map, to, to_source_map), *modifier)
+ }
+ TypeBound::ForLifetime(lifetimes, path) => TypeBound::ForLifetime(
+ lifetimes.clone(),
+ copy_path(path, from, from_source_map, to, to_source_map),
+ ),
+ TypeBound::Lifetime(lifetime) => TypeBound::Lifetime(lifetime.clone()),
+ TypeBound::Use(use_args) => TypeBound::Use(use_args.clone()),
+ TypeBound::Error => TypeBound::Error,
}
}