Store all generic arguments for method calls in AST
This commit is contained in:
parent
8b1271fcdd
commit
287de2595a
@ -1844,10 +1844,17 @@ impl<'a> LoweringContext<'a> {
|
||||
let f = P(self.lower_expr(f));
|
||||
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 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) => {
|
||||
let binop = self.lower_binop(binop);
|
||||
|
@ -125,6 +125,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
ExprKind::Continue(Some(ident)) => {
|
||||
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));
|
||||
return err;
|
||||
}
|
||||
ExprKind::MethodCall(ident, ..) => {
|
||||
ExprKind::MethodCall(ref segment, ..) => {
|
||||
err.span_label(parent.span, format!("did you mean `{}::{}(...)`?",
|
||||
path_str, ident.node));
|
||||
path_str, segment.identifier));
|
||||
return err;
|
||||
}
|
||||
_ => {}
|
||||
@ -3145,15 +3145,13 @@ impl<'a> Resolver<'a> {
|
||||
ExprKind::Field(ref subexpression, _) => {
|
||||
self.resolve_expr(subexpression, Some(expr));
|
||||
}
|
||||
ExprKind::MethodCall(_, ref types, ref arguments) => {
|
||||
ExprKind::MethodCall(ref segment, ref arguments) => {
|
||||
let mut arguments = arguments.iter();
|
||||
self.resolve_expr(arguments.next().unwrap(), Some(expr));
|
||||
for argument in arguments {
|
||||
self.resolve_expr(argument, None);
|
||||
}
|
||||
for ty in types.iter() {
|
||||
self.visit_ty(ty);
|
||||
}
|
||||
self.visit_path_segment(expr.span, segment);
|
||||
}
|
||||
|
||||
ExprKind::Repeat(ref element, ref count) => {
|
||||
@ -3185,10 +3183,10 @@ impl<'a> Resolver<'a> {
|
||||
let traits = self.get_traits_containing_item(name.node, ValueNS);
|
||||
self.trait_map.insert(expr.id, traits);
|
||||
}
|
||||
ExprKind::MethodCall(name, ..) => {
|
||||
ExprKind::MethodCall(ref segment, ..) => {
|
||||
debug!("(recording candidate traits for expr) recording traits for {}",
|
||||
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);
|
||||
}
|
||||
_ => {
|
||||
|
@ -848,19 +848,16 @@ pub enum ExprKind {
|
||||
/// The first field resolves to the function itself,
|
||||
/// and the second field is the list of arguments
|
||||
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 vector of `Ty`s are the ascripted type parameters for the method
|
||||
/// The `PathSegment` represents the method name and its generic arguments
|
||||
/// (within the angle brackets).
|
||||
///
|
||||
/// 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),
|
||||
/// and the remaining elements are the rest of the arguments.
|
||||
///
|
||||
/// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
|
||||
/// `ExprKind::MethodCall(foo, [Bar, Baz], [x, a, b, c, d])`.
|
||||
MethodCall(SpannedIdent, Vec<P<Ty>>, Vec<P<Expr>>),
|
||||
/// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`.
|
||||
MethodCall(PathSegment, Vec<P<Expr>>),
|
||||
/// A tuple (`(a, b, c ,d)`)
|
||||
Tup(Vec<P<Expr>>),
|
||||
/// A binary operation (For example: `a + b`, `a * b`)
|
||||
|
@ -673,9 +673,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||
expr: P<ast::Expr>,
|
||||
ident: ast::Ident,
|
||||
mut args: Vec<P<ast::Expr>> ) -> P<ast::Expr> {
|
||||
let id = Spanned { node: ident, span: span };
|
||||
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> {
|
||||
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),
|
||||
folder.fold_exprs(args))
|
||||
}
|
||||
ExprKind::MethodCall(i, tps, args) => {
|
||||
ExprKind::MethodCall(seg, args) => {
|
||||
ExprKind::MethodCall(
|
||||
respan(folder.new_span(i.span), folder.fold_ident(i.node)),
|
||||
tps.move_map(|x| folder.fold_ty(x)),
|
||||
PathSegment {
|
||||
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))
|
||||
}
|
||||
ExprKind::Binary(binop, lhs, rhs) => {
|
||||
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use abi::{self, Abi};
|
||||
use ast::{AttrStyle, BareFnTy};
|
||||
use ast::{AngleBracketedParameterData, AttrStyle, BareFnTy};
|
||||
use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
|
||||
use ast::Unsafety;
|
||||
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 (lifetimes, types, bindings) = self.parse_generic_args()?;
|
||||
self.expect_gt()?;
|
||||
ast::AngleBracketedParameterData {
|
||||
lifetimes: lifetimes,
|
||||
types: types,
|
||||
bindings: bindings,
|
||||
}.into()
|
||||
AngleBracketedParameterData { lifetimes, types, bindings }.into()
|
||||
} else if self.eat(&token::OpenDelim(token::Paren)) {
|
||||
let lo = self.prev_span;
|
||||
|
||||
@ -1898,11 +1894,7 @@ impl<'a> Parser<'a> {
|
||||
segments.push(PathSegment {
|
||||
identifier: identifier,
|
||||
span: ident_span,
|
||||
parameters: ast::AngleBracketedParameterData {
|
||||
lifetimes: lifetimes,
|
||||
types: types,
|
||||
bindings: bindings,
|
||||
}.into(),
|
||||
parameters: AngleBracketedParameterData { lifetimes, types, bindings }.into(),
|
||||
});
|
||||
|
||||
// Consumed `a::b::<T,U>`, check for `::` before proceeding
|
||||
@ -2023,14 +2015,6 @@ impl<'a> Parser<'a> {
|
||||
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 {
|
||||
ExprKind::Index(expr, idx)
|
||||
}
|
||||
@ -2460,7 +2444,7 @@ impl<'a> Parser<'a> {
|
||||
// parsing into an expression.
|
||||
fn parse_dot_suffix(&mut self, ident: Ident, ident_span: Span, self_value: P<Expr>, lo: Span)
|
||||
-> PResult<'a, P<Expr>> {
|
||||
let (_, tys, bindings) = if self.eat(&token::ModSep) {
|
||||
let (lifetimes, types, bindings) = if self.eat(&token::ModSep) {
|
||||
self.expect_lt()?;
|
||||
let args = self.parse_generic_args()?;
|
||||
self.expect_gt()?;
|
||||
@ -2469,11 +2453,6 @@ impl<'a> Parser<'a> {
|
||||
(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 {
|
||||
// expr.f() method call.
|
||||
token::OpenDelim(token::Paren) => {
|
||||
@ -2486,17 +2465,20 @@ impl<'a> Parser<'a> {
|
||||
let hi = self.prev_span;
|
||||
|
||||
es.insert(0, self_value);
|
||||
let id = respan(ident_span.to(ident_span), ident);
|
||||
let nd = self.mk_method_call(id, tys, es);
|
||||
self.mk_expr(lo.to(hi), nd, ThinVec::new())
|
||||
let seg = PathSegment {
|
||||
identifier: ident,
|
||||
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.
|
||||
_ => {
|
||||
if !tys.is_empty() {
|
||||
let prev_span = self.prev_span;
|
||||
self.span_err(prev_span,
|
||||
"field expressions may not \
|
||||
have type parameters");
|
||||
if let Some(generic_arg_span) = lifetimes.get(0).map(|x| x.span).or_else(||
|
||||
types.get(0).map(|x| x.span)).or_else(||
|
||||
bindings.get(0).map(|x| x.span)) {
|
||||
self.span_err(generic_arg_span,
|
||||
"field expressions may not have generic arguments");
|
||||
}
|
||||
|
||||
let id = respan(ident_span.to(ident_span), ident);
|
||||
|
@ -1951,18 +1951,14 @@ impl<'a> State<'a> {
|
||||
}
|
||||
|
||||
fn print_expr_method_call(&mut self,
|
||||
ident: ast::SpannedIdent,
|
||||
tys: &[P<ast::Ty>],
|
||||
segment: &ast::PathSegment,
|
||||
args: &[P<ast::Expr>]) -> io::Result<()> {
|
||||
let base_args = &args[1..];
|
||||
self.print_expr(&args[0])?;
|
||||
word(&mut self.s, ".")?;
|
||||
self.print_ident(ident.node)?;
|
||||
if !tys.is_empty() {
|
||||
word(&mut self.s, "::<")?;
|
||||
self.commasep(Inconsistent, tys,
|
||||
|s, ty| s.print_type(ty))?;
|
||||
word(&mut self.s, ">")?;
|
||||
self.print_ident(segment.identifier)?;
|
||||
if let Some(ref parameters) = segment.parameters {
|
||||
self.print_path_parameters(parameters, true)?;
|
||||
}
|
||||
self.print_call_post(base_args)
|
||||
}
|
||||
@ -2041,8 +2037,8 @@ impl<'a> State<'a> {
|
||||
ast::ExprKind::Call(ref func, ref args) => {
|
||||
self.print_expr_call(func, &args[..])?;
|
||||
}
|
||||
ast::ExprKind::MethodCall(ident, ref tys, ref args) => {
|
||||
self.print_expr_method_call(ident, &tys[..], &args[..])?;
|
||||
ast::ExprKind::MethodCall(ref segment, ref args) => {
|
||||
self.print_expr_method_call(segment, &args[..])?;
|
||||
}
|
||||
ast::ExprKind::Binary(op, ref lhs, ref 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);
|
||||
walk_list!(visitor, visit_expr, arguments);
|
||||
}
|
||||
ExprKind::MethodCall(ref ident, ref types, ref arguments) => {
|
||||
visitor.visit_ident(ident.span, ident.node);
|
||||
walk_list!(visitor, visit_ty, types);
|
||||
ExprKind::MethodCall(ref segment, ref arguments) => {
|
||||
visitor.visit_path_segment(expression.span, segment);
|
||||
walk_list!(visitor, visit_expr, arguments);
|
||||
}
|
||||
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,
|
||||
};
|
||||
f.x::<isize>;
|
||||
//~^ ERROR field expressions may not have type parameters
|
||||
//~^ ERROR field expressions may not have generic arguments
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user