separate the receiver from arguments in HIR

This commit is contained in:
Takayuki Maeda 2022-09-01 13:27:31 +09:00
parent 6e4a9ab650
commit 87c6da363f
27 changed files with 115 additions and 96 deletions

View file

@ -68,10 +68,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
ParenthesizedGenericArgs::Err, ParenthesizedGenericArgs::Err,
ImplTraitContext::Disallowed(ImplTraitPosition::Path), ImplTraitContext::Disallowed(ImplTraitPosition::Path),
)); ));
let args = self.arena.alloc_from_iter( let receiver = self.lower_expr(receiver);
[&*receiver].into_iter().chain(args.iter()).map(|x| self.lower_expr_mut(x)), let args =
); self.arena.alloc_from_iter(args.iter().map(|x| self.lower_expr_mut(x)));
hir::ExprKind::MethodCall(hir_seg, args, self.lower_span(span)) hir::ExprKind::MethodCall(hir_seg, receiver, args, self.lower_span(span))
} }
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);

View file

@ -711,8 +711,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
self.suggested = true; self.suggested = true;
} else if let hir::ExprKind::MethodCall(_path, args @ [_, ..], sp) = expr.kind } else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind
&& let hir::ExprKind::Index(val, index) = args[0].kind && let hir::ExprKind::Index(val, index) = receiver.kind
&& expr.span == self.assign_span && expr.span == self.assign_span
{ {
// val[index].path(args..); // val[index].path(args..);
@ -724,7 +724,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
".get_mut(".to_string(), ".get_mut(".to_string(),
), ),
( (
index.span.shrink_to_hi().with_hi(args[0].span.hi()), index.span.shrink_to_hi().with_hi(receiver.span.hi()),
").map(|val| val".to_string(), ").map(|val| val".to_string(),
), ),
(sp.shrink_to_hi(), ")".to_string()), (sp.shrink_to_hi(), ")".to_string()),
@ -911,11 +911,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
[ [
Expr { Expr {
kind: kind:
MethodCall( MethodCall(path_segment, _, _, span),
path_segment,
_args,
span,
),
hir_id, hir_id,
.. ..
}, },

View file

@ -901,13 +901,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
match expr.kind { match expr.kind {
hir::ExprKind::MethodCall(.., args, _) => { hir::ExprKind::MethodCall(.., args, _) => {
// only the first closre parameter of the method. args[0] is MethodCall PathSegment // only the first closre parameter of the method. args[0] is MethodCall PathSegment
for i in 1..args.len() {
for arg in args {
if let hir::ExprKind::Closure(hir::Closure { if let hir::ExprKind::Closure(hir::Closure {
capture_clause: hir::CaptureBy::Ref, capture_clause: hir::CaptureBy::Ref,
.. ..
}) = args[i].kind }) = arg.kind {
{ closure_span = Some(arg.span.shrink_to_lo());
closure_span = Some(args[i].span.shrink_to_lo());
break; break;
} }
} }

View file

@ -1893,7 +1893,7 @@ pub enum ExprKind<'hir> {
/// the `hir_id` of the `MethodCall` node itself. /// the `hir_id` of the `MethodCall` node itself.
/// ///
/// [`type_dependent_def_id`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.type_dependent_def_id /// [`type_dependent_def_id`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.type_dependent_def_id
MethodCall(&'hir PathSegment<'hir>, &'hir [Expr<'hir>], Span), MethodCall(&'hir PathSegment<'hir>, &'hir Expr<'hir>, &'hir [Expr<'hir>], Span),
/// A tuple (e.g., `(a, b, c, d)`). /// A tuple (e.g., `(a, b, c, d)`).
Tup(&'hir [Expr<'hir>]), Tup(&'hir [Expr<'hir>]),
/// A binary operation (e.g., `a + b`, `a * b`). /// A binary operation (e.g., `a + b`, `a * b`).
@ -3497,7 +3497,7 @@ mod size_asserts {
// These are in alphabetical order, which is easy to maintain. // These are in alphabetical order, which is easy to maintain.
static_assert_size!(Block<'_>, 48); static_assert_size!(Block<'_>, 48);
static_assert_size!(Body<'_>, 32); static_assert_size!(Body<'_>, 32);
static_assert_size!(Expr<'_>, 56); static_assert_size!(Expr<'_>, 64);
static_assert_size!(ExprKind<'_>, 40); static_assert_size!(ExprKind<'_>, 40);
static_assert_size!(FnDecl<'_>, 40); static_assert_size!(FnDecl<'_>, 40);
static_assert_size!(ForeignItem<'_>, 72); static_assert_size!(ForeignItem<'_>, 72);

View file

@ -1094,8 +1094,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
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 segment, arguments, _) => { ExprKind::MethodCall(ref segment, receiver, arguments, _) => {
visitor.visit_path_segment(expression.span, segment); visitor.visit_path_segment(expression.span, segment);
visitor.visit_expr(receiver);
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) => {

View file

@ -1181,9 +1181,14 @@ impl<'a> State<'a> {
self.print_call_post(args) self.print_call_post(args)
} }
fn print_expr_method_call(&mut self, segment: &hir::PathSegment<'_>, args: &[hir::Expr<'_>]) { fn print_expr_method_call(
let base_args = &args[1..]; &mut self,
self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX); segment: &hir::PathSegment<'_>,
receiver: &hir::Expr<'_>,
args: &[hir::Expr<'_>],
) {
let base_args = args;
self.print_expr_maybe_paren(&receiver, parser::PREC_POSTFIX);
self.word("."); self.word(".");
self.print_ident(segment.ident); self.print_ident(segment.ident);
@ -1394,8 +1399,8 @@ impl<'a> State<'a> {
hir::ExprKind::Call(func, args) => { hir::ExprKind::Call(func, args) => {
self.print_expr_call(func, args); self.print_expr_call(func, args);
} }
hir::ExprKind::MethodCall(segment, args, _) => { hir::ExprKind::MethodCall(segment, receiver, args, _) => {
self.print_expr_method_call(segment, args); self.print_expr_method_call(segment, receiver, args);
} }
hir::ExprKind::Binary(op, lhs, rhs) => { hir::ExprKind::Binary(op, lhs, rhs) => {
self.print_expr_binary(op, lhs, rhs); self.print_expr_binary(op, lhs, rhs);
@ -2413,9 +2418,9 @@ fn contains_exterior_struct_lit(value: &hir::Expr<'_>) -> bool {
contains_exterior_struct_lit(x) contains_exterior_struct_lit(x)
} }
hir::ExprKind::MethodCall(.., exprs, _) => { hir::ExprKind::MethodCall(_, receiver, ..) => {
// `X { y: 1 }.bar(...)` // `X { y: 1 }.bar(...)`
contains_exterior_struct_lit(&exprs[0]) contains_exterior_struct_lit(receiver)
} }
_ => false, _ => false,

View file

@ -901,7 +901,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
} }
} }
} }
hir::ExprKind::MethodCall(segment, _, _) => { hir::ExprKind::MethodCall(segment, ..) => {
if let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) { if let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) {
let generics = tcx.generics_of(def_id); let generics = tcx.generics_of(def_id);
let insertable: Option<_> = try { let insertable: Option<_> = try {
@ -1132,7 +1132,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
let generic_args = &generics.own_substs_no_defaults(tcx, substs) let generic_args = &generics.own_substs_no_defaults(tcx, substs)
[generics.own_counts().lifetimes..]; [generics.own_counts().lifetimes..];
let span = match expr.kind { let span = match expr.kind {
ExprKind::MethodCall(path, _, _) => path.ident.span, ExprKind::MethodCall(path, ..) => path.ident.span,
_ => expr.span, _ => expr.span,
}; };
@ -1181,7 +1181,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
}) })
.any(|generics| generics.has_impl_trait()) .any(|generics| generics.has_impl_trait())
}; };
if let ExprKind::MethodCall(path, args, span) = expr.kind if let ExprKind::MethodCall(path, receiver, args, span) = expr.kind
&& let Some(substs) = self.node_substs_opt(expr.hir_id) && let Some(substs) = self.node_substs_opt(expr.hir_id)
&& substs.iter().any(|arg| self.generic_arg_contains_target(arg)) && substs.iter().any(|arg| self.generic_arg_contains_target(arg))
&& let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) && let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id)
@ -1189,12 +1189,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
&& !has_impl_trait(def_id) && !has_impl_trait(def_id)
{ {
let successor = let successor =
args.get(1).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo())); args.get(0).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo()));
let substs = self.infcx.resolve_vars_if_possible(substs); let substs = self.infcx.resolve_vars_if_possible(substs);
self.update_infer_source(InferSource { self.update_infer_source(InferSource {
span: path.ident.span, span: path.ident.span,
kind: InferSourceKind::FullyQualifiedMethodCall { kind: InferSourceKind::FullyQualifiedMethodCall {
receiver: args.first().unwrap(), receiver,
successor, successor,
substs, substs,
def_id, def_id,

View file

@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
} }
// We only care about method call expressions. // We only care about method call expressions.
if let hir::ExprKind::MethodCall(call, args, _) = &expr.kind { if let hir::ExprKind::MethodCall(call, receiver, ..) = &expr.kind {
if call.ident.name != sym::into_iter { if call.ident.name != sym::into_iter {
return; return;
} }
@ -75,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
}; };
// As this is a method call expression, we have at least one argument. // As this is a method call expression, we have at least one argument.
let receiver_arg = &args[0]; let receiver_arg = receiver;
let receiver_ty = cx.typeck_results().expr_ty(receiver_arg); let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
let adjustments = cx.typeck_results().expr_adjustments(receiver_arg); let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);

View file

@ -2412,13 +2412,13 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
_ => {} _ => {}
} }
} }
} else if let hir::ExprKind::MethodCall(_, ref args, _) = expr.kind { } else if let hir::ExprKind::MethodCall(_, receiver, ..) = expr.kind {
// Find problematic calls to `MaybeUninit::assume_init`. // Find problematic calls to `MaybeUninit::assume_init`.
let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) { if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
// This is a call to *some* method named `assume_init`. // This is a call to *some* method named `assume_init`.
// See if the `self` parameter is one of the dangerous constructors. // See if the `self` parameter is one of the dangerous constructors.
if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind { if let hir::ExprKind::Call(ref path_expr, _) = receiver.kind {
if let hir::ExprKind::Path(ref qpath) = path_expr.kind { if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?; let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
match cx.tcx.get_diagnostic_name(def_id) { match cx.tcx.get_diagnostic_name(def_id) {

View file

@ -51,7 +51,7 @@ fn typeck_results_of_method_fn<'tcx>(
expr: &Expr<'_>, expr: &Expr<'_>,
) -> Option<(Span, DefId, ty::subst::SubstsRef<'tcx>)> { ) -> Option<(Span, DefId, ty::subst::SubstsRef<'tcx>)> {
match expr.kind { match expr.kind {
ExprKind::MethodCall(segment, _, _) ExprKind::MethodCall(segment, ..)
if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) =>
{ {
Some((segment.ident.span, def_id, cx.typeck_results().node_substs(expr.hir_id))) Some((segment.ident.span, def_id, cx.typeck_results().node_substs(expr.hir_id)))

View file

@ -44,9 +44,13 @@ fn in_macro(span: Span) -> bool {
fn first_method_call<'tcx>( fn first_method_call<'tcx>(
expr: &'tcx Expr<'tcx>, expr: &'tcx Expr<'tcx>,
) -> Option<(&'tcx PathSegment<'tcx>, &'tcx [Expr<'tcx>])> { ) -> Option<(&'tcx PathSegment<'tcx>, &'tcx Expr<'tcx>)> {
if let ExprKind::MethodCall(path, args, _) = &expr.kind { if let ExprKind::MethodCall(path, receiver, args, ..) = &expr.kind {
if args.iter().any(|e| e.span.from_expansion()) { None } else { Some((path, *args)) } if args.iter().any(|e| e.span.from_expansion()) || receiver.span.from_expansion() {
None
} else {
Some((path, *receiver))
}
} else { } else {
None None
} }
@ -59,14 +63,14 @@ impl<'tcx> LateLintPass<'tcx> for TemporaryCStringAsPtr {
} }
match first_method_call(expr) { match first_method_call(expr) {
Some((path, args)) if path.ident.name == sym::as_ptr => { Some((path, receiver)) if path.ident.name == sym::as_ptr => {
let unwrap_arg = &args[0]; let unwrap_arg = receiver;
let as_ptr_span = path.ident.span; let as_ptr_span = path.ident.span;
match first_method_call(unwrap_arg) { match first_method_call(unwrap_arg) {
Some((path, args)) Some((path, receiver))
if path.ident.name == sym::unwrap || path.ident.name == sym::expect => if path.ident.name == sym::unwrap || path.ident.name == sym::expect =>
{ {
let source_arg = &args[0]; let source_arg = receiver;
lint_cstring_as_ptr(cx, as_ptr_span, source_arg, unwrap_arg); lint_cstring_as_ptr(cx, as_ptr_span, source_arg, unwrap_arg);
} }
_ => return, _ => return,

View file

@ -41,7 +41,7 @@ declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]);
impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// We only care about method calls. // We only care about method calls.
let ExprKind::MethodCall(call, elements, _) = &expr.kind else { let ExprKind::MethodCall(call, receiver, ..) = &expr.kind else {
return return
}; };
// We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow` // We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
@ -81,7 +81,6 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
) { ) {
return; return;
} }
let receiver = &elements[0];
let receiver_ty = cx.typeck_results().expr_ty(receiver); let receiver_ty = cx.typeck_results().expr_ty(receiver);
let expr_ty = cx.typeck_results().expr_ty_adjusted(expr); let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
if receiver_ty != expr_ty { if receiver_ty != expr_ty {

View file

@ -1458,7 +1458,7 @@ impl InvalidAtomicOrdering {
sym::AtomicI64, sym::AtomicI64,
sym::AtomicI128, sym::AtomicI128,
]; ];
if let ExprKind::MethodCall(ref method_path, args, _) = &expr.kind if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind
&& recognized_names.contains(&method_path.ident.name) && recognized_names.contains(&method_path.ident.name)
&& let Some(m_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && let Some(m_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
&& let Some(impl_did) = cx.tcx.impl_of_method(m_def_id) && let Some(impl_did) = cx.tcx.impl_of_method(m_def_id)
@ -1494,8 +1494,8 @@ impl InvalidAtomicOrdering {
fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) { fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store]) if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store])
&& let Some((ordering_arg, invalid_ordering)) = match method { && let Some((ordering_arg, invalid_ordering)) = match method {
sym::load => Some((&args[1], sym::Release)), sym::load => Some((&args[0], sym::Release)),
sym::store => Some((&args[2], sym::Acquire)), sym::store => Some((&args[1], sym::Acquire)),
_ => None, _ => None,
} }
&& let Some(ordering) = Self::match_ordering(cx, ordering_arg) && let Some(ordering) = Self::match_ordering(cx, ordering_arg)
@ -1536,8 +1536,8 @@ impl InvalidAtomicOrdering {
else {return }; else {return };
let fail_order_arg = match method { let fail_order_arg = match method {
sym::fetch_update => &args[2], sym::fetch_update => &args[1],
sym::compare_exchange | sym::compare_exchange_weak => &args[4], sym::compare_exchange | sym::compare_exchange_weak => &args[3],
_ => return, _ => return,
}; };

View file

@ -261,15 +261,18 @@ impl<'tcx> Cx<'tcx> {
let kind = match expr.kind { let kind = match expr.kind {
// Here comes the interesting stuff: // Here comes the interesting stuff:
hir::ExprKind::MethodCall(segment, ref args, fn_span) => { hir::ExprKind::MethodCall(segment, receiver, ref args, fn_span) => {
// Rewrite a.b(c) into UFCS form like Trait::b(a, c) // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
let expr = self.method_callee(expr, segment.ident.span, None); let expr = self.method_callee(expr, segment.ident.span, None);
// When we apply adjustments to the receiver, use the span of // When we apply adjustments to the receiver, use the span of
// the overall method call for better diagnostics. args[0] // the overall method call for better diagnostics. args[0]
// is guaranteed to exist, since a method call always has a receiver. // is guaranteed to exist, since a method call always has a receiver.
let old_adjustment_span = self.adjustment_span.replace((args[0].hir_id, expr_span)); let old_adjustment_span = self.adjustment_span.replace((receiver.hir_id, expr_span));
info!("Using method span: {:?}", expr.span); info!("Using method span: {:?}", expr.span);
let args = self.mirror_exprs(args); let args = std::iter::once(receiver)
.chain(args.iter())
.map(|expr| self.mirror_expr(expr))
.collect();
self.adjustment_span = old_adjustment_span; self.adjustment_span = old_adjustment_span;
ExprKind::Call { ExprKind::Call {
ty: expr.ty, ty: expr.ty,

View file

@ -1039,9 +1039,12 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
self.propagate_through_expr(&f, succ) self.propagate_through_expr(&f, succ)
} }
hir::ExprKind::MethodCall(.., ref args, _) => { hir::ExprKind::MethodCall(.., receiver, ref args, _) => {
let succ = self.check_is_ty_uninhabited(expr, succ); let succ = self.check_is_ty_uninhabited(expr, succ);
self.propagate_through_exprs(args, succ) std::iter::once(receiver)
.chain(args.iter())
.rev()
.fold(succ, |succ, expr| self.propagate_through_expr(expr, succ))
} }
hir::ExprKind::Tup(ref exprs) => self.propagate_through_exprs(exprs, succ), hir::ExprKind::Tup(ref exprs) => self.propagate_through_exprs(exprs, succ),

View file

@ -803,6 +803,7 @@ impl<'tcx> DumpVisitor<'tcx> {
&mut self, &mut self,
ex: &'tcx hir::Expr<'tcx>, ex: &'tcx hir::Expr<'tcx>,
seg: &'tcx hir::PathSegment<'tcx>, seg: &'tcx hir::PathSegment<'tcx>,
receiver: &'tcx hir::Expr<'tcx>,
args: &'tcx [hir::Expr<'tcx>], args: &'tcx [hir::Expr<'tcx>],
) { ) {
debug!("process_method_call {:?} {:?}", ex, ex.span); debug!("process_method_call {:?} {:?}", ex, ex.span);
@ -823,6 +824,7 @@ impl<'tcx> DumpVisitor<'tcx> {
} }
// walk receiver and args // walk receiver and args
self.visit_expr(receiver);
walk_list!(self, visit_expr, args); walk_list!(self, visit_expr, args);
} }
@ -1340,7 +1342,9 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
let res = self.save_ctxt.get_path_res(hir_expr.hir_id); let res = self.save_ctxt.get_path_res(hir_expr.hir_id);
self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), *rest) self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), *rest)
} }
hir::ExprKind::MethodCall(ref seg, args, _) => self.process_method_call(ex, seg, args), hir::ExprKind::MethodCall(ref seg, receiver, args, _) => {
self.process_method_call(ex, seg, receiver, args)
}
hir::ExprKind::Field(ref sub_ex, _) => { hir::ExprKind::Field(ref sub_ex, _) => {
self.visit_expr(&sub_ex); self.visit_expr(&sub_ex);

View file

@ -590,7 +590,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let closure_params_len = closure_fn_decl.inputs.len(); let closure_params_len = closure_fn_decl.inputs.len();
let ( let (
Some(Node::Expr(hir::Expr { Some(Node::Expr(hir::Expr {
kind: hir::ExprKind::MethodCall(method_path, method_expr, _), kind: hir::ExprKind::MethodCall(method_path, receiver, ..),
.. ..
})), })),
1, 1,
@ -598,7 +598,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return None; return None;
}; };
let self_ty = self.typeck_results.borrow().expr_ty(&method_expr[0]); let self_ty = self.typeck_results.borrow().expr_ty(receiver);
let name = method_path.ident.name; let name = method_path.ident.name;
let is_as_ref_able = match self_ty.peel_refs().kind() { let is_as_ref_able = match self_ty.peel_refs().kind() {
ty::Adt(def, _) => { ty::Adt(def, _) => {
@ -767,11 +767,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}; };
if self.can_coerce(ref_ty, expected) { if self.can_coerce(ref_ty, expected) {
let mut sugg_sp = sp; let mut sugg_sp = sp;
if let hir::ExprKind::MethodCall(ref segment, ref args, _) = expr.kind { if let hir::ExprKind::MethodCall(ref segment, receiver, args, _) = expr.kind {
let clone_trait = let clone_trait =
self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span)); self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span));
if let ([arg], Some(true), sym::clone) = ( if let (true, Some(true), sym::clone) = (
&args[..], args.is_empty(),
self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map( self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map(
|did| { |did| {
let ai = self.tcx.associated_item(did); let ai = self.tcx.associated_item(did);
@ -782,7 +782,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) { ) {
// If this expression had a clone call when suggesting borrowing // If this expression had a clone call when suggesting borrowing
// we want to suggest removing it because it'd now be unnecessary. // we want to suggest removing it because it'd now be unnecessary.
sugg_sp = arg.span; sugg_sp = receiver.span;
} }
} }
if let Ok(src) = sm.span_to_snippet(sugg_sp) { if let Ok(src) = sm.span_to_snippet(sugg_sp) {

View file

@ -324,8 +324,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
ExprKind::Block(body, _) => self.check_block_with_expected(&body, expected), ExprKind::Block(body, _) => self.check_block_with_expected(&body, expected),
ExprKind::Call(callee, args) => self.check_call(expr, &callee, args, expected), ExprKind::Call(callee, args) => self.check_call(expr, &callee, args, expected),
ExprKind::MethodCall(segment, args, _) => { ExprKind::MethodCall(segment, receiver, args, _) => {
self.check_method_call(expr, segment, args, expected) self.check_method_call(expr, segment, receiver, args, expected)
} }
ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr), ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr),
ExprKind::Type(e, t) => { ExprKind::Type(e, t) => {
@ -1195,13 +1195,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self, &self,
expr: &'tcx hir::Expr<'tcx>, expr: &'tcx hir::Expr<'tcx>,
segment: &hir::PathSegment<'_>, segment: &hir::PathSegment<'_>,
receiver: &'tcx hir::Expr<'tcx>,
args: &'tcx [hir::Expr<'tcx>], args: &'tcx [hir::Expr<'tcx>],
expected: Expectation<'tcx>, expected: Expectation<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
let rcvr = &args[0]; let rcvr = &receiver;
let rcvr_t = self.check_expr(&rcvr); let rcvr_t = self.check_expr(&rcvr);
// no need to check for bot/err -- callee does that // no need to check for bot/err -- callee does that
let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t); let rcvr_t = self.structurally_resolved_type(receiver.span, rcvr_t);
let span = segment.ident.span; let span = segment.ident.span;
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) { let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) {
@ -1218,9 +1219,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span, span,
rcvr_t, rcvr_t,
segment.ident, segment.ident,
SelfSource::MethodCall(&args[0]), SelfSource::MethodCall(receiver),
error, error,
Some(args), Some((receiver, args)),
) { ) {
err.emit(); err.emit();
} }
@ -1230,14 +1231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}; };
// Call the generic checker. // Call the generic checker.
self.check_method_argument_types( self.check_method_argument_types(span, expr, method, &args, DontTupleArguments, expected)
span,
expr,
method,
&args[1..],
DontTupleArguments,
expected,
)
} }
fn check_expr_cast( fn check_expr_cast(

View file

@ -987,7 +987,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if found != self.tcx.types.unit { if found != self.tcx.types.unit {
return; return;
} }
if let ExprKind::MethodCall(path_segment, [rcvr, ..], _) = expr.kind { if let ExprKind::MethodCall(path_segment, rcvr, ..) = expr.kind {
if self if self
.typeck_results .typeck_results
.borrow() .borrow()

View file

@ -478,7 +478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None, false), hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None, false),
hir::ExprKind::MethodCall(path_segment, _, span) => { hir::ExprKind::MethodCall(path_segment, _, _, span) => {
let ident_span = path_segment.ident.span; let ident_span = path_segment.ident.span;
let ident_span = if let Some(args) = path_segment.args { let ident_span = if let Some(args) = path_segment.args {
ident_span.with_hi(args.span_ext.hi()) ident_span.with_hi(args.span_ext.hi())
@ -530,13 +530,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.collect(); .collect();
let callee_expr = match &call_expr.peel_blocks().kind { let callee_expr = match &call_expr.peel_blocks().kind {
hir::ExprKind::Call(callee, _) => Some(*callee), hir::ExprKind::Call(callee, _) => Some(*callee),
hir::ExprKind::MethodCall(_, callee, _) => { hir::ExprKind::MethodCall(_, receiver, ..) => {
if let Some((DefKind::AssocFn, def_id)) = if let Some((DefKind::AssocFn, def_id)) =
self.typeck_results.borrow().type_dependent_def(call_expr.hir_id) self.typeck_results.borrow().type_dependent_def(call_expr.hir_id)
&& let Some(assoc) = tcx.opt_associated_item(def_id) && let Some(assoc) = tcx.opt_associated_item(def_id)
&& assoc.fn_has_self_parameter && assoc.fn_has_self_parameter
{ {
Some(&callee[0]) Some(*receiver)
} else { } else {
None None
} }
@ -1805,6 +1805,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
param, param,
*call_hir_id, *call_hir_id,
callee.span, callee.span,
None,
args, args,
) )
{ {
@ -1823,7 +1824,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
} }
hir::ExprKind::MethodCall(segment, args, ..) => { hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
.into_iter() .into_iter()
.flatten() .flatten()
@ -1834,6 +1835,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
param, param,
hir_id, hir_id,
segment.ident.span, segment.ident.span,
Some(receiver),
args, args,
) { ) {
return true; return true;
@ -1901,7 +1903,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
param_to_point_at: ty::GenericArg<'tcx>, param_to_point_at: ty::GenericArg<'tcx>,
call_hir_id: hir::HirId, call_hir_id: hir::HirId,
callee_span: Span, callee_span: Span,
args: &[hir::Expr<'tcx>], receiver: Option<&'tcx hir::Expr<'tcx>>,
args: &'tcx [hir::Expr<'tcx>],
) -> bool { ) -> bool {
let sig = self.tcx.fn_sig(def_id).skip_binder(); let sig = self.tcx.fn_sig(def_id).skip_binder();
let args_referencing_param: Vec<_> = sig let args_referencing_param: Vec<_> = sig
@ -1910,6 +1913,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.enumerate() .enumerate()
.filter(|(_, ty)| find_param_in_ty(**ty, param_to_point_at)) .filter(|(_, ty)| find_param_in_ty(**ty, param_to_point_at))
.collect(); .collect();
let args: Vec<&'tcx hir::Expr<'tcx>> = if let Some(receiver) = receiver {
std::iter::once(receiver).chain(args.iter()).collect()
} else {
args.iter().collect()
};
// If there's one field that references the given generic, great! // If there's one field that references the given generic, great!
if let [(idx, _)] = args_referencing_param.as_slice() && let Some(arg) = args.get(*idx) { if let [(idx, _)] = args_referencing_param.as_slice() && let Some(arg) = args.get(*idx) {

View file

@ -1049,7 +1049,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
found_ty: Ty<'tcx>, found_ty: Ty<'tcx>,
expr: &hir::Expr<'_>, expr: &hir::Expr<'_>,
) { ) {
let hir::ExprKind::MethodCall(segment, &[ref callee_expr], _) = expr.kind else { return; }; let hir::ExprKind::MethodCall(segment, callee_expr, &[], _) = expr.kind else { return; };
let Some(clone_trait_did) = self.tcx.lang_items().clone_trait() else { return; }; let Some(clone_trait_did) = self.tcx.lang_items().clone_trait() else { return; };
let ty::Ref(_, pointee_ty, _) = found_ty.kind() else { return }; let ty::Ref(_, pointee_ty, _) = found_ty.kind() else { return };
let results = self.typeck_results.borrow(); let results = self.typeck_results.borrow();

View file

@ -434,7 +434,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
self.handle_uninhabited_return(expr); self.handle_uninhabited_return(expr);
} }
ExprKind::MethodCall(_, exprs, _) => { ExprKind::MethodCall(_, receiver, exprs, _) => {
self.visit_expr(receiver);
for expr in exprs { for expr in exprs {
self.visit_expr(expr); self.visit_expr(expr);
} }

View file

@ -160,7 +160,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if precise { if precise {
let args = args let args = args
.iter() .iter()
.skip(1)
.map(|arg| { .map(|arg| {
let span = arg.span.find_ancestor_inside(sp).unwrap_or_default(); let span = arg.span.find_ancestor_inside(sp).unwrap_or_default();
format!( format!(

View file

@ -95,7 +95,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_name: Ident, item_name: Ident,
source: SelfSource<'tcx>, source: SelfSource<'tcx>,
error: MethodError<'tcx>, error: MethodError<'tcx>,
args: Option<&'tcx [hir::Expr<'tcx>]>, args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> { ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
// Avoid suggestions when we don't know what's going on. // Avoid suggestions when we don't know what's going on.
if rcvr_ty.references_error() { if rcvr_ty.references_error() {
@ -998,7 +998,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span, span,
rcvr_ty, rcvr_ty,
item_name, item_name,
args.map(|args| args.len()), args.map(|(_, args)| args.len() + 1),
source, source,
out_of_scope_traits, out_of_scope_traits,
&unsatisfied_predicates, &unsatisfied_predicates,
@ -2310,7 +2310,7 @@ pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
fn print_disambiguation_help<'tcx>( fn print_disambiguation_help<'tcx>(
item_name: Ident, item_name: Ident,
args: Option<&'tcx [hir::Expr<'tcx>]>, args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
err: &mut Diagnostic, err: &mut Diagnostic,
trait_name: String, trait_name: String,
rcvr_ty: Ty<'_>, rcvr_ty: Ty<'_>,
@ -2322,7 +2322,7 @@ fn print_disambiguation_help<'tcx>(
fn_has_self_parameter: bool, fn_has_self_parameter: bool,
) { ) {
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;
let (span, sugg) = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) { let (span, sugg) = if let (ty::AssocKind::Fn, Some((receiver, args))) = (kind, args) {
let args = format!( let args = format!(
"({}{})", "({}{})",
if rcvr_ty.is_region_ptr() { if rcvr_ty.is_region_ptr() {
@ -2330,7 +2330,8 @@ fn print_disambiguation_help<'tcx>(
} else { } else {
"" ""
}, },
args.iter() std::iter::once(receiver)
.chain(args.iter())
.map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| { .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
applicability = Applicability::HasPlaceholders; applicability = Applicability::HasPlaceholders;
"_".to_owned() "_".to_owned()

View file

@ -233,8 +233,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
self.consume_exprs(args); self.consume_exprs(args);
} }
hir::ExprKind::MethodCall(.., args, _) => { hir::ExprKind::MethodCall(.., receiver, args, _) => {
// callee.m(args) // callee.m(args)
self.consume_expr(receiver);
self.consume_exprs(args); self.consume_exprs(args);
} }

View file

@ -758,13 +758,13 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
num_assoc_fn_excess_args: usize, num_assoc_fn_excess_args: usize,
num_trait_generics_except_self: usize, num_trait_generics_except_self: usize,
) { ) {
if let hir::ExprKind::MethodCall(_, args, _) = expr.kind { if let hir::ExprKind::MethodCall(_, receiver, args, ..) = expr.kind {
assert_eq!(args.len(), 1); assert_eq!(args.len(), 0);
if num_assoc_fn_excess_args == num_trait_generics_except_self { if num_assoc_fn_excess_args == num_trait_generics_except_self {
if let Some(gen_args) = self.gen_args.span_ext() if let Some(gen_args) = self.gen_args.span_ext()
&& let Ok(gen_args) = self.tcx.sess.source_map().span_to_snippet(gen_args) && let Ok(gen_args) = self.tcx.sess.source_map().span_to_snippet(gen_args)
&& let Ok(args) = self.tcx.sess.source_map().span_to_snippet(args[0].span) { && let Ok(receiver) = self.tcx.sess.source_map().span_to_snippet(receiver.span) {
let sugg = format!("{}::{}::{}({})", self.tcx.item_name(trait_), gen_args, self.tcx.item_name(self.def_id), args); let sugg = format!("{}::{}::{}({})", self.tcx.item_name(trait_), gen_args, self.tcx.item_name(self.def_id), receiver);
err.span_suggestion(expr.span, msg, sugg, Applicability::MaybeIncorrect); err.span_suggestion(expr.span, msg, sugg, Applicability::MaybeIncorrect);
} }
} }

View file

@ -159,7 +159,7 @@ where
return; return;
} }
} }
hir::ExprKind::MethodCall(path, _, call_span) => { hir::ExprKind::MethodCall(path, _, _, call_span) => {
let types = tcx.typeck(ex.hir_id.owner); let types = tcx.typeck(ex.hir_id.owner);
let Some(def_id) = types.type_dependent_def_id(ex.hir_id) else { let Some(def_id) = types.type_dependent_def_id(ex.hir_id) else {
trace!("type_dependent_def_id({}) = None", ex.hir_id); trace!("type_dependent_def_id({}) = None", ex.hir_id);