mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-30 22:12:15 +00:00
auto merge of #21077 : eddyb/rust/expr-qpath, r=nikomatsakis
Working towards #16293, this adds support for `<T as Trait>::method` in expressions.
This commit is contained in:
commit
9ade482b3b
@ -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
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
@ -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(..) |
|
||||
|
@ -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, \
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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| {
|
||||
|
@ -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 => {
|
||||
|
@ -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);
|
||||
|
@ -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)),
|
||||
|
@ -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, _), _))
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
},
|
||||
|
@ -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:
|
||||
|
@ -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(..) => {
|
||||
|
@ -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) |
|
||||
|
@ -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) => {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)]
|
||||
|
@ -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))),
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
17
src/test/compile-fail/ufcs-qpath-missing-params.rs
Normal file
17
src/test/compile-fail/ufcs-qpath-missing-params.rs
Normal file
@ -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
|
||||
}
|
||||
|
21
src/test/compile-fail/ufcs-qpath-self-mismatch.rs
Normal file
21
src/test/compile-fail/ufcs-qpath-self-mismatch.rs
Normal file
@ -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
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user