about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2015-02-05 13:20:48 +0200
committerEduard Burtescu <edy.burt@gmail.com>2015-02-24 14:14:17 +0200
commit0f49254b31353a80710af50e4f387740d154e60b (patch)
tree6df845d55cc576759ebb058248e11523ac408ba7
parent5809f8ae746dbde96e0924b8e422b9e0d092375b (diff)
downloadrust-0f49254b31353a80710af50e4f387740d154e60b.tar.gz
rust-0f49254b31353a80710af50e4f387740d154e60b.zip
rustc: use partially resolved definitions to replace the `T::A` hack.
-rw-r--r--src/librustc/middle/astconv_util.rs38
-rw-r--r--src/librustc/middle/astencode.rs4
-rw-r--r--src/librustc/middle/def.rs40
-rw-r--r--src/librustc/middle/mem_categorization.rs2
-rw-r--r--src/librustc/middle/ty.rs9
-rw-r--r--src/librustc_driver/driver.rs2
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs2
-rw-r--r--src/librustc_resolve/lib.rs150
-rw-r--r--src/librustc_trans/save/mod.rs1
-rw-r--r--src/librustc_trans/trans/callee.rs2
-rw-r--r--src/librustc_typeck/astconv.rs481
-rw-r--r--src/librustc_typeck/check/mod.rs7
-rw-r--r--src/test/compile-fail/issue-7607-1.rs4
-rw-r--r--src/test/compile-fail/issue-8767.rs2
-rw-r--r--src/test/compile-fail/trait-impl-for-module.rs2
-rw-r--r--src/test/compile-fail/trait-or-new-type-instead.rs5
16 files changed, 376 insertions, 375 deletions
diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs
index d45c18efee7..621a231ed7d 100644
--- a/src/librustc/middle/astconv_util.rs
+++ b/src/librustc/middle/astconv_util.rs
@@ -17,29 +17,47 @@
 use middle::def;
 use middle::ty::{self, Ty};
 use syntax::ast;
+use syntax::codemap::Span;
 use util::ppaux::Repr;
 
 pub const NO_REGIONS: uint = 1;
 pub const NO_TPS: uint = 2;
 
 pub fn check_path_args(tcx: &ty::ctxt,
-                       path: &ast::Path,
+                       span: Span,
+                       segments: &[ast::PathSegment],
                        flags: uint) {
     if (flags & NO_TPS) != 0 {
-        if path.segments.iter().any(|s| s.parameters.has_types()) {
-            span_err!(tcx.sess, path.span, E0109,
+        if segments.iter().any(|s| s.parameters.has_types()) {
+            span_err!(tcx.sess, span, E0109,
                 "type parameters are not allowed on this type");
         }
     }
 
     if (flags & NO_REGIONS) != 0 {
-        if path.segments.iter().any(|s| s.parameters.has_lifetimes()) {
-            span_err!(tcx.sess, path.span, E0110,
+        if segments.iter().any(|s| s.parameters.has_lifetimes()) {
+            span_err!(tcx.sess, span, E0110,
                 "lifetime parameters are not allowed on this type");
         }
     }
 }
 
+pub fn prim_ty_to_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
+                           span: Span,
+                           segments: &[ast::PathSegment],
+                           nty: ast::PrimTy)
+                           -> Ty<'tcx> {
+    check_path_args(tcx, span, segments, NO_TPS | NO_REGIONS);
+    match nty {
+        ast::TyBool => tcx.types.bool,
+        ast::TyChar => tcx.types.char,
+        ast::TyInt(it) => ty::mk_mach_int(tcx, it),
+        ast::TyUint(uit) => ty::mk_mach_uint(tcx, uit),
+        ast::TyFloat(ft) => ty::mk_mach_float(tcx, ft),
+        ast::TyStr => ty::mk_str(tcx)
+    }
+}
+
 pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty)
                                -> Option<Ty<'tcx>> {
     if let ast::TyPath(ref path) = ast_ty.node {
@@ -51,15 +69,7 @@ pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty)
             Some(&d) => d
         };
         if let def::DefPrimTy(nty) = def {
-            check_path_args(tcx, path, NO_TPS | NO_REGIONS);
-            Some(match nty {
-                ast::TyBool => tcx.types.bool,
-                ast::TyChar => tcx.types.char,
-                ast::TyInt(it) => ty::mk_mach_int(tcx, it),
-                ast::TyUint(uit) => ty::mk_mach_uint(tcx, uit),
-                ast::TyFloat(ft) => ty::mk_mach_float(tcx, ft),
-                ast::TyStr => ty::mk_str(tcx)
-            })
+            Some(prim_ty_to_ty(tcx, path.span, &path.segments[], nty))
         } else {
             None
         }
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 37586b08b36..f7d34f0056b 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -444,10 +444,6 @@ impl tr for def::Def {
           def::DefTy(did, is_enum) => def::DefTy(did.tr(dcx), is_enum),
           def::DefAssociatedTy(trait_did, did) =>
               def::DefAssociatedTy(trait_did.tr(dcx), did.tr(dcx)),
-          def::DefAssociatedPath(def::TyParamProvenance::FromSelf(did), ident) =>
-              def::DefAssociatedPath(def::TyParamProvenance::FromSelf(did.tr(dcx)), ident),
-          def::DefAssociatedPath(def::TyParamProvenance::FromParam(did), ident) =>
-              def::DefAssociatedPath(def::TyParamProvenance::FromParam(did.tr(dcx)), ident),
           def::DefPrimTy(p) => def::DefPrimTy(p),
           def::DefTyParam(s, index, def_id, n) => def::DefTyParam(s, index, def_id.tr(dcx), n),
           def::DefUse(did) => def::DefUse(did.tr(dcx)),
diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs
index 191672775f2..e1794cc0c8a 100644
--- a/src/librustc/middle/def.rs
+++ b/src/librustc/middle/def.rs
@@ -33,11 +33,6 @@ pub enum Def {
     DefVariant(ast::DefId /* enum */, ast::DefId /* variant */, bool /* is_structure */),
     DefTy(ast::DefId, bool /* is_enum */),
     DefAssociatedTy(ast::DefId /* trait */, ast::DefId),
-    // A partially resolved path to an associated type `T::U` where `T` is a concrete
-    // type (indicated by the DefId) which implements a trait which has an associated
-    // type `U` (indicated by the Ident).
-    // FIXME(#20301) -- should use Name
-    DefAssociatedPath(TyParamProvenance, ast::Ident),
     DefTrait(ast::DefId),
     DefPrimTy(ast::PrimTy),
     DefTyParam(ParamSpace, u32, ast::DefId, ast::Name),
@@ -59,8 +54,24 @@ pub enum Def {
     DefMethod(ast::DefId /* method */, Option<ast::DefId> /* trait */, MethodProvenance),
 }
 
+/// The result of resolving the prefix of a path to a type:
+///
+///     module::Type::AssocA::AssocB::AssocC::MethodOrAssocType
+///     ^~~~~~~~~~~~  ^~~~~~~~~~~~~~~~~~~~~~
+///     base_type     extra_associated_types
+///
+///     <T as Trait>::AssocA::AssocB::AssocC::MethodOrAssocType
+///           ^~~~~~~~~~~~~~  ^~~~~~~~~~~~~~
+///           base_type       extra_associated_types
+#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct PartialDef {
+    pub base_type: Def,
+    pub extra_associated_types: u32,
+}
+
 // Definition mapping
 pub type DefMap = RefCell<NodeMap<Def>>;
+pub type PartialDefMap = RefCell<NodeMap<PartialDef>>;
 // This is the replacement export map. It maps a module to all of the exports
 // within.
 pub type ExportMap = NodeMap<Vec<Export>>;
@@ -77,12 +88,6 @@ pub enum MethodProvenance {
     FromImpl(ast::DefId),
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum TyParamProvenance {
-    FromSelf(ast::DefId),
-    FromParam(ast::DefId),
-}
-
 impl MethodProvenance {
     pub fn map<F>(self, f: F) -> MethodProvenance where
         F: FnOnce(ast::DefId) -> ast::DefId,
@@ -94,15 +99,6 @@ impl MethodProvenance {
     }
 }
 
-impl TyParamProvenance {
-    pub fn def_id(&self) -> ast::DefId {
-        match *self {
-            TyParamProvenance::FromSelf(ref did) => did.clone(),
-            TyParamProvenance::FromParam(ref did) => did.clone(),
-        }
-    }
-}
-
 #[derive(Clone, Copy, Eq, PartialEq)]
 pub enum TraitItemKind {
     NonstaticMethodTraitItemKind,
@@ -135,9 +131,7 @@ impl Def {
             DefForeignMod(id) | DefStatic(id, _) |
             DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) |
             DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) |
-            DefMethod(id, _, _) | DefConst(id) |
-            DefAssociatedPath(TyParamProvenance::FromSelf(id), _) |
-            DefAssociatedPath(TyParamProvenance::FromParam(id), _) => {
+            DefMethod(id, _, _) | DefConst(id) => {
                 id
             }
             DefLocal(id) |
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 59e090a6037..57aac8f98b6 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -582,7 +582,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
           def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) |
           def::DefTyParam(..) | def::DefRegion(_) |
           def::DefLabel(_) | def::DefSelfTy(..) |
-          def::DefAssociatedTy(..) | def::DefAssociatedPath(..)=> {
+          def::DefAssociatedTy(..) => {
               Ok(Rc::new(cmt_ {
                   id:id,
                   span:span,
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index c4fe3f4df02..2b0d032aa6d 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -46,7 +46,7 @@ use metadata::csearch;
 use middle;
 use middle::check_const;
 use middle::const_eval;
-use middle::def::{self, DefMap, ExportMap};
+use middle::def::{self, DefMap, ExportMap, PartialDefMap};
 use middle::dependency_format;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem};
 use middle::lang_items::{FnOnceTraitLangItem, TyDescStructLangItem};
@@ -682,6 +682,7 @@ pub struct ctxt<'tcx> {
 
     pub sess: Session,
     pub def_map: DefMap,
+    pub partial_def_map: PartialDefMap,
 
     pub named_region_map: resolve_lifetime::NamedRegionMap,
 
@@ -2423,7 +2424,8 @@ impl<'tcx> CommonTypes<'tcx> {
 
 pub fn mk_ctxt<'tcx>(s: Session,
                      arenas: &'tcx CtxtArenas<'tcx>,
-                     dm: DefMap,
+                     def_map: DefMap,
+                     partial_def_map: PartialDefMap,
                      named_region_map: resolve_lifetime::NamedRegionMap,
                      map: ast_map::Map<'tcx>,
                      freevars: RefCell<FreevarMap>,
@@ -2445,7 +2447,8 @@ pub fn mk_ctxt<'tcx>(s: Session,
         item_variance_map: RefCell::new(DefIdMap()),
         variance_computed: Cell::new(false),
         sess: s,
-        def_map: dm,
+        def_map: def_map,
+        partial_def_map: partial_def_map,
         region_maps: region_maps,
         node_types: RefCell::new(FnvHashMap()),
         item_substs: RefCell::new(NodeMap()),
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index b12f05d7c50..b5933ca11ba 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -567,6 +567,7 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
 
     let resolve::CrateMap {
         def_map,
+        partial_def_map,
         freevars,
         export_map,
         trait_map,
@@ -607,6 +608,7 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
     let ty_cx = ty::mk_ctxt(sess,
                             arenas,
                             def_map,
+                            partial_def_map,
                             named_region_map,
                             ast_map,
                             freevars,
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index cc47090198b..fefb3c5fe7d 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -940,7 +940,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
                                                   is_public,
                                                   DUMMY_SP)
           }
-          DefTy(..) | DefAssociatedTy(..) | DefAssociatedPath(..) => {
+          DefTy(..) | DefAssociatedTy(..) => {
               debug!("(building reduced graph for external \
                       crate) building type {}", final_ident);
 
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index b211681992b..4a57dd0912e 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -935,6 +935,7 @@ struct Resolver<'a, 'tcx:'a> {
     primitive_type_table: PrimitiveTypeTable,
 
     def_map: DefMap,
+    partial_def_map: PartialDefMap,
     freevars: RefCell<FreevarMap>,
     freevars_seen: RefCell<NodeMap<NodeSet>>,
     export_map: ExportMap,
@@ -1008,6 +1009,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             primitive_type_table: PrimitiveTypeTable::new(),
 
             def_map: RefCell::new(NodeMap()),
+            partial_def_map: RefCell::new(NodeMap()),
             freevars: RefCell::new(NodeMap()),
             freevars_seen: RefCell::new(NodeMap()),
             export_map: NodeMap(),
@@ -2988,13 +2990,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                id: NodeId,
                                trait_path: &Path,
                                path_depth: usize)
-                               -> Result<(Def, LastPrivate), ()> {
+                               -> Result<(Def, LastPrivate, usize), ()> {
         match self.resolve_path(id, trait_path, path_depth, TypeNS, true) {
-            Some(def @ (DefTrait(_), _)) => {
+            Some(def @ (DefTrait(_), _, _)) => {
                 debug!("(resolving trait) found trait def: {:?}", def);
                 Ok(def)
             }
-            Some((def, _)) => {
+            Some((def, _, _)) => {
                 self.resolve_error(trait_path.span,
                     &format!("`{}` is not a trait",
                              self.path_names_to_string(trait_path, path_depth)));
@@ -3025,8 +3027,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 &ast::WherePredicate::RegionPredicate(_) => {}
                 &ast::WherePredicate::EqPredicate(ref eq_pred) => {
                     match self.resolve_path(eq_pred.id, &eq_pred.path, 0, TypeNS, true) {
-                        Some((def @ DefTyParam(..), last_private)) => {
-                            self.record_def(eq_pred.id, (def, last_private));
+                        Some(def @ (DefTyParam(..), _, _)) => {
+                            self.record_def(eq_pred.id, def);
                         }
                         _ => {
                             self.resolve_error(eq_pred.path.span,
@@ -3121,30 +3123,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 });
             });
         });
-
-        // Check that the current type is indeed a type, if we have an anonymous impl
-        if opt_trait_reference.is_none() {
-            match self_type.node {
-                // TyPath is the only thing that we handled in `build_reduced_graph_for_item`,
-                // where we created a module with the name of the type in order to implement
-                // an anonymous trait. In the case that the path does not resolve to an actual
-                // type, the result will be that the type name resolves to a module but not
-                // a type (shadowing any imported modules or types with this name), leading
-                // to weird user-visible bugs. So we ward this off here. See #15060.
-                TyPath(ref path) => {
-                    match self.def_map.borrow().get(&self_type.id) {
-                        // FIXME: should we catch other options and give more precise errors?
-                        Some(&DefMod(_)) => {
-                            self.resolve_error(path.span, "inherent implementations are not \
-                                                           allowed for types not defined in \
-                                                           the current module");
-                        }
-                        _ => {}
-                    }
-                }
-                _ => { }
-            }
-        }
     }
 
     fn check_trait_item(&self, name: Name, span: Span) {
@@ -3304,14 +3282,31 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             // on whether the path has multiple elements in it or not.
 
             TyPath(ref path) | TyQPath(ast::QPath { ref path, .. }) => {
-                if let TyQPath(_) = ty.node {
+                let max_assoc_types = if let TyQPath(_) = ty.node {
                     // Make sure the trait is valid.
-                    self.resolve_trait_reference(ty.id, path, 1);
+                    let _ = self.resolve_trait_reference(ty.id, path, 1);
+                    1
+                } else {
+                    path.segments.len()
+                };
+
+                let mut result = None;
+                for depth in 0..max_assoc_types {
+                    self.with_no_errors(|this| {
+                        result = this.resolve_path(ty.id, path, depth, TypeNS, true);
+                    });
+                    if result.is_some() {
+                        break;
+                    }
+                }
+                if let Some((DefMod(_), _, _)) = result {
+                    // A module is not a valid type.
+                    result = None;
                 }
 
                 // This is a path in the type namespace. Walk through scopes
                 // looking for it.
-                match self.resolve_path(ty.id, path, 0, TypeNS, true) {
+                match result {
                     Some(def) => {
                         // Write the result into the def map.
                         debug!("(resolving type) writing resolution for `{}` \
@@ -3321,6 +3316,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         self.record_def(ty.id, def);
                     }
                     None => {
+                        // Keep reporting some errors even if they're ignored above.
+                        self.resolve_path(ty.id, path, 0, TypeNS, true);
+
                         let kind = match ty.node {
                             TyQPath(_) => "associated type",
                             _ => "type name"
@@ -3371,7 +3369,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                 pattern,
                                 binding_mode,
                                 "an enum variant");
-                            self.record_def(pattern.id, (def, lp));
+                            self.record_def(pattern.id, (def, lp, 0));
                         }
                         FoundStructOrEnumVariant(..) => {
                             self.resolve_error(
@@ -3390,7 +3388,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                 pattern,
                                 binding_mode,
                                 "a constant");
-                            self.record_def(pattern.id, (def, lp));
+                            self.record_def(pattern.id, (def, lp, 0));
                         }
                         FoundConst(..) => {
                             self.resolve_error(pattern.span,
@@ -3407,7 +3405,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             // will be able to distinguish variants from
                             // locals in patterns.
 
-                            self.record_def(pattern.id, (def, LastMod(AllPublic)));
+                            self.record_def(pattern.id, (def, LastMod(AllPublic), 0));
 
                             // Add the binding to the local ribs, if it
                             // doesn't already exist in the bindings list. (We
@@ -3451,12 +3449,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 PatEnum(ref path, _) => {
                     // This must be an enum variant, struct or const.
                     match self.resolve_path(pat_id, path, 0, ValueNS, false) {
-                        Some(def @ (DefVariant(..), _)) |
-                        Some(def @ (DefStruct(..), _))  |
-                        Some(def @ (DefConst(..), _)) => {
+                        Some(def @ (DefVariant(..), _, _)) |
+                        Some(def @ (DefStruct(..), _, _))  |
+                        Some(def @ (DefConst(..), _, _)) => {
                             self.record_def(pattern.id, def);
                         }
-                        Some((DefStatic(..), _)) => {
+                        Some((DefStatic(..), _, _)) => {
                             self.resolve_error(path.span,
                                                "static variables cannot be \
                                                 referenced in a pattern, \
@@ -3573,40 +3571,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     path: &Path,
                     path_depth: usize,
                     namespace: Namespace,
-                    check_ribs: bool) -> Option<(Def, LastPrivate)> {
+                    check_ribs: bool) -> Option<(Def, LastPrivate, usize)> {
         let span = path.span;
         let segments = &path.segments[..path.segments.len()-path_depth];
 
-        // A special case for sugared associated type paths `T::A` where `T` is
-        // a type parameter and `A` is an associated type on some bound of `T`.
-        if namespace == TypeNS && segments.len() == 2 {
-            match self.resolve_identifier(segments[0].identifier,
-                                          TypeNS,
-                                          true,
-                                          span) {
-                Some((def, last_private)) => {
-                    match def {
-                        DefTyParam(_, _, did, _) => {
-                            let def = DefAssociatedPath(TyParamProvenance::FromParam(did),
-                                                        segments.last()
-                                                            .unwrap().identifier);
-                            return Some((def, last_private));
-                        }
-                        DefSelfTy(nid) => {
-                            let def = DefAssociatedPath(TyParamProvenance::FromSelf(local_def(nid)),
-                                                        segments.last()
-                                                            .unwrap().identifier);
-                            return Some((def, last_private));
-                        }
-                        _ => {}
-                    }
-                }
-                _ => {}
-            }
-        }
-
         if path.global {
-            return self.resolve_crate_relative_path(span, segments, namespace);
+            let def = self.resolve_crate_relative_path(span, segments, namespace);
+            return def.map(|(def, lp)| (def, lp, path_depth));
         }
 
         // Try to find a path to an item in a module.
@@ -3628,10 +3599,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 _ => ()
             }
 
-            return def;
+            def.map(|(def, lp)| (def, lp, path_depth))
+        } else {
+            unqualified_def.map(|(def, lp)| (def, lp, path_depth))
         }
-
-        unqualified_def
     }
 
     // resolve a single identifier (used as a varref)
@@ -4105,14 +4076,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             ExprPath(ref path) | ExprQPath(ast::QPath { ref path, .. }) => {
                 if let ExprQPath(_) = expr.node {
                     // Make sure the trait is valid.
-                    self.resolve_trait_reference(expr.id, path, 1);
+                    let _ = self.resolve_trait_reference(expr.id, path, 1);
                 }
 
                 // This is a local path in the value namespace. Walk through
                 // scopes looking for it.
                 match self.resolve_path(expr.id, path, 0, ValueNS, true) {
                     // Check if struct variant
-                    Some((DefVariant(_, _, true), _)) => {
+                    Some((DefVariant(_, _, true), _, _)) => {
                         let path_name = self.path_names_to_string(path, 0);
                         self.resolve_error(expr.span,
                                 &format!("`{}` is a struct variant name, but \
@@ -4140,7 +4111,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         let path_name = self.path_names_to_string(path, 0);
                         match self.with_no_errors(|this|
                             this.resolve_path(expr.id, path, 0, TypeNS, false)) {
-                            Some((DefTy(struct_id, _), _))
+                            Some((DefTy(struct_id, _), _, 0))
                               if self.structs.contains_key(&struct_id) => {
                                 self.resolve_error(expr.span,
                                         &format!("`{}` is a structure name, but \
@@ -4252,7 +4223,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     }
                     Some(DlDef(def @ DefLabel(_))) => {
                         // Since this def is a label, it is never read.
-                        self.record_def(expr.id, (def, LastMod(AllPublic)))
+                        self.record_def(expr.id, (def, LastMod(AllPublic), 0))
                     }
                     Some(_) => {
                         self.session.span_bug(expr.span,
@@ -4372,18 +4343,31 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
     fn record_def(&mut self,
                   node_id: NodeId,
-                  (def, lp): (Def, LastPrivate)) {
+                  (def, lp, depth): (Def, LastPrivate, usize)) {
         debug!("(recording def) recording {:?} for {}, last private {:?}",
                 def, node_id, lp);
         assert!(match lp {LastImport{..} => false, _ => true},
                 "Import should only be used for `use` directives");
         self.last_private.insert(node_id, lp);
 
-        if let Some(prev_def) = self.def_map.borrow_mut().insert(node_id, def) {
-            let span = self.ast_map.opt_span(node_id).unwrap_or(codemap::DUMMY_SP);
-            self.session.span_bug(span, &format!("path resolved multiple times \
-                                                  ({:?} before, {:?} now)",
-                                                  prev_def, def));
+        if depth == 0 {
+            if let Some(prev_def) = self.def_map.borrow_mut().insert(node_id, def) {
+                let span = self.ast_map.opt_span(node_id).unwrap_or(codemap::DUMMY_SP);
+                self.session.span_bug(span, &format!("path resolved multiple times \
+                                                      ({:?} before, {:?} now)",
+                                                     prev_def, def));
+            }
+        } else {
+            let def = PartialDef {
+                base_type: def,
+                extra_associated_types: (depth - 1) as u32
+            };
+            if let Some(prev_def) = self.partial_def_map.borrow_mut().insert(node_id, def) {
+                let span = self.ast_map.opt_span(node_id).unwrap_or(codemap::DUMMY_SP);
+                self.session.span_bug(span, &format!("path resolved multiple times \
+                                                      ({:?} before, {:?} now)",
+                                                     prev_def, def));
+            }
         }
     }
 
@@ -4474,6 +4458,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
 pub struct CrateMap {
     pub def_map: DefMap,
+    pub partial_def_map: PartialDefMap,
     pub freevars: RefCell<FreevarMap>,
     pub export_map: ExportMap,
     pub trait_map: TraitMap,
@@ -4513,6 +4498,7 @@ pub fn resolve_crate<'a, 'tcx>(session: &'a Session,
 
     CrateMap {
         def_map: resolver.def_map,
+        partial_def_map: resolver.partial_def_map,
         freevars: resolver.freevars,
         export_map: resolver.export_map,
         trait_map: resolver.trait_map,
diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs
index 531700b9563..0ba7bd84603 100644
--- a/src/librustc_trans/save/mod.rs
+++ b/src/librustc_trans/save/mod.rs
@@ -238,7 +238,6 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
             def::DefStruct(_) => Some(recorder::StructRef),
             def::DefTy(..) |
             def::DefAssociatedTy(..) |
-            def::DefAssociatedPath(..) |
             def::DefTrait(_) => Some(recorder::TypeRef),
             def::DefStatic(_, _) |
             def::DefConst(_) |
diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs
index 9dbcbc8b1a2..196686a70d1 100644
--- a/src/librustc_trans/trans/callee.rs
+++ b/src/librustc_trans/trans/callee.rs
@@ -210,7 +210,7 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
             def::DefMod(..) | def::DefForeignMod(..) | def::DefTrait(..) |
             def::DefTy(..) | def::DefPrimTy(..) | def::DefAssociatedTy(..) |
             def::DefUse(..) | def::DefRegion(..) | def::DefLabel(..) |
-            def::DefTyParam(..) | def::DefSelfTy(..) | def::DefAssociatedPath(..) => {
+            def::DefTyParam(..) | def::DefSelfTy(..) => {
                 bcx.tcx().sess.span_bug(
                     ref_expr.span,
                     &format!("cannot translate def {:?} \
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 8eb75ece4a1..bc0986eff1f 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -48,7 +48,7 @@
 //! case but `&a` in the second.  Basically, defaults that appear inside
 //! an rptr (`&r.T`) use the region `r` that appears in the rptr.
 
-use middle::astconv_util::{ast_ty_to_prim_ty, check_path_args, NO_TPS, NO_REGIONS};
+use middle::astconv_util::{prim_ty_to_ty, check_path_args, NO_TPS, NO_REGIONS};
 use middle::const_eval;
 use middle::def;
 use middle::resolve_lifetime as rl;
@@ -57,13 +57,13 @@ use middle::traits;
 use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
 use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
              ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
-use TypeAndSubsts;
 use util::common::{ErrorReported, FN_OUTPUT_NAME};
 use util::nodemap::DefIdMap;
 use util::ppaux::{self, Repr, UserString};
 
-use std::rc::Rc;
 use std::iter::{repeat, AdditiveIterator};
+use std::rc::Rc;
+use std::slice;
 use syntax::{abi, ast, ast_util};
 use syntax::codemap::Span;
 use syntax::parse::token;
@@ -245,8 +245,9 @@ pub fn opt_ast_region_to_region<'tcx>(
 pub fn ast_path_substs_for_ty<'tcx>(
     this: &AstConv<'tcx>,
     rscope: &RegionScope,
+    span: Span,
     decl_generics: &ty::Generics<'tcx>,
-    path: &ast::Path)
+    item_segment: &ast::PathSegment)
     -> Substs<'tcx>
 {
     let tcx = this.tcx();
@@ -262,12 +263,12 @@ pub fn ast_path_substs_for_ty<'tcx>(
     assert!(decl_generics.regions.all(|d| d.space == TypeSpace));
     assert!(decl_generics.types.all(|d| d.space != FnSpace));
 
-    let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters {
+    let (regions, types, assoc_bindings) = match item_segment.parameters {
         ast::AngleBracketedParameters(ref data) => {
             convert_angle_bracketed_parameters(this, rscope, path.span, decl_generics, data)
         }
         ast::ParenthesizedParameters(ref data) => {
-            span_err!(tcx.sess, path.span, E0214,
+            span_err!(tcx.sess, span, E0214,
                 "parenthesized parameters may only be used with a trait");
             convert_parenthesized_parameters(this, rscope, path.span, decl_generics, data)
         }
@@ -276,7 +277,7 @@ pub fn ast_path_substs_for_ty<'tcx>(
     prohibit_projections(this.tcx(), &assoc_bindings);
 
     create_substs_for_ast_path(this,
-                               path.span,
+                               span,
                                decl_generics,
                                None,
                                types,
@@ -625,8 +626,9 @@ pub fn instantiate_trait_ref<'tcx>(
 fn object_path_to_poly_trait_ref<'a,'tcx>(
     this: &AstConv<'tcx>,
     rscope: &RegionScope,
+    span: Span,
     trait_def_id: ast::DefId,
-    path: &ast::Path,
+    trait_segment: &ast::PathSegment,
     mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
     -> ty::PolyTraitRef<'tcx>
 {
@@ -637,10 +639,10 @@ fn object_path_to_poly_trait_ref<'a,'tcx>(
     let mut tmp = Vec::new();
     let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
                                                      &shifted_rscope,
-                                                     path.span,
+                                                     span,
                                                      trait_def_id,
                                                      None,
-                                                     path.segments.last().unwrap(),
+                                                     trait_segment,
                                                      Some(&mut tmp)));
     projections.extend(tmp.into_iter().map(ty::Binder));
     trait_ref
@@ -824,78 +826,28 @@ fn ast_type_binding_to_projection_predicate<'tcx>(
     })
 }
 
-pub fn ast_path_to_ty<'tcx>(
+fn ast_path_to_ty<'tcx>(
     this: &AstConv<'tcx>,
     rscope: &RegionScope,
+    span: Span,
     did: ast::DefId,
-    path: &ast::Path)
-    -> TypeAndSubsts<'tcx>
+    item_segment: &ast::PathSegment)
+    -> Ty<'tcx>
 {
-    let tcx = this.tcx();
     let ty::TypeScheme {
         generics,
         ty: decl_ty
     } = this.get_item_type_scheme(did);
 
-    let substs = ast_path_substs_for_ty(this,
-                                        rscope,
-                                        &generics,
-                                        path);
-    let ty = decl_ty.subst(tcx, &substs);
-    TypeAndSubsts { substs: substs, ty: ty }
-}
+    let substs = ast_path_substs_for_ty(this, rscope, span, &generics, item_segment);
 
-/// Converts the given AST type to a built-in type. A "built-in type" is, at
-/// present, either a core numeric type, a string, or `Box`.
-pub fn ast_ty_to_builtin_ty<'tcx>(
-        this: &AstConv<'tcx>,
-        rscope: &RegionScope,
-        ast_ty: &ast::Ty)
-        -> Option<Ty<'tcx>> {
-    match ast_ty_to_prim_ty(this.tcx(), ast_ty) {
-        Some(typ) => return Some(typ),
-        None => {}
+    // FIXME(#12938): This is a hack until we have full support for DST.
+    if Some(did) == this.tcx().lang_items.owned_box() {
+        assert_eq!(substs.types.len(TypeSpace), 1);
+        return ty::mk_uniq(this.tcx(), *substs.types.get(TypeSpace, 0));
     }
 
-    match ast_ty.node {
-        ast::TyPath(ref path) => {
-            let a_def = match this.tcx().def_map.borrow().get(&ast_ty.id) {
-                None => {
-                    this.tcx()
-                        .sess
-                        .span_bug(ast_ty.span,
-                                  &format!("unbound path {}",
-                                          path.repr(this.tcx())))
-                }
-                Some(&d) => d
-            };
-
-            // FIXME(#12938): This is a hack until we have full support for
-            // DST.
-            match a_def {
-                def::DefTy(did, _) |
-                def::DefStruct(did) if Some(did) == this.tcx().lang_items.owned_box() => {
-                    let ty = ast_path_to_ty(this, rscope, did, path).ty;
-                    match ty.sty {
-                        ty::ty_struct(struct_def_id, ref substs) => {
-                            assert_eq!(struct_def_id, did);
-                            assert_eq!(substs.types.len(TypeSpace), 1);
-                            let referent_ty = *substs.types.get(TypeSpace, 0);
-                            Some(ty::mk_uniq(this.tcx(), referent_ty))
-                        }
-                        _ => {
-                            this.tcx().sess.span_bug(
-                                path.span,
-                                &format!("converting `Box` to `{}`",
-                                        ty.repr(this.tcx())));
-                        }
-                    }
-                }
-                _ => None
-            }
-        }
-        _ => None
-    }
+    decl_ty.subst(this.tcx(), &substs)
 }
 
 type TraitAndProjections<'tcx> = (ty::PolyTraitRef<'tcx>, Vec<ty::PolyProjectionPredicate<'tcx>>);
@@ -919,13 +871,15 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>,
 
     match ty.node {
         ast::TyPath(ref path) => {
-            match this.tcx().def_map.borrow().get(&ty.id) {
-                Some(&def::DefTrait(trait_def_id)) => {
+            let def = this.tcx().def_map.borrow().get(&ty.id).cloned();
+            match def {
+                Some(def::DefTrait(trait_def_id)) => {
                     let mut projection_bounds = Vec::new();
                     let trait_ref = object_path_to_poly_trait_ref(this,
                                                                   rscope,
+                                                                  path.span,
                                                                   trait_def_id,
-                                                                  path,
+                                                                  path.segments.last().unwrap(),
                                                                   &mut projection_bounds);
                     Ok((trait_ref, projection_bounds))
                 }
@@ -989,21 +943,35 @@ fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>,
 }
 
 fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
-                                   ast_ty: &ast::Ty,
-                                   provenance: def::TyParamProvenance,
-                                   assoc_name: ast::Name)
-                                   -> Ty<'tcx>
+                                   span: Span,
+                                   ty: Ty<'tcx>,
+                                   ty_path_def: def::Def,
+                                   item_segment: &ast::PathSegment)
+                                   -> (Ty<'tcx>, def::Def)
 {
     let tcx = this.tcx();
-    let ty_param_def_id = provenance.def_id();
+    check_path_args(tcx, span, slice::ref_slice(item_segment),
+                    NO_TPS | NO_REGIONS);
+    let assoc_name = item_segment.identifier.name;
+
+    let ty_param_node_id = if let ty::ty_param(_) = ty.sty {
+        ty_path_def.local_node_id()
+    } else {
+        span_err!(tcx.sess, span, E0223,
+                "ambiguous associated type; specify the type using the syntax \
+                `<{} as Trait>::{}`",
+                ty.user_string(tcx), token::get_name(assoc_name));
+        return (tcx.types.err, ty_path_def);
+    };
 
     let mut suitable_bounds: Vec<_>;
     let ty_param_name: ast::Name;
     { // contain scope of refcell:
         let ty_param_defs = tcx.ty_param_defs.borrow();
-        let ty_param_def = &ty_param_defs[ty_param_def_id.node];
+        let ty_param_def = &ty_param_defs[ty_param_node_id];
         ty_param_name = ty_param_def.name;
 
+
         // FIXME(#20300) -- search where clauses, not bounds
         suitable_bounds =
             traits::transitive_bounds(tcx, &ty_param_def.bounds.trait_bounds)
@@ -1012,21 +980,21 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
     }
 
     if suitable_bounds.len() == 0 {
-        span_err!(tcx.sess, ast_ty.span, E0220,
+        span_err!(tcx.sess, span, E0220,
                           "associated type `{}` not found for type parameter `{}`",
                                   token::get_name(assoc_name),
                                   token::get_name(ty_param_name));
-        return this.tcx().types.err;
+        return (this.tcx().types.err, ty_path_def);
     }
 
     if suitable_bounds.len() > 1 {
-        span_err!(tcx.sess, ast_ty.span, E0221,
+        span_err!(tcx.sess, span, E0221,
                           "ambiguous associated type `{}` in bounds of `{}`",
                                   token::get_name(assoc_name),
                                   token::get_name(ty_param_name));
 
         for suitable_bound in &suitable_bounds {
-            span_note!(this.tcx().sess, ast_ty.span,
+            span_note!(this.tcx().sess, span,
                        "associated type `{}` could derive from `{}`",
                        token::get_name(ty_param_name),
                        suitable_bound.user_string(this.tcx()));
@@ -1034,7 +1002,32 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
     }
 
     let suitable_bound = suitable_bounds.pop().unwrap().clone();
-    return this.projected_ty_from_poly_trait_ref(ast_ty.span, suitable_bound, assoc_name);
+    let trait_did = suitable_bound.0.def_id;
+
+    let ty = this.projected_ty_from_poly_trait_ref(span, suitable_bound, assoc_name);
+
+    let item_did = if trait_did.krate == ast::LOCAL_CRATE {
+        // `ty::trait_items` used below requires information generated
+        // by type collection, which may be in progress at this point.
+        match this.tcx().map.expect_item(trait_did.node).node {
+            ast::ItemTrait(_, _, _, ref trait_items) => {
+                trait_items.iter().filter_map(|i| {
+                    if let ast::TypeTraitItem(ref assoc) = *i {
+                        if assoc.ty_param.ident.name == assoc_name {
+                            return Some(ast_util::local_def(assoc.ty_param.id));
+                        }
+                    }
+                    None
+                }).next().expect("missing associated type")
+            }
+            _ => unreachable!()
+        }
+    } else {
+        let trait_items = ty::trait_items(this.tcx(), trait_did);
+        let item = trait_items.iter().find(|i| i.name() == assoc_name);
+        item.expect("missing associated type").def_id()
+    };
+    (ty, def::DefAssociatedTy(trait_did, item_did))
 }
 
 fn trait_defines_associated_type_named(this: &AstConv,
@@ -1058,6 +1051,9 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
 {
     let tcx = this.tcx();
 
+    check_path_args(tcx, span, slice::ref_slice(item_segment),
+                    NO_TPS | NO_REGIONS);
+
     let self_ty = if let Some(ty) = opt_self_ty {
         ast_ty_to_ty(this, rscope, ty)
     } else {
@@ -1081,9 +1077,6 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
 
     debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx));
 
-    // `<T as Trait>::U<V>` shouldn't parse right now.
-    assert!(item_segment.parameters.is_empty());
-
     this.projected_ty(span, trait_ref, item_segment.identifier.name)
 }
 
@@ -1146,164 +1139,184 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
     ast_ty_to_ty_cache.insert(ast_ty.id, ty::atttce_unresolved);
     drop(ast_ty_to_ty_cache);
 
-    let typ = ast_ty_to_builtin_ty(this, rscope, ast_ty).unwrap_or_else(|| {
-        match ast_ty.node {
-            ast::TyVec(ref ty) => {
-                ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), None)
-            }
-            ast::TyObjectSum(ref ty, ref bounds) => {
-                match ast_ty_to_trait_ref(this, rscope, &**ty, &bounds[..]) {
-                    Ok((trait_ref, projection_bounds)) => {
-                        trait_ref_to_object_type(this,
-                                                 rscope,
-                                                 ast_ty.span,
-                                                 trait_ref,
-                                                 projection_bounds,
-                                                 &bounds[..])
-                    }
-                    Err(ErrorReported) => {
-                        this.tcx().types.err
-                    }
+    let typ = match ast_ty.node {
+        ast::TyVec(ref ty) => {
+            ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), None)
+        }
+        ast::TyObjectSum(ref ty, ref bounds) => {
+            match ast_ty_to_trait_ref(this, rscope, &**ty, bounds) {
+                Ok((trait_ref, projection_bounds)) => {
+                    trait_ref_to_object_type(this,
+                                             rscope,
+                                             ast_ty.span,
+                                             trait_ref,
+                                             projection_bounds,
+                                             bounds)
                 }
-            }
-            ast::TyPtr(ref mt) => {
-                ty::mk_ptr(tcx, ty::mt {
-                    ty: ast_ty_to_ty(this, rscope, &*mt.ty),
-                    mutbl: mt.mutbl
-                })
-            }
-            ast::TyRptr(ref region, ref mt) => {
-                let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region);
-                debug!("ty_rptr r={}", r.repr(this.tcx()));
-                let rscope1 =
-                    &ObjectLifetimeDefaultRscope::new(
-                        rscope,
-                        Some(ty::ObjectLifetimeDefault::Specific(r)));
-                let t = ast_ty_to_ty(this, rscope1, &*mt.ty);
-                ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty: t, mutbl: mt.mutbl})
-            }
-            ast::TyTup(ref fields) => {
-                let flds = fields.iter()
-                                 .map(|t| ast_ty_to_ty(this, rscope, &**t))
-                                 .collect();
-                ty::mk_tup(tcx, flds)
-            }
-            ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ),
-            ast::TyBareFn(ref bf) => {
-                if bf.decl.variadic && bf.abi != abi::C {
-                    span_err!(tcx.sess, ast_ty.span, E0222,
-                                      "variadic function must have C calling convention");
+                Err(ErrorReported) => {
+                    this.tcx().types.err
                 }
-                let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl);
-                ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(bare_fn))
             }
-            ast::TyPolyTraitRef(ref bounds) => {
-                conv_ty_poly_trait_ref(this, rscope, ast_ty.span, &bounds[..])
+        }
+        ast::TyPtr(ref mt) => {
+            ty::mk_ptr(tcx, ty::mt {
+                ty: ast_ty_to_ty(this, rscope, &*mt.ty),
+                mutbl: mt.mutbl
+            })
+        }
+        ast::TyRptr(ref region, ref mt) => {
+            let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region);
+            debug!("ty_rptr r={}", r.repr(this.tcx()));
+            let rscope1 =
+                &ObjectLifetimeDefaultRscope::new(
+                    rscope,
+                    Some(ty::ObjectLifetimeDefault::Specific(r)));
+            let t = ast_ty_to_ty(this, rscope1, &*mt.ty);
+            ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty: t, mutbl: mt.mutbl})
+        }
+        ast::TyTup(ref fields) => {
+            let flds = fields.iter()
+                             .map(|t| ast_ty_to_ty(this, rscope, &**t))
+                             .collect();
+            ty::mk_tup(tcx, flds)
+        }
+        ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ),
+        ast::TyBareFn(ref bf) => {
+            if bf.decl.variadic && bf.abi != abi::C {
+                span_err!(tcx.sess, ast_ty.span, E0222,
+                          "variadic function must have C calling convention");
             }
-            ast::TyPath(ref path) | ast::TyQPath(ast::QPath { ref path, .. }) => {
-                let a_def = match tcx.def_map.borrow().get(&ast_ty.id) {
-                    None => {
-                        tcx.sess
-                           .span_bug(ast_ty.span,
-                                     &format!("unbound path {}",
-                                             ast_ty.repr(tcx)))
-                    }
-                    Some(&d) => d
-                };
-                match a_def {
-                    def::DefTrait(trait_def_id) => {
-                        // N.B. this case overlaps somewhat with
-                        // TyObjectSum, see that fn for details
-                        let mut projection_bounds = Vec::new();
-
-                        let trait_ref = object_path_to_poly_trait_ref(this,
-                                                                      rscope,
-                                                                      trait_def_id,
-                                                                      path,
-                                                                      &mut projection_bounds);
-
-                        trait_ref_to_object_type(this, rscope, ast_ty.span,
-                                                 trait_ref, projection_bounds, &[])
-                    }
-                    def::DefTy(did, _) | def::DefStruct(did) => {
-                        ast_path_to_ty(this, rscope, did, path).ty
-                    }
-                    def::DefTyParam(space, index, _, name) => {
-                        check_path_args(tcx, path, NO_TPS | NO_REGIONS);
-                        ty::mk_param(tcx, space, index, name)
-                    }
-                    def::DefSelfTy(_) => {
-                        // n.b.: resolve guarantees that the this type only appears in a
-                        // trait, which we rely upon in various places when creating
-                        // substs
-                        check_path_args(tcx, path, NO_TPS | NO_REGIONS);
-                        ty::mk_self_type(tcx)
-                    }
-                    def::DefMod(id) => {
-                        span_fatal!(tcx.sess, ast_ty.span, E0247,
-                            "found module name used as a type: {}",
-                                    tcx.map.node_to_string(id.node));
-                    }
-                    def::DefPrimTy(_) => {
-                        panic!("DefPrimTy arm missed in previous ast_ty_to_prim_ty call");
-                    }
-                    def::DefAssociatedTy(trait_did, _) => {
-                        let opt_self_ty = if let ast::TyQPath(ref qpath) = ast_ty.node {
-                            Some(&*qpath.self_type)
-                        } else {
-                            None
-                        };
-                        qpath_to_ty(this, rscope, ast_ty.span, opt_self_ty, trait_did,
-                                    &path.segments[path.segments.len()-2],
-                                    path.segments.last().unwrap())
-                    }
-                    def::DefAssociatedPath(provenance, assoc_ident) => {
-                        associated_path_def_to_ty(this, ast_ty, provenance, assoc_ident.name)
-                    }
-                    _ => {
-                        span_fatal!(tcx.sess, ast_ty.span, E0248,
-                                            "found value name used \
-                                                     as a type: {:?}",
-                                                    a_def);
-                    }
+            let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl);
+            ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(bare_fn))
+        }
+        ast::TyPolyTraitRef(ref bounds) => {
+            conv_ty_poly_trait_ref(this, rscope, ast_ty.span, bounds)
+        }
+        ast::TyPath(ref path) | ast::TyQPath(ast::QPath { ref path, .. }) => {
+            let result = if let Some(&d) = tcx.def_map.borrow().get(&ast_ty.id) {
+                (d, 0)
+            } else if let Some(d) = tcx.partial_def_map.borrow().get(&ast_ty.id) {
+                (d.base_type, (d.extra_associated_types + 1) as usize)
+            } else {
+                tcx.sess.span_bug(ast_ty.span,
+                                  &format!("unbound path {}", ast_ty.repr(tcx)))
+            };
+            let (base_def, max_depth) = result;
+            let span = ast_ty.span; // Could be more granular.
+            let segments = &path.segments[..path.segments.len()-max_depth];
+            let base_ty = match base_def {
+                def::DefTrait(trait_def_id) => {
+                    // N.B. this case overlaps somewhat with
+                    // TyObjectSum, see that fn for details
+                    let mut projection_bounds = Vec::new();
+
+                    let trait_ref = object_path_to_poly_trait_ref(this,
+                                                                  rscope,
+                                                                  span,
+                                                                  trait_def_id,
+                                                                  segments.last().unwrap(),
+                                                                  &mut projection_bounds);
+
+                    check_path_args(tcx, span, segments.init(), NO_TPS | NO_REGIONS);
+                    trait_ref_to_object_type(this, rscope, span, trait_ref,
+                                             projection_bounds, &[])
+                }
+                def::DefTy(did, _) | def::DefStruct(did) => {
+                    check_path_args(tcx, span, segments.init(), NO_TPS | NO_REGIONS);
+                    ast_path_to_ty(this, rscope, span, did, segments.last().unwrap())
                 }
+                def::DefTyParam(space, index, _, name) => {
+                    check_path_args(tcx, span, segments, NO_TPS | NO_REGIONS);
+                    ty::mk_param(tcx, space, index, name)
+                }
+                def::DefSelfTy(_) => {
+                    // n.b.: resolve guarantees that the this type only appears in a
+                    // trait, which we rely upon in various places when creating
+                    // substs
+                    check_path_args(tcx, span, segments, NO_TPS | NO_REGIONS);
+                    ty::mk_self_type(tcx)
+                }
+                def::DefAssociatedTy(trait_did, _) => {
+                    let opt_self_ty = if let ast::TyQPath(ref qpath) = ast_ty.node {
+                        Some(&*qpath.self_type)
+                    } else {
+                        None
+                    };
+                    check_path_args(tcx, span, &segments[..segments.len()-2],
+                                    NO_TPS | NO_REGIONS);
+                    qpath_to_ty(this, rscope, span, opt_self_ty, trait_did,
+                                &segments[segments.len()-2],
+                                segments.last().unwrap())
+                }
+                def::DefMod(id) => {
+                    tcx.sess.span_bug(span,
+                                      &format!("found module name used as a type: {}",
+                                               tcx.map.node_to_string(id.node)));
+                }
+                def::DefPrimTy(prim_ty) => {
+                    prim_ty_to_ty(tcx, span, segments, prim_ty)
+                }
+                _ => {
+                    span_fatal!(tcx.sess, span, E0248,
+                                "found value name used as a type: {:?}", base_def);
+                }
+            };
+
+            // If any associated type segments remain, attempt to resolve them.
+            let mut ty = base_ty;
+            let mut def = base_def;
+            for depth in (0..max_depth).rev() {
+                if ty.sty == ty::ty_err {
+                    break;
+                }
+                // This is pretty bad (it will fail except for T::A and Self::A).
+                let segment = &path.segments[path.segments.len()-depth-1];
+                let (a_ty, a_def) = associated_path_def_to_ty(this, span,
+                                                              ty, def, segment);
+                ty = a_ty;
+                def = a_def;
             }
-            ast::TyFixedLengthVec(ref ty, ref e) => {
-                match const_eval::eval_const_expr_partial(tcx, &**e, Some(tcx.types.uint)) {
-                    Ok(ref r) => {
-                        match *r {
-                            const_eval::const_int(i) =>
-                                ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty),
-                                           Some(i as uint)),
-                            const_eval::const_uint(i) =>
-                                ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty),
-                                           Some(i as uint)),
-                            _ => {
-                                span_fatal!(tcx.sess, ast_ty.span, E0249,
-                                            "expected constant expr for array length");
-                            }
+
+            if max_depth != 0 && ty.sty != ty::ty_err {
+                // Write back the new resolution.
+                tcx.def_map.borrow_mut().insert(ast_ty.id, def);
+            }
+
+            ty
+        }
+        ast::TyFixedLengthVec(ref ty, ref e) => {
+            match const_eval::eval_const_expr_partial(tcx, &**e, Some(tcx.types.uint)) {
+                Ok(r) => {
+                    match r {
+                        const_eval::const_int(i) =>
+                            ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty),
+                                        Some(i as uint)),
+                        const_eval::const_uint(i) =>
+                            ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty),
+                                        Some(i as uint)),
+                        _ => {
+                            span_fatal!(tcx.sess, ast_ty.span, E0249,
+                                        "expected constant expr for array length");
                         }
                     }
-                    Err(ref r) => {
-                        span_fatal!(tcx.sess, ast_ty.span, E0250,
-                            "expected constant expr for array \
-                                     length: {}",
-                                    *r);
-                    }
                 }
-            }
-            ast::TyTypeof(ref _e) => {
-                tcx.sess.span_bug(ast_ty.span, "typeof is reserved but unimplemented");
-            }
-            ast::TyInfer => {
-                // TyInfer also appears as the type of arguments or return
-                // values in a ExprClosure, or as
-                // the type of local variables. Both of these cases are
-                // handled specially and will not descend into this routine.
-                this.ty_infer(ast_ty.span)
+                Err(r) => {
+                    span_fatal!(tcx.sess, ast_ty.span, E0250,
+                                "expected constant expr for array length: {}", r);
+                }
             }
         }
-    });
+        ast::TyTypeof(ref _e) => {
+            tcx.sess.span_bug(ast_ty.span, "typeof is reserved but unimplemented");
+        }
+        ast::TyInfer => {
+            // TyInfer also appears as the type of arguments or return
+            // values in a ExprClosure, or as
+            // the type of local variables. Both of these cases are
+            // handled specially and will not descend into this routine.
+            this.ty_infer(ast_ty.span)
+        }
+    };
 
     tcx.ast_ty_to_ty_cache.borrow_mut().insert(ast_ty.id, ty::atttce_resolved(typ));
     return typ;
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 9d303f492eb..f797d2b6fe7 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1613,7 +1613,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                                   generics.regions.get_slice(TypeSpace));
             Substs::new_type(tps, rps)
         } else {
-            astconv::ast_path_substs_for_ty(self, self, &generics, path)
+            astconv::ast_path_substs_for_ty(self, self,
+                                            path.span,
+                                            &generics,
+                                            path.segments.last().unwrap())
         };
 
         let ty = self.instantiate_type_scheme(path.span, &substs, &decl_ty);
@@ -4632,7 +4635,6 @@ fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         def::DefTrait(_) |
         def::DefTy(..) |
         def::DefAssociatedTy(..) |
-        def::DefAssociatedPath(..) |
         def::DefPrimTy(_) |
         def::DefTyParam(..) |
         def::DefMod(..) |
@@ -4731,7 +4733,6 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         def::DefVariant(..) |
         def::DefTy(..) |
         def::DefAssociatedTy(..) |
-        def::DefAssociatedPath(..) |
         def::DefTrait(..) |
         def::DefPrimTy(..) |
         def::DefTyParam(..) => {
diff --git a/src/test/compile-fail/issue-7607-1.rs b/src/test/compile-fail/issue-7607-1.rs
index 48fc393d0da..4ac90177609 100644
--- a/src/test/compile-fail/issue-7607-1.rs
+++ b/src/test/compile-fail/issue-7607-1.rs
@@ -8,13 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-tidy-linelength
-
 struct Foo {
     x: isize
 }
 
-impl Fo { //~ERROR inherent implementations are not allowed for types not defined in the current module
+impl Fo { //~ ERROR use of undeclared type name `Fo`
     fn foo() {}
 }
 
diff --git a/src/test/compile-fail/issue-8767.rs b/src/test/compile-fail/issue-8767.rs
index 6c5bac5e0cb..2ef0a75f77b 100644
--- a/src/test/compile-fail/issue-8767.rs
+++ b/src/test/compile-fail/issue-8767.rs
@@ -10,7 +10,7 @@
 
 // ignore-tidy-linelength
 
-impl B { //~ERROR inherent implementations are not allowed for types not defined in the current module
+impl B { //~ ERROR use of undeclared type name `B`
 }
 
 fn main() {
diff --git a/src/test/compile-fail/trait-impl-for-module.rs b/src/test/compile-fail/trait-impl-for-module.rs
index 28d20483c7e..969b6398fdb 100644
--- a/src/test/compile-fail/trait-impl-for-module.rs
+++ b/src/test/compile-fail/trait-impl-for-module.rs
@@ -14,7 +14,7 @@ mod a {
 trait A {
 }
 
-impl A for a { //~ERROR found module name used as a type
+impl A for a { //~ ERROR use of undeclared type name `a`
 }
 
 fn main() {
diff --git a/src/test/compile-fail/trait-or-new-type-instead.rs b/src/test/compile-fail/trait-or-new-type-instead.rs
index e621d77a65c..047e4e50c82 100644
--- a/src/test/compile-fail/trait-or-new-type-instead.rs
+++ b/src/test/compile-fail/trait-or-new-type-instead.rs
@@ -8,9 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-tidy-linelength
-
-impl<T> Option<T> { //~ERROR inherent implementations are not allowed for types not defined in the current module
+// FIXME(eddyb/UFCS) This should have a nicer error, but that's not possible just yet.
+impl<T> Option<T> { //~ ERROR use of undeclared type name `Option`
     pub fn foo(&self) { }
 }