Store all generic arguments for method calls in AST

This commit is contained in:
Vadim Petrochenkov 2017-07-07 02:39:55 +03:00
parent 8b1271fcdd
commit 287de2595a
11 changed files with 82 additions and 69 deletions

View File

@ -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) => &param_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);

View File

@ -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");
}
}
}
}
_ => {}
}

View File

@ -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);
}
_ => {

View File

@ -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`)

View File

@ -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))

View File

@ -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) => {

View File

@ -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);

View File

@ -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)?;

View File

@ -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) => {

View 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
}

View File

@ -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
}