Store all generic arguments for method calls in AST
This commit is contained in:
@@ -1844,10 +1844,17 @@ impl<'a> LoweringContext<'a> {
|
|||||||
let f = P(self.lower_expr(f));
|
let f = P(self.lower_expr(f));
|
||||||
hir::ExprCall(f, args.iter().map(|x| self.lower_expr(x)).collect())
|
hir::ExprCall(f, args.iter().map(|x| self.lower_expr(x)).collect())
|
||||||
}
|
}
|
||||||
ExprKind::MethodCall(i, ref tps, ref args) => {
|
ExprKind::MethodCall(ref seg, ref args) => {
|
||||||
|
let tps = match seg.parameters {
|
||||||
|
Some(ref params) => match **params {
|
||||||
|
PathParameters::AngleBracketed(ref param_data) => ¶m_data.types[..],
|
||||||
|
_ => &[],
|
||||||
|
},
|
||||||
|
_ => &[],
|
||||||
|
};
|
||||||
let tps = tps.iter().map(|x| self.lower_ty(x)).collect();
|
let tps = tps.iter().map(|x| self.lower_ty(x)).collect();
|
||||||
let args = args.iter().map(|x| self.lower_expr(x)).collect();
|
let args = args.iter().map(|x| self.lower_expr(x)).collect();
|
||||||
hir::ExprMethodCall(respan(i.span, self.lower_ident(i.node)), tps, args)
|
hir::ExprMethodCall(respan(seg.span, self.lower_ident(seg.identifier)), tps, args)
|
||||||
}
|
}
|
||||||
ExprKind::Binary(binop, ref lhs, ref rhs) => {
|
ExprKind::Binary(binop, ref lhs, ref rhs) => {
|
||||||
let binop = self.lower_binop(binop);
|
let binop = self.lower_binop(binop);
|
||||||
|
|||||||
@@ -125,6 +125,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||||||
ExprKind::Continue(Some(ident)) => {
|
ExprKind::Continue(Some(ident)) => {
|
||||||
self.check_label(ident.node, ident.span);
|
self.check_label(ident.node, ident.span);
|
||||||
}
|
}
|
||||||
|
ExprKind::MethodCall(ref segment, ..) => {
|
||||||
|
if let Some(ref params) = segment.parameters {
|
||||||
|
match **params {
|
||||||
|
PathParameters::AngleBracketed(ref param_data) => {
|
||||||
|
if !param_data.bindings.is_empty() {
|
||||||
|
let binding_span = param_data.bindings[0].span;
|
||||||
|
self.err_handler().span_err(binding_span,
|
||||||
|
"type bindings cannot be used in method calls");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PathParameters::Parenthesized(..) => {
|
||||||
|
self.err_handler().span_err(expr.span,
|
||||||
|
"parenthesized parameters cannot be used on method calls");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2467,9 +2467,9 @@ impl<'a> Resolver<'a> {
|
|||||||
path_str, ident.node));
|
path_str, ident.node));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
ExprKind::MethodCall(ident, ..) => {
|
ExprKind::MethodCall(ref segment, ..) => {
|
||||||
err.span_label(parent.span, format!("did you mean `{}::{}(...)`?",
|
err.span_label(parent.span, format!("did you mean `{}::{}(...)`?",
|
||||||
path_str, ident.node));
|
path_str, segment.identifier));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -3145,15 +3145,13 @@ impl<'a> Resolver<'a> {
|
|||||||
ExprKind::Field(ref subexpression, _) => {
|
ExprKind::Field(ref subexpression, _) => {
|
||||||
self.resolve_expr(subexpression, Some(expr));
|
self.resolve_expr(subexpression, Some(expr));
|
||||||
}
|
}
|
||||||
ExprKind::MethodCall(_, ref types, ref arguments) => {
|
ExprKind::MethodCall(ref segment, ref arguments) => {
|
||||||
let mut arguments = arguments.iter();
|
let mut arguments = arguments.iter();
|
||||||
self.resolve_expr(arguments.next().unwrap(), Some(expr));
|
self.resolve_expr(arguments.next().unwrap(), Some(expr));
|
||||||
for argument in arguments {
|
for argument in arguments {
|
||||||
self.resolve_expr(argument, None);
|
self.resolve_expr(argument, None);
|
||||||
}
|
}
|
||||||
for ty in types.iter() {
|
self.visit_path_segment(expr.span, segment);
|
||||||
self.visit_ty(ty);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprKind::Repeat(ref element, ref count) => {
|
ExprKind::Repeat(ref element, ref count) => {
|
||||||
@@ -3185,10 +3183,10 @@ impl<'a> Resolver<'a> {
|
|||||||
let traits = self.get_traits_containing_item(name.node, ValueNS);
|
let traits = self.get_traits_containing_item(name.node, ValueNS);
|
||||||
self.trait_map.insert(expr.id, traits);
|
self.trait_map.insert(expr.id, traits);
|
||||||
}
|
}
|
||||||
ExprKind::MethodCall(name, ..) => {
|
ExprKind::MethodCall(ref segment, ..) => {
|
||||||
debug!("(recording candidate traits for expr) recording traits for {}",
|
debug!("(recording candidate traits for expr) recording traits for {}",
|
||||||
expr.id);
|
expr.id);
|
||||||
let traits = self.get_traits_containing_item(name.node, ValueNS);
|
let traits = self.get_traits_containing_item(segment.identifier, ValueNS);
|
||||||
self.trait_map.insert(expr.id, traits);
|
self.trait_map.insert(expr.id, traits);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|||||||
@@ -848,19 +848,16 @@ pub enum ExprKind {
|
|||||||
/// The first field resolves to the function itself,
|
/// The first field resolves to the function itself,
|
||||||
/// and the second field is the list of arguments
|
/// and the second field is the list of arguments
|
||||||
Call(P<Expr>, Vec<P<Expr>>),
|
Call(P<Expr>, Vec<P<Expr>>),
|
||||||
/// A method call (`x.foo::<Bar, Baz>(a, b, c, d)`)
|
/// A method call (`x.foo::<'static, Bar, Baz>(a, b, c, d)`)
|
||||||
///
|
///
|
||||||
/// The `SpannedIdent` is the identifier for the method name.
|
/// The `PathSegment` represents the method name and its generic arguments
|
||||||
/// The vector of `Ty`s are the ascripted type parameters for the method
|
|
||||||
/// (within the angle brackets).
|
/// (within the angle brackets).
|
||||||
///
|
|
||||||
/// The first element of the vector of `Expr`s is the expression that evaluates
|
/// The first element of the vector of `Expr`s is the expression that evaluates
|
||||||
/// to the object on which the method is being called on (the receiver),
|
/// to the object on which the method is being called on (the receiver),
|
||||||
/// and the remaining elements are the rest of the arguments.
|
/// and the remaining elements are the rest of the arguments.
|
||||||
///
|
|
||||||
/// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
|
/// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
|
||||||
/// `ExprKind::MethodCall(foo, [Bar, Baz], [x, a, b, c, d])`.
|
/// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`.
|
||||||
MethodCall(SpannedIdent, Vec<P<Ty>>, Vec<P<Expr>>),
|
MethodCall(PathSegment, Vec<P<Expr>>),
|
||||||
/// A tuple (`(a, b, c ,d)`)
|
/// A tuple (`(a, b, c ,d)`)
|
||||||
Tup(Vec<P<Expr>>),
|
Tup(Vec<P<Expr>>),
|
||||||
/// A binary operation (For example: `a + b`, `a * b`)
|
/// A binary operation (For example: `a + b`, `a * b`)
|
||||||
|
|||||||
@@ -673,9 +673,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
|||||||
expr: P<ast::Expr>,
|
expr: P<ast::Expr>,
|
||||||
ident: ast::Ident,
|
ident: ast::Ident,
|
||||||
mut args: Vec<P<ast::Expr>> ) -> P<ast::Expr> {
|
mut args: Vec<P<ast::Expr>> ) -> P<ast::Expr> {
|
||||||
let id = Spanned { node: ident, span: span };
|
|
||||||
args.insert(0, expr);
|
args.insert(0, expr);
|
||||||
self.expr(span, ast::ExprKind::MethodCall(id, Vec::new(), args))
|
self.expr(span, ast::ExprKind::MethodCall(ast::PathSegment::from_ident(ident, span), args))
|
||||||
}
|
}
|
||||||
fn expr_block(&self, b: P<ast::Block>) -> P<ast::Expr> {
|
fn expr_block(&self, b: P<ast::Block>) -> P<ast::Expr> {
|
||||||
self.expr(b.span, ast::ExprKind::Block(b))
|
self.expr(b.span, ast::ExprKind::Block(b))
|
||||||
|
|||||||
@@ -1151,10 +1151,15 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
|
|||||||
ExprKind::Call(folder.fold_expr(f),
|
ExprKind::Call(folder.fold_expr(f),
|
||||||
folder.fold_exprs(args))
|
folder.fold_exprs(args))
|
||||||
}
|
}
|
||||||
ExprKind::MethodCall(i, tps, args) => {
|
ExprKind::MethodCall(seg, args) => {
|
||||||
ExprKind::MethodCall(
|
ExprKind::MethodCall(
|
||||||
respan(folder.new_span(i.span), folder.fold_ident(i.node)),
|
PathSegment {
|
||||||
tps.move_map(|x| folder.fold_ty(x)),
|
identifier: folder.fold_ident(seg.identifier),
|
||||||
|
span: folder.new_span(seg.span),
|
||||||
|
parameters: seg.parameters.map(|ps| {
|
||||||
|
ps.map(|ps| folder.fold_path_parameters(ps))
|
||||||
|
}),
|
||||||
|
},
|
||||||
folder.fold_exprs(args))
|
folder.fold_exprs(args))
|
||||||
}
|
}
|
||||||
ExprKind::Binary(binop, lhs, rhs) => {
|
ExprKind::Binary(binop, lhs, rhs) => {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use abi::{self, Abi};
|
use abi::{self, Abi};
|
||||||
use ast::{AttrStyle, BareFnTy};
|
use ast::{AngleBracketedParameterData, AttrStyle, BareFnTy};
|
||||||
use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
|
use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
|
||||||
use ast::Unsafety;
|
use ast::Unsafety;
|
||||||
use ast::{Mod, Arg, Arm, Attribute, BindingMode, TraitItemKind};
|
use ast::{Mod, Arg, Arm, Attribute, BindingMode, TraitItemKind};
|
||||||
@@ -1831,11 +1831,7 @@ impl<'a> Parser<'a> {
|
|||||||
let parameters = if parse_generics && self.eat_lt() {
|
let parameters = if parse_generics && self.eat_lt() {
|
||||||
let (lifetimes, types, bindings) = self.parse_generic_args()?;
|
let (lifetimes, types, bindings) = self.parse_generic_args()?;
|
||||||
self.expect_gt()?;
|
self.expect_gt()?;
|
||||||
ast::AngleBracketedParameterData {
|
AngleBracketedParameterData { lifetimes, types, bindings }.into()
|
||||||
lifetimes: lifetimes,
|
|
||||||
types: types,
|
|
||||||
bindings: bindings,
|
|
||||||
}.into()
|
|
||||||
} else if self.eat(&token::OpenDelim(token::Paren)) {
|
} else if self.eat(&token::OpenDelim(token::Paren)) {
|
||||||
let lo = self.prev_span;
|
let lo = self.prev_span;
|
||||||
|
|
||||||
@@ -1898,11 +1894,7 @@ impl<'a> Parser<'a> {
|
|||||||
segments.push(PathSegment {
|
segments.push(PathSegment {
|
||||||
identifier: identifier,
|
identifier: identifier,
|
||||||
span: ident_span,
|
span: ident_span,
|
||||||
parameters: ast::AngleBracketedParameterData {
|
parameters: AngleBracketedParameterData { lifetimes, types, bindings }.into(),
|
||||||
lifetimes: lifetimes,
|
|
||||||
types: types,
|
|
||||||
bindings: bindings,
|
|
||||||
}.into(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Consumed `a::b::<T,U>`, check for `::` before proceeding
|
// Consumed `a::b::<T,U>`, check for `::` before proceeding
|
||||||
@@ -2023,14 +2015,6 @@ impl<'a> Parser<'a> {
|
|||||||
ExprKind::Call(f, args)
|
ExprKind::Call(f, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_method_call(&mut self,
|
|
||||||
ident: ast::SpannedIdent,
|
|
||||||
tps: Vec<P<Ty>>,
|
|
||||||
args: Vec<P<Expr>>)
|
|
||||||
-> ast::ExprKind {
|
|
||||||
ExprKind::MethodCall(ident, tps, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mk_index(&mut self, expr: P<Expr>, idx: P<Expr>) -> ast::ExprKind {
|
pub fn mk_index(&mut self, expr: P<Expr>, idx: P<Expr>) -> ast::ExprKind {
|
||||||
ExprKind::Index(expr, idx)
|
ExprKind::Index(expr, idx)
|
||||||
}
|
}
|
||||||
@@ -2460,7 +2444,7 @@ impl<'a> Parser<'a> {
|
|||||||
// parsing into an expression.
|
// parsing into an expression.
|
||||||
fn parse_dot_suffix(&mut self, ident: Ident, ident_span: Span, self_value: P<Expr>, lo: Span)
|
fn parse_dot_suffix(&mut self, ident: Ident, ident_span: Span, self_value: P<Expr>, lo: Span)
|
||||||
-> PResult<'a, P<Expr>> {
|
-> PResult<'a, P<Expr>> {
|
||||||
let (_, tys, bindings) = if self.eat(&token::ModSep) {
|
let (lifetimes, types, bindings) = if self.eat(&token::ModSep) {
|
||||||
self.expect_lt()?;
|
self.expect_lt()?;
|
||||||
let args = self.parse_generic_args()?;
|
let args = self.parse_generic_args()?;
|
||||||
self.expect_gt()?;
|
self.expect_gt()?;
|
||||||
@@ -2469,11 +2453,6 @@ impl<'a> Parser<'a> {
|
|||||||
(Vec::new(), Vec::new(), Vec::new())
|
(Vec::new(), Vec::new(), Vec::new())
|
||||||
};
|
};
|
||||||
|
|
||||||
if !bindings.is_empty() {
|
|
||||||
let prev_span = self.prev_span;
|
|
||||||
self.span_err(prev_span, "type bindings are only permitted on trait paths");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(match self.token {
|
Ok(match self.token {
|
||||||
// expr.f() method call.
|
// expr.f() method call.
|
||||||
token::OpenDelim(token::Paren) => {
|
token::OpenDelim(token::Paren) => {
|
||||||
@@ -2486,17 +2465,20 @@ impl<'a> Parser<'a> {
|
|||||||
let hi = self.prev_span;
|
let hi = self.prev_span;
|
||||||
|
|
||||||
es.insert(0, self_value);
|
es.insert(0, self_value);
|
||||||
let id = respan(ident_span.to(ident_span), ident);
|
let seg = PathSegment {
|
||||||
let nd = self.mk_method_call(id, tys, es);
|
identifier: ident,
|
||||||
self.mk_expr(lo.to(hi), nd, ThinVec::new())
|
span: ident_span.to(ident_span),
|
||||||
|
parameters: AngleBracketedParameterData { lifetimes, types, bindings }.into(),
|
||||||
|
};
|
||||||
|
self.mk_expr(lo.to(hi), ExprKind::MethodCall(seg, es), ThinVec::new())
|
||||||
}
|
}
|
||||||
// Field access.
|
// Field access.
|
||||||
_ => {
|
_ => {
|
||||||
if !tys.is_empty() {
|
if let Some(generic_arg_span) = lifetimes.get(0).map(|x| x.span).or_else(||
|
||||||
let prev_span = self.prev_span;
|
types.get(0).map(|x| x.span)).or_else(||
|
||||||
self.span_err(prev_span,
|
bindings.get(0).map(|x| x.span)) {
|
||||||
"field expressions may not \
|
self.span_err(generic_arg_span,
|
||||||
have type parameters");
|
"field expressions may not have generic arguments");
|
||||||
}
|
}
|
||||||
|
|
||||||
let id = respan(ident_span.to(ident_span), ident);
|
let id = respan(ident_span.to(ident_span), ident);
|
||||||
|
|||||||
@@ -1951,18 +1951,14 @@ impl<'a> State<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn print_expr_method_call(&mut self,
|
fn print_expr_method_call(&mut self,
|
||||||
ident: ast::SpannedIdent,
|
segment: &ast::PathSegment,
|
||||||
tys: &[P<ast::Ty>],
|
|
||||||
args: &[P<ast::Expr>]) -> io::Result<()> {
|
args: &[P<ast::Expr>]) -> io::Result<()> {
|
||||||
let base_args = &args[1..];
|
let base_args = &args[1..];
|
||||||
self.print_expr(&args[0])?;
|
self.print_expr(&args[0])?;
|
||||||
word(&mut self.s, ".")?;
|
word(&mut self.s, ".")?;
|
||||||
self.print_ident(ident.node)?;
|
self.print_ident(segment.identifier)?;
|
||||||
if !tys.is_empty() {
|
if let Some(ref parameters) = segment.parameters {
|
||||||
word(&mut self.s, "::<")?;
|
self.print_path_parameters(parameters, true)?;
|
||||||
self.commasep(Inconsistent, tys,
|
|
||||||
|s, ty| s.print_type(ty))?;
|
|
||||||
word(&mut self.s, ">")?;
|
|
||||||
}
|
}
|
||||||
self.print_call_post(base_args)
|
self.print_call_post(base_args)
|
||||||
}
|
}
|
||||||
@@ -2041,8 +2037,8 @@ impl<'a> State<'a> {
|
|||||||
ast::ExprKind::Call(ref func, ref args) => {
|
ast::ExprKind::Call(ref func, ref args) => {
|
||||||
self.print_expr_call(func, &args[..])?;
|
self.print_expr_call(func, &args[..])?;
|
||||||
}
|
}
|
||||||
ast::ExprKind::MethodCall(ident, ref tys, ref args) => {
|
ast::ExprKind::MethodCall(ref segment, ref args) => {
|
||||||
self.print_expr_method_call(ident, &tys[..], &args[..])?;
|
self.print_expr_method_call(segment, &args[..])?;
|
||||||
}
|
}
|
||||||
ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
|
ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
|
||||||
self.print_expr_binary(op, lhs, rhs)?;
|
self.print_expr_binary(op, lhs, rhs)?;
|
||||||
|
|||||||
@@ -674,9 +674,8 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
|||||||
visitor.visit_expr(callee_expression);
|
visitor.visit_expr(callee_expression);
|
||||||
walk_list!(visitor, visit_expr, arguments);
|
walk_list!(visitor, visit_expr, arguments);
|
||||||
}
|
}
|
||||||
ExprKind::MethodCall(ref ident, ref types, ref arguments) => {
|
ExprKind::MethodCall(ref segment, ref arguments) => {
|
||||||
visitor.visit_ident(ident.span, ident.node);
|
visitor.visit_path_segment(expression.span, segment);
|
||||||
walk_list!(visitor, visit_ty, types);
|
|
||||||
walk_list!(visitor, visit_expr, arguments);
|
walk_list!(visitor, visit_expr, arguments);
|
||||||
}
|
}
|
||||||
ExprKind::Binary(_, ref left_expression, ref right_expression) => {
|
ExprKind::Binary(_, ref left_expression, ref right_expression) => {
|
||||||
|
|||||||
13
src/test/compile-fail/method-call-type-binding.rs
Normal file
13
src/test/compile-fail/method-call-type-binding.rs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
0.clone::<T = u8>(); //~ ERROR type bindings cannot be used in method calls
|
||||||
|
}
|
||||||
@@ -21,5 +21,5 @@ fn main() {
|
|||||||
y: 2,
|
y: 2,
|
||||||
};
|
};
|
||||||
f.x::<isize>;
|
f.x::<isize>;
|
||||||
//~^ ERROR field expressions may not have type parameters
|
//~^ ERROR field expressions may not have generic arguments
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user