From d31b9ebef5c39de3fff9da02eea880d1838a8a3b Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 17 Feb 2015 19:29:13 +0200 Subject: [PATCH] Implement `::method` UFCS expression syntax. --- src/librustc/lint/builtin.rs | 6 +- src/librustc/metadata/encoder.rs | 2 +- src/librustc/middle/astconv_util.rs | 2 +- src/librustc/middle/cfg/construct.rs | 3 +- src/librustc/middle/check_const.rs | 2 +- src/librustc/middle/check_static_recursion.rs | 4 +- src/librustc/middle/const_eval.rs | 11 +-- src/librustc/middle/effect.rs | 2 +- src/librustc/middle/expr_use_visitor.rs | 2 +- src/librustc/middle/infer/error_reporting.rs | 11 ++- src/librustc/middle/liveness.rs | 12 ++-- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/middle/reachable.rs | 2 +- src/librustc/middle/resolve_lifetime.rs | 2 +- src/librustc/middle/ty.rs | 4 +- src/librustc_back/svh.rs | 6 +- src/librustc_privacy/lib.rs | 12 ++-- src/librustc_resolve/lib.rs | 46 +++++++----- src/librustc_trans/save/mod.rs | 6 +- src/librustc_trans/trans/_match.rs | 2 +- src/librustc_trans/trans/callee.rs | 2 +- src/librustc_trans/trans/consts.rs | 4 +- src/librustc_trans/trans/debuginfo.rs | 3 +- src/librustc_trans/trans/expr.rs | 6 +- src/librustc_typeck/astconv.rs | 39 ++++++++--- src/librustc_typeck/check/mod.rs | 22 +++--- src/librustc_typeck/collect.rs | 19 ++--- src/librustdoc/clean/mod.rs | 10 +-- src/libsyntax/ast.rs | 37 +++++----- src/libsyntax/ast_util.rs | 2 +- src/libsyntax/ext/build.rs | 26 +++---- src/libsyntax/ext/concat_idents.rs | 2 +- src/libsyntax/ext/expand.rs | 11 ++- src/libsyntax/feature_gate.rs | 2 +- src/libsyntax/fold.rs | 28 +++++--- src/libsyntax/parse/mod.rs | 12 ++-- src/libsyntax/parse/parser.rs | 70 ++++++++++++++----- src/libsyntax/print/pprust.rs | 23 +++--- src/libsyntax/visit.rs | 18 +++-- src/test/run-pass/ufcs-polymorphic-paths.rs | 11 +++ 40 files changed, 286 insertions(+), 200 deletions(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 28baeb5dc9e62..3c0d9e93ccb93 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -437,7 +437,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { impl<'a, 'tcx, 'v> Visitor<'v> for ImproperCTypesVisitor<'a, 'tcx> { fn visit_ty(&mut self, ty: &ast::Ty) { - if let ast::TyPath(_) = ty.node { + if let ast::TyPath(..) = ty.node { self.check_def(ty.span, ty.id); } visit::walk_ty(self, ty); @@ -682,8 +682,8 @@ impl LintPass for PathStatements { match s.node { ast::StmtSemi(ref expr, _) => { match expr.node { - ast::ExprPath(_) => cx.span_lint(PATH_STATEMENTS, s.span, - "path statement with no effect"), + ast::ExprPath(..) => cx.span_lint(PATH_STATEMENTS, s.span, + "path statement with no effect"), _ => () } } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 4aea73cfb0ec0..a01b17ac194de 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -1221,7 +1221,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_unsafety(rbml_w, unsafety); encode_polarity(rbml_w, polarity); match ty.node { - ast::TyPath(ref path) if path.segments.len() == 1 => { + ast::TyPath(None, ref path) if path.segments.len() == 1 => { let ident = path.segments.last().unwrap().identifier; encode_impl_type_basename(rbml_w, ident); } diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs index c9196f0cb2a64..17fd80ceaea42 100644 --- a/src/librustc/middle/astconv_util.rs +++ b/src/librustc/middle/astconv_util.rs @@ -59,7 +59,7 @@ pub fn prim_ty_to_ty<'tcx>(tcx: &ty::ctxt<'tcx>, pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty) -> Option> { - if let ast::TyPath(ref path) = ast_ty.node { + if let ast::TyPath(None, ref path) = ast_ty.node { let def = match tcx.def_map.borrow().get(&ast_ty.id) { None => { tcx.sess.span_bug(ast_ty.span, diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index ca9455ac421f2..24c54b53590c0 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -398,8 +398,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { ast::ExprMac(..) | ast::ExprClosure(..) | ast::ExprLit(..) | - ast::ExprPath(..) | - ast::ExprQPath(..) => { + ast::ExprPath(..) => { self.straightline(expr, pred, None::.iter()) } } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 57e4d3d2f0203..8401d25024d35 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -439,7 +439,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, } } } - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { let def = v.tcx.def_map.borrow().get(&e.id).map(|d| d.full_def()); match def { Some(def::DefVariant(_, _, _)) => { diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs index a4393f4648b1e..b97978fc03fff 100644 --- a/src/librustc/middle/check_static_recursion.rs +++ b/src/librustc/middle/check_static_recursion.rs @@ -93,8 +93,8 @@ impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> { fn visit_expr(&mut self, e: &ast::Expr) { match e.node { - ast::ExprPath(_) | ast::ExprQPath(_) => { - match self.def_map.borrow().get(&e.id).map(|d| d.full_def()) { + ast::ExprPath(..) => { + match self.def_map.borrow().get(&e.id).map(|d| d.base_def) { Some(DefStatic(def_id, _)) | Some(DefConst(def_id)) if ast_util::is_local(def_id) => { diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index d3c6a585fa3fd..f793d3ce2fb45 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -178,7 +178,7 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P ast::PatVec(pats, None, vec![]) } - ast::ExprPath(ref path) => { + ast::ExprPath(_, ref path) => { let opt_def = tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()); match opt_def { Some(def::DefStruct(..)) => @@ -194,13 +194,6 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P } } - ast::ExprQPath(_) => { - match lookup_const(tcx, expr) { - Some(actual) => return const_expr_to_pat(tcx, actual, span), - _ => unreachable!() - } - } - _ => ast::PatLit(P(expr.clone())) }; P(ast::Pat { id: expr.id, node: pat, span: span }) @@ -388,7 +381,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, let val = try!(eval_const_expr_partial(tcx, &**base, Some(base_hint))); cast_const(val, ety) } - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { let opt_def = tcx.def_map.borrow().get(&e.id).map(|d| d.full_def()); let (const_expr, const_ty) = match opt_def { Some(def::DefConst(def_id)) => { diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index ba81b2f3899a8..9c85b7748ab0c 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::ExprQPath(_) => { + ast::ExprPath(..) => { 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 f7c723c68746f..a1e38a1c8bda7 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -422,7 +422,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { self.walk_expr(&**subexpr) } - ast::ExprPath(_) | ast::ExprQPath(_) => { } + ast::ExprPath(..) => { } ast::ExprUnary(ast::UnDeref, ref base) => { // *base if !self.walk_overloaded_operator(expr, &**base, Vec::new(), PassArgs::ByRef) { diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 60b7e1169b49b..da4df813030c3 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -1233,7 +1233,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { } ty_queue.push(&*mut_ty.ty); } - ast::TyPath(ref path) => { + ast::TyPath(ref maybe_qself, ref path) => { let a_def = match self.tcx.def_map.borrow().get(&cur_ty.id) { None => { self.tcx @@ -1277,9 +1277,16 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { region_names: region_names }; let new_path = self.rebuild_path(rebuild_info, lifetime); + let qself = maybe_qself.as_ref().map(|qself| { + ast::QSelf { + ty: self.rebuild_arg_ty_or_output(&qself.ty, lifetime, + anon_nums, region_names), + position: qself.position + } + }); let to = ast::Ty { id: cur_ty.id, - node: ast::TyPath(new_path), + node: ast::TyPath(qself, new_path), span: cur_ty.span }; new_ty = self.rebuild_ty(new_ty, P(to)); diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 4685a05f41604..2ac019aa964dc 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -445,7 +445,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::ExprQPath(_) => { + ast::ExprPath(..) => { let def = ir.tcx.def_map.borrow()[expr.id].full_def(); debug!("expr {}: path that leads to {:?}", expr.id, def); if let DefLocal(..) = def { @@ -947,7 +947,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { match expr.node { // Interesting cases with control flow or which gen/kill - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { self.access_path(expr, succ, ACC_READ | ACC_USE) } @@ -1275,7 +1275,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // just ignore such cases and treat them as reads. match expr.node { - ast::ExprPath(_) | ast::ExprQPath(_) => succ, + ast::ExprPath(..) => 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) @@ -1286,7 +1286,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn write_lvalue(&mut self, expr: &Expr, succ: LiveNode, acc: uint) -> LiveNode { match expr.node { - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { self.access_path(expr, succ, acc) } @@ -1468,7 +1468,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::ExprQPath(..) => { + ast::ExprRange(..) => { visit::walk_expr(this, expr); } ast::ExprIfLet(..) => { @@ -1561,7 +1561,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn check_lvalue(&mut self, expr: &Expr) { match expr.node { - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { if let DefLocal(nid) = self.ir.tcx.def_map.borrow()[expr.id].full_def() { // 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 44ab3cf60aaa3..c4446b87855ca 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -529,7 +529,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { } } - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { let def = self.tcx().def_map.borrow()[expr.id].full_def(); self.cat_def(expr.id, expr.span, expr_ty, def) } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index a140c766758e3..45d565ec69380 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -94,7 +94,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::ExprQPath(_) => { + ast::ExprPath(..) => { let def = match self.tcx.def_map.borrow().get(&expr.id) { Some(d) => d.full_def(), None => { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 9bcda68eb3ad7..a8a2887644a9d 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -165,7 +165,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { visit::walk_ty(this, ty); }); } - ast::TyPath(ref path) => { + ast::TyPath(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.borrow().get(&ty.id).map(|d| (d.base_def, d.depth)) { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 7cd047279028c..7b05e51085279 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4550,7 +4550,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { } match expr.node { - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { match resolve_expr(tcx, expr) { def::DefVariant(tid, vid, _) => { let variant_info = enum_variant_with_id(tcx, tid, vid); @@ -5838,7 +5838,7 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> uint { } Err(_) => { let found = match count_expr.node { - ast::ExprPath(ast::Path { + ast::ExprPath(None, ast::Path { global: false, ref segments, .. diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index 2fc43ab26b58e..e16df61c25c47 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -244,8 +244,7 @@ mod svh_visitor { SawExprAssignOp(ast::BinOp_), SawExprIndex, SawExprRange, - SawExprPath, - SawExprQPath, + SawExprPath(Option), SawExprAddrOf(ast::Mutability), SawExprRet, SawExprInlineAsm(&'a ast::InlineAsm), @@ -277,8 +276,7 @@ mod svh_visitor { ExprTupField(_, id) => SawExprTupField(id.node), ExprIndex(..) => SawExprIndex, ExprRange(..) => SawExprRange, - ExprPath(..) => SawExprPath, - ExprQPath(..) => SawExprQPath, + ExprPath(ref qself, _) => SawExprPath(qself.as_ref().map(|q| q.position)), ExprAddrOf(m, _) => SawExprAddrOf(m), ExprBreak(id) => SawExprBreak(id.map(content)), ExprAgain(id) => SawExprAgain(id.map(content)), diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index f325a6abede51..29448c68c80b9 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -258,7 +258,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { // * Private trait impls for private types can be completely ignored ast::ItemImpl(_, _, _, _, ref ty, ref impl_items) => { let public_ty = match ty.node { - ast::TyPath(_) => { + ast::TyPath(..) => { match self.tcx.def_map.borrow()[ty.id].full_def() { def::DefPrimTy(..) => true, def => { @@ -325,7 +325,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { } ast::ItemTy(ref ty, _) if public_first => { - if let ast::TyPath(_) = ty.node { + if let ast::TyPath(..) = ty.node { match self.tcx.def_map.borrow()[ty.id].full_def() { def::DefPrimTy(..) | def::DefTyParam(..) => {}, def => { @@ -627,7 +627,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // was private. ast::ItemImpl(_, _, _, _, ref ty, _) => { match ty.node { - ast::TyPath(_) => {} + ast::TyPath(..) => {} _ => return Some((err_span, err_msg, None)), }; let def = self.tcx.def_map.borrow()[ty.id].full_def(); @@ -908,7 +908,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { struct type?!"), } } - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { let guard = |did: ast::DefId| { let fields = ty::lookup_struct_fields(self.tcx, did); let any_priv = fields.iter().any(|f| { @@ -1254,7 +1254,7 @@ impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> { impl<'a, 'b, 'tcx, 'v> Visitor<'v> for CheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> { fn visit_ty(&mut self, ty: &ast::Ty) { - if let ast::TyPath(_) = ty.node { + if let ast::TyPath(..) = ty.node { if self.inner.path_is_private_type(ty.id) { self.contains_private = true; // found what we're looking for so let's stop @@ -1460,7 +1460,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { } fn visit_ty(&mut self, t: &ast::Ty) { - if let ast::TyPath(ref p) = t.node { + if let ast::TyPath(_, ref p) = t.node { if !self.tcx.sess.features.borrow().visible_private_types && self.path_is_private_type(t.id) { self.tcx.sess.span_err(p.span, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 265f398d25ca5..cb7224f7cbfe8 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -65,7 +65,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::{ExprLoop, ExprWhile, ExprMethodCall}; -use syntax::ast::{ExprPath, ExprQPath, ExprStruct, FnDecl}; +use syntax::ast::{ExprPath, ExprStruct, FnDecl}; use syntax::ast::{ForeignItemFn, ForeignItemStatic, Generics}; use syntax::ast::{Ident, ImplItem, Item, ItemConst, ItemEnum, ItemExternCrate}; use syntax::ast::{ItemFn, ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic, ItemDefaultImpl}; @@ -75,7 +75,7 @@ use syntax::ast::{Pat, PatEnum, PatIdent, PatLit}; use syntax::ast::{PatRange, PatStruct, Path, PrimTy}; use syntax::ast::{TraitRef, Ty, TyBool, TyChar, TyF32}; use syntax::ast::{TyF64, TyFloat, TyIs, TyI8, TyI16, TyI32, TyI64, TyInt}; -use syntax::ast::{TyPath, TyPtr, TyQPath}; +use syntax::ast::{TyPath, TyPtr}; use syntax::ast::{TyRptr, TyStr, TyUs, TyU8, TyU16, TyU32, TyU64, TyUint}; use syntax::ast::{TypeImplItem}; use syntax::ast; @@ -2821,7 +2821,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { FnSpace, MethodRibKind) } - ast::TypeTraitItem(_) => NoTypeParameters, + ast::TypeTraitItem(ref assoc_ty) => { + let ty_param = &assoc_ty.ty_param; + this.check_if_primitive_type_name(ty_param.ident.name, + ty_param.span); + NoTypeParameters + } }; this.with_type_parameter_rib(type_parameters, |this| { visit::walk_trait_item(this, trait_item) @@ -3243,14 +3248,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn resolve_type(&mut self, ty: &Ty) { match ty.node { - // Like path expressions, the interpretation of path types depends - // on whether the path has multiple elements in it or not. + // `::a::b::c` is resolved by typeck alone. + TyPath(Some(ast::QSelf { position: 0, .. }), _) => {} - TyPath(ref path) | TyQPath(ast::QPath { ref path, .. }) => { - let max_assoc_types = if let TyQPath(_) = ty.node { + TyPath(ref maybe_qself, ref path) => { + let max_assoc_types = if let Some(ref qself) = *maybe_qself { // Make sure the trait is valid. let _ = self.resolve_trait_reference(ty.id, path, 1); - 1 + path.segments.len() - qself.position } else { path.segments.len() }; @@ -3284,10 +3289,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Keep reporting some errors even if they're ignored above. self.resolve_path(ty.id, path, 0, TypeNS, true); - let kind = match ty.node { - TyQPath(_) => "associated type", - _ => "type name" + let kind = if maybe_qself.is_some() { + "associated type" + } else { + "type name" }; + let msg = format!("use of undeclared {} `{}`", kind, self.path_names_to_string(path, 0)); self.resolve_error(ty.span, &msg[..]); @@ -3905,7 +3912,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn extract_path_and_node_id(t: &Ty, allow: FallbackChecks) -> Option<(Path, NodeId, FallbackChecks)> { match t.node { - TyPath(ref path) => Some((path.clone(), t.id, allow)), + TyPath(None, ref path) => Some((path.clone(), t.id, allow)), TyPtr(ref mut_ty) => extract_path_and_node_id(&*mut_ty.ty, OnlyTraitAndStatics), TyRptr(_, ref mut_ty) => extract_path_and_node_id(&*mut_ty.ty, allow), // This doesn't handle the remaining `Ty` variants as they are not @@ -4063,14 +4070,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Next, resolve the node. match expr.node { - // The interpretation of paths depends on whether the path has - // multiple elements in it or not. + // `::a::b::c` is resolved by typeck alone. + ExprPath(Some(ast::QSelf { position: 0, .. }), ref path) => { + let method_name = path.segments.last().unwrap().identifier.name; + let traits = self.search_for_traits_containing_method(method_name); + self.trait_map.insert(expr.id, traits); + visit::walk_expr(self, expr); + } - ExprPath(ref path) | ExprQPath(ast::QPath { ref path, .. }) => { - let max_assoc_types = if let ExprQPath(_) = expr.node { + ExprPath(ref maybe_qself, ref path) => { + let max_assoc_types = if let Some(ref qself) = *maybe_qself { // Make sure the trait is valid. let _ = self.resolve_trait_reference(expr.id, path, 1); - 1 + path.segments.len() - qself.position } else { path.segments.len() }; diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index ea346798679c0..ab7f3916728c5 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -659,7 +659,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { let trait_id = trait_ref.as_ref().and_then(|tr| self.lookup_type_ref(tr.ref_id)); match typ.node { // Common case impl for a struct or something basic. - ast::TyPath(ref path) => { + ast::TyPath(None, ref path) => { let sub_span = self.span.sub_span_for_type_name(path.span); let self_id = self.lookup_type_ref(typ.id).map(|id| { self.fmt.ref_str(recorder::TypeRef, @@ -1306,7 +1306,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { } match t.node { - ast::TyPath(ref path) => { + ast::TyPath(_, ref path) => { match self.lookup_type_ref(t.id) { Some(id) => { let sub_span = self.span.sub_span_for_type_name(t.span); @@ -1338,7 +1338,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { // because just walking the callee path does what we want. visit::walk_expr(self, ex); } - ast::ExprPath(ref path) | ast::ExprQPath(ast::QPath { ref path, .. }) => { + ast::ExprPath(_, ref path) => { self.process_path(ex.id, path.span, path, None); visit::walk_expr(self, ex); } diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 3e741640117aa..9a121a8830b2b 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -1277,7 +1277,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(_) | ast::ExprQPath(_) => match bcx.def(discr.id) { + ast::ExprPath(..) => 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 41e3d4b5bab25..59fcd5492ebde 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -93,7 +93,7 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) // pick out special kinds of expressions that can be called: match expr.node { - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { return trans_def(bcx, bcx.def(expr.id), expr); } _ => {} diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 6e1d2da02c101..93ab4a96e6f56 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -193,7 +193,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, -> ValueRef { // Special-case constants to cache a common global for all uses. match expr.node { - ast::ExprPath(_) => { + ast::ExprPath(..) => { let def = ccx.tcx().def_map.borrow()[expr.id].full_def(); match def { def::DefConst(def_id) => { @@ -663,7 +663,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, C_array(llunitty, &vs[..]) } } - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { let def = cx.tcx().def_map.borrow()[e.id].full_def(); match def { def::DefFn(..) | def::DefMethod(..) => { diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 162881f58c74e..d70a904b81189 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -3487,8 +3487,7 @@ fn create_scope_map(cx: &CrateContext, ast::ExprLit(_) | ast::ExprBreak(_) | ast::ExprAgain(_) | - ast::ExprPath(_) | - ast::ExprQPath(_) => {} + ast::ExprPath(..) => {} 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 80fe2ed8f3af3..5cc1baf66c621 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -143,7 +143,7 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // it prefers in-place instantiation, likely because it contains // `[x; N]` somewhere within. match expr.node { - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { match bcx.def(expr.id) { def::DefConst(did) => { let expr = consts::get_const_expr(bcx.ccx(), did, expr); @@ -629,7 +629,7 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ast::ExprParen(ref e) => { trans(bcx, &**e) } - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { trans_def(bcx, expr, bcx.def(expr.id)) } ast::ExprField(ref base, ident) => { @@ -1033,7 +1033,7 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ast::ExprParen(ref e) => { trans_into(bcx, &**e, dest) } - ast::ExprPath(_) | ast::ExprQPath(_) => { + ast::ExprPath(..) => { 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 982cc1e3792e1..602f041222f27 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -52,6 +52,7 @@ use middle::astconv_util::{prim_ty_to_ty, check_path_args, NO_TPS, NO_REGIONS}; use middle::const_eval; use middle::def; use middle::resolve_lifetime as rl; +use middle::privacy::{AllPublic, LastMod}; use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; use middle::traits; use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty}; @@ -897,7 +898,7 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>, */ match ty.node { - ast::TyPath(ref path) => { + ast::TyPath(None, ref path) => { let def = this.tcx().def_map.borrow().get(&ty.id).map(|d| d.full_def()); match def { Some(def::DefTrait(trait_def_id)) => { @@ -981,7 +982,13 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS); let assoc_name = item_segment.identifier.name; - let ty_param_node_id = if let ty::ty_param(_) = ty.sty { + let is_param = match (&ty.sty, ty_path_def) { + (&ty::ty_param(_), def::DefTyParam(..)) | + (&ty::ty_param(_), def::DefSelfTy(_)) => true, + _ => false + }; + + let ty_param_node_id = if is_param { ty_path_def.local_node_id() } else { span_err!(tcx.sess, span, E0223, @@ -1195,9 +1202,14 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, segments.last().unwrap()) } def::DefMod(id) => { - tcx.sess.span_bug(span, - &format!("found module name used as a type: {}", - tcx.map.node_to_string(id.node))); + // Used as sentinel by callers to indicate the `::a::b::c` form. + if segments.is_empty() { + opt_self_ty.expect("missing T in ::a::b::c") + } else { + tcx.sess.span_bug(span, + &format!("found module name used as a type: {}", + tcx.map.node_to_string(id.node))); + } } def::DefPrimTy(prim_ty) => { prim_ty_to_ty(tcx, segments, prim_ty) @@ -1302,20 +1314,25 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, ast::TyPolyTraitRef(ref bounds) => { conv_ty_poly_trait_ref(this, rscope, ast_ty.span, bounds) } - ast::TyPath(ref path) | ast::TyQPath(ast::QPath { ref path, .. }) => { + ast::TyPath(ref maybe_qself, ref path) => { let path_res = if let Some(&d) = tcx.def_map.borrow().get(&ast_ty.id) { d + } else if let Some(ast::QSelf { position: 0, .. }) = *maybe_qself { + // Create some fake resolution that can't possibly be a type. + def::PathResolution { + base_def: def::DefMod(ast_util::local_def(ast::CRATE_NODE_ID)), + last_private: LastMod(AllPublic), + depth: path.segments.len() + } } else { tcx.sess.span_bug(ast_ty.span, &format!("unbound path {}", ast_ty.repr(tcx))) }; let mut def = path_res.base_def; let base_ty_end = path.segments.len() - path_res.depth; - let opt_self_ty = if let ast::TyQPath(ref qpath) = ast_ty.node { - Some(ast_ty_to_ty(this, rscope, &*qpath.self_type)) - } else { - None - }; + let opt_self_ty = maybe_qself.as_ref().map(|qself| { + ast_ty_to_ty(this, rscope, &qself.ty) + }); let ty = finish_resolving_def_to_ty(this, rscope, ast_ty.span, PathParamMode::Explicit, &mut def, opt_self_ty, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f99e4e4b2ed8a..f5d6d5baf9380 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -91,6 +91,7 @@ use middle::infer; use middle::mem_categorization as mc; use middle::mem_categorization::McResult; use middle::pat_util::{self, pat_id_map}; +use middle::privacy::{AllPublic, LastMod}; use middle::region::{self, CodeExtent}; use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace}; use middle::traits; @@ -3397,7 +3398,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let mut checked = false; opt_place.as_ref().map(|place| match place.node { - ast::ExprPath(ref path) => { + ast::ExprPath(None, ref path) => { // FIXME(pcwalton): For now we hardcode the two permissible // places: the exchange heap and the managed heap. let definition = lookup_def(fcx, path.span, place.id); @@ -3590,16 +3591,21 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }; fcx.write_ty(id, oprnd_t); } - ast::ExprPath(ref path) | ast::ExprQPath(ast::QPath { ref path, .. }) => { - let opt_self_ty = if let ast::ExprQPath(ref qpath) = expr.node { - Some(fcx.to_ty(&*qpath.self_type)) - } else { - None - }; + ast::ExprPath(ref maybe_qself, ref path) => { + let opt_self_ty = maybe_qself.as_ref().map(|qself| { + fcx.to_ty(&qself.ty) + }); let path_res = if let Some(&d) = tcx.def_map.borrow().get(&id) { d - } else { + } else if let Some(ast::QSelf { position: 0, .. }) = *maybe_qself { + // Create some fake resolution that can't possibly be a type. + def::PathResolution { + base_def: def::DefMod(local_def(ast::CRATE_NODE_ID)), + last_private: LastMod(AllPublic), + depth: path.segments.len() + } + } else { tcx.sess.span_bug(expr.span, &format!("unbound path {}", expr.repr(tcx))[]) }; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 976c794735fbb..7ed372d1b4b03 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1683,20 +1683,15 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, index: u32) -> bool { - match ast_ty.node { - ast::TyPath(_) => { - match ccx.tcx.def_map.borrow()[ast_ty.id] { - def::DefTyParam(s, i, _, _) => { - space == s && index == i - } - _ => { - false - } - } - } - _ => { + if let ast::TyPath(None, _) = ast_ty.node { + let path_res = ccx.tcx.def_map.borrow()[ast_ty.id]; + if let def::DefTyParam(s, i, _, _) = path_res.base_def { + path_res.depth == 0 && space == s && index == i + } else { false } + } else { + false } } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0aa1a23ad7e76..b88620d577f37 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1494,15 +1494,15 @@ impl Clean for ast::Ty { TyFixedLengthVec(ref ty, ref e) => FixedVector(box ty.clean(cx), e.span.to_src(cx)), TyTup(ref tys) => Tuple(tys.clean(cx)), - TyPath(ref p) => { + TyPath(None, ref p) => { resolve_type(cx, p.clean(cx), self.id) } - TyQPath(ref qp) => { - let mut trait_path = qp.path.clone(); + TyPath(Some(ref qself), ref p) => { + let mut trait_path = p.clone(); trait_path.segments.pop(); Type::QPath { - name: qp.path.segments.last().unwrap().identifier.clean(cx), - self_type: box qp.self_type.clean(cx), + name: p.segments.last().unwrap().identifier.clean(cx), + self_type: box qself.ty.clean(cx), trait_: box resolve_type(cx, trait_path.clean(cx), self.id) } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 80a5527cb948d..6d6fdffa95095 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -753,11 +753,10 @@ pub enum Expr_ { ExprIndex(P, P), ExprRange(Option>, Option>), - /// Variable reference, possibly containing `::` and/or - /// type parameters, e.g. foo::bar:: - ExprPath(Path), - /// A "qualified path", e.g. ` as SomeTrait>::SomeType` - ExprQPath(QPath), + /// Variable reference, possibly containing `::` and/or type + /// parameters, e.g. foo::bar::. Optionally "qualified", + /// e.g. ` as SomeTrait>::SomeType`. + ExprPath(Option, Path), ExprAddrOf(Mutability, P), ExprBreak(Option), @@ -778,15 +777,22 @@ pub enum Expr_ { ExprParen(P) } -/// A "qualified path": +/// The explicit Self type in a "qualified path". The actual +/// path, including the trait and the associated item, is stored +/// sepparately. `position` represents the index of the associated +/// item qualified with this Self type. /// -/// as SomeTrait>::SomeAssociatedItem -/// ^~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -/// self_type path +/// as a::b::Trait>::AssociatedItem +/// ^~~~~ ~~~~~~~~~~~~~~^ +/// ty position = 3 +/// +/// >::AssociatedItem +/// ^~~~~ ^ +/// ty position = 0 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct QPath { - pub self_type: P, - pub path: Path, +pub struct QSelf { + pub ty: P, + pub position: usize } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] @@ -1253,12 +1259,11 @@ pub enum Ty_ { TyBareFn(P), /// A tuple (`(A, B, C, D,...)`) TyTup(Vec> ), - /// A path (`module::module::...::Type`) or primitive + /// A path (`module::module::...::Type`), optionally + /// "qualified", e.g. ` as SomeTrait>::SomeType`. /// /// Type parameters are stored in the Path itself - TyPath(Path), - /// A "qualified path", e.g. ` as SomeTrait>::SomeType` - TyQPath(QPath), + TyPath(Option, Path), /// Something like `A+B`. Note that `B` must always be a path. TyObjectSum(P, TyParamBounds), /// A type like `for<'a> Foo<&'a Bar>` diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index f207efc5b6c34..79f0433761da5 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -134,7 +134,7 @@ pub fn unop_to_string(op: UnOp) -> &'static str { } pub fn is_path(e: P) -> bool { - return match e.node { ExprPath(_) => true, _ => false }; + match e.node { ExprPath(..) => true, _ => false } } /// Get a string representation of a signed int type, with its value. diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 90842bbab47d2..d916651b05617 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -43,14 +43,14 @@ pub trait AstBuilder { fn qpath(&self, self_type: P, trait_path: ast::Path, ident: ast::Ident) - -> ast::QPath; + -> (ast::QSelf, ast::Path); fn qpath_all(&self, self_type: P, trait_path: ast::Path, ident: ast::Ident, lifetimes: Vec, types: Vec>, bindings: Vec>) - -> ast::QPath; + -> (ast::QSelf, ast::Path); // types fn ty_mt(&self, ty: P, mutbl: ast::Mutability) -> ast::MutTy; @@ -114,7 +114,7 @@ pub trait AstBuilder { // expressions fn expr(&self, span: Span, node: ast::Expr_) -> P; fn expr_path(&self, path: ast::Path) -> P; - fn expr_qpath(&self, span: Span, qpath: ast::QPath) -> P; + fn expr_qpath(&self, span: Span, qself: ast::QSelf, path: ast::Path) -> P; fn expr_ident(&self, span: Span, id: ast::Ident) -> P; fn expr_self(&self, span: Span) -> P; @@ -351,7 +351,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self_type: P, trait_path: ast::Path, ident: ast::Ident) - -> ast::QPath { + -> (ast::QSelf, ast::Path) { self.qpath_all(self_type, trait_path, ident, vec![], vec![], vec![]) } @@ -365,7 +365,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { lifetimes: Vec, types: Vec>, bindings: Vec>) - -> ast::QPath { + -> (ast::QSelf, ast::Path) { let mut path = trait_path; path.segments.push(ast::PathSegment { identifier: ident, @@ -376,10 +376,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> { }) }); - ast::QPath { - self_type: self_type, - path: path - } + (ast::QSelf { + ty: self_type, + position: path.segments.len() - 1 + }, path) } fn ty_mt(&self, ty: P, mutbl: ast::Mutability) -> ast::MutTy { @@ -398,7 +398,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn ty_path(&self, path: ast::Path) -> P { - self.ty(path.span, ast::TyPath(path)) + self.ty(path.span, ast::TyPath(None, path)) } fn ty_sum(&self, path: ast::Path, bounds: OwnedSlice) -> P { @@ -603,12 +603,12 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn expr_path(&self, path: ast::Path) -> P { - self.expr(path.span, ast::ExprPath(path)) + self.expr(path.span, ast::ExprPath(None, path)) } /// Constructs a QPath expression. - fn expr_qpath(&self, span: Span, qpath: ast::QPath) -> P { - self.expr(span, ast::ExprQPath(qpath)) + fn expr_qpath(&self, span: Span, qself: ast::QSelf, path: ast::Path) -> P { + self.expr(span, ast::ExprPath(Some(qself), path)) } fn expr_ident(&self, span: Span, id: ast::Ident) -> P { diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index 9410a51e7a5f6..2303eb9645b64 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -53,7 +53,7 @@ pub fn expand_syntax_ext<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree] let e = P(ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprPath( + node: ast::ExprPath(None, ast::Path { span: sp, global: false, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f7014d6cc3c00..b6e7b309f356c 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -41,7 +41,7 @@ pub fn expand_type(t: P, debug!("expanding type {:?} with impl_ty {:?}", t, impl_ty); let t = match (t.node.clone(), impl_ty) { // Expand uses of `Self` in impls to the concrete type. - (ast::Ty_::TyPath(ref path), Some(ref impl_ty)) => { + (ast::Ty_::TyPath(None, ref path), Some(ref impl_ty)) => { let path_as_ident = path_to_ident(path); // Note unhygenic comparison here. I think this is correct, since // even though `Self` is almost just a type parameter, the treatment @@ -1594,13 +1594,10 @@ mod test { impl<'v> Visitor<'v> for PathExprFinderContext { fn visit_expr(&mut self, expr: &ast::Expr) { - match expr.node { - ast::ExprPath(ref p) => { - self.path_accumulator.push(p.clone()); - // not calling visit_path, but it should be fine. - } - _ => visit::walk_expr(self, expr) + if let ast::ExprPath(None, ref p) = expr.node { + self.path_accumulator.push(p.clone()); } + visit::walk_expr(self, expr); } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 4efae84fea5ae..32fd5b49f9a44 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -549,7 +549,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { fn visit_ty(&mut self, t: &ast::Ty) { match t.node { - ast::TyPath(ref p) => { + ast::TyPath(None, ref p) => { match &*p.segments { [ast::PathSegment { identifier, .. }] => { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index c706ce9065dd5..a556b2dfd2a99 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -424,12 +424,14 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { } TyTup(tys) => TyTup(tys.move_map(|ty| fld.fold_ty(ty))), TyParen(ty) => TyParen(fld.fold_ty(ty)), - TyPath(path) => TyPath(fld.fold_path(path)), - TyQPath(qpath) => { - TyQPath(QPath { - self_type: fld.fold_ty(qpath.self_type), - path: fld.fold_path(qpath.path) - }) + TyPath(qself, path) => { + let qself = qself.map(|QSelf { ty, position }| { + QSelf { + ty: fld.fold_ty(ty), + position: position + } + }); + TyPath(qself, fld.fold_path(path)) } TyObjectSum(ty, bounds) => { TyObjectSum(fld.fold_ty(ty), @@ -1347,11 +1349,15 @@ pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> ExprRange(e1.map(|x| folder.fold_expr(x)), e2.map(|x| folder.fold_expr(x))) } - ExprPath(pth) => ExprPath(folder.fold_path(pth)), - ExprQPath(qpath) => ExprQPath(QPath { - self_type: folder.fold_ty(qpath.self_type), - path: folder.fold_path(qpath.path) - }), + ExprPath(qself, path) => { + let qself = qself.map(|QSelf { ty, position }| { + QSelf { + ty: folder.fold_ty(ty), + position: position + } + }); + ExprPath(qself, folder.fold_path(path)) + } 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/mod.rs b/src/libsyntax/parse/mod.rs index d4c66529e77df..4d099529cb49a 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -774,7 +774,7 @@ mod test { assert!(string_to_expr("a".to_string()) == P(ast::Expr{ id: ast::DUMMY_NODE_ID, - node: ast::ExprPath(ast::Path { + node: ast::ExprPath(None, ast::Path { span: sp(0, 1), global: false, segments: vec!( @@ -792,7 +792,7 @@ mod test { assert!(string_to_expr("::a::b".to_string()) == P(ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprPath(ast::Path { + node: ast::ExprPath(None, ast::Path { span: sp(0, 6), global: true, segments: vec!( @@ -974,7 +974,7 @@ mod test { id: ast::DUMMY_NODE_ID, node:ast::ExprRet(Some(P(ast::Expr{ id: ast::DUMMY_NODE_ID, - node:ast::ExprPath(ast::Path{ + node:ast::ExprPath(None, ast::Path{ span: sp(7, 8), global: false, segments: vec!( @@ -995,7 +995,7 @@ mod test { P(Spanned{ node: ast::StmtExpr(P(ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprPath(ast::Path { + node: ast::ExprPath(None, ast::Path { span:sp(0,1), global:false, segments: vec!( @@ -1041,7 +1041,7 @@ mod test { node: ast::ItemFn(P(ast::FnDecl { inputs: vec!(ast::Arg{ ty: P(ast::Ty{id: ast::DUMMY_NODE_ID, - node: ast::TyPath(ast::Path{ + node: ast::TyPath(None, ast::Path{ span:sp(10,13), global:false, segments: vec!( @@ -1084,7 +1084,7 @@ mod test { stmts: vec!(P(Spanned{ node: ast::StmtSemi(P(ast::Expr{ id: ast::DUMMY_NODE_ID, - node: ast::ExprPath( + node: ast::ExprPath(None, ast::Path{ span:sp(17,18), global:false, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ad290da7d0a62..f171e8279f49c 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, ExprQPath}; +use ast::{ExprMethodCall, ExprParen, ExprPath}; use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary}; use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl}; use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod, FunctionRetTy}; @@ -43,7 +43,7 @@ use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, NodeId, UnNot}; use ast::{Pat, PatEnum, PatIdent, PatLit, PatRange, PatRegion, PatStruct}; use ast::{PatTup, PatBox, PatWild, PatWildMulti, PatWildSingle}; use ast::{PolyTraitRef}; -use ast::{QPath, RequiredMethod}; +use ast::{QSelf, RequiredMethod}; use ast::{Return, BiShl, BiShr, Stmt, StmtDecl}; use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField}; use ast::{StructVariantKind, BiSub, StrStyle}; @@ -53,7 +53,7 @@ use ast::{TtDelimited, TtSequence, TtToken}; use ast::{TupleVariantKind, Ty, Ty_, TypeBinding}; use ast::{TyFixedLengthVec, TyBareFn}; use ast::{TyTypeof, TyInfer, TypeMethod}; -use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath}; +use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr}; use ast::{TyRptr, TyTup, TyU32, TyVec, UnUniq}; use ast::{TypeImplItem, TypeTraitItem, Typedef,}; use ast::{UnnamedField, UnsafeBlock}; @@ -143,7 +143,7 @@ macro_rules! maybe_whole_expr { _ => unreachable!() }; let span = $p.span; - Some($p.mk_expr(span.lo, span.hi, ExprPath(pt))) + Some($p.mk_expr(span.lo, span.hi, ExprPath(None, pt))) } token::Interpolated(token::NtBlock(_)) => { // FIXME: The following avoids an issue with lexical borrowck scopes, @@ -1076,7 +1076,7 @@ impl<'a> Parser<'a> { } pub fn parse_ty_path(&mut self) -> Ty_ { - TyPath(self.parse_path(LifetimeAndTypesWithoutColons)) + TyPath(None, self.parse_path(LifetimeAndTypesWithoutColons)) } /// parse a TyBareFn type: @@ -1524,15 +1524,36 @@ impl<'a> Parser<'a> { } else if self.eat_lt() { // QUALIFIED PATH `::item` let self_type = self.parse_ty_sum(); - self.expect_keyword(keywords::As); - let mut path = self.parse_path(LifetimeAndTypesWithoutColons); + + let mut path = if self.eat_keyword(keywords::As) { + self.parse_path(LifetimeAndTypesWithoutColons) + } else { + ast::Path { + span: self.span, + global: false, + segments: vec![] + } + }; + + let qself = QSelf { + ty: self_type, + position: path.segments.len() + }; + self.expect(&token::Gt); self.expect(&token::ModSep); + path.segments.push(ast::PathSegment { identifier: self.parse_ident(), parameters: ast::PathParameters::none() }); - TyQPath(QPath { self_type: self_type, path: path }) + + if path.segments.len() == 1 { + path.span.lo = self.last_span.lo; + } + path.span.hi = self.last_span.hi; + + TyPath(Some(qself), path) } else if self.check(&token::ModSep) || self.token.is_ident() || self.token.is_path() { @@ -2173,7 +2194,7 @@ impl<'a> Parser<'a> { }, token::Plain) => { self.bump(); let path = ast_util::ident_to_path(mk_sp(lo, hi), id); - ex = ExprPath(path); + ex = ExprPath(None, path); hi = self.last_span.hi; } token::OpenDelim(token::Bracket) => { @@ -2215,10 +2236,22 @@ impl<'a> Parser<'a> { if self.eat_lt() { // QUALIFIED PATH `::item::<'a, T>` let self_type = self.parse_ty_sum(); - self.expect_keyword(keywords::As); - let mut path = self.parse_path(LifetimeAndTypesWithoutColons); + let mut path = if self.eat_keyword(keywords::As) { + self.parse_path(LifetimeAndTypesWithoutColons) + } else { + ast::Path { + span: self.span, + global: false, + segments: vec![] + } + }; + let qself = QSelf { + ty: self_type, + position: path.segments.len() + }; self.expect(&token::Gt); self.expect(&token::ModSep); + let item_name = self.parse_ident(); let parameters = if self.eat(&token::ModSep) { self.expect_lt(); @@ -2237,9 +2270,14 @@ impl<'a> Parser<'a> { identifier: item_name, parameters: parameters }); + + if path.segments.len() == 1 { + path.span.lo = self.last_span.lo; + } + path.span.hi = self.last_span.hi; + let hi = self.span.hi; - return self.mk_expr(lo, hi, - ExprQPath(QPath { self_type: self_type, path: path })); + return self.mk_expr(lo, hi, ExprPath(Some(qself), path)); } if self.eat_keyword(keywords::Move) { return self.parse_lambda_expr(CaptureByValue); @@ -2379,7 +2417,7 @@ impl<'a> Parser<'a> { } hi = pth.span.hi; - ex = ExprPath(pth); + ex = ExprPath(None, pth); } else { // other literal expression let lit = self.parse_lit(); @@ -3421,7 +3459,7 @@ impl<'a> Parser<'a> { let end = if self.token.is_ident() || self.token.is_path() { let path = self.parse_path(LifetimeAndTypesWithColons); let hi = self.span.hi; - self.mk_expr(lo, hi, ExprPath(path)) + self.mk_expr(lo, hi, ExprPath(None, path)) } else { self.parse_literal_maybe_minus() }; @@ -4808,7 +4846,7 @@ impl<'a> Parser<'a> { let opt_trait = if could_be_trait && self.eat_keyword(keywords::For) { // New-style trait. Reinterpret the type as a trait. match ty.node { - TyPath(ref path) => { + TyPath(None, ref path) => { Some(TraitRef { path: (*path).clone(), ref_id: ty.id, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 11502c29ebb15..78b9487d1c98b 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -729,11 +729,11 @@ impl<'a> State<'a> { &generics, None)); } - ast::TyPath(ref path) => { + ast::TyPath(None, ref path) => { try!(self.print_path(path, false, 0)); } - ast::TyQPath(ref qpath) => { - try!(self.print_qpath(qpath, false)) + ast::TyPath(Some(ref qself), ref path) => { + try!(self.print_qpath(path, qself, false)) } ast::TyObjectSum(ref ty, ref bounds) => { try!(self.print_type(&**ty)); @@ -1852,8 +1852,12 @@ impl<'a> State<'a> { try!(self.print_expr(&**e)); } } - ast::ExprPath(ref path) => try!(self.print_path(path, true, 0)), - ast::ExprQPath(ref qpath) => try!(self.print_qpath(qpath, true)), + ast::ExprPath(None, ref path) => { + try!(self.print_path(path, true, 0)) + } + ast::ExprPath(Some(ref qself), ref path) => { + try!(self.print_qpath(path, qself, true)) + } ast::ExprBreak(opt_ident) => { try!(word(&mut self.s, "break")); try!(space(&mut self.s)); @@ -2037,18 +2041,19 @@ impl<'a> State<'a> { } fn print_qpath(&mut self, - qpath: &ast::QPath, + path: &ast::Path, + qself: &ast::QSelf, colons_before_params: bool) -> IoResult<()> { try!(word(&mut self.s, "<")); - try!(self.print_type(&*qpath.self_type)); + try!(self.print_type(&qself.ty)); try!(space(&mut self.s)); try!(self.word_space("as")); - try!(self.print_path(&qpath.path, false, 1)); + try!(self.print_path(&path, false, 1)); try!(word(&mut self.s, ">")); try!(word(&mut self.s, "::")); - let item_segment = qpath.path.segments.last().unwrap(); + let item_segment = path.segments.last().unwrap(); try!(self.print_ident(item_segment.identifier)); self.print_path_parameters(&item_segment.parameters, colons_before_params) } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 55372585062d8..33d8d56b4b114 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -396,13 +396,12 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { walk_fn_ret_ty(visitor, &function_declaration.decl.output); walk_lifetime_decls_helper(visitor, &function_declaration.lifetimes); } - TyPath(ref path) => { + TyPath(ref maybe_qself, ref path) => { + if let Some(ref qself) = *maybe_qself { + visitor.visit_ty(&qself.ty); + } visitor.visit_path(path, typ.id); } - TyQPath(ref qpath) => { - visitor.visit_ty(&*qpath.self_type); - visitor.visit_path(&qpath.path, typ.id); - } TyObjectSum(ref ty, ref bounds) => { visitor.visit_ty(&**ty); walk_ty_param_bounds_helper(visitor, bounds); @@ -859,13 +858,12 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { walk_expr_opt(visitor, start); walk_expr_opt(visitor, end) } - ExprPath(ref path) => { + ExprPath(ref maybe_qself, ref path) => { + if let Some(ref qself) = *maybe_qself { + visitor.visit_ty(&qself.ty); + } visitor.visit_path(path, expression.id) } - ExprQPath(ref qpath) => { - visitor.visit_ty(&*qpath.self_type); - visitor.visit_path(&qpath.path, expression.id); - } ExprBreak(_) | ExprAgain(_) => {} ExprRet(ref optional_expression) => { walk_expr_opt(visitor, optional_expression) diff --git a/src/test/run-pass/ufcs-polymorphic-paths.rs b/src/test/run-pass/ufcs-polymorphic-paths.rs index 277aaf086f419..29b1c8f81d3c6 100644 --- a/src/test/run-pass/ufcs-polymorphic-paths.rs +++ b/src/test/run-pass/ufcs-polymorphic-paths.rs @@ -61,8 +61,10 @@ tests! { // Inherent static methods. Vec::new, fn() -> Vec<()>, (); Vec::<()>::new, fn() -> Vec<()>, (); + >::new, fn() -> Vec<()>, (); Vec::with_capacity, fn(usize) -> Vec<()>, (5); Vec::<()>::with_capacity, fn(usize) -> Vec<()>, (5); + >::with_capacity, fn(usize) -> Vec<()>, (5); BitVec::from_fn, fn(usize, fn(usize) -> bool) -> BitVec, (5, odd); BitVec::from_fn:: bool>, fn(usize, fn(usize) -> bool) -> BitVec, (5, odd); @@ -78,26 +80,32 @@ tests! { // Trait static methods. bool::size, fn() -> usize, (); + ::size, fn() -> usize, (); ::size, fn() -> usize, (); Default::default, fn() -> i32, (); i32::default, fn() -> i32, (); + ::default, fn() -> i32, (); ::default, fn() -> i32, (); Rand::rand, fn(&mut DummyRng) -> i32, (&mut dummy_rng()); i32::rand, fn(&mut DummyRng) -> i32, (&mut dummy_rng()); + ::rand, fn(&mut DummyRng) -> i32, (&mut dummy_rng()); ::rand, fn(&mut DummyRng) -> i32, (&mut dummy_rng()); Rand::rand::, fn(&mut DummyRng) -> i32, (&mut dummy_rng()); i32::rand::, fn(&mut DummyRng) -> i32, (&mut dummy_rng()); + ::rand::, fn(&mut DummyRng) -> i32, (&mut dummy_rng()); ::rand::, fn(&mut DummyRng) -> i32, (&mut dummy_rng()); // Trait non-static methods. Clone::clone, fn(&i32) -> i32, (&5); i32::clone, fn(&i32) -> i32, (&5); + ::clone, fn(&i32) -> i32, (&5); ::clone, fn(&i32) -> i32, (&5); FromIterator::from_iter, fn(OptionIter) -> Vec, (Some(5).into_iter()); Vec::from_iter, fn(OptionIter) -> Vec, (Some(5).into_iter()); + >::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, @@ -109,11 +117,14 @@ tests! { Add::add, fn(i32, i32) -> i32, (5, 6); i32::add, fn(i32, i32) -> i32, (5, 6); + ::add, fn(i32, i32) -> i32, (5, 6); >::add, fn(i32, i32) -> i32, (5, 6); >::add, fn(i32, i32) -> i32, (5, 6); String::into_cow, fn(String) -> Cow<'static, str>, ("foo".to_string()); + ::into_cow, fn(String) -> Cow<'static, str>, + ("foo".to_string()); >::into_cow, fn(String) -> Cow<'static, str>, ("foo".to_string()); >::into_cow, fn(String) -> Cow<'static, str>,