summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_ast/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:11:38 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:13:23 +0000
commit20431706a863f92cb37dc512fef6e48d192aaf2c (patch)
tree2867f13f5fd5437ba628c67d7f87309ccadcd286 /compiler/rustc_ast/src
parentReleasing progress-linux version 1.65.0+dfsg1-2~progress7.99u1. (diff)
downloadrustc-20431706a863f92cb37dc512fef6e48d192aaf2c.tar.xz
rustc-20431706a863f92cb37dc512fef6e48d192aaf2c.zip
Merging upstream version 1.66.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_ast/src')
-rw-r--r--compiler/rustc_ast/src/ast.rs43
-rw-r--r--compiler/rustc_ast/src/lib.rs2
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs17
-rw-r--r--compiler/rustc_ast/src/token.rs49
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs150
-rw-r--r--compiler/rustc_ast/src/util/parser.rs4
-rw-r--r--compiler/rustc_ast/src/visit.rs24
7 files changed, 137 insertions, 152 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index d86db8f8b..4ef43735a 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1112,24 +1112,6 @@ pub struct Expr {
}
impl Expr {
- /// Returns `true` if this expression would be valid somewhere that expects a value;
- /// for example, an `if` condition.
- pub fn returns(&self) -> bool {
- if let ExprKind::Block(ref block, _) = self.kind {
- match block.stmts.last().map(|last_stmt| &last_stmt.kind) {
- // Implicit return
- Some(StmtKind::Expr(_)) => true,
- // Last statement is an explicit return?
- Some(StmtKind::Semi(expr)) => matches!(expr.kind, ExprKind::Ret(_)),
- // This is a block that doesn't end in either an implicit or explicit return.
- _ => false,
- }
- } else {
- // This is not a block, it is a value.
- true
- }
- }
-
/// Is this expr either `N`, or `{ N }`.
///
/// If this is not the case, name resolution does not resolve `N` when using
@@ -1338,14 +1320,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`).
@@ -2957,7 +2938,7 @@ pub enum AssocItemKind {
/// An associated function.
Fn(Box<Fn>),
/// An associated type.
- TyAlias(Box<TyAlias>),
+ Type(Box<TyAlias>),
/// A macro expanding to associated items.
MacCall(P<MacCall>),
}
@@ -2967,7 +2948,7 @@ impl AssocItemKind {
match *self {
Self::Const(defaultness, ..)
| Self::Fn(box Fn { defaultness, .. })
- | Self::TyAlias(box TyAlias { defaultness, .. }) => defaultness,
+ | Self::Type(box TyAlias { defaultness, .. }) => defaultness,
Self::MacCall(..) => Defaultness::Final,
}
}
@@ -2978,7 +2959,7 @@ impl From<AssocItemKind> for ItemKind {
match assoc_item_kind {
AssocItemKind::Const(a, b, c) => ItemKind::Const(a, b, c),
AssocItemKind::Fn(fn_kind) => ItemKind::Fn(fn_kind),
- AssocItemKind::TyAlias(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
+ AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
AssocItemKind::MacCall(a) => ItemKind::MacCall(a),
}
}
@@ -2991,7 +2972,7 @@ impl TryFrom<ItemKind> for AssocItemKind {
Ok(match item_kind {
ItemKind::Const(a, b, c) => AssocItemKind::Const(a, b, c),
ItemKind::Fn(fn_kind) => AssocItemKind::Fn(fn_kind),
- ItemKind::TyAlias(ty_alias_kind) => AssocItemKind::TyAlias(ty_alias_kind),
+ ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind),
ItemKind::MacCall(a) => AssocItemKind::MacCall(a),
_ => return Err(item_kind),
})
@@ -3043,14 +3024,13 @@ pub type ForeignItem = Item<ForeignItemKind>;
mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;
- // These are in alphabetical order, which is easy to maintain.
+ // tidy-alphabetical-start
static_assert_size!(AssocItem, 104);
static_assert_size!(AssocItemKind, 32);
static_assert_size!(Attribute, 32);
static_assert_size!(Block, 48);
static_assert_size!(Expr, 104);
static_assert_size!(ExprKind, 72);
- #[cfg(not(bootstrap))]
static_assert_size!(Fn, 184);
static_assert_size!(ForeignItem, 96);
static_assert_size!(ForeignItemKind, 24);
@@ -3065,11 +3045,12 @@ mod size_asserts {
static_assert_size!(Local, 72);
static_assert_size!(Param, 40);
static_assert_size!(Pat, 120);
- static_assert_size!(PatKind, 96);
static_assert_size!(Path, 40);
static_assert_size!(PathSegment, 24);
+ static_assert_size!(PatKind, 96);
static_assert_size!(Stmt, 32);
static_assert_size!(StmtKind, 16);
static_assert_size!(Ty, 96);
static_assert_size!(TyKind, 72);
+ // tidy-alphabetical-end
}
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index bd7a85b07..eeb7e56e2 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -13,9 +13,7 @@
#![feature(const_default_impls)]
#![feature(const_trait_impl)]
#![feature(if_let_guard)]
-#![cfg_attr(bootstrap, feature(label_break_value))]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(min_specialization)]
#![feature(negative_impls)]
#![feature(slice_internals)]
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 9fd0b63c4..b970e57e0 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -152,6 +152,12 @@ pub trait MutVisitor: Sized {
noop_visit_expr(e, self);
}
+ /// This method is a hack to workaround unstable of `stmt_expr_attributes`.
+ /// It can be removed once that feature is stabilized.
+ fn visit_method_receiver_expr(&mut self, ex: &mut P<Expr>) {
+ self.visit_expr(ex)
+ }
+
fn filter_map_expr(&mut self, e: P<Expr>) -> Option<P<Expr>> {
noop_filter_map_expr(e, self)
}
@@ -1106,7 +1112,7 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
visit_fn_sig(sig, visitor);
visit_opt(body, |body| visitor.visit_block(body));
}
- AssocItemKind::TyAlias(box TyAlias {
+ AssocItemKind::Type(box TyAlias {
defaultness,
generics,
where_clauses,
@@ -1297,10 +1303,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_method_receiver_expr(receiver);
visit_exprs(exprs, vis);
vis.visit_span(span);
}
@@ -1588,3 +1595,9 @@ impl DummyAstNode for Crate {
}
}
}
+
+impl<N: DummyAstNode, T: DummyAstNode> DummyAstNode for crate::ast_traits::AstNodeWrapper<N, T> {
+ fn dummy() -> Self {
+ crate::ast_traits::AstNodeWrapper::new(N::dummy(), T::dummy())
+ }
+}
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 97dfb7837..83b10d906 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -13,7 +13,7 @@ use rustc_span::symbol::{kw, sym};
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{self, edition::Edition, Span, DUMMY_SP};
use std::borrow::Cow;
-use std::{fmt, mem};
+use std::fmt;
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum CommentKind {
@@ -256,10 +256,6 @@ pub enum TokenKind {
Eof,
}
-// `TokenKind` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(TokenKind, 16);
-
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct Token {
pub kind: TokenKind,
@@ -335,11 +331,6 @@ impl Token {
Token::new(Ident(ident.name, ident.is_raw_guess()), ident.span)
}
- /// Return this token by value and leave a dummy token in its place.
- pub fn take(&mut self) -> Self {
- mem::replace(self, Token::dummy())
- }
-
/// For interpolated tokens, returns a span of the fragment to which the interpolated
/// token refers. For all other tokens this is just a regular span.
/// It is particularly important to use this for identifiers and lifetimes
@@ -354,17 +345,14 @@ impl Token {
}
pub fn is_op(&self) -> bool {
- !matches!(
- self.kind,
- OpenDelim(..)
- | CloseDelim(..)
- | Literal(..)
- | DocComment(..)
- | Ident(..)
- | Lifetime(..)
- | Interpolated(..)
- | Eof
- )
+ match self.kind {
+ Eq | Lt | Le | EqEq | Ne | Ge | Gt | AndAnd | OrOr | Not | Tilde | BinOp(_)
+ | BinOpEq(_) | At | Dot | DotDot | DotDotDot | DotDotEq | Comma | Semi | Colon
+ | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | SingleQuote => true,
+
+ OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
+ | Lifetime(..) | Interpolated(..) | Eof => false,
+ }
}
pub fn is_like_plus(&self) -> bool {
@@ -733,6 +721,7 @@ impl Token {
}
impl PartialEq<TokenKind> for Token {
+ #[inline]
fn eq(&self, rhs: &TokenKind) -> bool {
self.kind == *rhs
}
@@ -756,10 +745,6 @@ pub enum Nonterminal {
NtVis(P<ast::Visibility>),
}
-// `Nonterminal` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Nonterminal, 16);
-
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)]
pub enum NonterminalKind {
Item,
@@ -898,3 +883,17 @@ where
panic!("interpolated tokens should not be present in the HIR")
}
}
+
+// Some types are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+ use super::*;
+ use rustc_data_structures::static_assert_size;
+ // tidy-alphabetical-start
+ static_assert_size!(Lit, 12);
+ static_assert_size!(LitKind, 2);
+ static_assert_size!(Nonterminal, 16);
+ static_assert_size!(Token, 24);
+ static_assert_size!(TokenKind, 16);
+ // tidy-alphabetical-end
+}
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 875cd620d..015f5c1ee 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -47,10 +47,6 @@ pub enum TokenTree {
Delimited(DelimSpan, Delimiter, TokenStream),
}
-// This type is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(TokenTree, 32);
-
// Ensure all fields of `TokenTree` is `Send` and `Sync`.
#[cfg(parallel_compiler)]
fn _dummy()
@@ -249,12 +245,12 @@ impl AttrTokenStream {
// properly implemented - we always synthesize fake tokens,
// so we never reach this code.
- let mut builder = TokenStreamBuilder::new();
+ let mut stream = TokenStream::default();
for inner_attr in inner_attrs {
- builder.push(inner_attr.tokens());
+ stream.push_stream(inner_attr.tokens());
}
- builder.push(delim_tokens.clone());
- *tree = TokenTree::Delimited(*span, *delim, builder.build());
+ stream.push_stream(delim_tokens.clone());
+ *tree = TokenTree::Delimited(*span, *delim, stream);
found = true;
break;
}
@@ -308,13 +304,20 @@ pub struct AttributesData {
#[derive(Clone, Debug, Default, Encodable, Decodable)]
pub struct TokenStream(pub(crate) Lrc<Vec<TokenTree>>);
-// `TokenStream` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(TokenStream, 8);
-
+/// Similar to `proc_macro::Spacing`, but for tokens.
+///
+/// Note that all `ast::TokenTree::Token` instances have a `Spacing`, but when
+/// we convert to `proc_macro::TokenTree` for proc macros only `Punct`
+/// `TokenTree`s have a `proc_macro::Spacing`.
#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
pub enum Spacing {
+ /// The token is not immediately followed by an operator token (as
+ /// determined by `Token::is_op`). E.g. a `+` token is `Alone` in `+ =`,
+ /// `+/*foo*/=`, `+ident`, and `+()`.
Alone,
+
+ /// The token is immediately followed by an operator token. E.g. a `+`
+ /// token is `Joint` in `+=` and `++`.
Joint,
}
@@ -502,76 +505,49 @@ impl TokenStream {
self.trees().map(|tree| TokenStream::flatten_token_tree(tree)).collect()
}
-}
-// 99.5%+ of the time we have 1 or 2 elements in this vector.
-#[derive(Clone)]
-pub struct TokenStreamBuilder(SmallVec<[TokenStream; 2]>);
-
-impl TokenStreamBuilder {
- pub fn new() -> TokenStreamBuilder {
- TokenStreamBuilder(SmallVec::new())
- }
-
- pub fn push(&mut self, stream: TokenStream) {
- self.0.push(stream);
- }
-
- pub fn build(self) -> TokenStream {
- let mut streams = self.0;
- match streams.len() {
- 0 => TokenStream::default(),
- 1 => streams.pop().unwrap(),
- _ => {
- // We will extend the first stream in `streams` with the
- // elements from the subsequent streams. This requires using
- // `make_mut()` on the first stream, and in practice this
- // doesn't cause cloning 99.9% of the time.
- //
- // One very common use case is when `streams` has two elements,
- // where the first stream has any number of elements within
- // (often 1, but sometimes many more) and the second stream has
- // a single element within.
-
- // Determine how much the first stream will be extended.
- // Needed to avoid quadratic blow up from on-the-fly
- // reallocations (#57735).
- let num_appends = streams.iter().skip(1).map(|ts| ts.len()).sum();
-
- // Get the first stream, which will become the result stream.
- // If it's `None`, create an empty stream.
- let mut iter = streams.into_iter();
- let mut res_stream_lrc = iter.next().unwrap().0;
-
- // Append the subsequent elements to the result stream, after
- // reserving space for them.
- let res_vec_mut = Lrc::make_mut(&mut res_stream_lrc);
- res_vec_mut.reserve(num_appends);
- for stream in iter {
- let stream_iter = stream.0.iter().cloned();
-
- // If (a) `res_mut_vec` is not empty and the last tree
- // within it is a token tree marked with `Joint`, and (b)
- // `stream` is not empty and the first tree within it is a
- // token tree, and (c) the two tokens can be glued
- // together...
- if let Some(TokenTree::Token(last_tok, Spacing::Joint)) = res_vec_mut.last()
- && let Some(TokenTree::Token(tok, spacing)) = stream.0.first()
- && let Some(glued_tok) = last_tok.glue(&tok)
- {
- // ...then overwrite the last token tree in
- // `res_vec_mut` with the glued token, and skip the
- // first token tree from `stream`.
- *res_vec_mut.last_mut().unwrap() = TokenTree::Token(glued_tok, *spacing);
- res_vec_mut.extend(stream_iter.skip(1));
- } else {
- // Append all of `stream`.
- res_vec_mut.extend(stream_iter);
- }
- }
+ // If `vec` is not empty, try to glue `tt` onto its last token. The return
+ // value indicates if gluing took place.
+ fn try_glue_to_last(vec: &mut Vec<TokenTree>, tt: &TokenTree) -> bool {
+ if let Some(TokenTree::Token(last_tok, Spacing::Joint)) = vec.last()
+ && let TokenTree::Token(tok, spacing) = tt
+ && let Some(glued_tok) = last_tok.glue(&tok)
+ {
+ // ...then overwrite the last token tree in `vec` with the
+ // glued token, and skip the first token tree from `stream`.
+ *vec.last_mut().unwrap() = TokenTree::Token(glued_tok, *spacing);
+ true
+ } else {
+ false
+ }
+ }
- TokenStream(res_stream_lrc)
- }
+ // Push `tt` onto the end of the stream, possibly gluing it to the last
+ // token. Uses `make_mut` to maximize efficiency.
+ pub fn push_tree(&mut self, tt: TokenTree) {
+ let vec_mut = Lrc::make_mut(&mut self.0);
+
+ if Self::try_glue_to_last(vec_mut, &tt) {
+ // nothing else to do
+ } else {
+ vec_mut.push(tt);
+ }
+ }
+
+ // Push `stream` onto the end of the stream, possibly gluing the first
+ // token tree to the last token. (No other token trees will be glued.)
+ // Uses `make_mut` to maximize efficiency.
+ pub fn push_stream(&mut self, stream: TokenStream) {
+ let vec_mut = Lrc::make_mut(&mut self.0);
+
+ let stream_iter = stream.0.iter().cloned();
+
+ if let Some(first) = stream.0.first() && Self::try_glue_to_last(vec_mut, first) {
+ // Now skip the first token tree from `stream`.
+ vec_mut.extend(stream_iter.skip(1));
+ } else {
+ // Append all of `stream`.
+ vec_mut.extend(stream_iter);
}
}
}
@@ -664,3 +640,17 @@ impl DelimSpan {
self.open.with_hi(self.close.hi())
}
}
+
+// Some types are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+ use super::*;
+ use rustc_data_structures::static_assert_size;
+ // tidy-alphabetical-start
+ static_assert_size!(AttrTokenStream, 8);
+ static_assert_size!(AttrTokenTree, 32);
+ static_assert_size!(LazyAttrTokenStream, 8);
+ static_assert_size!(TokenStream, 8);
+ static_assert_size!(TokenTree, 32);
+ // tidy-alphabetical-end
+}
diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs
index 6c5c7f66f..b40ad6f70 100644
--- a/compiler/rustc_ast/src/util/parser.rs
+++ b/compiler/rustc_ast/src/util/parser.rs
@@ -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,
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 1d0de5a4b..6f56c1ef0 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -140,6 +140,11 @@ pub trait Visitor<'ast>: Sized {
fn visit_expr(&mut self, ex: &'ast Expr) {
walk_expr(self, ex)
}
+ /// This method is a hack to workaround unstable of `stmt_expr_attributes`.
+ /// It can be removed once that feature is stabilized.
+ fn visit_method_receiver_expr(&mut self, ex: &'ast Expr) {
+ self.visit_expr(ex)
+ }
fn visit_expr_post(&mut self, _ex: &'ast Expr) {}
fn visit_ty(&mut self, t: &'ast Ty) {
walk_ty(self, t)
@@ -244,14 +249,12 @@ pub trait Visitor<'ast>: Sized {
#[macro_export]
macro_rules! walk_list {
- ($visitor: expr, $method: ident, $list: expr) => {
- for elem in $list {
- $visitor.$method(elem)
- }
- };
- ($visitor: expr, $method: ident, $list: expr, $($extra_args: expr),*) => {
- for elem in $list {
- $visitor.$method(elem, $($extra_args,)*)
+ ($visitor: expr, $method: ident, $list: expr $(, $($extra_args: expr),* )?) => {
+ {
+ #[cfg_attr(not(bootstrap), allow(for_loops_over_fallibles))]
+ for elem in $list {
+ $visitor.$method(elem $(, $($extra_args,)* )?)
+ }
}
}
}
@@ -685,7 +688,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref());
visitor.visit_fn(kind, span, id);
}
- AssocItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
+ AssocItemKind::Type(box TyAlias { generics, bounds, ty, .. }) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
walk_list!(visitor, visit_ty, ty);
@@ -795,8 +798,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(segment);
+ visitor.visit_expr(receiver);
walk_list!(visitor, visit_expr, arguments);
}
ExprKind::Binary(_, ref left_expression, ref right_expression) => {