From 413c87f155ab6b389b1cc122b5739716acccb476 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 26 Mar 2019 23:07:26 +0100 Subject: Get substs for trait refs in impl blocks --- crates/ra_hir/src/ty/lower.rs | 95 +++++++++++++++++++++++-------- crates/ra_hir/src/ty/method_resolution.rs | 6 +- 2 files changed, 74 insertions(+), 27 deletions(-) (limited to 'crates/ra_hir/src/ty') diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 003a89f0d..4523b3954 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -17,9 +17,9 @@ use crate::{ resolve::{Resolver, Resolution}, path::{ PathSegment, GenericArg}, generics::GenericParams, - adt::VariantDef, + adt::VariantDef, Trait }; -use super::{Ty, primitive, FnSig, Substs, TypeCtor}; +use super::{Ty, primitive, FnSig, Substs, TypeCtor, TraitRef}; impl Ty { pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { @@ -115,7 +115,6 @@ impl Ty { segment: &PathSegment, resolved: TypableDef, ) -> Substs { - let mut substs = Vec::new(); let def_generics = match resolved { TypableDef::Function(func) => func.generic_params(db), TypableDef::Struct(s) => s.generic_params(db), @@ -124,28 +123,7 @@ impl Ty { TypableDef::TypeAlias(t) => t.generic_params(db), TypableDef::Const(_) | TypableDef::Static(_) => GenericParams::default().into(), }; - let parent_param_count = def_generics.count_parent_params(); - substs.extend((0..parent_param_count).map(|_| Ty::Unknown)); - if let Some(generic_args) = &segment.args_and_bindings { - // if args are provided, it should be all of them, but we can't rely on that - let param_count = def_generics.params.len(); - for arg in generic_args.args.iter().take(param_count) { - match arg { - GenericArg::Type(type_ref) => { - let ty = Ty::from_hir(db, resolver, type_ref); - substs.push(ty); - } - } - } - } - // add placeholders for args that were not provided - // FIXME: handle defaults - let supplied_params = substs.len(); - for _ in supplied_params..def_generics.count_params_including_parent() { - substs.push(Ty::Unknown); - } - assert_eq!(substs.len(), def_generics.count_params_including_parent()); - Substs(substs.into()) + substs_from_path_segment(db, resolver, segment, &def_generics, false) } /// Collect generic arguments from a path into a `Substs`. See also @@ -185,6 +163,73 @@ impl Ty { } } +pub(super) fn substs_from_path_segment( + db: &impl HirDatabase, + resolver: &Resolver, + segment: &PathSegment, + def_generics: &GenericParams, + add_self_param: bool, +) -> Substs { + let mut substs = Vec::new(); + let parent_param_count = def_generics.count_parent_params(); + substs.extend((0..parent_param_count).map(|_| Ty::Unknown)); + if add_self_param { + // FIXME this add_self_param argument is kind of a hack: Traits have the + // Self type as an implicit first type parameter, but it can't be + // actually provided in the type arguments + substs.push(Ty::Unknown); + } + if let Some(generic_args) = &segment.args_and_bindings { + // if args are provided, it should be all of them, but we can't rely on that + let param_count = def_generics.params.len(); + for arg in generic_args.args.iter().take(param_count) { + match arg { + GenericArg::Type(type_ref) => { + let ty = Ty::from_hir(db, resolver, type_ref); + substs.push(ty); + } + } + } + } + // add placeholders for args that were not provided + // FIXME: handle defaults + let supplied_params = substs.len(); + for _ in supplied_params..def_generics.count_params_including_parent() { + substs.push(Ty::Unknown); + } + assert_eq!(substs.len(), def_generics.count_params_including_parent()); + Substs(substs.into()) +} + +impl TraitRef { + pub(crate) fn from_hir( + db: &impl HirDatabase, + resolver: &Resolver, + type_ref: &TypeRef, + ) -> Option { + let path = match type_ref { + TypeRef::Path(path) => path, + _ => return None, + }; + let resolved = match resolver.resolve_path(db, &path).take_types()? { + Resolution::Def(ModuleDef::Trait(tr)) => tr, + _ => return None, + }; + let substs = Self::substs_from_path(db, resolver, path, resolved); + Some(TraitRef { trait_: resolved, substs }) + } + + fn substs_from_path( + db: &impl HirDatabase, + resolver: &Resolver, + path: &Path, + resolved: Trait, + ) -> Substs { + let segment = path.segments.last().expect("path should have at least one segment"); + substs_from_path_segment(db, resolver, segment, &resolved.generic_params(db), true) + } +} + /// Build the declared type of an item. This depends on the namespace; e.g. for /// `struct Foo(usize)`, we have two types: The type of the struct itself, and /// the constructor function `(usize) -> Foo` which lives in the values diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index bb23246a6..aac7d6384 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -72,9 +72,9 @@ impl CrateImplBlocks { let target_ty = impl_block.target_ty(db); - if let Some(tr) = impl_block.target_trait(db) { + if let Some(tr) = impl_block.target_trait_ref(db) { self.impls_by_trait - .entry(tr) + .entry(tr.trait_) .or_insert_with(Vec::new) .push((module.module_id, impl_id)); } else { @@ -185,6 +185,8 @@ impl Ty { // well (in fact, the 'implements' condition could just be considered a // 'where Self: Trait' clause) candidates.retain(|(t, _m)| { + // FIXME construct substs of the correct length for the trait + // - check in rustc whether it does anything smarter than putting variables for everything let trait_ref = TraitRef { trait_: *t, substs: Substs::single(self.clone()) }; db.implements(trait_ref) }); -- cgit v1.2.3