Skip to content

Commit 38491c6

Browse files
Consider method return type for various method suggestions
1 parent 7ee6ceb commit 38491c6

18 files changed

+224
-38
lines changed

compiler/rustc_hir_typeck/src/callee.rs

+1
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
499499
.probe_for_name(
500500
Mode::MethodCall,
501501
segment.ident,
502+
expected.only_has_type(self),
502503
IsSuggestion(true),
503504
callee_ty,
504505
call_expr.hir_id,

compiler/rustc_hir_typeck/src/demand.rs

+8
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
560560
.probe_for_name(
561561
probe::Mode::MethodCall,
562562
path.ident,
563+
None,
563564
probe::IsSuggestion(true),
564565
self_ty,
565566
deref.hir_id,
@@ -570,6 +571,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
570571
let in_scope_methods = self.probe_for_name_many(
571572
probe::Mode::MethodCall,
572573
path.ident,
574+
Some(expected),
573575
probe::IsSuggestion(true),
574576
self_ty,
575577
deref.hir_id,
@@ -581,6 +583,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
581583
let all_methods = self.probe_for_name_many(
582584
probe::Mode::MethodCall,
583585
path.ident,
586+
Some(expected),
584587
probe::IsSuggestion(true),
585588
self_ty,
586589
deref.hir_id,
@@ -1850,10 +1853,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18501853
return;
18511854
}
18521855
let mut expr = end.expr;
1856+
let mut expectation = Some(expected_ty);
18531857
while let hir::ExprKind::MethodCall(_, rcvr, ..) = expr.kind {
18541858
// Getting to the root receiver and asserting it is a fn call let's us ignore cases in
18551859
// `src/test/ui/methods/issues/issue-90315.stderr`.
18561860
expr = rcvr;
1861+
// If we have more than one layer of calls, then the expected ty
1862+
// cannot guide the method probe.
1863+
expectation = None;
18571864
}
18581865
let hir::ExprKind::Call(method_name, _) = expr.kind else { return; };
18591866
let ty::Adt(adt, _) = checked_ty.kind() else { return; };
@@ -1872,6 +1879,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18721879
let Ok(_pick) = self.probe_for_name(
18731880
probe::Mode::MethodCall,
18741881
*ident,
1882+
expectation,
18751883
probe::IsSuggestion(true),
18761884
self_ty,
18771885
expr.hir_id,

compiler/rustc_hir_typeck/src/expr.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
351351
ExprKind::Struct(qpath, fields, ref base_expr) => {
352352
self.check_expr_struct(expr, expected, qpath, fields, base_expr)
353353
}
354-
ExprKind::Field(base, field) => self.check_field(expr, &base, field),
354+
ExprKind::Field(base, field) => self.check_field(expr, &base, field, expected),
355355
ExprKind::Index(base, idx) => self.check_expr_index(base, idx, expr),
356356
ExprKind::Yield(value, ref src) => self.check_expr_yield(value, expr, src),
357357
hir::ExprKind::Err => tcx.ty_error(),
@@ -1244,6 +1244,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12441244
SelfSource::MethodCall(rcvr),
12451245
error,
12461246
Some((rcvr, args)),
1247+
expected,
12471248
) {
12481249
err.emit();
12491250
}
@@ -2186,6 +2187,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
21862187
expr: &'tcx hir::Expr<'tcx>,
21872188
base: &'tcx hir::Expr<'tcx>,
21882189
field: Ident,
2190+
expected: Expectation<'tcx>,
21892191
) -> Ty<'tcx> {
21902192
debug!("check_field(expr: {:?}, base: {:?}, field: {:?})", expr, base, field);
21912193
let base_ty = self.check_expr(base);
@@ -2244,12 +2246,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22442246
// (#90483) apply adjustments to avoid ExprUseVisitor from
22452247
// creating erroneous projection.
22462248
self.apply_adjustments(base, adjustments);
2247-
self.ban_private_field_access(expr, base_ty, field, did);
2249+
self.ban_private_field_access(expr, base_ty, field, did, expected.only_has_type(self));
22482250
return self.tcx().ty_error();
22492251
}
22502252

22512253
if field.name == kw::Empty {
2252-
} else if self.method_exists(field, base_ty, expr.hir_id, true) {
2254+
} else if self.method_exists(
2255+
field,
2256+
base_ty,
2257+
expr.hir_id,
2258+
true,
2259+
expected.only_has_type(self),
2260+
) {
22532261
self.ban_take_value_of_method(expr, base_ty, field);
22542262
} else if !base_ty.is_primitive_ty() {
22552263
self.ban_nonexisting_field(field, base, expr, base_ty);
@@ -2427,6 +2435,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24272435
expr_t: Ty<'tcx>,
24282436
field: Ident,
24292437
base_did: DefId,
2438+
return_ty: Option<Ty<'tcx>>,
24302439
) {
24312440
let struct_path = self.tcx().def_path_str(base_did);
24322441
let kind_name = self.tcx().def_kind(base_did).descr(base_did);
@@ -2438,7 +2447,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24382447
);
24392448
err.span_label(field.span, "private field");
24402449
// Also check if an accessible method exists, which is often what is meant.
2441-
if self.method_exists(field, expr_t, expr.hir_id, false) && !self.expr_in_place(expr.hir_id)
2450+
if self.method_exists(field, expr_t, expr.hir_id, false, return_ty)
2451+
&& !self.expr_in_place(expr.hir_id)
24422452
{
24432453
self.suggest_method_call(
24442454
&mut err,

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+1
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
841841
SelfSource::QPath(qself),
842842
error,
843843
None,
844+
Expectation::NoExpectation,
844845
) {
845846
e.emit();
846847
}

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1343,6 +1343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13431343
if let Ok(pick) = self.probe_for_name(
13441344
Mode::Path,
13451345
Ident::new(capitalized_name, segment.ident.span),
1346+
Some(expected_ty),
13461347
IsSuggestion(true),
13471348
self_ty,
13481349
expr.hir_id,

compiler/rustc_hir_typeck/src/method/mod.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
9797
self_ty: Ty<'tcx>,
9898
call_expr_id: hir::HirId,
9999
allow_private: bool,
100+
return_type: Option<Ty<'tcx>>,
100101
) -> bool {
101102
match self.probe_for_name(
102103
probe::Mode::MethodCall,
103104
method_name,
105+
return_type,
104106
IsSuggestion(false),
105107
self_ty,
106108
call_expr_id,
@@ -118,7 +120,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
118120
Err(Ambiguity(..)) => true,
119121
Err(PrivateMatch(..)) => allow_private,
120122
Err(IllegalSizedBound { .. }) => true,
121-
Err(BadReturnType) => bug!("no return type expectations but got BadReturnType"),
123+
Err(BadReturnType) => false,
122124
}
123125
}
124126

@@ -137,6 +139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
137139
.probe_for_name(
138140
probe::Mode::MethodCall,
139141
method_name,
142+
None,
140143
IsSuggestion(true),
141144
self_ty,
142145
call_expr.hir_id,
@@ -258,6 +261,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
258261
let pick = self.probe_for_name(
259262
probe::Mode::MethodCall,
260263
method_name,
264+
None,
261265
IsSuggestion(false),
262266
self_ty,
263267
call_expr.hir_id,
@@ -484,6 +488,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
484488
let pick = self.probe_for_name(
485489
probe::Mode::Path,
486490
method_name,
491+
None,
487492
IsSuggestion(false),
488493
self_ty,
489494
expr_id,

compiler/rustc_hir_typeck/src/method/probe.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
304304
&self,
305305
mode: Mode,
306306
item_name: Ident,
307+
return_type: Option<Ty<'tcx>>,
307308
is_suggestion: IsSuggestion,
308309
self_ty: Ty<'tcx>,
309310
scope_expr_id: hir::HirId,
@@ -313,7 +314,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
313314
item_name.span,
314315
mode,
315316
Some(item_name),
316-
None,
317+
return_type,
317318
is_suggestion,
318319
self_ty,
319320
scope_expr_id,
@@ -327,6 +328,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
327328
&self,
328329
mode: Mode,
329330
item_name: Ident,
331+
return_type: Option<Ty<'tcx>>,
330332
is_suggestion: IsSuggestion,
331333
self_ty: Ty<'tcx>,
332334
scope_expr_id: hir::HirId,
@@ -336,7 +338,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
336338
item_name.span,
337339
mode,
338340
Some(item_name),
339-
None,
341+
return_type,
340342
is_suggestion,
341343
self_ty,
342344
scope_expr_id,

compiler/rustc_hir_typeck/src/method/suggest.rs

+42-9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! found or is otherwise invalid.
33
44
use crate::errors;
5+
use crate::Expectation;
56
use crate::FnCtxt;
67
use rustc_ast::ast::Mutability;
78
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -108,6 +109,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
108109
source: SelfSource<'tcx>,
109110
error: MethodError<'tcx>,
110111
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
112+
expected: Expectation<'tcx>,
111113
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
112114
// Avoid suggestions when we don't know what's going on.
113115
if rcvr_ty.references_error() {
@@ -131,6 +133,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
131133
args,
132134
sugg_span,
133135
&mut no_match_data,
136+
expected,
134137
);
135138
}
136139

@@ -250,6 +253,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
250253
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
251254
sugg_span: Span,
252255
no_match_data: &mut NoMatchData<'tcx>,
256+
expected: Expectation<'tcx>,
253257
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
254258
let mode = no_match_data.mode;
255259
let tcx = self.tcx;
@@ -320,7 +324,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
320324

321325
if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
322326
self.suggest_await_before_method(
323-
&mut err, item_name, rcvr_ty, cal, span,
327+
&mut err, item_name, rcvr_ty, cal, span, expected.only_has_type(self),
324328
);
325329
}
326330
if let Some(span) =
@@ -898,7 +902,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
898902
// Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
899903
// can't be called due to `typeof(expr): Clone` not holding.
900904
if unsatisfied_predicates.is_empty() {
901-
self.suggest_calling_method_on_field(&mut err, source, span, rcvr_ty, item_name);
905+
self.suggest_calling_method_on_field(
906+
&mut err,
907+
source,
908+
span,
909+
rcvr_ty,
910+
item_name,
911+
expected.only_has_type(self),
912+
);
902913
}
903914

904915
self.check_for_inner_self(&mut err, source, rcvr_ty, item_name);
@@ -922,6 +933,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
922933
&unsatisfied_predicates,
923934
&static_candidates,
924935
unsatisfied_bounds,
936+
expected.only_has_type(self),
925937
);
926938
}
927939

@@ -987,7 +999,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
987999
}
9881000
}
9891001

990-
self.check_for_deref_method(&mut err, source, rcvr_ty, item_name);
1002+
self.check_for_deref_method(&mut err, source, rcvr_ty, item_name, expected);
9911003
return Some(err);
9921004
}
9931005

@@ -1377,6 +1389,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13771389
let pick = self.probe_for_name(
13781390
Mode::MethodCall,
13791391
item_name,
1392+
None,
13801393
IsSuggestion(true),
13811394
range_ty,
13821395
expr.hir_id,
@@ -1587,6 +1600,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15871600
span: Span,
15881601
actual: Ty<'tcx>,
15891602
item_name: Ident,
1603+
return_type: Option<Ty<'tcx>>,
15901604
) {
15911605
if let SelfSource::MethodCall(expr) = source
15921606
&& let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
@@ -1610,10 +1624,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16101624
self.check_for_nested_field_satisfying(
16111625
span,
16121626
&|_, field_ty| {
1613-
self.lookup_probe(
1627+
self.probe_for_name(
1628+
Mode::MethodCall,
16141629
item_name,
1630+
return_type,
1631+
IsSuggestion(true),
16151632
field_ty,
1616-
call_expr,
1633+
call_expr.hir_id,
16171634
ProbeScope::TraitsInScope,
16181635
)
16191636
.map_or(false, |pick| {
@@ -2010,12 +2027,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20102027
self_source: SelfSource<'tcx>,
20112028
rcvr_ty: Ty<'tcx>,
20122029
item_name: Ident,
2030+
expected: Expectation<'tcx>,
20132031
) {
20142032
let SelfSource::QPath(ty) = self_source else { return; };
20152033
for (deref_ty, _) in self.autoderef(rustc_span::DUMMY_SP, rcvr_ty).skip(1) {
20162034
if let Ok(pick) = self.probe_for_name(
20172035
Mode::Path,
20182036
item_name,
2037+
expected.only_has_type(self),
20192038
IsSuggestion(true),
20202039
deref_ty,
20212040
ty.hir_id,
@@ -2080,12 +2099,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20802099
ty: Ty<'tcx>,
20812100
call: &hir::Expr<'_>,
20822101
span: Span,
2102+
return_type: Option<Ty<'tcx>>,
20832103
) {
20842104
let output_ty = match self.get_impl_future_output_ty(ty) {
20852105
Some(output_ty) => self.resolve_vars_if_possible(output_ty),
20862106
_ => return,
20872107
};
2088-
let method_exists = self.method_exists(item_name, output_ty, call.hir_id, true);
2108+
let method_exists =
2109+
self.method_exists(item_name, output_ty, call.hir_id, true, return_type);
20892110
debug!("suggest_await_before_method: is_method_exist={}", method_exists);
20902111
if method_exists {
20912112
err.span_suggestion_verbose(
@@ -2199,6 +2220,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
21992220
)],
22002221
static_candidates: &[CandidateSource],
22012222
unsatisfied_bounds: bool,
2223+
return_type: Option<Ty<'tcx>>,
22022224
) {
22032225
let mut alt_rcvr_sugg = false;
22042226
if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) {
@@ -2221,7 +2243,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22212243
(self.tcx.mk_mut_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "),
22222244
(self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&"),
22232245
] {
2224-
match self.lookup_probe(item_name, *rcvr_ty, rcvr, ProbeScope::AllTraits) {
2246+
match self.probe_for_name(
2247+
Mode::MethodCall,
2248+
item_name,
2249+
return_type,
2250+
IsSuggestion(true),
2251+
*rcvr_ty,
2252+
rcvr.hir_id,
2253+
ProbeScope::AllTraits,
2254+
) {
22252255
Ok(pick) => {
22262256
// If the method is defined for the receiver we have, it likely wasn't `use`d.
22272257
// We point at the method, but we just skip the rest of the check for arbitrary
@@ -2254,10 +2284,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22542284
(self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Rc), "Rc::new"),
22552285
] {
22562286
if let Some(new_rcvr_t) = *rcvr_ty
2257-
&& let Ok(pick) = self.lookup_probe(
2287+
&& let Ok(pick) = self.probe_for_name(
2288+
Mode::MethodCall,
22582289
item_name,
2290+
return_type,
2291+
IsSuggestion(true),
22592292
new_rcvr_t,
2260-
rcvr,
2293+
rcvr.hir_id,
22612294
ProbeScope::AllTraits,
22622295
)
22632296
{

0 commit comments

Comments
 (0)