Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not consider method call receiver as an argument in AST. #100232

Merged
merged 2 commits into from
Aug 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1338,14 +1338,13 @@ pub enum ExprKind {
///
/// The `PathSegment` represents the method name and its generic arguments
/// (within the angle brackets).
/// The first element of the vector of an `Expr` 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(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`.
/// The standalone `Expr` is the receiver expression.
/// The vector of `Expr` is the arguments.
/// `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
/// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, x, [a, b, c, d])`.
/// This `Span` is the span of the function, without the dot and receiver
/// (e.g. `foo(a, b)` in `x.foo(a, b)`
MethodCall(PathSegment, Vec<P<Expr>>, Span),
MethodCall(PathSegment, P<Expr>, Vec<P<Expr>>, Span),
/// A tuple (e.g., `(a, b, c, d)`).
Tup(Vec<P<Expr>>),
/// A binary operation (e.g., `a + b`, `a * b`).
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1302,10 +1302,11 @@ pub fn noop_visit_expr<T: MutVisitor>(
vis.visit_expr(f);
visit_exprs(args, vis);
}
ExprKind::MethodCall(PathSegment { ident, id, args }, exprs, span) => {
ExprKind::MethodCall(PathSegment { ident, id, args }, receiver, exprs, span) => {
vis.visit_ident(ident);
vis.visit_id(id);
visit_opt(args, |args| vis.visit_generic_args(args));
vis.visit_expr(receiver);
visit_exprs(exprs, vis);
vis.visit_span(span);
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_ast/src/util/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,9 +396,9 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
contains_exterior_struct_lit(&x)
}

ast::ExprKind::MethodCall(.., ref exprs, _) => {
ast::ExprKind::MethodCall(_, ref receiver, _, _) => {
// X { y: 1 }.bar(...)
contains_exterior_struct_lit(&exprs[0])
contains_exterior_struct_lit(&receiver)
}

_ => false,
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -813,8 +813,9 @@ 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 segment, ref arguments, _span) => {
ExprKind::MethodCall(ref segment, ref receiver, ref arguments, _span) => {
visitor.visit_path_segment(expression.span, segment);
visitor.visit_expr(receiver);
walk_list!(visitor, visit_expr, arguments);
}
ExprKind::Binary(_, ref left_expression, ref right_expression) => {
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ExprKind::Call(f, self.lower_exprs(args))
}
}
ExprKind::MethodCall(ref seg, ref args, span) => {
ExprKind::MethodCall(ref seg, ref receiver, ref args, span) => {
let hir_seg = self.arena.alloc(self.lower_path_segment(
e.span,
seg,
ParamMode::Optional,
ParenthesizedGenericArgs::Err,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
));
let args = self.lower_exprs(args);
let args = self.arena.alloc_from_iter(
[&*receiver].into_iter().chain(args.iter()).map(|x| self.lower_expr_mut(x)),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given how much better the AST is from having the receiver be separate, it makes me wonder if HIR would benefit just as much…

);
hir::ExprKind::MethodCall(hir_seg, args, self.lower_span(span))
}
ExprKind::Binary(binop, ref lhs, ref rhs) => {
Expand Down
14 changes: 9 additions & 5 deletions compiler/rustc_ast_pretty/src/pprust/state/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,13 @@ impl<'a> State<'a> {
self.print_call_post(args)
}

fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) {
let base_args = &args[1..];
self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
fn print_expr_method_call(
&mut self,
segment: &ast::PathSegment,
receiver: &ast::Expr,
base_args: &[P<ast::Expr>],
) {
self.print_expr_maybe_paren(receiver, parser::PREC_POSTFIX);
self.word(".");
self.print_ident(segment.ident);
if let Some(ref args) = segment.args {
Expand Down Expand Up @@ -303,8 +307,8 @@ impl<'a> State<'a> {
ast::ExprKind::Call(ref func, ref args) => {
self.print_expr_call(func, &args);
}
ast::ExprKind::MethodCall(ref segment, ref args, _) => {
self.print_expr_method_call(segment, &args);
ast::ExprKind::MethodCall(ref segment, ref receiver, ref args, _) => {
self.print_expr_method_call(segment, &receiver, &args);
}
ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
self.print_expr_binary(op, lhs, rhs);
Expand Down
21 changes: 10 additions & 11 deletions compiler/rustc_builtin_macros/src/assert/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,8 @@ impl<'cx, 'a> Context<'cx, 'a> {
self.manage_cond_expr(prefix);
self.manage_cond_expr(suffix);
}
ExprKind::MethodCall(_, ref mut local_exprs, _) => {
for local_expr in local_exprs.iter_mut().skip(1) {
ExprKind::MethodCall(_, _,ref mut local_exprs, _) => {
for local_expr in local_exprs.iter_mut() {
self.manage_cond_expr(local_expr);
}
}
Expand Down Expand Up @@ -377,14 +377,12 @@ impl<'cx, 'a> Context<'cx, 'a> {
id: DUMMY_NODE_ID,
ident: Ident::new(sym::try_capture, self.span),
},
vec![
expr_paren(self.cx, self.span, self.cx.expr_addr_of(self.span, wrapper)),
expr_addr_of_mut(
self.cx,
self.span,
self.cx.expr_path(Path::from_ident(capture)),
),
],
expr_paren(self.cx, self.span, self.cx.expr_addr_of(self.span, wrapper)),
vec![expr_addr_of_mut(
self.cx,
self.span,
self.cx.expr_path(Path::from_ident(capture)),
)],
self.span,
))
.add_trailing_semicolon();
Expand Down Expand Up @@ -442,10 +440,11 @@ fn expr_addr_of_mut(cx: &ExtCtxt<'_>, sp: Span, e: P<Expr>) -> P<Expr> {
fn expr_method_call(
cx: &ExtCtxt<'_>,
path: PathSegment,
receiver: P<Expr>,
args: Vec<P<Expr>>,
span: Span,
) -> P<Expr> {
cx.expr(span, ExprKind::MethodCall(path, args, span))
cx.expr(span, ExprKind::MethodCall(path, receiver, args, span))
}

fn expr_paren(cx: &ExtCtxt<'_>, sp: Span, e: P<Expr>) -> P<Expr> {
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_lint/src/unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -608,8 +608,7 @@ trait UnusedDelimLint {
ref call_or_other => {
let (args_to_check, ctx) = match *call_or_other {
Call(_, ref args) => (&args[..], UnusedDelimsCtx::FunctionArg),
// first "argument" is self (which sometimes needs delims)
MethodCall(_, ref args, _) => (&args[1..], UnusedDelimsCtx::MethodArg),
MethodCall(_, _, ref args, _) => (&args[..], UnusedDelimsCtx::MethodArg),
// actual catch-all arm
_ => {
return;
Expand Down
12 changes: 7 additions & 5 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -850,7 +850,7 @@ impl<'a> Parser<'a> {
ExprKind::Index(_, _) => "indexing",
ExprKind::Try(_) => "`?`",
ExprKind::Field(_, _) => "a field access",
ExprKind::MethodCall(_, _, _) => "a method call",
ExprKind::MethodCall(_, _, _, _) => "a method call",
ExprKind::Call(_, _) => "a function call",
ExprKind::Await(_) => "`.await`",
ExprKind::Err => return Ok(with_postfix),
Expand Down Expand Up @@ -1280,12 +1280,14 @@ impl<'a> Parser<'a> {

if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
// Method call `expr.f()`
let mut args = self.parse_paren_expr_seq()?;
args.insert(0, self_arg);

let args = self.parse_paren_expr_seq()?;
let fn_span = fn_span_lo.to(self.prev_token.span);
let span = lo.to(self.prev_token.span);
Ok(self.mk_expr(span, ExprKind::MethodCall(segment, args, fn_span), AttrVec::new()))
Ok(self.mk_expr(
span,
ExprKind::MethodCall(segment, self_arg, args, fn_span),
AttrVec::new(),
))
} else {
// Field access `expr.f`
if let Some(args) = segment.args {
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3796,9 +3796,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
ExprKind::Field(ref subexpression, _) => {
self.resolve_expr(subexpression, Some(expr));
}
ExprKind::MethodCall(ref segment, ref arguments, _) => {
let mut arguments = arguments.iter();
self.resolve_expr(arguments.next().unwrap(), Some(expr));
ExprKind::MethodCall(ref segment, ref receiver, ref arguments, _) => {
self.resolve_expr(receiver, Some(expr));
for argument in arguments {
self.resolve_expr(argument, None);
}
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui-fulldeps/pprust-expr-roundtrip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
2 => {
let seg = PathSegment::from_ident(Ident::from_str("x"));
iter_exprs(depth - 1, &mut |e| {
g(ExprKind::MethodCall(seg.clone(), vec![e, make_x()], DUMMY_SP))
g(ExprKind::MethodCall(seg.clone(), e, vec![make_x()], DUMMY_SP))
});
iter_exprs(depth - 1, &mut |e| {
g(ExprKind::MethodCall(seg.clone(), vec![make_x(), e], DUMMY_SP))
g(ExprKind::MethodCall(seg.clone(), make_x(), vec![e], DUMMY_SP))
});
}
3..=8 => {
Expand Down
12 changes: 12 additions & 0 deletions src/test/ui/cfg/cfg-method-receiver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
macro_rules! cbor_map {
($key:expr) => {
$key.signum();
//~^ ERROR can't call method `signum` on ambiguous numeric type `{integer}` [E0689]
};
}

fn main() {
cbor_map! { #[cfg(test)] 4};
//~^ ERROR attributes on expressions are experimental
//~| ERROR removing an expression is not supported in this position
}
34 changes: 34 additions & 0 deletions src/test/ui/cfg/cfg-method-receiver.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
error[E0658]: attributes on expressions are experimental
--> $DIR/cfg-method-receiver.rs:9:17
|
LL | cbor_map! { #[cfg(test)] 4};
| ^^^^^^^^^^^^
|
= note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
= help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable

error: removing an expression is not supported in this position
--> $DIR/cfg-method-receiver.rs:9:17
|
LL | cbor_map! { #[cfg(test)] 4};
| ^^^^^^^^^^^^

error[E0689]: can't call method `signum` on ambiguous numeric type `{integer}`
--> $DIR/cfg-method-receiver.rs:3:14
|
LL | $key.signum();
| ^^^^^^
...
LL | cbor_map! { #[cfg(test)] 4};
| --------------------------- in this macro invocation
|
= note: this error originates in the macro `cbor_map` (in Nightly builds, run with -Z macro-backtrace for more info)
help: you must specify a concrete type for this numeric value, like `i32`
|
LL | cbor_map! { #[cfg(test)] 4_i32};
| ~~~~~

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0658, E0689.
For more information about an error, try `rustc --explain E0658`.
5 changes: 2 additions & 3 deletions src/tools/clippy/clippy_lints/src/double_parens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,8 @@ impl EarlyLintPass for DoubleParens {
}
}
},
ExprKind::MethodCall(_, ref params, _) => {
if params.len() == 2 {
let param = &params[1];
ExprKind::MethodCall(_, _, ref params, _) => {
if let [ref param] = params[..] {
if let ExprKind::Paren(_) = param.kind {
span_lint(cx, DOUBLE_PARENS, param.span, msg);
}
Expand Down
4 changes: 2 additions & 2 deletions src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ declare_lint_pass!(OptionEnvUnwrap => [OPTION_ENV_UNWRAP]);
impl EarlyLintPass for OptionEnvUnwrap {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
if_chain! {
if let ExprKind::MethodCall(path_segment, args, _) = &expr.kind;
if let ExprKind::MethodCall(path_segment, receiver, _, _) = &expr.kind;
if matches!(path_segment.ident.name, sym::expect | sym::unwrap);
if let ExprKind::Call(caller, _) = &args[0].kind;
if let ExprKind::Call(caller, _) = &receiver.kind;
if is_direct_expn_of(caller.span, "option_env").is_some();
then {
span_lint_and_help(
Expand Down
4 changes: 2 additions & 2 deletions src/tools/clippy/clippy_lints/src/precedence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,12 @@ impl EarlyLintPass for Precedence {
let mut arg = operand;

let mut all_odd = true;
while let ExprKind::MethodCall(path_segment, args, _) = &arg.kind {
while let ExprKind::MethodCall(path_segment, receiver, _, _) = &arg.kind {
let path_segment_str = path_segment.ident.name.as_str();
all_odd &= ALLOWED_ODD_FUNCTIONS
.iter()
.any(|odd_function| **odd_function == *path_segment_str);
arg = args.first().expect("A method always has a receiver.");
arg = receiver;
}

if_chain! {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ fn ident_difference_expr_with_base_location(
| (Unary(_, _), Unary(_, _))
| (Binary(_, _, _), Binary(_, _, _))
| (Tup(_), Tup(_))
| (MethodCall(_, _, _), MethodCall(_, _, _))
| (MethodCall(_, _, _, _), MethodCall(_, _, _, _))
| (Call(_, _), Call(_, _))
| (ConstBlock(_), ConstBlock(_))
| (Array(_), Array(_))
Expand Down
5 changes: 2 additions & 3 deletions src/tools/clippy/clippy_lints/src/unused_rounding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,10 @@ declare_clippy_lint! {
declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]);

fn is_useless_rounding(expr: &Expr) -> Option<(&str, String)> {
if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind
if let ExprKind::MethodCall(name_ident, receiver, _, _) = &expr.kind
&& let method_name = name_ident.ident.name.as_str()
&& (method_name == "ceil" || method_name == "round" || method_name == "floor")
&& !args.is_empty()
&& let ExprKind::Lit(spanned) = &args[0].kind
&& let ExprKind::Lit(spanned) = &receiver.kind
&& let LitKind::Float(symbol, ty) = spanned.kind {
let f = symbol.as_str().parse::<f64>().unwrap();
let f_str = symbol.to_string() + if let LitFloatType::Suffixed(ty) = ty {
Expand Down
4 changes: 3 additions & 1 deletion src/tools/clippy/clippy_utils/src/ast_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,9 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
(Array(l), Array(r)) | (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)),
(Repeat(le, ls), Repeat(re, rs)) => eq_expr(le, re) && eq_expr(&ls.value, &rs.value),
(Call(lc, la), Call(rc, ra)) => eq_expr(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)),
(MethodCall(lc, la, _), MethodCall(rc, ra, _)) => eq_path_seg(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)),
(MethodCall(lc, ls, la, _), MethodCall(rc, rs, ra, _)) => {
eq_path_seg(lc, rc) && eq_expr(ls, rs) && over(la, ra, |l, r| eq_expr(l, r))
},
(Binary(lo, ll, lr), Binary(ro, rl, rr)) => lo.node == ro.node && eq_expr(ll, rl) && eq_expr(lr, rr),
(Unary(lo, l), Unary(ro, r)) => mem::discriminant(lo) == mem::discriminant(ro) && eq_expr(l, r),
(Lit(l), Lit(r)) => l.kind == r.kind,
Expand Down
10 changes: 5 additions & 5 deletions src/tools/rustfmt/src/chains.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ impl ChainItemKind {

fn from_ast(context: &RewriteContext<'_>, expr: &ast::Expr) -> (ChainItemKind, Span) {
let (kind, span) = match expr.kind {
ast::ExprKind::MethodCall(ref segment, ref expressions, _) => {
ast::ExprKind::MethodCall(ref segment, ref receiver, ref expressions, _) => {
let types = if let Some(ref generic_args) = segment.args {
if let ast::GenericArgs::AngleBracketed(ref data) = **generic_args {
data.args
Expand All @@ -163,7 +163,7 @@ impl ChainItemKind {
} else {
vec![]
};
let span = mk_sp(expressions[0].span.hi(), expr.span.hi());
let span = mk_sp(receiver.span.hi(), expr.span.hi());
let kind = ChainItemKind::MethodCall(segment.clone(), types, expressions.clone());
(kind, span)
}
Expand Down Expand Up @@ -253,7 +253,7 @@ impl ChainItem {
format!("::<{}>", type_list.join(", "))
};
let callee_str = format!(".{}{}", rewrite_ident(context, method_name), type_str);
rewrite_call(context, &callee_str, &args[1..], span, shape)
rewrite_call(context, &callee_str, &args, span, shape)
}
}

Expand Down Expand Up @@ -400,8 +400,8 @@ impl Chain {
// is a try! macro, we'll convert it to shorthand when the option is set.
fn pop_expr_chain(expr: &ast::Expr, context: &RewriteContext<'_>) -> Option<ast::Expr> {
match expr.kind {
ast::ExprKind::MethodCall(_, ref expressions, _) => {
Some(Self::convert_try(&expressions[0], context))
ast::ExprKind::MethodCall(_, ref receiver, _, _) => {
Some(Self::convert_try(&receiver, context))
}
ast::ExprKind::Field(ref subexpr, _)
| ast::ExprKind::Try(ref subexpr)
Expand Down