about summary refs log tree commit diff
path: root/src/librustc
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2016-10-27 05:17:42 +0300
committerEduard-Mihai Burtescu <edy.burt@gmail.com>2016-11-28 04:18:10 +0200
commit16b5c2cfef811feebe2797bcb7e01d2b6ff12db1 (patch)
treee2a17a7e621aff09521fb522bdde1599b1194f18 /src/librustc
parent34d1352f0eb7e7511e34b1e7640e854ffaf3f137 (diff)
downloadrust-16b5c2cfef811feebe2797bcb7e01d2b6ff12db1.tar.gz
rust-16b5c2cfef811feebe2797bcb7e01d2b6ff12db1.zip
rustc: desugar UFCS as much as possible during HIR lowering.
Diffstat (limited to 'src/librustc')
-rw-r--r--src/librustc/cfg/construct.rs4
-rw-r--r--src/librustc/hir/intravisit.rs51
-rw-r--r--src/librustc/hir/lowering.rs189
-rw-r--r--src/librustc/hir/mod.rs68
-rw-r--r--src/librustc/hir/pat_util.rs13
-rw-r--r--src/librustc/hir/print.rs118
-rw-r--r--src/librustc/infer/error_reporting.rs11
-rw-r--r--src/librustc/middle/astconv_util.rs24
-rw-r--r--src/librustc/middle/dead.rs3
-rw-r--r--src/librustc/middle/effect.rs2
-rw-r--r--src/librustc/middle/expr_use_visitor.rs2
-rw-r--r--src/librustc/middle/intrinsicck.rs32
-rw-r--r--src/librustc/middle/liveness.rs16
-rw-r--r--src/librustc/middle/mem_categorization.rs4
-rw-r--r--src/librustc/middle/reachable.rs2
-rw-r--r--src/librustc/middle/resolve_lifetime.rs7
-rw-r--r--src/librustc/middle/stability.rs28
-rw-r--r--src/librustc/ty/mod.rs11
18 files changed, 365 insertions, 220 deletions
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index c399623462b..609d492a93a 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -100,7 +100,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
     fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex {
         match pat.node {
             PatKind::Binding(.., None) |
-            PatKind::Path(..) |
+            PatKind::Path(_) |
             PatKind::Lit(..) |
             PatKind::Range(..) |
             PatKind::Wild => {
@@ -361,7 +361,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
 
             hir::ExprClosure(..) |
             hir::ExprLit(..) |
-            hir::ExprPath(..) => {
+            hir::ExprPath(_) => {
                 self.straightline(expr, pred, None::<hir::Expr>.iter())
             }
         }
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 7dd88e36dd1..743eed74d0c 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -244,6 +244,9 @@ pub trait Visitor<'v> : Sized {
     fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) {
         walk_lifetime_def(self, lifetime)
     }
+    fn visit_qpath(&mut self, qpath: &'v QPath, id: NodeId, span: Span) {
+        walk_qpath(self, qpath, id, span)
+    }
     fn visit_path(&mut self, path: &'v Path, _id: NodeId) {
         walk_path(self, path)
     }
@@ -481,11 +484,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
             walk_fn_decl(visitor, &function_declaration.decl);
             walk_list!(visitor, visit_lifetime_def, &function_declaration.lifetimes);
         }
-        TyPath(ref maybe_qself, ref path) => {
-            if let Some(ref qself) = *maybe_qself {
-                visitor.visit_ty(&qself.ty);
-            }
-            visitor.visit_path(path, typ.id);
+        TyPath(ref qpath) => {
+            visitor.visit_qpath(qpath, typ.id, typ.span);
         }
         TyObjectSum(ref ty, ref bounds) => {
             visitor.visit_ty(ty);
@@ -508,6 +508,21 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
     }
 }
 
+pub fn walk_qpath<'v, V: Visitor<'v>>(visitor: &mut V, qpath: &'v QPath, id: NodeId, span: Span) {
+    match *qpath {
+        QPath::Resolved(ref maybe_qself, ref path) => {
+            if let Some(ref qself) = *maybe_qself {
+                visitor.visit_ty(qself);
+            }
+            visitor.visit_path(path, id)
+        }
+        QPath::TypeRelative(ref qself, ref segment) => {
+            visitor.visit_ty(qself);
+            visitor.visit_path_segment(span, segment);
+        }
+    }
+}
+
 pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) {
     for segment in &path.segments {
         visitor.visit_path_segment(path.span, segment);
@@ -555,18 +570,15 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V,
 pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
     visitor.visit_id(pattern.id);
     match pattern.node {
-        PatKind::TupleStruct(ref path, ref children, _) => {
-            visitor.visit_path(path, pattern.id);
+        PatKind::TupleStruct(ref qpath, ref children, _) => {
+            visitor.visit_qpath(qpath, pattern.id, pattern.span);
             walk_list!(visitor, visit_pat, children);
         }
-        PatKind::Path(ref opt_qself, ref path) => {
-            if let Some(ref qself) = *opt_qself {
-                visitor.visit_ty(&qself.ty);
-            }
-            visitor.visit_path(path, pattern.id)
+        PatKind::Path(ref qpath) => {
+            visitor.visit_qpath(qpath, pattern.id, pattern.span);
         }
-        PatKind::Struct(ref path, ref fields, _) => {
-            visitor.visit_path(path, pattern.id);
+        PatKind::Struct(ref qpath, ref fields, _) => {
+            visitor.visit_qpath(qpath, pattern.id, pattern.span);
             for field in fields {
                 visitor.visit_name(field.span, field.node.name);
                 visitor.visit_pat(&field.node.pat)
@@ -840,8 +852,8 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             visitor.visit_expr(element);
             visitor.visit_expr(count)
         }
-        ExprStruct(ref path, ref fields, ref optional_base) => {
-            visitor.visit_path(path, expression.id);
+        ExprStruct(ref qpath, ref fields, ref optional_base) => {
+            visitor.visit_qpath(qpath, expression.id, expression.span);
             for field in fields {
                 visitor.visit_name(field.name.span, field.name.node);
                 visitor.visit_expr(&field.expr)
@@ -917,11 +929,8 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             visitor.visit_expr(main_expression);
             visitor.visit_expr(index_expression)
         }
-        ExprPath(ref maybe_qself, ref path) => {
-            if let Some(ref qself) = *maybe_qself {
-                visitor.visit_ty(&qself.ty);
-            }
-            visitor.visit_path(path, expression.id)
+        ExprPath(ref qpath) => {
+            visitor.visit_qpath(qpath, expression.id, expression.span);
         }
         ExprBreak(ref opt_sp_name, ref opt_expr) => {
             walk_opt_sp_name(visitor, opt_sp_name);
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 264a5722bcd..056c1b90620 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -188,13 +188,13 @@ impl<'a> LoweringContext<'a> {
             node: match view_path.node {
                 ViewPathSimple(ident, ref path) => {
                     hir::ViewPathSimple(ident.name,
-                                        self.lower_path(path, None, ParamMode::Explicit))
+                                        self.lower_path(path, ParamMode::Explicit))
                 }
                 ViewPathGlob(ref path) => {
-                    hir::ViewPathGlob(self.lower_path(path, None, ParamMode::Explicit))
+                    hir::ViewPathGlob(self.lower_path(path, ParamMode::Explicit))
                 }
                 ViewPathList(ref path, ref path_list_idents) => {
-                    hir::ViewPathList(self.lower_path(path, None, ParamMode::Explicit),
+                    hir::ViewPathList(self.lower_path(path, ParamMode::Explicit),
                                       path_list_idents.iter()
                                                       .map(|item| self.lower_path_list_item(item))
                                                       .collect())
@@ -259,14 +259,7 @@ impl<'a> LoweringContext<'a> {
                     return self.lower_ty(ty);
                 }
                 TyKind::Path(ref qself, ref path) => {
-                    let qself = qself.as_ref().map(|&QSelf { ref ty, position }| {
-                        hir::QSelf {
-                            ty: self.lower_ty(ty),
-                            position: position,
-                        }
-                    });
-                    let path = self.lower_path(path, qself.as_ref(), ParamMode::Explicit);
-                    hir::TyPath(qself, path)
+                    hir::TyPath(self.lower_qpath(t.id, qself, path, ParamMode::Explicit))
                 }
                 TyKind::ObjectSum(ref ty, ref bounds) => {
                     hir::TyObjectSum(self.lower_ty(ty), self.lower_bounds(bounds))
@@ -308,17 +301,24 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_path(&mut self,
-                  p: &Path,
-                  qself: Option<&hir::QSelf>,
-                  param_mode: ParamMode)
-                  -> hir::Path {
-        hir::Path {
+    fn lower_qpath(&mut self,
+                   id: NodeId,
+                   qself: &Option<QSelf>,
+                   p: &Path,
+                   param_mode: ParamMode)
+                   -> hir::QPath {
+        let qself_position = qself.as_ref().map(|q| q.position);
+        let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty));
+
+        let resolution = self.resolver.get_resolution(id)
+                                      .unwrap_or(PathResolution::new(Def::Err));
+
+        let proj_start = p.segments.len() - resolution.depth;
+        let path = P(hir::Path {
             global: p.global,
-            segments: p.segments.iter().enumerate().map(|(i, segment)| {
-                let PathSegment { identifier, ref parameters } = *segment;
-                let param_mode = match (qself, param_mode) {
-                    (Some(qself), ParamMode::Optional) if i < qself.position => {
+            segments: p.segments[..proj_start].iter().enumerate().map(|(i, segment)| {
+                let param_mode = match (qself_position, param_mode) {
+                    (Some(j), ParamMode::Optional) if i < j => {
                         // This segment is part of the trait path in a
                         // qualified path - one of `a`, `b` or `Trait`
                         // in `<X as a::b::Trait>::T::U::method`.
@@ -326,26 +326,91 @@ impl<'a> LoweringContext<'a> {
                     }
                     _ => param_mode
                 };
-                hir::PathSegment {
-                    name: identifier.name,
-                    parameters: self.lower_path_parameters(parameters, param_mode),
-                }
+                self.lower_path_segment(segment, param_mode)
             }).collect(),
             span: p.span,
+        });
+
+        // Simple case, either no projections, or only fully-qualified.
+        // E.g. `std::mem::size_of` or `<I as Iterator>::Item`.
+        if resolution.depth == 0 {
+            return hir::QPath::Resolved(qself, path);
         }
+
+        // Create the innermost type that we're projecting from.
+        let mut ty = if path.segments.is_empty() {
+            // If the base path is empty that means there exists a
+            // syntactical `Self`, e.g. `&i32` in `<&i32>::clone`.
+            qself.expect("missing QSelf for <T>::...")
+        } else {
+            // Otherwise, the base path is an implicit `Self` type path,
+            // e.g. `Vec` in `Vec::new` or `<I as Iterator>::Item` in
+            // `<I as Iterator>::Item::default`.
+            let ty = self.ty(p.span, hir::TyPath(hir::QPath::Resolved(qself, path)));
+
+            // Associate that innermost path type with the base Def.
+            self.resolver.record_resolution(ty.id, resolution.base_def);
+
+            ty
+        };
+
+        // Anything after the base path are associated "extensions",
+        // out of which all but the last one are associated types,
+        // e.g. for `std::vec::Vec::<T>::IntoIter::Item::clone`:
+        // * base path is `std::vec::Vec<T>`
+        // * "extensions" are `IntoIter`, `Item` and `clone`
+        // * type nodes are:
+        //   1. `std::vec::Vec<T>` (created above)
+        //   2. `<std::vec::Vec<T>>::IntoIter`
+        //   3. `<<std::vec::Vec<T>>::IntoIter>::Item`
+        // * final path is `<<<std::vec::Vec<T>>::IntoIter>::Item>::clone`
+        for (i, segment) in p.segments.iter().enumerate().skip(proj_start) {
+            let segment = P(self.lower_path_segment(segment, param_mode));
+            let qpath = hir::QPath::TypeRelative(ty, segment);
+
+            // It's finished, return the extension of the right node type.
+            if i == p.segments.len() - 1 {
+                return qpath;
+            }
+
+            // Wrap the associated extension in another type node.
+            ty = self.ty(p.span, hir::TyPath(qpath));
+        }
+
+        // Should've returned in the for loop above.
+        span_bug!(p.span, "lower_qpath: no final extension segment in {}..{}",
+                  proj_start, p.segments.len())
     }
 
-    fn lower_path_parameters(&mut self,
-                             path_parameters: &PathParameters,
-                             param_mode: ParamMode)
-                             -> hir::PathParameters {
-        match *path_parameters {
+    fn lower_path(&mut self,
+                  p: &Path,
+                  param_mode: ParamMode)
+                  -> hir::Path {
+        hir::Path {
+            global: p.global,
+            segments: p.segments.iter().map(|segment| {
+                self.lower_path_segment(segment, param_mode)
+            }).collect(),
+            span: p.span,
+        }
+    }
+
+    fn lower_path_segment(&mut self,
+                          segment: &PathSegment,
+                          param_mode: ParamMode)
+                          -> hir::PathSegment {
+        let parameters = match segment.parameters {
             PathParameters::AngleBracketed(ref data) => {
                 let data = self.lower_angle_bracketed_parameter_data(data, param_mode);
                 hir::AngleBracketedParameters(data)
             }
             PathParameters::Parenthesized(ref data) =>
                 hir::ParenthesizedParameters(self.lower_parenthesized_parameter_data(data)),
+        };
+
+        hir::PathSegment {
+            name: segment.identifier.name,
+            parameters: parameters,
         }
     }
 
@@ -521,7 +586,7 @@ impl<'a> LoweringContext<'a> {
                                                           span}) => {
                 hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
                     id: id,
-                    path: self.lower_path(path, None, ParamMode::Explicit),
+                    path: self.lower_path(path, ParamMode::Explicit),
                     ty: self.lower_ty(ty),
                     span: span,
                 })
@@ -551,7 +616,7 @@ impl<'a> LoweringContext<'a> {
 
     fn lower_trait_ref(&mut self, p: &TraitRef) -> hir::TraitRef {
         hir::TraitRef {
-            path: self.lower_path(&p.path, None, ParamMode::Explicit),
+            path: self.lower_path(&p.path, ParamMode::Explicit),
             ref_id: p.ref_id,
         }
     }
@@ -908,26 +973,26 @@ impl<'a> LoweringContext<'a> {
                                                       respan(pth1.span, pth1.node.name),
                                                       sub.as_ref().map(|x| this.lower_pat(x)))
                             }
-                            _ => hir::PatKind::Path(None, hir::Path::from_name(pth1.span,
-                                                                               pth1.node.name))
+                            _ => {
+                                let path = hir::Path::from_name(pth1.span, pth1.node.name);
+                                hir::PatKind::Path(hir::QPath::Resolved(None, P(path)))
+                            }
                         }
                     })
                 }
                 PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))),
                 PatKind::TupleStruct(ref path, ref pats, ddpos) => {
-                    hir::PatKind::TupleStruct(self.lower_path(path, None, ParamMode::Optional),
+                    let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional);
+                    hir::PatKind::TupleStruct(qpath,
                                               pats.iter().map(|x| self.lower_pat(x)).collect(),
                                               ddpos)
                 }
                 PatKind::Path(ref qself, ref path) => {
-                    let qself = qself.as_ref().map(|qself| {
-                        hir::QSelf { ty: self.lower_ty(&qself.ty), position: qself.position }
-                    });
-                    let path = self.lower_path(path, qself.as_ref(), ParamMode::Optional);
-                    hir::PatKind::Path(qself, path)
+                    hir::PatKind::Path(self.lower_qpath(p.id, qself, path, ParamMode::Optional))
                 }
-                PatKind::Struct(ref pth, ref fields, etc) => {
-                    let pth = self.lower_path(pth, None, ParamMode::Optional);
+                PatKind::Struct(ref path, ref fields, etc) => {
+                    let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional);
+
                     let fs = fields.iter()
                                    .map(|f| {
                                        Spanned {
@@ -940,7 +1005,7 @@ impl<'a> LoweringContext<'a> {
                                        }
                                    })
                                    .collect();
-                    hir::PatKind::Struct(pth, fs, etc)
+                    hir::PatKind::Struct(qpath, fs, etc)
                 }
                 PatKind::Tuple(ref elts, ddpos) => {
                     hir::PatKind::Tuple(elts.iter().map(|x| self.lower_pat(x)).collect(), ddpos)
@@ -1266,14 +1331,7 @@ impl<'a> LoweringContext<'a> {
                     };
                 }
                 ExprKind::Path(ref qself, ref path) => {
-                    let qself = qself.as_ref().map(|&QSelf { ref ty, position }| {
-                        hir::QSelf {
-                            ty: self.lower_ty(ty),
-                            position: position,
-                        }
-                    });
-                    let path = self.lower_path(path, qself.as_ref(), ParamMode::Optional);
-                    hir::ExprPath(qself, path)
+                    hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional))
                 }
                 ExprKind::Break(opt_ident, ref opt_expr) => {
                     hir::ExprBreak(self.lower_opt_sp_ident(opt_ident),
@@ -1306,7 +1364,7 @@ impl<'a> LoweringContext<'a> {
                     hir::ExprInlineAsm(P(hir_asm), outputs, inputs)
                 }
                 ExprKind::Struct(ref path, ref fields, ref maybe_expr) => {
-                    hir::ExprStruct(P(self.lower_path(path, None, ParamMode::Optional)),
+                    hir::ExprStruct(self.lower_qpath(e.id, &None, path, ParamMode::Optional),
                                     fields.iter().map(|x| self.lower_field(x)).collect(),
                                     maybe_expr.as_ref().map(|x| P(self.lower_expr(x))))
                 }
@@ -1688,7 +1746,7 @@ impl<'a> LoweringContext<'a> {
             Visibility::Crate(_) => hir::Visibility::Crate,
             Visibility::Restricted { ref path, id } => {
                 hir::Visibility::Restricted {
-                    path: P(self.lower_path(path, None, ParamMode::Explicit)),
+                    path: P(self.lower_path(path, ParamMode::Explicit)),
                     id: id
                 }
             }
@@ -1774,7 +1832,8 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn expr_ident(&mut self, span: Span, id: Name, binding: NodeId) -> hir::Expr {
-        let expr_path = hir::ExprPath(None, self.path_ident(span, id));
+        let path = self.path_ident(span, id);
+        let expr_path = hir::ExprPath(hir::QPath::Resolved(None, P(path)));
         let expr = self.expr(span, expr_path, ThinVec::new());
 
         let def = {
@@ -1792,9 +1851,9 @@ impl<'a> LoweringContext<'a> {
 
     fn expr_path(&mut self, path: hir::Path, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
         let def = self.resolver.resolve_generated_global_path(&path, true);
-        let expr = P(self.expr(path.span, hir::ExprPath(None, path), attrs));
+        let expr = self.expr(path.span, hir::ExprPath(hir::QPath::Resolved(None, P(path))), attrs);
         self.resolver.record_resolution(expr.id, def);
-        expr
+        P(expr)
     }
 
     fn expr_match(&mut self,
@@ -1821,9 +1880,10 @@ impl<'a> LoweringContext<'a> {
                    e: Option<P<hir::Expr>>,
                    attrs: ThinVec<Attribute>) -> P<hir::Expr> {
         let def = self.resolver.resolve_generated_global_path(&path, false);
-        let expr = P(self.expr(sp, hir::ExprStruct(P(path), fields, e), attrs));
+        let qpath = hir::QPath::Resolved(None, P(path));
+        let expr = self.expr(sp, hir::ExprStruct(qpath, fields, e), attrs);
         self.resolver.record_resolution(expr.id, def);
-        expr
+        P(expr)
     }
 
     fn expr(&mut self, span: Span, node: hir::Expr_, attrs: ThinVec<Attribute>) -> hir::Expr {
@@ -1902,10 +1962,11 @@ impl<'a> LoweringContext<'a> {
     fn pat_enum(&mut self, span: Span, path: hir::Path, subpats: hir::HirVec<P<hir::Pat>>)
                 -> P<hir::Pat> {
         let def = self.resolver.resolve_generated_global_path(&path, true);
+        let qpath = hir::QPath::Resolved(None, P(path));
         let pt = if subpats.is_empty() {
-            hir::PatKind::Path(None, path)
+            hir::PatKind::Path(qpath)
         } else {
-            hir::PatKind::TupleStruct(path, subpats, None)
+            hir::PatKind::TupleStruct(qpath, subpats, None)
         };
         let pat = self.pat(span, pt);
         self.resolver.record_resolution(pat.id, def);
@@ -2045,4 +2106,12 @@ impl<'a> LoweringContext<'a> {
         });
         self.expr_block(block, attrs)
     }
+
+    fn ty(&mut self, span: Span, node: hir::Ty_) -> P<hir::Ty> {
+        P(hir::Ty {
+            id: self.next_id(),
+            node: node,
+            span: span,
+        })
+    }
 }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 6f0a3a02380..e9e84eed3e7 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -533,7 +533,7 @@ impl Pat {
             PatKind::Lit(_) |
             PatKind::Range(..) |
             PatKind::Binding(..) |
-            PatKind::Path(..) => {
+            PatKind::Path(_) => {
                 true
             }
         }
@@ -576,16 +576,15 @@ pub enum PatKind {
 
     /// A struct or struct variant pattern, e.g. `Variant {x, y, ..}`.
     /// The `bool` is `true` in the presence of a `..`.
-    Struct(Path, HirVec<Spanned<FieldPat>>, bool),
+    Struct(QPath, HirVec<Spanned<FieldPat>>, bool),
 
     /// A tuple struct/variant pattern `Variant(x, y, .., z)`.
     /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
     /// 0 <= position <= subpats.len()
-    TupleStruct(Path, HirVec<P<Pat>>, Option<usize>),
+    TupleStruct(QPath, HirVec<P<Pat>>, Option<usize>),
 
-    /// A possibly qualified path pattern.
-    /// Such pattern can be resolved to a unit struct/variant or a constant.
-    Path(Option<QSelf>, Path),
+    /// A path pattern for an unit struct/variant or a (maybe-associated) constant.
+    Path(QPath),
 
     /// A tuple pattern `(a, b)`.
     /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
@@ -940,12 +939,8 @@ pub enum Expr_ {
     /// An indexing operation (`foo[2]`)
     ExprIndex(P<Expr>, P<Expr>),
 
-    /// Variable reference, possibly containing `::` and/or type
-    /// parameters, e.g. foo::bar::<baz>.
-    ///
-    /// Optionally "qualified",
-    /// e.g. `<HirVec<T> as SomeTrait>::SomeType`.
-    ExprPath(Option<QSelf>, Path),
+    /// Path to a definition, possibly containing lifetime or type parameters.
+    ExprPath(QPath),
 
     /// A referencing operation (`&a` or `&mut a`)
     ExprAddrOf(Mutability, P<Expr>),
@@ -963,7 +958,7 @@ pub enum Expr_ {
     ///
     /// For example, `Foo {x: 1, y: 2}`, or
     /// `Foo {x: 1, .. base}`, where `base` is the `Option<Expr>`.
-    ExprStruct(P<Path>, HirVec<Field>, Option<P<Expr>>),
+    ExprStruct(QPath, HirVec<Field>, Option<P<Expr>>),
 
     /// An array literal constructed from one repeated element.
     ///
@@ -972,22 +967,30 @@ pub enum Expr_ {
     ExprRepeat(P<Expr>, P<Expr>),
 }
 
-/// The explicit Self type in a "qualified path". The actual
-/// path, including the trait and the associated item, is stored
-/// separately. `position` represents the index of the associated
-/// item qualified with this Self type.
-///
-///     <HirVec<T> as a::b::Trait>::AssociatedItem
-///      ^~~~~     ~~~~~~~~~~~~~~^
-///      ty        position = 3
-///
-///     <HirVec<T>>::AssociatedItem
-///      ^~~~~    ^
-///      ty       position = 0
+/// Optionally `Self`-qualified value/type path or associated extension.
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct QSelf {
-    pub ty: P<Ty>,
-    pub position: usize,
+pub enum QPath {
+    /// Path to a definition, optionally "fully-qualified" with a `Self`
+    /// type, if the path points to an associated item in a trait.
+    ///
+    /// E.g. an unqualified path like `Clone::clone` has `None` for `Self`,
+    /// while `<Vec<T> as Clone>::clone` has `Some(Vec<T>)` for `Self`,
+    /// even though they both have the same two-segment `Clone::clone` `Path`.
+    Resolved(Option<P<Ty>>, P<Path>),
+
+    /// Type-related paths, e.g. `<T>::default` or `<T>::Output`.
+    /// Will be resolved by type-checking to an associated item.
+    ///
+    /// UFCS source paths can desugar into this, with `Vec::new` turning into
+    /// `<Vec>::new`, and `T::X::Y::method` into `<<<T>::X>::Y>::method`,
+    /// the `X` and `Y` nodes being each a `TyPath(QPath::TypeRelative(..))`.
+    TypeRelative(P<Ty>, P<PathSegment>)
+}
+
+impl fmt::Display for QPath {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", print::qpath_to_string(self))
+    }
 }
 
 /// Hints at the original code for a `match _ { .. }`
@@ -1161,11 +1164,12 @@ pub enum Ty_ {
     TyNever,
     /// A tuple (`(A, B, C, D,...)`)
     TyTup(HirVec<P<Ty>>),
-    /// A path (`module::module::...::Type`), optionally
-    /// "qualified", e.g. `<HirVec<T> as SomeTrait>::SomeType`.
+    /// A path to a type definition (`module::module::...::Type`), or an
+    /// associated type, e.g. `<Vec<T> as Trait>::Type` or `<T>::Target`.
     ///
-    /// Type parameters are stored in the Path itself
-    TyPath(Option<QSelf>, Path),
+    /// Type parameters may be stored in each `PathSegment`.
+    TyPath(QPath),
+
     /// Something like `A+B`. Note that `B` must always be a path.
     TyObjectSum(P<Ty>, TyParamBounds),
     /// A type like `for<'a> Foo<&'a Bar>`
diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs
index 0deea941463..8e39fde367b 100644
--- a/src/librustc/hir/pat_util.rs
+++ b/src/librustc/hir/pat_util.rs
@@ -53,9 +53,13 @@ impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
 
 pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool {
     match pat.node {
-        PatKind::Lit(_) | PatKind::Range(..) | PatKind::Path(Some(..), _) => true,
+        PatKind::Lit(_) |
+        PatKind::Range(..) |
+        PatKind::Path(hir::QPath::Resolved(Some(..), _)) |
+        PatKind::Path(hir::QPath::TypeRelative(..)) => true,
+
         PatKind::TupleStruct(..) |
-        PatKind::Path(..) |
+        PatKind::Path(hir::QPath::Resolved(..)) |
         PatKind::Struct(..) => {
             match dm.get(&pat.id).map(|d| d.full_def()) {
                 Some(Def::Variant(..)) | Some(Def::VariantCtor(..)) => true,
@@ -69,7 +73,8 @@ pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool {
 
 pub fn pat_is_const(dm: &DefMap, pat: &hir::Pat) -> bool {
     match pat.node {
-        PatKind::Path(..) => {
+        PatKind::Path(hir::QPath::TypeRelative(..)) => true,
+        PatKind::Path(hir::QPath::Resolved(..)) => {
             match dm.get(&pat.id).map(|d| d.full_def()) {
                 Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => true,
                 _ => false
@@ -171,7 +176,7 @@ pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec<DefId> {
     pat.walk(|p| {
         match p.node {
             PatKind::TupleStruct(..) |
-            PatKind::Path(..) |
+            PatKind::Path(hir::QPath::Resolved(..)) |
             PatKind::Struct(..) => {
                 match dm.get(&p.id).map(|d| d.full_def()) {
                     Some(Def::Variant(id)) |
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 9934259c5d1..448139c37e6 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -272,7 +272,11 @@ pub fn fn_block_to_string(p: &hir::FnDecl) -> String {
 }
 
 pub fn path_to_string(p: &hir::Path) -> String {
-    to_string(|s| s.print_path(p, false, 0))
+    to_string(|s| s.print_path(p, false))
+}
+
+pub fn qpath_to_string(p: &hir::QPath) -> String {
+    to_string(|s| s.print_qpath(p, false))
 }
 
 pub fn name_to_string(name: ast::Name) -> String {
@@ -528,11 +532,8 @@ impl<'a> State<'a> {
                 };
                 self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &generics)?;
             }
-            hir::TyPath(None, ref path) => {
-                self.print_path(path, false, 0)?;
-            }
-            hir::TyPath(Some(ref qself), ref path) => {
-                self.print_qpath(path, qself, false)?
+            hir::TyPath(ref qpath) => {
+                self.print_qpath(qpath, false)?
             }
             hir::TyObjectSum(ref ty, ref bounds) => {
                 self.print_type(&ty)?;
@@ -845,7 +846,7 @@ impl<'a> State<'a> {
     }
 
     fn print_trait_ref(&mut self, t: &hir::TraitRef) -> io::Result<()> {
-        self.print_path(&t.path, false, 0)
+        self.print_path(&t.path, false)
     }
 
     fn print_formal_lifetime_list(&mut self, lifetimes: &[hir::LifetimeDef]) -> io::Result<()> {
@@ -1237,11 +1238,11 @@ impl<'a> State<'a> {
     }
 
     fn print_expr_struct(&mut self,
-                         path: &hir::Path,
+                         qpath: &hir::QPath,
                          fields: &[hir::Field],
                          wth: &Option<P<hir::Expr>>)
                          -> io::Result<()> {
-        self.print_path(path, true, 0)?;
+        self.print_qpath(qpath, true)?;
         word(&mut self.s, "{")?;
         self.commasep_cmnt(Consistent,
                            &fields[..],
@@ -1345,8 +1346,8 @@ impl<'a> State<'a> {
             hir::ExprRepeat(ref element, ref count) => {
                 self.print_expr_repeat(&element, &count)?;
             }
-            hir::ExprStruct(ref path, ref fields, ref wth) => {
-                self.print_expr_struct(path, &fields[..], wth)?;
+            hir::ExprStruct(ref qpath, ref fields, ref wth) => {
+                self.print_expr_struct(qpath, &fields[..], wth)?;
             }
             hir::ExprTup(ref exprs) => {
                 self.print_expr_tup(exprs)?;
@@ -1465,11 +1466,8 @@ impl<'a> State<'a> {
                 self.print_expr(&index)?;
                 word(&mut self.s, "]")?;
             }
-            hir::ExprPath(None, ref path) => {
-                self.print_path(path, true, 0)?
-            }
-            hir::ExprPath(Some(ref qself), ref path) => {
-                self.print_qpath(path, qself, true)?
+            hir::ExprPath(ref qpath) => {
+                self.print_qpath(qpath, true)?
             }
             hir::ExprBreak(opt_name, ref opt_expr) => {
                 word(&mut self.s, "break")?;
@@ -1622,13 +1620,12 @@ impl<'a> State<'a> {
 
     fn print_path(&mut self,
                   path: &hir::Path,
-                  colons_before_params: bool,
-                  depth: usize)
+                  colons_before_params: bool)
                   -> io::Result<()> {
         self.maybe_print_comment(path.span.lo)?;
 
         let mut first = !path.global;
-        for segment in &path.segments[..path.segments.len() - depth] {
+        for segment in &path.segments {
             if first {
                 first = false
             } else {
@@ -1644,23 +1641,45 @@ impl<'a> State<'a> {
     }
 
     fn print_qpath(&mut self,
-                   path: &hir::Path,
-                   qself: &hir::QSelf,
+                   qpath: &hir::QPath,
                    colons_before_params: bool)
                    -> io::Result<()> {
-        word(&mut self.s, "<")?;
-        self.print_type(&qself.ty)?;
-        if qself.position > 0 {
-            space(&mut self.s)?;
-            self.word_space("as")?;
-            let depth = path.segments.len() - qself.position;
-            self.print_path(&path, false, depth)?;
+        match *qpath {
+            hir::QPath::Resolved(None, ref path) => {
+                self.print_path(path, colons_before_params)
+            }
+            hir::QPath::Resolved(Some(ref qself), ref path) => {
+                word(&mut self.s, "<")?;
+                self.print_type(qself)?;
+                space(&mut self.s)?;
+                self.word_space("as")?;
+
+                let mut first = !path.global;
+                for segment in &path.segments[..path.segments.len() - 1] {
+                    if first {
+                        first = false
+                    } else {
+                        word(&mut self.s, "::")?
+                    }
+                    self.print_name(segment.name)?;
+                    self.print_path_parameters(&segment.parameters, colons_before_params)?;
+                }
+
+                word(&mut self.s, ">")?;
+                word(&mut self.s, "::")?;
+                let item_segment = path.segments.last().unwrap();
+                self.print_name(item_segment.name)?;
+                self.print_path_parameters(&item_segment.parameters, colons_before_params)
+            }
+            hir::QPath::TypeRelative(ref qself, ref item_segment) => {
+                word(&mut self.s, "<")?;
+                self.print_type(qself)?;
+                word(&mut self.s, ">")?;
+                word(&mut self.s, "::")?;
+                self.print_name(item_segment.name)?;
+                self.print_path_parameters(&item_segment.parameters, colons_before_params)
+            }
         }
-        word(&mut self.s, ">")?;
-        word(&mut self.s, "::")?;
-        let item_segment = path.segments.last().unwrap();
-        self.print_name(item_segment.name)?;
-        self.print_path_parameters(&item_segment.parameters, colons_before_params)
     }
 
     fn print_path_parameters(&mut self,
@@ -1668,7 +1687,15 @@ impl<'a> State<'a> {
                              colons_before_params: bool)
                              -> io::Result<()> {
         if parameters.is_empty() {
-            return Ok(());
+            let infer_types = match *parameters {
+                hir::AngleBracketedParameters(ref data) => data.infer_types,
+                hir::ParenthesizedParameters(_) => false
+            };
+
+            // FIXME(eddyb) See the comment below about infer_types.
+            if !(infer_types && false) {
+                return Ok(());
+            }
         }
 
         if colons_before_params {
@@ -1760,8 +1787,8 @@ impl<'a> State<'a> {
                     self.print_pat(&p)?;
                 }
             }
-            PatKind::TupleStruct(ref path, ref elts, ddpos) => {
-                self.print_path(path, true, 0)?;
+            PatKind::TupleStruct(ref qpath, ref elts, ddpos) => {
+                self.print_qpath(qpath, true)?;
                 self.popen()?;
                 if let Some(ddpos) = ddpos {
                     self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?;
@@ -1778,14 +1805,11 @@ impl<'a> State<'a> {
                 }
                 self.pclose()?;
             }
-            PatKind::Path(None, ref path) => {
-                self.print_path(path, true, 0)?;
-            }
-            PatKind::Path(Some(ref qself), ref path) => {
-                self.print_qpath(path, qself, false)?;
+            PatKind::Path(ref qpath) => {
+                self.print_qpath(qpath, true)?;
             }
-            PatKind::Struct(ref path, ref fields, etc) => {
-                self.print_path(path, true, 0)?;
+            PatKind::Struct(ref qpath, ref fields, etc) => {
+                self.print_qpath(qpath, true)?;
                 self.nbsp()?;
                 self.word_space("{")?;
                 self.commasep_cmnt(Consistent,
@@ -2118,7 +2142,7 @@ impl<'a> State<'a> {
                     }
                 }
                 &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{ref path, ref ty, ..}) => {
-                    self.print_path(path, false, 0)?;
+                    self.print_path(path, false)?;
                     space(&mut self.s)?;
                     self.word_space("=")?;
                     self.print_type(&ty)?;
@@ -2132,7 +2156,7 @@ impl<'a> State<'a> {
     pub fn print_view_path(&mut self, vp: &hir::ViewPath) -> io::Result<()> {
         match vp.node {
             hir::ViewPathSimple(name, ref path) => {
-                self.print_path(path, false, 0)?;
+                self.print_path(path, false)?;
 
                 if path.segments.last().unwrap().name != name {
                     space(&mut self.s)?;
@@ -2144,7 +2168,7 @@ impl<'a> State<'a> {
             }
 
             hir::ViewPathGlob(ref path) => {
-                self.print_path(path, false, 0)?;
+                self.print_path(path, false)?;
                 word(&mut self.s, "::*")
             }
 
@@ -2152,7 +2176,7 @@ impl<'a> State<'a> {
                 if path.segments.is_empty() {
                     word(&mut self.s, "{")?;
                 } else {
-                    self.print_path(path, false, 0)?;
+                    self.print_path(path, false)?;
                     word(&mut self.s, "::{")?;
                 }
                 self.commasep(Inconsistent, &segments[..], |s, w| s.print_name(w.node.name))?;
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index b9b97473340..406d345992a 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -1440,7 +1440,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
                     }
                     ty_queue.push(&mut_ty.ty);
                 }
-                hir::TyPath(ref maybe_qself, ref path) => {
+                hir::TyPath(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
                     match self.tcx.expect_def(cur_ty.id) {
                         Def::Enum(did) | Def::TyAlias(did) |
                         Def::Struct(did) | Def::Union(did) => {
@@ -1476,15 +1476,12 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
                             };
                             let new_path = self.rebuild_path(rebuild_info, lifetime);
                             let qself = maybe_qself.as_ref().map(|qself| {
-                                hir::QSelf {
-                                    ty: self.rebuild_arg_ty_or_output(&qself.ty, lifetime,
-                                                                      anon_nums, region_names),
-                                    position: qself.position
-                                }
+                                self.rebuild_arg_ty_or_output(qself, lifetime,
+                                                              anon_nums, region_names)
                             });
                             let to = hir::Ty {
                                 id: cur_ty.id,
-                                node: hir::TyPath(qself, new_path),
+                                node: hir::TyPath(hir::QPath::Resolved(qself, P(new_path))),
                                 span: cur_ty.span
                             };
                             new_ty = self.rebuild_ty(new_ty, P(to));
diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs
index 86422835c8c..5b0f241f8a8 100644
--- a/src/librustc/middle/astconv_util.rs
+++ b/src/librustc/middle/astconv_util.rs
@@ -14,14 +14,14 @@
  * Almost certainly this could (and should) be refactored out of existence.
  */
 
+use hir;
 use hir::def::Def;
 use ty::{Ty, TyCtxt};
 
 use syntax_pos::Span;
-use hir as ast;
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-    pub fn prohibit_type_params(self, segments: &[ast::PathSegment]) {
+    pub fn prohibit_type_params(self, segments: &[hir::PathSegment]) {
         for segment in segments {
             for typ in segment.parameters.types() {
                 struct_span_err!(self.sess, typ.span, E0109,
@@ -53,24 +53,24 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn prim_ty_to_ty(self,
-                         segments: &[ast::PathSegment],
-                         nty: ast::PrimTy)
+                         segments: &[hir::PathSegment],
+                         nty: hir::PrimTy)
                          -> Ty<'tcx> {
         self.prohibit_type_params(segments);
         match nty {
-            ast::TyBool => self.types.bool,
-            ast::TyChar => self.types.char,
-            ast::TyInt(it) => self.mk_mach_int(it),
-            ast::TyUint(uit) => self.mk_mach_uint(uit),
-            ast::TyFloat(ft) => self.mk_mach_float(ft),
-            ast::TyStr => self.mk_str()
+            hir::TyBool => self.types.bool,
+            hir::TyChar => self.types.char,
+            hir::TyInt(it) => self.mk_mach_int(it),
+            hir::TyUint(uit) => self.mk_mach_uint(uit),
+            hir::TyFloat(ft) => self.mk_mach_float(ft),
+            hir::TyStr => self.mk_str()
         }
     }
 
     /// If a type in the AST is a primitive type, return the ty::Ty corresponding
     /// to it.
-    pub fn ast_ty_to_prim_ty(self, ast_ty: &ast::Ty) -> Option<Ty<'tcx>> {
-        if let ast::TyPath(None, ref path) = ast_ty.node {
+    pub fn ast_ty_to_prim_ty(self, ast_ty: &hir::Ty) -> Option<Ty<'tcx>> {
+        if let hir::TyPath(hir::QPath::Resolved(None, ref path)) = ast_ty.node {
             if let Def::PrimTy(nty) = self.expect_def(ast_ty.id) {
                 Some(self.prim_ty_to_ty(&path.segments, nty))
             } else {
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index f47eab013c2..efbec7bf13b 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -240,6 +240,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
 
     fn visit_expr(&mut self, expr: &hir::Expr) {
         match expr.node {
+            hir::ExprPath(hir::QPath::TypeRelative(..)) => {
+                self.lookup_and_handle_definition(expr.id);
+            }
             hir::ExprMethodCall(..) => {
                 self.lookup_and_handle_method(expr.id);
             }
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index 25fe407271b..2892f249c5e 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -186,7 +186,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
             hir::ExprInlineAsm(..) => {
                 self.require_unsafe(expr.span, "use of inline assembly");
             }
-            hir::ExprPath(..) => {
+            hir::ExprPath(hir::QPath::Resolved(..)) => {
                 if let Def::Static(def_id, mutbl) = self.tcx.expect_def(expr.id) {
                     if mutbl {
                         self.require_unsafe(expr.span, "use of mutable static");
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 594ed408d8c..6c952825554 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -374,7 +374,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         self.walk_adjustment(expr);
 
         match expr.node {
-            hir::ExprPath(..) => { }
+            hir::ExprPath(_) => { }
 
             hir::ExprType(ref subexpr, _) => {
                 self.walk_expr(&subexpr)
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index 80cf64865ab..c610c6f75b0 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -160,23 +160,27 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
 
 impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for ExprVisitor<'a, 'gcx, 'tcx> {
     fn visit_expr(&mut self, expr: &hir::Expr) {
-        if let hir::ExprPath(..) = expr.node {
-            match self.infcx.tcx.expect_def(expr.id) {
-                Def::Fn(did) if self.def_id_is_transmute(did) => {
-                    let typ = self.infcx.tcx.tables().node_id_to_type(expr.id);
-                    match typ.sty {
-                        ty::TyFnDef(.., ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
-                            let from = bare_fn_ty.sig.0.inputs[0];
-                            let to = bare_fn_ty.sig.0.output;
-                            self.check_transmute(expr.span, from, to, expr.id);
-                        }
-                        _ => {
-                            span_bug!(expr.span, "transmute wasn't a bare fn?!");
-                        }
+        let def = match expr.node {
+            hir::ExprPath(_) => {
+                self.infcx.tcx.expect_def(expr.id)
+            }
+            _ => Def::Err
+        };
+        match def {
+            Def::Fn(did) if self.def_id_is_transmute(did) => {
+                let typ = self.infcx.tcx.tables().node_id_to_type(expr.id);
+                match typ.sty {
+                    ty::TyFnDef(.., ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
+                        let from = bare_fn_ty.sig.0.inputs[0];
+                        let to = bare_fn_ty.sig.0.output;
+                        self.check_transmute(expr.span, from, to, expr.id);
+                    }
+                    _ => {
+                        span_bug!(expr.span, "transmute wasn't a bare fn?!");
                     }
                 }
-                _ => {}
             }
+            _ => {}
         }
 
         intravisit::walk_expr(self, expr);
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 4b1787ba593..eefed0a5a74 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -443,7 +443,7 @@ fn visit_arm(ir: &mut IrMaps, arm: &hir::Arm) {
 fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
     match expr.node {
       // live nodes required for uses or definitions of variables:
-      hir::ExprPath(..) => {
+      hir::ExprPath(_) => {
         let def = ir.tcx.expect_def(expr.id);
         debug!("expr {}: path that leads to {:?}", expr.id, def);
         if let Def::Local(..) = def {
@@ -922,7 +922,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         match expr.node {
           // Interesting cases with control flow or which gen/kill
 
-          hir::ExprPath(..) => {
+          hir::ExprPath(hir::QPath::Resolved(..)) => {
               self.access_path(expr, succ, ACC_READ | ACC_USE)
           }
 
@@ -1171,7 +1171,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             self.propagate_through_exprs(inputs, succ)
           }
 
-          hir::ExprLit(..) => {
+          hir::ExprLit(..) | hir::ExprPath(hir::QPath::TypeRelative(..)) => {
             succ
           }
 
@@ -1235,7 +1235,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         // just ignore such cases and treat them as reads.
 
         match expr.node {
-            hir::ExprPath(..) => succ,
+            hir::ExprPath(_) => succ,
             hir::ExprField(ref e, _) => self.propagate_through_expr(&e, succ),
             hir::ExprTupField(ref e, _) => self.propagate_through_expr(&e, succ),
             _ => self.propagate_through_expr(expr, succ)
@@ -1246,7 +1246,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
     fn write_lvalue(&mut self, expr: &Expr, succ: LiveNode, acc: u32)
                     -> LiveNode {
         match expr.node {
-          hir::ExprPath(..) => {
+          hir::ExprPath(hir::QPath::Resolved(..)) => {
               self.access_path(expr, succ, acc)
           }
 
@@ -1431,8 +1431,8 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
       hir::ExprBreak(..) | hir::ExprAgain(..) | hir::ExprLit(_) |
       hir::ExprBlock(..) | hir::ExprAddrOf(..) |
       hir::ExprStruct(..) | hir::ExprRepeat(..) |
-      hir::ExprClosure(..) | hir::ExprPath(..) | hir::ExprBox(..) |
-      hir::ExprType(..) => {
+      hir::ExprClosure(..) | hir::ExprPath(_) |
+      hir::ExprBox(..) | hir::ExprType(..) => {
         intravisit::walk_expr(this, expr);
       }
     }
@@ -1482,7 +1482,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
     fn check_lvalue(&mut self, expr: &Expr) {
         match expr.node {
-            hir::ExprPath(..) => {
+            hir::ExprPath(hir::QPath::Resolved(..)) => {
                 if let Def::Local(def_id) = self.ir.tcx.expect_def(expr.id) {
                     // Assignment to an immutable variable or argument: only legal
                     // if there is no later assignment. If this local is actually
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index fedf8c2ec74..1ca078dcd2e 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -488,7 +488,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             }
           }
 
-          hir::ExprPath(..) => {
+          hir::ExprPath(_) => {
             self.cat_def(expr.id, expr.span, expr_ty, self.tcx().expect_def(expr.id))
           }
 
@@ -1157,7 +1157,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             }
           }
 
-          PatKind::Path(..) | PatKind::Binding(.., None) |
+          PatKind::Path(_) | PatKind::Binding(.., None) |
           PatKind::Lit(..) | PatKind::Range(..) | PatKind::Wild => {
             // always ok
           }
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 35e0e494771..0329b4c4a30 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -91,7 +91,7 @@ struct ReachableContext<'a, 'tcx: 'a> {
 impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &hir::Expr) {
         match expr.node {
-            hir::ExprPath(..) => {
+            hir::ExprPath(_) => {
                 let def = self.tcx.expect_def(expr.id);
                 let def_id = def.def_id();
                 if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 41da5562e23..c65fd25950d 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -244,7 +244,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     intravisit::walk_ty(this, ty);
                 });
             }
-            hir::TyPath(None, ref path) => {
+            hir::TyPath(hir::QPath::Resolved(None, ref path)) => {
                 // if this path references a trait, then this will resolve to
                 // a trait ref, which introduces a binding scope.
                 match self.def_map.get(&ty.id).map(|d| (d.base_def, d.depth)) {
@@ -944,13 +944,14 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
     impl<'v> Visitor<'v> for ConstrainedCollector {
         fn visit_ty(&mut self, ty: &'v hir::Ty) {
             match ty.node {
-                hir::TyPath(Some(_), _) => {
+                hir::TyPath(hir::QPath::Resolved(Some(_), _)) |
+                hir::TyPath(hir::QPath::TypeRelative(..)) => {
                     // ignore lifetimes appearing in associated type
                     // projections, as they are not *constrained*
                     // (defined above)
                 }
 
-                hir::TyPath(None, ref path) => {
+                hir::TyPath(hir::QPath::Resolved(None, ref path)) => {
                     // consider only the lifetimes on the final
                     // segment; I am not sure it's even currently
                     // valid to have them elsewhere, but even if it
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 86a89eff3a4..a044ffd9a7f 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -486,6 +486,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
         intravisit::walk_pat(self, pat)
     }
 
+    fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
+        check_ty(self.tcx, ty,
+                 &mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
+        intravisit::walk_ty(self, ty)
+    }
+
     fn visit_block(&mut self, b: &'tcx hir::Block) {
         let old_skip_count = self.in_skip_block;
         match b.rules {
@@ -553,6 +559,10 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr,
             let method_call = ty::MethodCall::expr(e.id);
             tcx.tables().method_map[&method_call].def_id
         }
+        hir::ExprPath(hir::QPath::TypeRelative(..)) => {
+            span = e.span;
+            tcx.expect_def(e.id).def_id()
+        }
         hir::ExprField(ref base_e, ref field) => {
             span = field.span;
             match tcx.tables().expr_ty_adjusted(base_e).sty {
@@ -633,6 +643,11 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat,
     debug!("check_pat(pat = {:?})", pat);
     if is_internal(tcx, pat.span) { return; }
 
+    if let PatKind::Path(hir::QPath::TypeRelative(..)) = pat.node {
+        let def_id = tcx.expect_def(pat.id).def_id();
+        maybe_do_stability_check(tcx, def_id, pat.span, cb)
+    }
+
     let v = match tcx.tables().pat_ty_opt(pat).map(|ty| &ty.sty) {
         Some(&ty::TyAdt(adt, _)) if !adt.is_enum() => adt.struct_variant(),
         _ => return,
@@ -656,6 +671,19 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat,
     }
 }
 
+pub fn check_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: &hir::Ty,
+                          cb: &mut FnMut(DefId, Span,
+                                         &Option<&Stability>,
+                                         &Option<DeprecationEntry>)) {
+    debug!("check_ty(ty = {:?})", ty);
+    if is_internal(tcx, ty.span) { return; }
+
+    if let hir::TyPath(hir::QPath::TypeRelative(..)) = ty.node {
+        let def_id = tcx.expect_def(ty.id).def_id();
+        maybe_do_stability_check(tcx, def_id, ty.span, cb);
+    }
+}
+
 fn maybe_do_stability_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                       id: DefId, span: Span,
                                       cb: &mut FnMut(DefId, Span,
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 7982c641ede..3d02ff4651f 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -2059,11 +2059,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     pub fn expr_is_lval(self, expr: &hir::Expr) -> bool {
          match expr.node {
-            hir::ExprPath(..) => {
-                // This function can be used during type checking when not all paths are
-                // fully resolved. Partially resolved paths in expressions can only legally
-                // refer to associated items which are always rvalues.
-                match self.expect_resolution(expr.id).base_def {
+            hir::ExprPath(hir::QPath::Resolved(..)) => {
+                match self.expect_def(expr.id) {
                     Def::Local(..) | Def::Upvar(..) | Def::Static(..) | Def::Err => true,
                     _ => false,
                 }
@@ -2080,6 +2077,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 true
             }
 
+            // Partially qualified paths in expressions can only legally
+            // refer to associated items which are always rvalues.
+            hir::ExprPath(hir::QPath::TypeRelative(..)) |
+
             hir::ExprCall(..) |
             hir::ExprMethodCall(..) |
             hir::ExprStruct(..) |