Skip to content

Commit

Permalink
auto merge of #21077 : eddyb/rust/expr-qpath, r=nikomatsakis
Browse files Browse the repository at this point in the history
Working towards #16293, this adds support for `<T as Trait>::method` in expressions.
  • Loading branch information
bors committed Jan 15, 2015
2 parents 1c78ad9 + 85ba817 commit 9ade482
Show file tree
Hide file tree
Showing 33 changed files with 256 additions and 87 deletions.
2 changes: 1 addition & 1 deletion src/librustc/lint/builtin.rs
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/cfg/construct.rs
Expand Up @@ -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())
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/check_const.rs
Expand Up @@ -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(..) |
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/check_static.rs
Expand Up @@ -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, \
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/check_static_recursion.rs
Expand Up @@ -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
Expand Down
11 changes: 9 additions & 2 deletions src/librustc/middle/const_eval.rs
Expand Up @@ -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,

Expand Down Expand Up @@ -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 })
Expand Down Expand Up @@ -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())
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/effect.rs
Expand Up @@ -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");
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/expr_use_visitor.rs
Expand Up @@ -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) {
Expand Down
14 changes: 8 additions & 6 deletions src/librustc/middle/liveness.rs
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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(..) => {
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/mem_categorization.rs
Expand Up @@ -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)
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/privacy.rs
Expand Up @@ -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| {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/reachable.rs
Expand Up @@ -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 => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/ty.rs
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_back/svh.rs
Expand Up @@ -252,6 +252,7 @@ mod svh_visitor {
SawExprIndex,
SawExprRange,
SawExprPath,
SawExprQPath,
SawExprAddrOf(ast::Mutability),
SawExprRet,
SawExprInlineAsm(&'a ast::InlineAsm),
Expand Down Expand Up @@ -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)),
Expand Down
53 changes: 28 additions & 25 deletions src/librustc_resolve/lib.rs
Expand Up @@ -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};
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 => {
Expand All @@ -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) => {
Expand Down Expand Up @@ -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 \
Expand All @@ -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);
}
Expand All @@ -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, _), _))
Expand Down
16 changes: 11 additions & 5 deletions src/librustc_trans/save/mod.rs
Expand Up @@ -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
}

Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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(_, _) => {}
Expand All @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/_match.rs
Expand Up @@ -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
},
Expand Down
7 changes: 5 additions & 2 deletions src/librustc_trans/trans/callee.rs
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/consts.rs
Expand Up @@ -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(..) => {
Expand Down

0 comments on commit 9ade482

Please sign in to comment.