From 2cdc86c180296ff2c929ec55fcf33a0f6b391b3a Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 13 Jan 2015 06:02:56 +0200 Subject: [PATCH 1/3] syntax: add fully qualified UFCS expressions. --- src/librustc/lint/builtin.rs | 2 +- src/librustc/middle/cfg/construct.rs | 3 ++- src/librustc/middle/check_const.rs | 2 +- src/librustc/middle/check_static.rs | 2 +- src/librustc/middle/check_static_recursion.rs | 2 +- src/librustc/middle/const_eval.rs | 11 ++++++-- src/librustc/middle/effect.rs | 2 +- src/librustc/middle/expr_use_visitor.rs | 2 +- src/librustc/middle/liveness.rs | 14 +++++----- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/middle/privacy.rs | 2 +- src/librustc/middle/reachable.rs | 2 +- src/librustc/middle/ty.rs | 2 +- src/librustc_back/svh.rs | 2 ++ src/librustc_trans/trans/_match.rs | 2 +- src/librustc_trans/trans/callee.rs | 7 +++-- src/librustc_trans/trans/consts.rs | 2 +- src/librustc_trans/trans/debuginfo.rs | 3 ++- src/librustc_trans/trans/expr.rs | 4 +-- src/librustc_typeck/astconv.rs | 5 +++- src/librustdoc/clean/mod.rs | 2 +- src/libsyntax/ast.rs | 6 +++-- src/libsyntax/fold.rs | 6 ++++- src/libsyntax/print/pprust.rs | 26 +++++++++++++------ src/libsyntax/visit.rs | 18 ++++++++++--- 25 files changed, 89 insertions(+), 42 deletions(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index d95000ece5ae6..59808b302f47d 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 b601ea59486ce..07b520e5865b2 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::.iter()) } } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 621d7274b3f7c..202020a9033ed 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 154272d2deb41..026aa3c5ccf83 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 e2a0738def180..86a58dae45aa4 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 52352e920ce36..c998d178c2245 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::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 (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 f7eea6e5cb7c9..abb8f35f662b5 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 e5eb439d42c75..a5f2dc398e9e2 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 1b1dca004228e..6b9e5b2ceea3a 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 51ec75284326c..90fe6b4991138 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 aa37c2fe348b5..b92870cfa42b0 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 906607ddc5ba1..b7e6da8c5f63a 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 755983c71bba8..525fe86cf24e6 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 4e260da2e4ded..789a87bbcdafc 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_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index f182045efd23b..b01604bd39753 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 6196f9e5eab65..11006f37531d2 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 00b97286de367..29cf9f72ef8e8 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 5bbd83344bfba..d5416ae0631fc 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 ac50445be2f9b..0e921d8e52283 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 45e05c12713bf..27d31a3a2f728 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())); + // `::U` 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/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b65e1d1d664b4..8dc3adad3b27a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1614,7 +1614,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { impl Clean 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 c2cfa484aff3f..61bc1865517f6 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:: ExprPath(Path), + /// A "qualified path", e.g. ` as SomeTrait>::SomeType` + ExprQPath(P), ExprAddrOf(Mutability, P), ExprBreak(Option), @@ -771,12 +773,12 @@ pub enum Expr_ { /// /// 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, pub trait_ref: P, - 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 c45a4005339ba..2a7043492959f 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -454,7 +454,10 @@ pub fn noop_fold_qpath(qpath: P, fld: &mut T) -> P { 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(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/print/pprust.rs b/src/libsyntax/print/pprust.rs index 9b6f8e6002d8a..ec6672d22a97a 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 3f91304dcc5f2..7778b4fa34aa1 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) From b51026e09cd749393eddec31179a8f940b4e595c Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 13 Jan 2015 06:03:12 +0200 Subject: [PATCH 2/3] syntax: parse fully qualified UFCS expressions. --- src/libsyntax/parse/parser.rs | 44 +++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 33f9e35d8b7af..543b746849955 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 `::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); } From 85ba8178e2e995c0da6eb9268612baca8a6ba2e3 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 15 Jan 2015 09:46:12 +0200 Subject: [PATCH 3/3] rustc: implement fully qualified UFCS expressions. --- src/librustc_resolve/lib.rs | 53 ++++++++++--------- src/librustc_trans/save/mod.rs | 16 ++++-- src/librustc_typeck/check/_match.rs | 4 +- src/librustc_typeck/check/mod.rs | 27 ++++++++-- .../compile-fail/ufcs-qpath-missing-params.rs | 17 ++++++ .../compile-fail/ufcs-qpath-self-mismatch.rs | 21 ++++++++ src/test/run-pass/const-polymorphic-paths.rs | 30 +++++++++-- 7 files changed, 130 insertions(+), 38 deletions(-) create mode 100644 src/test/compile-fail/ufcs-qpath-missing-params.rs create mode 100644 src/test/compile-fail/ufcs-qpath-self-mismatch.rs diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index ae55f8fb3aa61..7743a437858d2 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 815a6fe846da6..f2a67029170b7 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) { - 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_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 5c8c8b485d87d..47346592c86bb 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 d412ed39c7271..e4c333a0e1ea5 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>, 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 { + // `::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/test/compile-fail/ufcs-qpath-missing-params.rs b/src/test/compile-fail/ufcs-qpath-missing-params.rs new file mode 100644 index 0000000000000..5fa66eb98e1af --- /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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::borrow::IntoCow; + +fn main() { + ::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 0000000000000..868c1eae4a9e1 --- /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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::Add; + +fn main() { + >::add(1, 2); + //~^ ERROR the trait `core::ops::Add` is not implemented for the type `i32` + >::add(1u32, 2); + //~^ ERROR mismatched types + >::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 28b346c9ed4d0..f8f92a56adb1a 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::() } +} +impl 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. ::method. + ::size, fn() -> uint, (); Default::default, fn() -> int, (); + ::default, fn() -> int, (); Rand::rand, fn(&mut DummyRng) -> int, (&mut dummy_rng()); + ::rand, fn(&mut DummyRng) -> int, (&mut dummy_rng()); Rand::rand::, fn(&mut DummyRng) -> int, (&mut dummy_rng()); + ::rand::, fn(&mut DummyRng) -> int, (&mut dummy_rng()); // Trait non-static methods. Clone::clone, fn(&int) -> int, (&5); + ::clone, fn(&int) -> int, (&5); FromIterator::from_iter, fn(OptionIter) -> Vec, (Some(5).into_iter()); - FromIterator::from_iter::>, fn(OptionIter) -> Vec - , (Some(5).into_iter()); + as FromIterator<_>>::from_iter, fn(OptionIter) -> Vec, + (Some(5).into_iter()); + as FromIterator<_>>::from_iter, fn(OptionIter) -> Vec, + (Some(5).into_iter()); + FromIterator::from_iter::>, fn(OptionIter) -> Vec, + (Some(5).into_iter()); + as FromIterator<_>>::from_iter::>, fn(OptionIter) -> Vec, + (Some(5).into_iter()); + Add::add, fn(i32, i32) -> i32, (5, 6); + >::add, fn(i32, i32) -> i32, (5, 6); + >::add, fn(i32, i32) -> i32, (5, 6); + >::into_cow, fn(String) -> Cow<'static, String, str>, + ("foo".to_string()); + >::into_cow, fn(String) -> Cow<'static, String, str>, + ("foo".to_string()); }