about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-01-15 17:12:55 +0000
committerbors <bors@rust-lang.org>2015-01-15 17:12:55 +0000
commit9ade482b3bdc7a967ca98f1f1138b596ef45191e (patch)
tree84335c40ee3bd03d89f14d22a8d60c479a0d2c51
parent1c78ad937b4da9dd872b0a865025f3e2e885f90d (diff)
parent85ba8178e2e995c0da6eb9268612baca8a6ba2e3 (diff)
auto merge of #21077 : eddyb/rust/expr-qpath, r=nikomatsakis
Working towards #16293, this adds support for `<T as Trait>::method` in expressions.
-rw-r--r--src/librustc/lint/builtin.rs2
-rw-r--r--src/librustc/middle/cfg/construct.rs3
-rw-r--r--src/librustc/middle/check_const.rs2
-rw-r--r--src/librustc/middle/check_static.rs2
-rw-r--r--src/librustc/middle/check_static_recursion.rs2
-rw-r--r--src/librustc/middle/const_eval.rs11
-rw-r--r--src/librustc/middle/effect.rs2
-rw-r--r--src/librustc/middle/expr_use_visitor.rs2
-rw-r--r--src/librustc/middle/liveness.rs14
-rw-r--r--src/librustc/middle/mem_categorization.rs2
-rw-r--r--src/librustc/middle/privacy.rs2
-rw-r--r--src/librustc/middle/reachable.rs2
-rw-r--r--src/librustc/middle/ty.rs2
-rw-r--r--src/librustc_back/svh.rs2
-rw-r--r--src/librustc_resolve/lib.rs53
-rw-r--r--src/librustc_trans/save/mod.rs16
-rw-r--r--src/librustc_trans/trans/_match.rs2
-rw-r--r--src/librustc_trans/trans/callee.rs7
-rw-r--r--src/librustc_trans/trans/consts.rs2
-rw-r--r--src/librustc_trans/trans/debuginfo.rs3
-rw-r--r--src/librustc_trans/trans/expr.rs4
-rw-r--r--src/librustc_typeck/astconv.rs5
-rw-r--r--src/librustc_typeck/check/_match.rs4
-rw-r--r--src/librustc_typeck/check/mod.rs27
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/libsyntax/ast.rs6
-rw-r--r--src/libsyntax/fold.rs6
-rw-r--r--src/libsyntax/parse/parser.rs44
-rw-r--r--src/libsyntax/print/pprust.rs26
-rw-r--r--src/libsyntax/visit.rs18
-rw-r--r--src/test/compile-fail/ufcs-qpath-missing-params.rs17
-rw-r--r--src/test/compile-fail/ufcs-qpath-self-mismatch.rs21
-rw-r--r--src/test/run-pass/const-polymorphic-paths.rs30
33 files changed, 256 insertions, 87 deletions
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index d95000ece5a..59808b302f4 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -1731,7 +1731,7 @@ impl LintPass for Stability {
         let mut span = e.span;
 
         let id = match e.node {
-            ast::ExprPath(..) | ast::ExprStruct(..) => {
+            ast::ExprPath(..) | ast::ExprQPath(..) | ast::ExprStruct(..) => {
                 match cx.tcx.def_map.borrow().get(&e.id) {
                     Some(&def) => def.def_id(),
                     None => return
diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs
index b601ea59486..07b520e5865 100644
--- a/src/librustc/middle/cfg/construct.rs
+++ b/src/librustc/middle/cfg/construct.rs
@@ -495,7 +495,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             ast::ExprMac(..) |
             ast::ExprClosure(..) |
             ast::ExprLit(..) |
-            ast::ExprPath(..) => {
+            ast::ExprPath(..) |
+            ast::ExprQPath(..) => {
                 self.straightline(expr, pred, None::<ast::Expr>.iter())
             }
         }
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index 621d7274b3f..202020a9033 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -111,7 +111,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) {
                            expression");
             }
         }
-        ast::ExprPath(_) => {
+        ast::ExprPath(_) | ast::ExprQPath(_) => {
             match v.tcx.def_map.borrow()[e.id] {
                 DefStatic(..) | DefConst(..) |
                 DefFn(..) | DefStaticMethod(..) | DefMethod(..) |
diff --git a/src/librustc/middle/check_static.rs b/src/librustc/middle/check_static.rs
index 154272d2deb..026aa3c5ccf 100644
--- a/src/librustc/middle/check_static.rs
+++ b/src/librustc/middle/check_static.rs
@@ -228,7 +228,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckStaticVisitor<'a, 'tcx> {
                           "{} are not allowed to have custom pointers",
                           self.msg());
             }
-            ast::ExprPath(..) => {
+            ast::ExprPath(_) | ast::ExprQPath(_) => {
                 match ty::resolve_expr(self.tcx, e) {
                     def::DefStatic(..) if self.mode == InConstant => {
                         let msg = "constants cannot refer to other statics, \
diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs
index e2a0738def1..86a58dae45a 100644
--- a/src/librustc/middle/check_static_recursion.rs
+++ b/src/librustc/middle/check_static_recursion.rs
@@ -93,7 +93,7 @@ impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> {
 
     fn visit_expr(&mut self, e: &ast::Expr) {
         match e.node {
-            ast::ExprPath(..) => {
+            ast::ExprPath(_) | ast::ExprQPath(_) => {
                 match self.def_map.borrow().get(&e.id) {
                     Some(&DefStatic(def_id, _)) |
                     Some(&DefConst(def_id)) if
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 52352e920ce..c998d178c22 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -244,7 +244,7 @@ impl<'a, 'tcx> ConstEvalVisitor<'a, 'tcx> {
 
             // FIXME: (#3728) we can probably do something CCI-ish
             // surrounding nonlocal constants. But we don't yet.
-            ast::ExprPath(_) => self.lookup_constness(e),
+            ast::ExprPath(_) | ast::ExprQPath(_) => self.lookup_constness(e),
 
             ast::ExprRepeat(..) => general_const,
 
@@ -356,6 +356,13 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr) -> P<ast::Pat> {
             }
         }
 
+        ast::ExprQPath(_) => {
+            match lookup_const(tcx, expr) {
+                Some(actual) => return const_expr_to_pat(tcx, actual),
+                _ => unreachable!()
+            }
+        }
+
         _ => ast::PatLit(P(expr.clone()))
     };
     P(ast::Pat { id: expr.id, node: pat, span: expr.span })
@@ -542,7 +549,7 @@ pub fn eval_const_expr_partial(tcx: &ty::ctxt, e: &Expr) -> Result<const_val, St
                 ty::ty_float(ast::TyF64) => (f64, const_float, f64)
             }))
       }
-      ast::ExprPath(_) => {
+      ast::ExprPath(_) | ast::ExprQPath(_) => {
           match lookup_const(tcx, e) {
               Some(actual_e) => eval_const_expr_partial(tcx, &*actual_e),
               None => Err("non-constant path in constant expr".to_string())
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index f7eea6e5cb7..abb8f35f662 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -175,7 +175,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
             ast::ExprInlineAsm(..) => {
                 self.require_unsafe(expr.span, "use of inline assembly");
             }
-            ast::ExprPath(..) => {
+            ast::ExprPath(_) | ast::ExprQPath(_) => {
                 if let def::DefStatic(_, true) = ty::resolve_expr(self.tcx, expr) {
                     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 e5eb439d42c..a5f2dc398e9 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -424,7 +424,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
                 self.walk_expr(&**subexpr)
             }
 
-            ast::ExprPath(..) => { }
+            ast::ExprPath(_) | ast::ExprQPath(_) => { }
 
             ast::ExprUnary(ast::UnDeref, ref base) => {      // *base
                 if !self.walk_overloaded_operator(expr, &**base, Vec::new(), PassArgs::ByRef) {
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 1b1dca00422..6b9e5b2ceea 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -447,7 +447,7 @@ fn visit_arm(ir: &mut IrMaps, arm: &ast::Arm) {
 fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
     match expr.node {
       // live nodes required for uses or definitions of variables:
-      ast::ExprPath(_) => {
+      ast::ExprPath(_) | ast::ExprQPath(_) => {
         let def = ir.tcx.def_map.borrow()[expr.id].clone();
         debug!("expr {}: path that leads to {:?}", expr.id, def);
         if let DefLocal(..) = def {
@@ -960,7 +960,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         match expr.node {
           // Interesting cases with control flow or which gen/kill
 
-          ast::ExprPath(_) => {
+          ast::ExprPath(_) | ast::ExprQPath(_) => {
               self.access_path(expr, succ, ACC_READ | ACC_USE)
           }
 
@@ -1289,7 +1289,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         // just ignore such cases and treat them as reads.
 
         match expr.node {
-            ast::ExprPath(_) => succ,
+            ast::ExprPath(_) | ast::ExprQPath(_) => succ,
             ast::ExprField(ref e, _) => self.propagate_through_expr(&**e, succ),
             ast::ExprTupField(ref e, _) => self.propagate_through_expr(&**e, succ),
             _ => self.propagate_through_expr(expr, succ)
@@ -1300,7 +1300,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
     fn write_lvalue(&mut self, expr: &Expr, succ: LiveNode, acc: uint)
                     -> LiveNode {
         match expr.node {
-          ast::ExprPath(_) => self.access_path(expr, succ, acc),
+          ast::ExprPath(_) | ast::ExprQPath(_) => {
+              self.access_path(expr, succ, acc)
+          }
 
           // We do not track other lvalues, so just propagate through
           // to their subcomponents.  Also, it may happen that
@@ -1492,7 +1494,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
       ast::ExprBlock(..) | ast::ExprMac(..) | ast::ExprAddrOf(..) |
       ast::ExprStruct(..) | ast::ExprRepeat(..) | ast::ExprParen(..) |
       ast::ExprClosure(..) | ast::ExprPath(..) | ast::ExprBox(..) |
-      ast::ExprRange(..) => {
+      ast::ExprRange(..) | ast::ExprQPath(..) => {
         visit::walk_expr(this, expr);
       }
       ast::ExprIfLet(..) => {
@@ -1583,7 +1585,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
     fn check_lvalue(&mut self, expr: &Expr) {
         match expr.node {
-            ast::ExprPath(_) => {
+            ast::ExprPath(_) | ast::ExprQPath(_) => {
                 if let DefLocal(nid) = self.ir.tcx.def_map.borrow()[expr.id].clone() {
                     // 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 51ec7528432..90fe6b49911 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -520,7 +520,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
             }
           }
 
-          ast::ExprPath(_) => {
+          ast::ExprPath(_) | ast::ExprQPath(_) => {
             let def = (*self.tcx().def_map.borrow())[expr.id];
             self.cat_def(expr.id, expr.span, expr_ty, def)
           }
diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs
index aa37c2fe348..b92870cfa42 100644
--- a/src/librustc/middle/privacy.rs
+++ b/src/librustc/middle/privacy.rs
@@ -920,7 +920,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
                                                             struct type?!"),
                 }
             }
-            ast::ExprPath(..) => {
+            ast::ExprPath(_) | ast::ExprQPath(_) => {
                 let guard = |&: did: ast::DefId| {
                     let fields = ty::lookup_struct_fields(self.tcx, did);
                     let any_priv = fields.iter().any(|f| {
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 906607ddc5b..b7e6da8c5f6 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -104,7 +104,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &ast::Expr) {
 
         match expr.node {
-            ast::ExprPath(_) => {
+            ast::ExprPath(_) | ast::ExprQPath(_) => {
                 let def = match self.tcx.def_map.borrow().get(&expr.id) {
                     Some(&def) => def,
                     None => {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 755983c71bb..525fe86cf24 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -4515,7 +4515,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
     }
 
     match expr.node {
-        ast::ExprPath(..) => {
+        ast::ExprPath(_) | ast::ExprQPath(_) => {
             match resolve_expr(tcx, expr) {
                 def::DefVariant(tid, vid, _) => {
                     let variant_info = enum_variant_with_id(tcx, tid, vid);
diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs
index 4e260da2e4d..789a87bbcda 100644
--- a/src/librustc_back/svh.rs
+++ b/src/librustc_back/svh.rs
@@ -252,6 +252,7 @@ mod svh_visitor {
         SawExprIndex,
         SawExprRange,
         SawExprPath,
+        SawExprQPath,
         SawExprAddrOf(ast::Mutability),
         SawExprRet,
         SawExprInlineAsm(&'a ast::InlineAsm),
@@ -285,6 +286,7 @@ mod svh_visitor {
             ExprIndex(..)            => SawExprIndex,
             ExprRange(..)            => SawExprRange,
             ExprPath(..)             => SawExprPath,
+            ExprQPath(..)            => SawExprQPath,
             ExprAddrOf(m, _)         => SawExprAddrOf(m),
             ExprBreak(id)            => SawExprBreak(id.map(content)),
             ExprAgain(id)            => SawExprAgain(id.map(content)),
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index ae55f8fb3aa..7743a437858 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -61,7 +61,7 @@ use rustc::util::lev_distance::lev_distance;
 use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block, Crate, CrateNum};
 use syntax::ast::{DefId, Expr, ExprAgain, ExprBreak, ExprField};
 use syntax::ast::{ExprClosure, ExprForLoop, ExprLoop, ExprWhile, ExprMethodCall};
-use syntax::ast::{ExprPath, ExprStruct, FnDecl};
+use syntax::ast::{ExprPath, ExprQPath, ExprStruct, FnDecl};
 use syntax::ast::{ForeignItemFn, ForeignItemStatic, Generics};
 use syntax::ast::{Ident, ImplItem, Item, ItemConst, ItemEnum, ItemFn};
 use syntax::ast::{ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic};
@@ -3169,7 +3169,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     TraitImplementation        => "implement",
                     TraitDerivation            => "derive",
                     TraitObject                => "reference",
-                    TraitQPath                 => "extract an associated type from",
+                    TraitQPath                 => "extract an associated item from",
                 };
 
                 let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str);
@@ -3565,31 +3565,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     }
                 }
 
-                match result_def {
-                    None => {
-                        match self.resolve_path(ty.id, path, TypeNS, true) {
-                            Some(def) => {
-                                debug!("(resolving type) resolved `{:?}` to \
-                                        type {:?}",
-                                       token::get_ident(path.segments.last().unwrap() .identifier),
-                                       def);
-                                result_def = Some(def);
-                            }
-                            None => {
-                                result_def = None;
-                            }
-                        }
-                    }
-                    Some(_) => {}   // Continue.
+                if let None = result_def {
+                    result_def = self.resolve_path(ty.id, path, TypeNS, true);
                 }
 
                 match result_def {
                     Some(def) => {
                         // Write the result into the def map.
                         debug!("(resolving type) writing resolution for `{}` \
-                                (id {})",
+                                (id {}) = {:?}",
                                self.path_names_to_string(path),
-                               path_id);
+                               path_id, def);
                         self.record_def(path_id, def);
                     }
                     None => {
@@ -3609,6 +3595,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             TyQPath(ref qpath) => {
                 self.resolve_type(&*qpath.self_type);
                 self.resolve_trait_reference(ty.id, &*qpath.trait_ref, TraitQPath);
+                for ty in qpath.item_path.parameters.types().into_iter() {
+                    self.resolve_type(&**ty);
+                }
+                for binding in qpath.item_path.parameters.bindings().into_iter() {
+                    self.resolve_type(&*binding.ty);
+                }
             }
 
             TyPolyTraitRef(ref bounds) => {
@@ -4400,15 +4392,25 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             // The interpretation of paths depends on whether the path has
             // multiple elements in it or not.
 
-            ExprPath(ref path) => {
+            ExprPath(_) | ExprQPath(_) => {
+                let mut path_from_qpath;
+                let path = match expr.node {
+                    ExprPath(ref path) => path,
+                    ExprQPath(ref qpath) => {
+                        self.resolve_type(&*qpath.self_type);
+                        self.resolve_trait_reference(expr.id, &*qpath.trait_ref, TraitQPath);
+                        path_from_qpath = qpath.trait_ref.path.clone();
+                        path_from_qpath.segments.push(qpath.item_path.clone());
+                        &path_from_qpath
+                    }
+                    _ => unreachable!()
+                };
                 // This is a local path in the value namespace. Walk through
                 // scopes looking for it.
-
-                let path_name = self.path_names_to_string(path);
-
                 match self.resolve_path(expr.id, path, ValueNS, true) {
                     // Check if struct variant
                     Some((DefVariant(_, _, true), _)) => {
+                        let path_name = self.path_names_to_string(path);
                         self.resolve_error(expr.span,
                                 format!("`{}` is a struct variant name, but \
                                          this expression \
@@ -4423,7 +4425,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     Some(def) => {
                         // Write the result into the def map.
                         debug!("(resolving expr) resolved `{}`",
-                               path_name);
+                               self.path_names_to_string(path));
 
                         self.record_def(expr.id, def);
                     }
@@ -4432,6 +4434,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         // (The pattern matching def_tys where the id is in self.structs
                         // matches on regular structs while excluding tuple- and enum-like
                         // structs, which wouldn't result in this error.)
+                        let path_name = self.path_names_to_string(path);
                         match self.with_no_errors(|this|
                             this.resolve_path(expr.id, path, TypeNS, false)) {
                             Some((DefTy(struct_id, _), _))
diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs
index 815a6fe846d..f2a67029170 100644
--- a/src/librustc_trans/save/mod.rs
+++ b/src/librustc_trans/save/mod.rs
@@ -767,7 +767,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
                     span: Span,
                     path: &ast::Path,
                     ref_kind: Option<recorder::Row>) {
-        if generated_code(path.span) {
+        if generated_code(span) {
             return
         }
 
@@ -1307,9 +1307,15 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
                 visit::walk_expr(self, ex);
             },
             ast::ExprPath(ref path) => {
-                self.process_path(ex.id, ex.span, path, None);
+                self.process_path(ex.id, path.span, path, None);
                 visit::walk_path(self, path);
             }
+            ast::ExprQPath(ref qpath) => {
+                let mut path = qpath.trait_ref.path.clone();
+                path.segments.push(qpath.item_path.clone());
+                self.process_path(ex.id, ex.span, &path, None);
+                visit::walk_qpath(self, ex.span, &**qpath);
+            }
             ast::ExprStruct(ref path, ref fields, ref base) =>
                 self.process_struct_lit(ex, path, fields, base),
             ast::ExprMethodCall(_, _, ref args) => self.process_method_call(ex, args),
@@ -1439,7 +1445,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
                                           "")
                 }
                 def::DefVariant(..) => {
-                    paths_to_process.push((id, p.span, p.clone(), Some(ref_kind)))
+                    paths_to_process.push((id, p.clone(), Some(ref_kind)))
                 }
                 // FIXME(nrc) what are these doing here?
                 def::DefStatic(_, _) => {}
@@ -1448,8 +1454,8 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
                             *def)
             }
         }
-        for &(id, span, ref path, ref_kind) in paths_to_process.iter() {
-            self.process_path(id, span, path, ref_kind);
+        for &(id, ref path, ref_kind) in paths_to_process.iter() {
+            self.process_path(id, path.span, path, ref_kind);
         }
         self.collecting = false;
         self.collected_paths.clear();
diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs
index f182045efd2..b01604bd397 100644
--- a/src/librustc_trans/trans/_match.rs
+++ b/src/librustc_trans/trans/_match.rs
@@ -1235,7 +1235,7 @@ pub fn trans_match<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 /// Checks whether the binding in `discr` is assigned to anywhere in the expression `body`
 fn is_discr_reassigned(bcx: Block, discr: &ast::Expr, body: &ast::Expr) -> bool {
     let (vid, field) = match discr.node {
-        ast::ExprPath(..) => match bcx.def(discr.id) {
+        ast::ExprPath(_) | ast::ExprQPath(_) => match bcx.def(discr.id) {
             def::DefLocal(vid) | def::DefUpvar(vid, _, _) => (vid, None),
             _ => return false
         },
diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs
index 6196f9e5eab..11006f37531 100644
--- a/src/librustc_trans/trans/callee.rs
+++ b/src/librustc_trans/trans/callee.rs
@@ -91,8 +91,11 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
     debug!("callee::trans(expr={})", expr.repr(bcx.tcx()));
 
     // pick out special kinds of expressions that can be called:
-    if let ast::ExprPath(_) = expr.node {
-        return trans_def(bcx, bcx.def(expr.id), expr);
+    match expr.node {
+        ast::ExprPath(_) | ast::ExprQPath(_) => {
+            return trans_def(bcx, bcx.def(expr.id), expr);
+        }
+        _ => {}
     }
 
     // any other expressions are closures:
diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs
index 00b97286de3..29cf9f72ef8 100644
--- a/src/librustc_trans/trans/consts.rs
+++ b/src/librustc_trans/trans/consts.rs
@@ -600,7 +600,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr) -> ValueRef {
                 C_array(llunitty, &vs[])
             }
           }
-          ast::ExprPath(_) => {
+          ast::ExprPath(_) | ast::ExprQPath(_) => {
             let def = cx.tcx().def_map.borrow()[e.id];
             match def {
                 def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) => {
diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs
index 5bbd83344bf..d5416ae0631 100644
--- a/src/librustc_trans/trans/debuginfo.rs
+++ b/src/librustc_trans/trans/debuginfo.rs
@@ -3526,7 +3526,8 @@ fn create_scope_map(cx: &CrateContext,
             ast::ExprLit(_)   |
             ast::ExprBreak(_) |
             ast::ExprAgain(_) |
-            ast::ExprPath(_)  => {}
+            ast::ExprPath(_)  |
+            ast::ExprQPath(_) => {}
 
             ast::ExprCast(ref sub_exp, _)     |
             ast::ExprAddrOf(_, ref sub_exp)  |
diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs
index ac50445be2f..0e921d8e522 100644
--- a/src/librustc_trans/trans/expr.rs
+++ b/src/librustc_trans/trans/expr.rs
@@ -564,7 +564,7 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         ast::ExprParen(ref e) => {
             trans(bcx, &**e)
         }
-        ast::ExprPath(_) => {
+        ast::ExprPath(_) | ast::ExprQPath(_) => {
             trans_def(bcx, expr, bcx.def(expr.id))
         }
         ast::ExprField(ref base, ident) => {
@@ -997,7 +997,7 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         ast::ExprParen(ref e) => {
             trans_into(bcx, &**e, dest)
         }
-        ast::ExprPath(_) => {
+        ast::ExprPath(_) | ast::ExprQPath(_) => {
             trans_def_dps_unadjusted(bcx, expr, bcx.def(expr.id), dest)
         }
         ast::ExprIf(ref cond, ref thn, ref els) => {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 45e05c12713..27d31a3a2f7 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1001,9 +1001,12 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
 
     debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(this.tcx()));
 
+    // `<T as Trait>::U<V>` shouldn't parse right now.
+    assert!(qpath.item_path.parameters.is_empty());
+
     return this.projected_ty(ast_ty.span,
                              trait_ref,
-                             qpath.item_name.name);
+                             qpath.item_path.identifier.name);
 }
 
 // Parses the programmer's textual representation of a type into our
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 5c8c8b485d8..47346592c86 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -467,7 +467,7 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
     };
 
     instantiate_path(pcx.fcx, path, ty::lookup_item_type(tcx, enum_def_id),
-                     def, pat.span, pat.id);
+                     None, def, pat.span, pat.id);
 
     let pat_ty = fcx.node_ty(pat.id);
     demand::eqtype(fcx, pat.span, expected, pat_ty);
@@ -505,7 +505,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
     } else {
         ctor_scheme
     };
-    instantiate_path(pcx.fcx, path, path_scheme, def, pat.span, pat.id);
+    instantiate_path(pcx.fcx, path, path_scheme, None, def, pat.span, pat.id);
 
     let pat_ty = fcx.node_ty(pat.id);
     demand::eqtype(fcx, pat.span, expected, pat_ty);
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index d412ed39c72..e4c333a0e1e 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3553,10 +3553,25 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
         };
         fcx.write_ty(id, oprnd_t);
       }
-      ast::ExprPath(ref pth) => {
-          let defn = lookup_def(fcx, pth.span, id);
+      ast::ExprPath(ref path) => {
+          let defn = lookup_def(fcx, path.span, id);
           let pty = type_scheme_for_def(fcx, expr.span, defn);
-          instantiate_path(fcx, pth, pty, defn, expr.span, expr.id);
+          instantiate_path(fcx, path, pty, None, defn, expr.span, expr.id);
+
+          // We always require that the type provided as the value for
+          // a type parameter outlives the moment of instantiation.
+          constrain_path_type_parameters(fcx, expr);
+      }
+      ast::ExprQPath(ref qpath) => {
+          // Require explicit type params for the trait.
+          let self_ty = fcx.to_ty(&*qpath.self_type);
+          astconv::instantiate_trait_ref(fcx, fcx, &*qpath.trait_ref, Some(self_ty), None);
+
+          let defn = lookup_def(fcx, expr.span, id);
+          let pty = type_scheme_for_def(fcx, expr.span, defn);
+          let mut path = qpath.trait_ref.path.clone();
+          path.segments.push(qpath.item_path.clone());
+          instantiate_path(fcx, &path, pty, Some(self_ty), defn, expr.span, expr.id);
 
           // We always require that the type provided as the value for
           // a type parameter outlives the moment of instantiation.
@@ -4619,6 +4634,7 @@ pub fn type_scheme_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                   path: &ast::Path,
                                   type_scheme: TypeScheme<'tcx>,
+                                  opt_self_ty: Option<Ty<'tcx>>,
                                   def: def::Def,
                                   span: Span,
                                   node_id: ast::NodeId) {
@@ -4776,6 +4792,11 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             }
         }
     }
+    if let Some(self_ty) = opt_self_ty {
+        // `<T as Trait>::foo` shouldn't have resolved to a `Self`-less item.
+        assert_eq!(type_defs.len(subst::SelfSpace), 1);
+        substs.types.push(subst::SelfSpace, self_ty);
+    }
 
     // Now we have to compare the types that the user *actually*
     // provided against the types that were *expected*. If the user
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index b65e1d1d664..8dc3adad3b2 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1614,7 +1614,7 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
 impl Clean<Type> for ast::QPath {
     fn clean(&self, cx: &DocContext) -> Type {
         Type::QPath {
-            name: self.item_name.clean(cx),
+            name: self.item_path.identifier.clean(cx),
             self_type: box self.self_type.clean(cx),
             trait_: box self.trait_ref.clean(cx)
         }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index c2cfa484aff..61bc1865517 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -747,6 +747,8 @@ pub enum Expr_ {
     /// Variable reference, possibly containing `::` and/or
     /// type parameters, e.g. foo::bar::<baz>
     ExprPath(Path),
+    /// A "qualified path", e.g. `<Vec<T> as SomeTrait>::SomeType`
+    ExprQPath(P<QPath>),
 
     ExprAddrOf(Mutability, P<Expr>),
     ExprBreak(Option<Ident>),
@@ -771,12 +773,12 @@ pub enum Expr_ {
 ///
 ///     <Vec<T> as SomeTrait>::SomeAssociatedItem
 ///      ^~~~~     ^~~~~~~~~   ^~~~~~~~~~~~~~~~~~
-///      self_type  trait_name  item_name
+///      self_type  trait_name  item_path
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show)]
 pub struct QPath {
     pub self_type: P<Ty>,
     pub trait_ref: P<TraitRef>,
-    pub item_name: Ident, // FIXME(#20301) -- should use Name
+    pub item_path: PathSegment,
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show, Copy)]
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index c45a4005339..2a704349295 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -454,7 +454,10 @@ pub fn noop_fold_qpath<T: Folder>(qpath: P<QPath>, fld: &mut T) -> P<QPath> {
         QPath {
             self_type: fld.fold_ty(qpath.self_type),
             trait_ref: qpath.trait_ref.map(|tr| fld.fold_trait_ref(tr)),
-            item_name: fld.fold_ident(qpath.item_name),
+            item_path: PathSegment {
+                identifier: fld.fold_ident(qpath.item_path.identifier),
+                parameters: fld.fold_path_parameters(qpath.item_path.parameters),
+            }
         }
     })
 }
@@ -1381,6 +1384,7 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
                           e2.map(|x| folder.fold_expr(x)))
             }
             ExprPath(pth) => ExprPath(folder.fold_path(pth)),
+            ExprQPath(qpath) => ExprQPath(folder.fold_qpath(qpath)),
             ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|x| folder.fold_ident(x))),
             ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|x| folder.fold_ident(x))),
             ExprRet(e) => ExprRet(e.map(|x| folder.fold_expr(x))),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 33f9e35d8b7..543b7468499 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -25,7 +25,7 @@ use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox};
 use ast::{ExprBreak, ExprCall, ExprCast};
 use ast::{ExprField, ExprTupField, ExprClosure, ExprIf, ExprIfLet, ExprIndex};
 use ast::{ExprLit, ExprLoop, ExprMac, ExprRange};
-use ast::{ExprMethodCall, ExprParen, ExprPath};
+use ast::{ExprMethodCall, ExprParen, ExprPath, ExprQPath};
 use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary};
 use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl};
 use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind};
@@ -1573,7 +1573,10 @@ impl<'a> Parser<'a> {
             TyQPath(P(QPath {
                 self_type: self_type,
                 trait_ref: P(trait_ref),
-                item_name: item_name,
+                item_path: ast::PathSegment {
+                    identifier: item_name,
+                    parameters: ast::PathParameters::none()
+                }
             }))
         } else if self.check(&token::ModSep) ||
                   self.token.is_ident() ||
@@ -1894,11 +1897,7 @@ impl<'a> Parser<'a> {
             if !self.eat(&token::ModSep) {
                 segments.push(ast::PathSegment {
                     identifier: identifier,
-                    parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
-                        lifetimes: Vec::new(),
-                        types: OwnedSlice::empty(),
-                        bindings: OwnedSlice::empty(),
-                    })
+                    parameters: ast::PathParameters::none()
                 });
                 return segments;
             }
@@ -2253,6 +2252,37 @@ impl<'a> Parser<'a> {
                 hi = self.last_span.hi;
             }
             _ => {
+                if self.eat_lt() {
+                    // QUALIFIED PATH `<TYPE as TRAIT_REF>::item::<'a, T>`
+                    let self_type = self.parse_ty_sum();
+                    self.expect_keyword(keywords::As);
+                    let trait_ref = self.parse_trait_ref();
+                    self.expect(&token::Gt);
+                    self.expect(&token::ModSep);
+                    let item_name = self.parse_ident();
+                    let parameters = if self.eat(&token::ModSep) {
+                        self.expect_lt();
+                        // Consumed `item::<`, go look for types
+                        let (lifetimes, types, bindings) =
+                            self.parse_generic_values_after_lt();
+                        ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
+                            lifetimes: lifetimes,
+                            types: OwnedSlice::from_vec(types),
+                            bindings: OwnedSlice::from_vec(bindings),
+                        })
+                    } else {
+                        ast::PathParameters::none()
+                    };
+                    let hi = self.span.hi;
+                    return self.mk_expr(lo, hi, ExprQPath(P(QPath {
+                        self_type: self_type,
+                        trait_ref: P(trait_ref),
+                        item_path: ast::PathSegment {
+                            identifier: item_name,
+                            parameters: parameters
+                        }
+                    })));
+                }
                 if self.eat_keyword(keywords::Move) {
                     return self.parse_lambda_expr(CaptureByValue);
                 }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 9b6f8e6002d..ec6672d22a9 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -727,14 +727,7 @@ impl<'a> State<'a> {
                 try!(self.print_bounds("", &bounds[]));
             }
             ast::TyQPath(ref qpath) => {
-                try!(word(&mut self.s, "<"));
-                try!(self.print_type(&*qpath.self_type));
-                try!(space(&mut self.s));
-                try!(self.word_space("as"));
-                try!(self.print_trait_ref(&*qpath.trait_ref));
-                try!(word(&mut self.s, ">"));
-                try!(word(&mut self.s, "::"));
-                try!(self.print_ident(qpath.item_name));
+                try!(self.print_qpath(&**qpath, false))
             }
             ast::TyFixedLengthVec(ref ty, ref v) => {
                 try!(word(&mut self.s, "["));
@@ -1749,6 +1742,7 @@ impl<'a> State<'a> {
                 }
             }
             ast::ExprPath(ref path) => try!(self.print_path(path, true)),
+            ast::ExprQPath(ref qpath) => try!(self.print_qpath(&**qpath, true)),
             ast::ExprBreak(opt_ident) => {
                 try!(word(&mut self.s, "break"));
                 try!(space(&mut self.s));
@@ -1933,6 +1927,22 @@ impl<'a> State<'a> {
         Ok(())
     }
 
+    fn print_qpath(&mut self,
+                   qpath: &ast::QPath,
+                   colons_before_params: bool)
+                   -> IoResult<()>
+    {
+        try!(word(&mut self.s, "<"));
+        try!(self.print_type(&*qpath.self_type));
+        try!(space(&mut self.s));
+        try!(self.word_space("as"));
+        try!(self.print_trait_ref(&*qpath.trait_ref));
+        try!(word(&mut self.s, ">"));
+        try!(word(&mut self.s, "::"));
+        try!(self.print_ident(qpath.item_path.identifier));
+        self.print_path_parameters(&qpath.item_path.parameters, colons_before_params)
+    }
+
     fn print_path_parameters(&mut self,
                              parameters: &ast::PathParameters,
                              colons_before_params: bool)
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 3f91304dcc5..7778b4fa34a 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -126,6 +126,9 @@ pub trait Visitor<'v> : Sized {
     fn visit_path(&mut self, path: &'v Path, _id: ast::NodeId) {
         walk_path(self, path)
     }
+    fn visit_qpath(&mut self, qpath_span: Span, qpath: &'v QPath) {
+        walk_qpath(self, qpath_span, qpath)
+    }
     fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment) {
         walk_path_segment(self, path_span, path_segment)
     }
@@ -419,9 +422,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
             walk_ty_param_bounds_helper(visitor, bounds);
         }
         TyQPath(ref qpath) => {
-            visitor.visit_ty(&*qpath.self_type);
-            visitor.visit_trait_ref(&*qpath.trait_ref);
-            visitor.visit_ident(typ.span, qpath.item_name);
+            visitor.visit_qpath(typ.span, &**qpath);
         }
         TyFixedLengthVec(ref ty, ref expression) => {
             visitor.visit_ty(&**ty);
@@ -450,6 +451,14 @@ pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) {
     }
 }
 
+pub fn walk_qpath<'v, V: Visitor<'v>>(visitor: &mut V,
+                                      qpath_span: Span,
+                                      qpath: &'v QPath) {
+    visitor.visit_ty(&*qpath.self_type);
+    visitor.visit_trait_ref(&*qpath.trait_ref);
+    visitor.visit_path_segment(qpath_span, &qpath.item_path);
+}
+
 pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V,
                                              path_span: Span,
                                              segment: &'v PathSegment) {
@@ -881,6 +890,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
         ExprPath(ref path) => {
             visitor.visit_path(path, expression.id)
         }
+        ExprQPath(ref qpath) => {
+            visitor.visit_qpath(expression.span, &**qpath)
+        }
         ExprBreak(_) | ExprAgain(_) => {}
         ExprRet(ref optional_expression) => {
             walk_expr_opt(visitor, optional_expression)
diff --git a/src/test/compile-fail/ufcs-qpath-missing-params.rs b/src/test/compile-fail/ufcs-qpath-missing-params.rs
new file mode 100644
index 00000000000..5fa66eb98e1
--- /dev/null
+++ b/src/test/compile-fail/ufcs-qpath-missing-params.rs
@@ -0,0 +1,17 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::borrow::IntoCow;
+
+fn main() {
+    <String as IntoCow>::into_cow("foo".to_string());
+    //~^ ERROR wrong number of type arguments: expected 2, found 0
+}
+
diff --git a/src/test/compile-fail/ufcs-qpath-self-mismatch.rs b/src/test/compile-fail/ufcs-qpath-self-mismatch.rs
new file mode 100644
index 00000000000..868c1eae4a9
--- /dev/null
+++ b/src/test/compile-fail/ufcs-qpath-self-mismatch.rs
@@ -0,0 +1,21 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::ops::Add;
+
+fn main() {
+    <i32 as Add<u32>>::add(1, 2);
+    //~^ ERROR the trait `core::ops::Add<u32>` is not implemented for the type `i32`
+    <i32 as Add<i32>>::add(1u32, 2);
+    //~^ ERROR mismatched types
+    <i32 as Add<i32>>::add(1, 2u32);
+    //~^ ERROR mismatched types
+}
+
diff --git a/src/test/run-pass/const-polymorphic-paths.rs b/src/test/run-pass/const-polymorphic-paths.rs
index 28b346c9ed4..f8f92a56adb 100644
--- a/src/test/run-pass/const-polymorphic-paths.rs
+++ b/src/test/run-pass/const-polymorphic-paths.rs
@@ -10,9 +10,11 @@
 
 #![feature(macro_rules)]
 
+use std::borrow::{Cow, IntoCow};
 use std::collections::Bitv;
 use std::default::Default;
 use std::iter::FromIterator;
+use std::ops::Add;
 use std::option::IntoIter as OptionIter;
 use std::rand::Rand;
 use std::rand::XorShiftRng as DummyRng;
@@ -28,6 +30,11 @@ fn u8_as_i8(x: u8) -> i8 { x as i8 }
 fn odd(x: uint) -> bool { x % 2 == 1 }
 fn dummy_rng() -> DummyRng { DummyRng::new_unseeded() }
 
+trait Size: Sized {
+    fn size() -> uint { std::mem::size_of::<Self>() }
+}
+impl<T> Size for T {}
+
 macro_rules! tests {
     ($($expr:expr, $ty:ty, ($($test:expr),*);)+) => (pub fn main() {$({
         const C: $ty = $expr;
@@ -70,14 +77,31 @@ tests! {
     //    , (vec![b'f', b'o', b'o'], u8_as_i8);
 
     // Trait static methods.
-    // FIXME qualified path expressions aka UFCS i.e. <T as Trait>::method.
+    <bool as Size>::size, fn() -> uint, ();
     Default::default, fn() -> int, ();
+    <int as Default>::default, fn() -> int, ();
     Rand::rand, fn(&mut DummyRng) -> int, (&mut dummy_rng());
+    <int as Rand>::rand, fn(&mut DummyRng) -> int, (&mut dummy_rng());
     Rand::rand::<DummyRng>, fn(&mut DummyRng) -> int, (&mut dummy_rng());
+    <int as Rand>::rand::<DummyRng>, fn(&mut DummyRng) -> int, (&mut dummy_rng());
 
     // Trait non-static methods.
     Clone::clone, fn(&int) -> int, (&5);
+    <int as Clone>::clone, fn(&int) -> int, (&5);
     FromIterator::from_iter, fn(OptionIter<int>) -> Vec<int>, (Some(5).into_iter());
-    FromIterator::from_iter::<OptionIter<int>>, fn(OptionIter<int>) -> Vec<int>
-       , (Some(5).into_iter());
+    <Vec<_> as FromIterator<_>>::from_iter, fn(OptionIter<int>) -> Vec<int>,
+        (Some(5).into_iter());
+    <Vec<int> as FromIterator<_>>::from_iter, fn(OptionIter<int>) -> Vec<int>,
+        (Some(5).into_iter());
+    FromIterator::from_iter::<OptionIter<int>>, fn(OptionIter<int>) -> Vec<int>,
+        (Some(5).into_iter());
+    <Vec<int> as FromIterator<_>>::from_iter::<OptionIter<int>>, fn(OptionIter<int>) -> Vec<int>,
+        (Some(5).into_iter());
+    Add::add, fn(i32, i32) -> i32, (5, 6);
+    <i32 as Add<_>>::add, fn(i32, i32) -> i32, (5, 6);
+    <i32 as Add<i32>>::add, fn(i32, i32) -> i32, (5, 6);
+    <String as IntoCow<_, _>>::into_cow, fn(String) -> Cow<'static, String, str>,
+        ("foo".to_string());
+    <String as IntoCow<'static, _, _>>::into_cow, fn(String) -> Cow<'static, String, str>,
+        ("foo".to_string());
 }