- fn def_ids_for_path_segments(&self,
- segments: &[hir::PathSegment],
- def: Def)
- -> Vec<PathSeg> {
- // We need to extract the type parameters supplied by the user in
- // the path `path`. Due to the current setup, this is a bit of a
- // tricky-process; the problem is that resolve only tells us the
- // end-point of the path resolution, and not the intermediate steps.
- // Luckily, we can (at least for now) deduce the intermediate steps
- // just from the end-point.
- //
- // There are basically four cases to consider:
- //
- // 1. Reference to a constructor of enum variant or struct:
- //
- // struct Foo<T>(...)
- // enum E<T> { Foo(...) }
- //
- // In these cases, the parameters are declared in the type
- // space.
- //
- // 2. Reference to a fn item or a free constant:
- //
- // fn foo<T>() { }
- //
- // In this case, the path will again always have the form
- // `a::b::foo::<T>` where only the final segment should have
- // type parameters. However, in this case, those parameters are
- // declared on a value, and hence are in the `FnSpace`.
- //
- // 3. Reference to a method or an associated constant:
- //
- // impl<A> SomeStruct<A> {
- // fn foo<B>(...)
- // }
- //
- // Here we can have a path like
- // `a::b::SomeStruct::<A>::foo::<B>`, in which case parameters
- // may appear in two places. The penultimate segment,
- // `SomeStruct::<A>`, contains parameters in TypeSpace, and the
- // final segment, `foo::<B>` contains parameters in fn space.
- //
- // 4. Reference to a local variable
- //
- // Local variables can't have any type parameters.
- //
- // The first step then is to categorize the segments appropriately.
-
- assert!(!segments.is_empty());
- let last = segments.len() - 1;
-
- let mut path_segs = vec![];
-
- match def {
- // Case 1. Reference to a struct/variant constructor.
- Def::StructCtor(def_id, ..) |
- Def::VariantCtor(def_id, ..) |
- Def::SelfCtor(.., def_id) => {
- // Everything but the final segment should have no
- // parameters at all.
- let generics = self.tcx.generics_of(def_id);
- // Variant and struct constructors use the
- // generics of their parent type definition.
- let generics_def_id = generics.parent.unwrap_or(def_id);
- path_segs.push(PathSeg(generics_def_id, last));
- }
-
- // Case 2. Reference to a top-level value.
- Def::Fn(def_id) |
- Def::Const(def_id) |
- Def::Static(def_id, _) => {
- path_segs.push(PathSeg(def_id, last));
- }
-
- // Case 3. Reference to a method or associated const.
- Def::Method(def_id) |
- Def::AssociatedConst(def_id) => {
- if segments.len() >= 2 {
- let generics = self.tcx.generics_of(def_id);
- path_segs.push(PathSeg(generics.parent.unwrap(), last - 1));
- }
- path_segs.push(PathSeg(def_id, last));
- }
-
- // Case 4. Local variable, no generics.
- Def::Local(..) | Def::Upvar(..) => {}
-
- _ => bug!("unexpected definition: {:?}", def),
- }
-
- debug!("path_segs = {:?}", path_segs);
-
- path_segs
- }
-