From 8e9837df21942ca12a5aece0a868ea46eb405742 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 7 Dec 2019 11:50:36 +0100 Subject: Remove idx and parent generics from generics This makes `hir_def::GenericParams` flatter. The logic for re-numbering the params is moved to hir instead. --- crates/ra_hir/src/code_model.rs | 5 +- crates/ra_hir/src/source_binder.rs | 10 +--- crates/ra_hir_def/src/generics.rs | 90 ++++++++---------------------------- crates/ra_hir_def/src/resolver.rs | 38 +++++++++------ crates/ra_hir_ty/src/autoderef.rs | 8 ++-- crates/ra_hir_ty/src/infer/expr.rs | 24 +++++----- crates/ra_hir_ty/src/lib.rs | 32 +++++-------- crates/ra_hir_ty/src/lower.rs | 35 +++++++------- crates/ra_hir_ty/src/traits/chalk.rs | 14 +++--- crates/ra_hir_ty/src/utils.rs | 82 +++++++++++++++++++++++++++++++- 10 files changed, 181 insertions(+), 157 deletions(-) diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 7706399ae..29ace8479 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -15,7 +15,7 @@ use hir_def::{ per_ns::PerNs, resolver::HasResolver, type_ref::{Mutability, TypeRef}, - AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, GenericDefId, + AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, GenericParamId, HasModule, ImplId, LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId, }; @@ -857,8 +857,7 @@ impl Local { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct GenericParam { - pub(crate) parent: GenericDefId, - pub(crate) idx: u32, + pub(crate) id: GenericParamId, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 0e136b904..8c4b635d2 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -262,10 +262,7 @@ impl SourceAnalyzer { ) -> Option { let types = self.resolver.resolve_path_in_type_ns_fully(db, &path).map(|ty| match ty { TypeNs::SelfType(it) => PathResolution::SelfType(it.into()), - TypeNs::GenericParam(idx) => PathResolution::GenericParam(GenericParam { - parent: self.resolver.generic_def().unwrap(), - idx, - }), + TypeNs::GenericParam(id) => PathResolution::GenericParam(GenericParam { id }), TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => { PathResolution::Def(Adt::from(it).into()) } @@ -337,10 +334,7 @@ impl SourceAnalyzer { resolver::ScopeDef::PerNs(it) => it.into(), resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()), resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()), - resolver::ScopeDef::GenericParam(idx) => { - let parent = self.resolver.generic_def().unwrap(); - ScopeDef::GenericParam(GenericParam { parent, idx }) - } + resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(GenericParam { id }), resolver::ScopeDef::Local(pat_id) => { let parent = self.resolver.body_owner().unwrap().into(); ScopeDef::Local(Local { parent, pat_id }) diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs index abe749a40..94ce83564 100644 --- a/crates/ra_hir_def/src/generics.rs +++ b/crates/ra_hir_def/src/generics.rs @@ -12,14 +12,12 @@ use crate::{ db::DefDatabase, src::HasSource, type_ref::{TypeBound, TypeRef}, - AdtId, AstItemDef, ContainerId, GenericDefId, LocalGenericParamId, Lookup, + AdtId, AstItemDef, GenericDefId, LocalGenericParamId, Lookup, }; /// Data about a generic parameter (to a function, struct, impl, ...). #[derive(Clone, PartialEq, Eq, Debug)] pub struct GenericParamData { - // FIXME: give generic params proper IDs - pub idx: u32, pub name: Name, pub default: Option, } @@ -27,7 +25,6 @@ pub struct GenericParamData { /// Data about the generic parameters of a function, struct, impl, etc. #[derive(Clone, PartialEq, Eq, Debug)] pub struct GenericParams { - pub parent_params: Option>, pub params: Arena, pub where_predicates: Vec, } @@ -47,51 +44,40 @@ impl GenericParams { db: &impl DefDatabase, def: GenericDefId, ) -> Arc { - let parent_generics = parent_generic_def(db, def).map(|it| db.generic_params(it)); - Arc::new(GenericParams::new(db, def.into(), parent_generics)) + Arc::new(GenericParams::new(db, def.into())) } - fn new( - db: &impl DefDatabase, - def: GenericDefId, - parent_params: Option>, - ) -> GenericParams { - let mut generics = - GenericParams { params: Arena::default(), parent_params, where_predicates: Vec::new() }; - let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32; + fn new(db: &impl DefDatabase, def: GenericDefId) -> GenericParams { + let mut generics = GenericParams { params: Arena::default(), where_predicates: Vec::new() }; // FIXME: add `: Sized` bound for everything except for `Self` in traits match def { - GenericDefId::FunctionId(it) => generics.fill(&it.lookup(db).source(db).value, start), - GenericDefId::AdtId(AdtId::StructId(it)) => generics.fill(&it.source(db).value, start), - GenericDefId::AdtId(AdtId::UnionId(it)) => generics.fill(&it.source(db).value, start), - GenericDefId::AdtId(AdtId::EnumId(it)) => generics.fill(&it.source(db).value, start), + GenericDefId::FunctionId(it) => generics.fill(&it.lookup(db).source(db).value), + GenericDefId::AdtId(AdtId::StructId(it)) => generics.fill(&it.source(db).value), + GenericDefId::AdtId(AdtId::UnionId(it)) => generics.fill(&it.source(db).value), + GenericDefId::AdtId(AdtId::EnumId(it)) => generics.fill(&it.source(db).value), GenericDefId::TraitId(it) => { // traits get the Self type as an implicit first type parameter - generics.params.alloc(GenericParamData { - idx: start, - name: name::SELF_TYPE, - default: None, - }); - generics.fill(&it.source(db).value, start + 1); + generics.params.alloc(GenericParamData { name: name::SELF_TYPE, default: None }); + generics.fill(&it.source(db).value); // 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_TYPE.into()); generics.fill_bounds(&it.source(db).value, self_param); } - GenericDefId::TypeAliasId(it) => generics.fill(&it.lookup(db).source(db).value, start), + GenericDefId::TypeAliasId(it) => generics.fill(&it.lookup(db).source(db).value), // 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. - GenericDefId::ImplId(it) => generics.fill(&it.source(db).value, start), + GenericDefId::ImplId(it) => generics.fill(&it.source(db).value), GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => {} } generics } - fn fill(&mut self, node: &impl TypeParamsOwner, start: u32) { + fn fill(&mut self, node: &impl TypeParamsOwner) { if let Some(params) = node.type_param_list() { - self.fill_params(params, start) + self.fill_params(params) } if let Some(where_clause) = node.where_clause() { self.fill_where_predicates(where_clause); @@ -106,12 +92,12 @@ impl GenericParams { } } - fn fill_params(&mut self, params: ast::TypeParamList, start: u32) { - for (idx, type_param) in params.type_params().enumerate() { + fn fill_params(&mut self, params: ast::TypeParamList) { + for type_param in params.type_params() { 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(TypeRef::from_ast); - let param = GenericParamData { idx: idx as u32 + start, name: name.clone(), default }; + let param = GenericParamData { name: name.clone(), default }; self.params.alloc(param); let type_ref = TypeRef::Path(name.into()); @@ -141,45 +127,7 @@ impl GenericParams { self.where_predicates.push(WherePredicate { type_ref, bound }); } - pub fn find_by_name(&self, name: &Name) -> Option<&GenericParamData> { - self.params.iter().map(|(_id, data)| data).find(|p| &p.name == name) - } - - pub fn count_parent_params(&self) -> usize { - self.parent_params.as_ref().map(|p| p.count_params_including_parent()).unwrap_or(0) - } - - pub fn count_params_including_parent(&self) -> usize { - let parent_count = self.count_parent_params(); - parent_count + self.params.len() - } - - fn for_each_param<'a>(&'a self, f: &mut impl FnMut(&'a GenericParamData)) { - if let Some(parent) = &self.parent_params { - parent.for_each_param(f); - } - self.params.iter().map(|(_id, data)| data).for_each(f); - } - - pub fn params_including_parent(&self) -> Vec<&GenericParamData> { - let mut vec = Vec::with_capacity(self.count_params_including_parent()); - self.for_each_param(&mut |p| vec.push(p)); - vec - } -} - -fn parent_generic_def(db: &impl DefDatabase, def: GenericDefId) -> Option { - let container = match def { - GenericDefId::FunctionId(it) => it.lookup(db).container, - GenericDefId::TypeAliasId(it) => it.lookup(db).container, - GenericDefId::ConstId(it) => it.lookup(db).container, - GenericDefId::EnumVariantId(it) => return Some(it.parent.into()), - GenericDefId::AdtId(_) | GenericDefId::TraitId(_) | GenericDefId::ImplId(_) => return None, - }; - - match container { - ContainerId::ImplId(it) => Some(it.into()), - ContainerId::TraitId(it) => Some(it.into()), - ContainerId::ModuleId(_) => None, + pub fn find_by_name(&self, name: &Name) -> Option { + self.params.iter().find_map(|(id, p)| if &p.name == name { Some(id) } else { None }) } } diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs index ee19d79a7..e00bd03d5 100644 --- a/crates/ra_hir_def/src/resolver.rs +++ b/crates/ra_hir_def/src/resolver.rs @@ -18,12 +18,13 @@ use crate::{ path::{Path, PathKind}, per_ns::PerNs, AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, - GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId, - StructId, TraitId, TypeAliasId, + GenericDefId, GenericParamId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, + StaticId, StructId, TraitId, TypeAliasId, }; #[derive(Debug, Clone, Default)] pub struct Resolver { + // FIXME: all usages generally call `.rev`, so maybe reverse once in consturciton? scopes: Vec, } @@ -58,7 +59,7 @@ enum Scope { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum TypeNs { SelfType(ImplId), - GenericParam(u32), + GenericParam(GenericParamId), AdtId(AdtId), AdtSelfType(AdtId), // Yup, enum variants are added to the types ns, but any usage of variant as @@ -152,10 +153,13 @@ impl Resolver { Scope::ExprScope(_) => continue, Scope::GenericParams { .. } | Scope::ImplBlockScope(_) if skip_to_mod => continue, - Scope::GenericParams { params, .. } => { - if let Some(param) = params.find_by_name(first_name) { + Scope::GenericParams { params, def } => { + if let Some(local_id) = params.find_by_name(first_name) { let idx = if path.segments.len() == 1 { None } else { Some(1) }; - return Some((TypeNs::GenericParam(param.idx), idx)); + return Some(( + TypeNs::GenericParam(GenericParamId { local_id, parent: *def }), + idx, + )); } } Scope::ImplBlockScope(impl_) => { @@ -246,9 +250,9 @@ impl Resolver { } Scope::ExprScope(_) => continue, - Scope::GenericParams { params, .. } if n_segments > 1 => { - if let Some(param) = params.find_by_name(first_name) { - let ty = TypeNs::GenericParam(param.idx); + Scope::GenericParams { params, def } if n_segments > 1 => { + if let Some(local_id) = params.find_by_name(first_name) { + let ty = TypeNs::GenericParam(GenericParamId { local_id, parent: *def }); return Some(ResolveValueResult::Partial(ty, 1)); } } @@ -368,6 +372,7 @@ impl Resolver { ) -> impl Iterator + 'a { self.scopes .iter() + .rev() .filter_map(|scope| match scope { Scope::GenericParams { params, .. } => Some(params), _ => None, @@ -376,14 +381,14 @@ impl Resolver { } pub fn generic_def(&self) -> Option { - self.scopes.iter().find_map(|scope| match scope { + self.scopes.iter().rev().find_map(|scope| match scope { Scope::GenericParams { def, .. } => Some(*def), _ => None, }) } pub fn body_owner(&self) -> Option { - self.scopes.iter().find_map(|scope| match scope { + self.scopes.iter().rev().find_map(|scope| match scope { Scope::ExprScope(it) => Some(it.owner), _ => None, }) @@ -394,7 +399,7 @@ pub enum ScopeDef { PerNs(PerNs), ImplSelfType(ImplId), AdtSelfType(AdtId), - GenericParam(u32), + GenericParam(GenericParamId), Local(PatId), } @@ -425,9 +430,12 @@ impl Scope { }); } } - Scope::GenericParams { params, .. } => { - for (_id, param) in params.params.iter() { - f(param.name.clone(), ScopeDef::GenericParam(param.idx)) + Scope::GenericParams { params, def } => { + for (local_id, param) in params.params.iter() { + f( + param.name.clone(), + ScopeDef::GenericParam(GenericParamId { local_id, parent: *def }), + ) } } Scope::ImplBlockScope(i) => { diff --git a/crates/ra_hir_ty/src/autoderef.rs b/crates/ra_hir_ty/src/autoderef.rs index 9d1d4e48c..a6db7f623 100644 --- a/crates/ra_hir_ty/src/autoderef.rs +++ b/crates/ra_hir_ty/src/autoderef.rs @@ -10,10 +10,10 @@ use hir_expand::name; use log::{info, warn}; use ra_db::CrateId; -use crate::db::HirDatabase; - -use super::{ +use crate::{ + db::HirDatabase, traits::{InEnvironment, Solution}, + utils::generics, Canonical, Substs, Ty, TypeWalk, }; @@ -54,7 +54,7 @@ fn deref_by_trait( }; let target = db.trait_data(deref_trait).associated_type_by_name(&name::TARGET_TYPE)?; - let generic_params = db.generic_params(target.into()); + let generic_params = generics(db, target.into()); if generic_params.count_params_including_parent() != 1 { // the Target type + Deref trait should only have one generic parameter, // namely Deref's Self type diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 0c3428999..e52040eb5 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -6,7 +6,6 @@ use std::sync::Arc; use hir_def::{ builtin_type::Signedness, expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, - generics::GenericParams, path::{GenericArg, GenericArgs}, resolver::resolver_for_expr, AdtId, ContainerId, Lookup, StructFieldId, @@ -15,7 +14,11 @@ use hir_expand::name::{self, Name}; use ra_syntax::ast::RangeOp; use crate::{ - autoderef, db::HirDatabase, method_resolution, op, traits::InEnvironment, utils::variant_data, + autoderef, + db::HirDatabase, + method_resolution, op, + traits::InEnvironment, + utils::{generics, variant_data, Generics}, CallableDef, InferTy, IntTy, Mutability, Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, Uncertain, }; @@ -596,7 +599,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Some((ty, func)) => { let ty = canonicalized_receiver.decanonicalize_ty(ty); self.write_method_resolution(tgt_expr, func); - (ty, self.db.value_ty(func.into()), Some(self.db.generic_params(func.into()))) + (ty, self.db.value_ty(func.into()), Some(generics(self.db, func.into()))) } None => (receiver_ty, Ty::Unknown, None), }; @@ -653,16 +656,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn substs_for_method_call( &mut self, - def_generics: Option>, + def_generics: Option, generic_args: Option<&GenericArgs>, receiver_ty: &Ty, ) -> Substs { - let (parent_param_count, param_count) = - def_generics.as_ref().map_or((0, 0), |g| (g.count_parent_params(), g.params.len())); + let (parent_param_count, param_count) = def_generics + .as_ref() + .map_or((0, 0), |g| (g.count_parent_params(), g.params.params.len())); let mut substs = Vec::with_capacity(parent_param_count + param_count); // Parent arguments are unknown, except for the receiver type - if let Some(parent_generics) = def_generics.and_then(|p| p.parent_params.clone()) { - for (_id, param) in parent_generics.params.iter() { + if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) { + for (_id, param) in parent_generics { if param.name == name::SELF_TYPE { substs.push(receiver_ty.clone()); } else { @@ -706,9 +710,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { if let ContainerId::TraitId(trait_) = f.lookup(self.db).container { // construct a TraitDef let substs = a_ty.parameters.prefix( - self.db - .generic_params(trait_.into()) - .count_params_including_parent(), + generics(self.db, trait_.into()).count_params_including_parent(), ); self.obligations.push(Obligation::Trait(TraitRef { trait_: trait_.into(), diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 3c1f738df..99fd7158e 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -44,7 +44,7 @@ use std::sync::Arc; use std::{fmt, iter, mem}; use hir_def::{ - expr::ExprId, generics::GenericParams, type_ref::Mutability, AdtId, ContainerId, DefWithBodyId, + expr::ExprId, type_ref::Mutability, AdtId, ContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, }; use hir_expand::name::Name; @@ -53,7 +53,7 @@ use ra_db::{impl_intern_key, salsa, CrateId}; use crate::{ db::HirDatabase, primitive::{FloatTy, IntTy, Uncertain}, - utils::make_mut_slice, + utils::{generics, make_mut_slice, Generics}, }; use display::{HirDisplay, HirFormatter}; @@ -166,15 +166,15 @@ impl TypeCtor { | TypeCtor::Closure { .. } // 1 param representing the signature of the closure => 1, TypeCtor::Adt(adt) => { - let generic_params = db.generic_params(AdtId::from(adt).into()); + let generic_params = generics(db, AdtId::from(adt).into()); generic_params.count_params_including_parent() } TypeCtor::FnDef(callable) => { - let generic_params = db.generic_params(callable.into()); + let generic_params = generics(db, callable.into()); generic_params.count_params_including_parent() } TypeCtor::AssociatedType(type_alias) => { - let generic_params = db.generic_params(type_alias.into()); + let generic_params = generics(db, type_alias.into()); generic_params.count_params_including_parent() } TypeCtor::FnPtr { num_args } => num_args as usize + 1, @@ -364,35 +364,25 @@ impl Substs { } /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). - pub fn identity(generic_params: &GenericParams) -> Substs { + pub(crate) fn identity(generic_params: &Generics) -> Substs { Substs( - generic_params - .params_including_parent() - .into_iter() - .map(|p| Ty::Param { idx: p.idx, name: p.name.clone() }) - .collect(), + generic_params.iter().map(|(idx, p)| Ty::Param { idx, name: p.name.clone() }).collect(), ) } /// Return Substs that replace each parameter by a bound variable. - pub fn bound_vars(generic_params: &GenericParams) -> Substs { - Substs( - generic_params - .params_including_parent() - .into_iter() - .map(|p| Ty::Bound(p.idx)) - .collect(), - ) + pub(crate) fn bound_vars(generic_params: &Generics) -> Substs { + Substs(generic_params.iter().map(|(idx, _p)| Ty::Bound(idx)).collect()) } pub fn build_for_def(db: &impl HirDatabase, def: impl Into) -> SubstsBuilder { let def = def.into(); - let params = db.generic_params(def); + let params = generics(db, def); let param_count = params.count_params_including_parent(); Substs::builder(param_count) } - pub fn build_for_generics(generic_params: &GenericParams) -> SubstsBuilder { + pub(crate) fn build_for_generics(generic_params: &Generics) -> SubstsBuilder { Substs::builder(generic_params.count_params_including_parent()) } diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 32569ac66..d31f6a2d2 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -24,7 +24,7 @@ use crate::{ db::HirDatabase, primitive::{FloatTy, IntTy}, utils::{ - all_super_traits, associated_type_by_name_including_super_traits, make_mut_slice, + all_super_traits, associated_type_by_name_including_super_traits, generics, make_mut_slice, variant_data, }, FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, @@ -111,7 +111,9 @@ impl Ty { Some((it, None)) => it, _ => return None, }; - if let TypeNs::GenericParam(idx) = resolution { + if let TypeNs::GenericParam(param_id) = resolution { + let generics = generics(db, resolver.generic_def().expect("generics in scope")); + let idx = generics.param_idx(param_id); Some(idx) } else { None @@ -174,9 +176,11 @@ impl Ty { Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)])) }; } - TypeNs::GenericParam(idx) => { + TypeNs::GenericParam(param_id) => { + let generics = generics(db, resolver.generic_def().expect("generics in scope")); + let idx = generics.param_idx(param_id); // FIXME: maybe return name in resolution? - let name = resolved_segment.name.clone(); + let name = generics.param_name(param_id); Ty::Param { idx, name } } TypeNs::SelfType(impl_id) => db.impl_self_ty(impl_id).clone(), @@ -315,10 +319,10 @@ pub(super) fn substs_from_path_segment( add_self_param: bool, ) -> Substs { let mut substs = Vec::new(); - let def_generics = def_generic.map(|def| db.generic_params(def.into())); + let def_generics = def_generic.map(|def| generics(db, def.into())); let (parent_param_count, param_count) = - def_generics.map_or((0, 0), |g| (g.count_parent_params(), g.params.len())); + def_generics.map_or((0, 0), |g| (g.count_parent_params(), g.params.params.len())); substs.extend(iter::repeat(Ty::Unknown).take(parent_param_count)); if add_self_param { // FIXME this add_self_param argument is kind of a hack: Traits have the @@ -567,12 +571,11 @@ pub(crate) fn generic_predicates_query( /// Resolve the default type params from generics pub(crate) fn generic_defaults_query(db: &impl HirDatabase, def: GenericDefId) -> Substs { let resolver = def.resolver(db); - let generic_params = db.generic_params(def.into()); + let generic_params = generics(db, def.into()); let defaults = generic_params - .params_including_parent() - .into_iter() - .map(|p| p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(db, &resolver, t))) + .iter() + .map(|(_idx, p)| p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(db, &resolver, t))) .collect(); Substs(defaults) @@ -589,7 +592,7 @@ fn fn_sig_for_fn(db: &impl HirDatabase, def: FunctionId) -> FnSig { /// Build the declared type of a function. This should not need to look at the /// function body. fn type_for_fn(db: &impl HirDatabase, def: FunctionId) -> Ty { - let generics = db.generic_params(def.into()); + let generics = generics(db, def.into()); let substs = Substs::identity(&generics); Ty::apply(TypeCtor::FnDef(def.into()), substs) } @@ -639,7 +642,7 @@ fn type_for_struct_constructor(db: &impl HirDatabase, def: StructId) -> Ty { if struct_data.variant_data.is_unit() { return type_for_adt(db, def.into()); // Unit struct } - let generics = db.generic_params(def.into()); + let generics = generics(db, def.into()); let substs = Substs::identity(&generics); Ty::apply(TypeCtor::FnDef(def.into()), substs) } @@ -653,7 +656,7 @@ fn fn_sig_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariantId .iter() .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) .collect::>(); - let generics = db.generic_params(def.parent.into()); + let generics = generics(db, def.parent.into()); let substs = Substs::identity(&generics); let ret = type_for_adt(db, def.parent.into()).subst(&substs); FnSig::from_params_and_return(params, ret) @@ -666,18 +669,18 @@ fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariantId) if var_data.is_unit() { return type_for_adt(db, def.parent.into()); // Unit variant } - let generics = db.generic_params(def.parent.into()); + let generics = generics(db, def.parent.into()); let substs = Substs::identity(&generics); Ty::apply(TypeCtor::FnDef(EnumVariantId::from(def).into()), substs) } fn type_for_adt(db: &impl HirDatabase, adt: AdtId) -> Ty { - let generics = db.generic_params(adt.into()); + let generics = generics(db, adt.into()); Ty::apply(TypeCtor::Adt(adt), Substs::identity(&generics)) } fn type_for_type_alias(db: &impl HirDatabase, t: TypeAliasId) -> Ty { - let generics = db.generic_params(t.into()); + let generics = generics(db, t.into()); let resolver = t.resolver(db); let type_ref = &db.type_alias_data(t).type_ref; let substs = Substs::identity(&generics); diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index e3f02fa15..1d44320b9 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -19,8 +19,8 @@ use ra_db::{ use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; use crate::{ - db::HirDatabase, display::HirDisplay, ApplicationTy, GenericPredicate, ProjectionTy, Substs, - TraitRef, Ty, TypeCtor, TypeWalk, + db::HirDatabase, display::HirDisplay, utils::generics, ApplicationTy, GenericPredicate, + ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, }; /// This represents a trait whose name we could not resolve. @@ -547,7 +547,7 @@ pub(crate) fn associated_ty_data_query( ContainerId::TraitId(t) => t, _ => panic!("associated type not in trait"), }; - let generic_params = db.generic_params(type_alias.into()); + let generic_params = generics(db, type_alias.into()); let bound_data = chalk_rust_ir::AssociatedTyDatumBound { // FIXME add bounds and where clauses bounds: vec![], @@ -589,7 +589,7 @@ pub(crate) fn trait_datum_query( let trait_: TraitId = from_chalk(db, trait_id); let trait_data = db.trait_data(trait_); debug!("trait {:?} = {:?}", trait_id, trait_data.name); - let generic_params = db.generic_params(trait_.into()); + let generic_params = generics(db, trait_.into()); let bound_vars = Substs::bound_vars(&generic_params); let flags = chalk_rust_ir::TraitFlags { auto: trait_data.auto, @@ -626,7 +626,7 @@ pub(crate) fn struct_datum_query( let where_clauses = type_ctor .as_generic_def() .map(|generic_def| { - let generic_params = db.generic_params(generic_def.into()); + let generic_params = generics(db, generic_def.into()); let bound_vars = Substs::bound_vars(&generic_params); convert_where_clauses(db, generic_def, &bound_vars) }) @@ -669,7 +669,7 @@ fn impl_block_datum( let trait_ref = db.impl_trait(impl_id)?; let impl_data = db.impl_data(impl_id); - let generic_params = db.generic_params(impl_id.into()); + let generic_params = generics(db, impl_id.into()); let bound_vars = Substs::bound_vars(&generic_params); let trait_ref = trait_ref.subst(&bound_vars); let trait_ = trait_ref.trait_; @@ -767,7 +767,7 @@ fn type_alias_associated_ty_value( .trait_data(trait_ref.trait_) .associated_type_by_name(&type_alias_data.name) .expect("assoc ty value should not exist"); // validated when building the impl data as well - let generic_params = db.generic_params(impl_id.into()); + let generic_params = generics(db, impl_id.into()); let bound_vars = Substs::bound_vars(&generic_params); let ty = db.ty(type_alias.into()).subst(&bound_vars); let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(db) }; diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index e4ba890ef..2c458867f 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs @@ -5,9 +5,10 @@ use std::sync::Arc; use hir_def::{ adt::VariantData, db::DefDatabase, + generics::{GenericParamData, GenericParams}, resolver::{HasResolver, TypeNs}, type_ref::TypeRef, - TraitId, TypeAliasId, VariantId, + ContainerId, GenericDefId, GenericParamId, Lookup, TraitId, TypeAliasId, VariantId, }; use hir_expand::name::{self, Name}; @@ -82,3 +83,82 @@ pub(crate) fn make_mut_slice(a: &mut Arc<[T]>) -> &mut [T] { } Arc::get_mut(a).unwrap() } + +pub(crate) fn generics(db: &impl DefDatabase, def: GenericDefId) -> Generics { + let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); + Generics { def, params: db.generic_params(def), parent_generics } +} + +pub(crate) struct Generics { + def: GenericDefId, + pub(crate) params: Arc, + parent_generics: Option>, +} + +impl Generics { + pub(crate) fn iter<'a>(&'a self) -> impl Iterator + 'a { + self.parent_generics + .as_ref() + .into_iter() + .flat_map(|it| it.params.params.iter()) + .chain(self.params.params.iter()) + .enumerate() + .map(|(i, (_local_id, p))| (i as u32, p)) + } + + pub(crate) fn iter_parent<'a>( + &'a self, + ) -> impl Iterator + 'a { + self.parent_generics + .as_ref() + .into_iter() + .flat_map(|it| it.params.params.iter()) + .enumerate() + .map(|(i, (_local_id, p))| (i as u32, p)) + } + + pub(crate) fn count_parent_params(&self) -> usize { + self.parent_generics.as_ref().map_or(0, |p| p.count_params_including_parent()) + } + + pub(crate) fn count_params_including_parent(&self) -> usize { + let parent_count = self.count_parent_params(); + parent_count + self.params.params.len() + } + pub(crate) fn param_idx(&self, param: GenericParamId) -> u32 { + self.find_param(param).0 + } + pub(crate) fn param_name(&self, param: GenericParamId) -> Name { + self.find_param(param).1.name.clone() + } + fn find_param(&self, param: GenericParamId) -> (u32, &GenericParamData) { + if param.parent == self.def { + let (idx, (_local_id, data)) = self + .params + .params + .iter() + .enumerate() + .find(|(_, (idx, _))| *idx == param.local_id) + .unwrap(); + + return ((self.count_parent_params() + idx) as u32, data); + } + self.parent_generics.as_ref().unwrap().find_param(param) + } +} + +fn parent_generic_def(db: &impl DefDatabase, def: GenericDefId) -> Option { + let container = match def { + GenericDefId::FunctionId(it) => it.lookup(db).container, + GenericDefId::TypeAliasId(it) => it.lookup(db).container, + GenericDefId::ConstId(it) => it.lookup(db).container, + GenericDefId::EnumVariantId(it) => return Some(it.parent.into()), + GenericDefId::AdtId(_) | GenericDefId::TraitId(_) | GenericDefId::ImplId(_) => return None, + }; + + match container { + ContainerId::ImplId(it) => Some(it.into()), + ContainerId::TraitId(it) => Some(it.into()), + ContainerId::ModuleId(_) => None, + } +} -- cgit v1.2.3