Skip to content

Commit 4bd3078

Browse files
committed
Auto merge of rust-lang#102726 - matthiaskrgr:rollup-2ghn38b, r=matthiaskrgr
Rollup of 5 pull requests Successful merges: - rust-lang#102672 (rustdoc: remove unused CSS class `in-band`) - rust-lang#102693 (Revert "Use getentropy when possible on all Apple platforms") - rust-lang#102694 (Suggest calling method if fn does not exist) - rust-lang#102708 (Suggest `==` to wrong assign expr) - rust-lang#102710 (Add test for issue 82633) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents 0152393 + b7642fb commit 4bd3078

File tree

62 files changed

+903
-502
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+903
-502
lines changed

compiler/rustc_errors/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,7 @@ pub enum StashKey {
460460
ItemNoType,
461461
UnderscoreForArrayLengths,
462462
EarlySyntaxWarning,
463+
CallIntoMethod,
463464
}
464465

465466
fn default_track_diagnostic(_: &Diagnostic) {}

compiler/rustc_hir_analysis/src/check/callee.rs

+136-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
use super::method::probe::{IsSuggestion, Mode, ProbeScope};
12
use super::method::MethodCallee;
23
use super::{DefIdOrName, Expectation, FnCtxt, TupleArgumentsFlag};
34
use crate::type_error_struct;
45

5-
use rustc_errors::{struct_span_err, Applicability, Diagnostic};
6+
use rustc_ast::util::parser::PREC_POSTFIX;
7+
use rustc_errors::{struct_span_err, Applicability, Diagnostic, StashKey};
68
use rustc_hir as hir;
79
use rustc_hir::def::{self, Namespace, Res};
810
use rustc_hir::def_id::DefId;
@@ -60,6 +62,7 @@ pub fn check_legal_trait_for_method_call(
6062
}
6163
}
6264

65+
#[derive(Debug)]
6366
enum CallStep<'tcx> {
6467
Builtin(Ty<'tcx>),
6568
DeferredClosure(LocalDefId, ty::FnSig<'tcx>),
@@ -188,6 +191,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
188191
return None;
189192
}
190193

194+
ty::Error(_) => {
195+
return None;
196+
}
197+
191198
_ => {}
192199
}
193200

@@ -394,6 +401,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
394401
}
395402
ty::FnPtr(sig) => (sig, None),
396403
_ => {
404+
if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = &callee_expr.kind
405+
&& let [segment] = path.segments
406+
&& let Some(mut diag) = self
407+
.tcx
408+
.sess
409+
.diagnostic()
410+
.steal_diagnostic(segment.ident.span, StashKey::CallIntoMethod)
411+
{
412+
// Try suggesting `foo(a)` -> `a.foo()` if possible.
413+
if let Some(ty) =
414+
self.suggest_call_as_method(
415+
&mut diag,
416+
segment,
417+
arg_exprs,
418+
call_expr,
419+
expected
420+
)
421+
{
422+
diag.emit();
423+
return ty;
424+
} else {
425+
diag.emit();
426+
}
427+
}
428+
397429
self.report_invalid_callee(call_expr, callee_expr, callee_ty, arg_exprs);
398430

399431
// This is the "default" function signature, used in case of error.
@@ -441,6 +473,105 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
441473
fn_sig.output()
442474
}
443475

476+
/// Attempts to reinterpret `method(rcvr, args...)` as `rcvr.method(args...)`
477+
/// and suggesting the fix if the method probe is successful.
478+
fn suggest_call_as_method(
479+
&self,
480+
diag: &mut Diagnostic,
481+
segment: &'tcx hir::PathSegment<'tcx>,
482+
arg_exprs: &'tcx [hir::Expr<'tcx>],
483+
call_expr: &'tcx hir::Expr<'tcx>,
484+
expected: Expectation<'tcx>,
485+
) -> Option<Ty<'tcx>> {
486+
if let [callee_expr, rest @ ..] = arg_exprs {
487+
let callee_ty = self.check_expr(callee_expr);
488+
// First, do a probe with `IsSuggestion(true)` to avoid emitting
489+
// any strange errors. If it's successful, then we'll do a true
490+
// method lookup.
491+
let Ok(pick) = self
492+
.probe_for_name(
493+
call_expr.span,
494+
Mode::MethodCall,
495+
segment.ident,
496+
IsSuggestion(true),
497+
callee_ty,
498+
call_expr.hir_id,
499+
// We didn't record the in scope traits during late resolution
500+
// so we need to probe AllTraits unfortunately
501+
ProbeScope::AllTraits,
502+
) else {
503+
return None;
504+
};
505+
506+
let pick = self.confirm_method(
507+
call_expr.span,
508+
callee_expr,
509+
call_expr,
510+
callee_ty,
511+
pick,
512+
segment,
513+
);
514+
if pick.illegal_sized_bound.is_some() {
515+
return None;
516+
}
517+
518+
let up_to_rcvr_span = segment.ident.span.until(callee_expr.span);
519+
let rest_span = callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi());
520+
let rest_snippet = if let Some(first) = rest.first() {
521+
self.tcx
522+
.sess
523+
.source_map()
524+
.span_to_snippet(first.span.to(call_expr.span.shrink_to_hi()))
525+
} else {
526+
Ok(")".to_string())
527+
};
528+
529+
if let Ok(rest_snippet) = rest_snippet {
530+
let sugg = if callee_expr.precedence().order() >= PREC_POSTFIX {
531+
vec![
532+
(up_to_rcvr_span, "".to_string()),
533+
(rest_span, format!(".{}({rest_snippet}", segment.ident)),
534+
]
535+
} else {
536+
vec![
537+
(up_to_rcvr_span, "(".to_string()),
538+
(rest_span, format!(").{}({rest_snippet}", segment.ident)),
539+
]
540+
};
541+
let self_ty = self.resolve_vars_if_possible(pick.callee.sig.inputs()[0]);
542+
diag.multipart_suggestion(
543+
format!(
544+
"use the `.` operator to call the method `{}{}` on `{self_ty}`",
545+
self.tcx
546+
.associated_item(pick.callee.def_id)
547+
.trait_container(self.tcx)
548+
.map_or_else(
549+
|| String::new(),
550+
|trait_def_id| self.tcx.def_path_str(trait_def_id) + "::"
551+
),
552+
segment.ident
553+
),
554+
sugg,
555+
Applicability::MaybeIncorrect,
556+
);
557+
558+
// Let's check the method fully now
559+
let return_ty = self.check_method_argument_types(
560+
segment.ident.span,
561+
call_expr,
562+
Ok(pick.callee),
563+
rest,
564+
TupleArgumentsFlag::DontTupleArguments,
565+
expected,
566+
);
567+
568+
return Some(return_ty);
569+
}
570+
}
571+
572+
None
573+
}
574+
444575
fn report_invalid_callee(
445576
&self,
446577
call_expr: &'tcx hir::Expr<'tcx>,
@@ -459,10 +590,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
459590
def::CtorOf::Struct => "struct",
460591
def::CtorOf::Variant => "enum variant",
461592
};
462-
let removal_span =
463-
callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi());
464-
unit_variant =
465-
Some((removal_span, descr, rustc_hir_pretty::qpath_to_string(qpath)));
593+
let removal_span = callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi());
594+
unit_variant = Some((removal_span, descr, rustc_hir_pretty::qpath_to_string(qpath)));
466595
}
467596

468597
let callee_ty = self.resolve_vars_if_possible(callee_ty);
@@ -525,7 +654,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
525654
};
526655

527656
if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
528-
if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_expr, callee_ty)
657+
if let Some((maybe_def, output_ty, _)) =
658+
self.extract_callable_info(callee_expr, callee_ty)
529659
&& !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
530660
{
531661
let descr = match maybe_def {

compiler/rustc_hir_analysis/src/check/expr.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10451045
let rhs_ty = self.check_expr(&rhs);
10461046
let (applicability, eq) = if self.can_coerce(rhs_ty, lhs_ty) {
10471047
(Applicability::MachineApplicable, true)
1048+
} else if let ExprKind::Binary(
1049+
Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },
1050+
_,
1051+
rhs_expr,
1052+
) = lhs.kind
1053+
{
1054+
let actual_lhs_ty = self.check_expr(&rhs_expr);
1055+
(Applicability::MaybeIncorrect, self.can_coerce(rhs_ty, actual_lhs_ty))
10481056
} else {
10491057
(Applicability::MaybeIncorrect, false)
10501058
};
@@ -1067,9 +1075,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10671075
}
10681076
if eq {
10691077
err.span_suggestion_verbose(
1070-
span,
1078+
span.shrink_to_hi(),
10711079
"you might have meant to compare for equality",
1072-
"==",
1080+
'=',
10731081
applicability,
10741082
);
10751083
}

compiler/rustc_resolve/src/diagnostics.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,15 @@ impl<'a> Resolver<'a> {
120120
}
121121

122122
fn report_with_use_injections(&mut self, krate: &Crate) {
123-
for UseError { mut err, candidates, def_id, instead, suggestion, path } in
123+
for UseError { mut err, candidates, def_id, instead, suggestion, path, is_call } in
124124
self.use_injections.drain(..)
125125
{
126126
let (span, found_use) = if let Some(def_id) = def_id.as_local() {
127127
UsePlacementFinder::check(krate, self.def_id_to_node_id[def_id])
128128
} else {
129129
(None, FoundUse::No)
130130
};
131+
131132
if !candidates.is_empty() {
132133
show_candidates(
133134
&self.session,
@@ -140,10 +141,15 @@ impl<'a> Resolver<'a> {
140141
IsPattern::No,
141142
path,
142143
);
144+
err.emit();
143145
} else if let Some((span, msg, sugg, appl)) = suggestion {
144146
err.span_suggestion(span, msg, sugg, appl);
147+
err.emit();
148+
} else if let [segment] = path.as_slice() && is_call {
149+
err.stash(segment.ident.span, rustc_errors::StashKey::CallIntoMethod);
150+
} else {
151+
err.emit();
145152
}
146-
err.emit();
147153
}
148154
}
149155

compiler/rustc_resolve/src/late.rs

+2
Original file line numberDiff line numberDiff line change
@@ -3263,6 +3263,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
32633263
instead,
32643264
suggestion,
32653265
path: path.into(),
3266+
is_call: source.is_call(),
32663267
});
32673268
}
32683269

@@ -3327,6 +3328,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
33273328
instead: false,
33283329
suggestion: None,
33293330
path: path.into(),
3331+
is_call: source.is_call(),
33303332
});
33313333
} else {
33323334
err.cancel();

compiler/rustc_resolve/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,8 @@ struct UseError<'a> {
674674
/// Path `Segment`s at the place of use that failed. Used for accurate suggestion after telling
675675
/// the user to import the item directly.
676676
path: Vec<Segment>,
677+
/// Whether the expected source is a call
678+
is_call: bool,
677679
}
678680

679681
#[derive(Clone, Copy, PartialEq, Debug)]

0 commit comments

Comments
 (0)