Skip to content

Commit af13f34

Browse files
committed
Modify turbofish suggestion probing logic
1 parent 40d36b1 commit af13f34

File tree

10 files changed

+230
-153
lines changed

10 files changed

+230
-153
lines changed

compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,8 +1462,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
14621462
let bound_predicate = predicate.bound_atom();
14631463
let mut err = match bound_predicate.skip_binder() {
14641464
ty::PredicateAtom::Trait(data, _) => {
1465-
let trait_ref = bound_predicate.rebind(data.trait_ref);
1466-
debug!("trait_ref {:?}", trait_ref);
1465+
let self_ty = data.trait_ref.self_ty();
14671466

14681467
if predicate.references_error() {
14691468
return;
@@ -1504,7 +1503,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
15041503
// avoid inundating the user with unnecessary errors, but we now
15051504
// check upstream for type errors and don't add the obligations to
15061505
// begin with in those cases.
1507-
if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
1506+
if self.tcx.lang_items().sized_trait() == Some(data.trait_ref.def_id) {
15081507
self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0282, &[])
15091508
.emit();
15101509
return;
@@ -1523,7 +1522,12 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
15231522
err.note(&format!("cannot satisfy `{}`", predicate));
15241523

15251524
if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code {
1526-
self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
1525+
self.suggest_fully_qualified_path(
1526+
&mut err,
1527+
def_id,
1528+
span,
1529+
data.trait_ref.def_id,
1530+
);
15271531
} else if let (
15281532
Ok(ref snippet),
15291533
ObligationCauseCode::BindingObligation(ref def_id, _),

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

Lines changed: 38 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use super::{
44
};
55

66
use crate::autoderef::Autoderef;
7-
use crate::infer::{InferCtxt, InferOk};
7+
use crate::infer::InferCtxt;
88
use crate::traits::{self, normalize_projection_type};
99

1010
use rustc_data_structures::fx::FxHashSet;
@@ -16,12 +16,11 @@ use rustc_hir::def_id::DefId;
1616
use rustc_hir::intravisit::Visitor;
1717
use rustc_hir::lang_items::LangItem;
1818
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
19-
use rustc_middle::ty::subst::{GenericArgKind, Subst};
19+
use rustc_middle::ty::subst::InternalSubsts;
2020
use rustc_middle::ty::{
2121
self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty,
22-
TyCtxt, TypeFoldable, WithConstness,
22+
TyCtxt, TypeAndMut, TypeFoldable, TypeckResults, WithConstness,
2323
};
24-
use rustc_middle::ty::{TypeAndMut, TypeckResults};
2524
use rustc_span::symbol::{kw, sym, Ident, Symbol};
2625
use rustc_span::{MultiSpan, Span, DUMMY_SP};
2726
use rustc_target::spec::abi;
@@ -338,67 +337,45 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
338337
let mut turbofish_suggestions = FxHashSet::default();
339338
self.tcx.for_each_relevant_impl(data.trait_ref.def_id, self_ty, |impl_def_id| {
340339
self.probe(|_| {
341-
let impl_substs = self.fresh_substs_for_item(DUMMY_SP, impl_def_id);
340+
let trait_args = InternalSubsts::identity_for_item(self.tcx, data.trait_ref.def_id);
341+
let impl_args = traits::specialize::fulfill_implication(
342+
self,
343+
obligation.param_env,
344+
data.trait_ref,
345+
impl_def_id,
346+
);
347+
let substs = match impl_args {
348+
Ok(impl_args) => trait_args.rebase_onto(self.tcx, impl_def_id, impl_args),
349+
_ => return,
350+
};
342351
let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
343-
let trait_ref = trait_ref.subst(self.tcx, impl_substs);
344352

345-
// Require the type the impl is implemented on to match
346-
// our type, and ignore the impl if there was a mismatch.
347353
let cause = traits::ObligationCause::dummy();
348-
let eq_result =
349-
self.at(&cause, obligation.param_env).eq(trait_ref.self_ty(), self_ty);
350-
if let Ok(InferOk { value: (), obligations: _ }) = eq_result {
351-
if let Ok(eval_result) = self.evaluate_obligation(&Obligation::new(
354+
let mut selcx = SelectionContext::new(&self);
355+
let param_env = obligation.param_env.clone();
356+
let (target_trait_ref, obligations) = traits::util::impl_trait_ref_and_oblig(
357+
&mut selcx,
358+
param_env,
359+
impl_def_id,
360+
substs,
361+
);
362+
self.resolve_vars_if_possible(&target_trait_ref);
363+
if let Ok(eval_result) = selcx.evaluate_predicates(
364+
Some(Obligation::new(
352365
cause.clone(),
353-
obligation.param_env,
354-
trait_ref.without_const().to_predicate(self.tcx),
355-
)) {
356-
// FIXME: We will also suggest cases where `eval_result` is
357-
// `EvaluatedToAmbig`, we just put them at the end of the sugg list.
358-
// Ideally we would only suggest types that would always apply cleanly.
359-
// This means that for `collect` we will suggest `PathBuf` as a valid type
360-
// whereas that `impl` has an extra requirement `T: AsRef<Path>` which we
361-
// don't evaluate.
362-
if eval_result.may_apply()
363-
&& data.trait_ref.substs.iter().zip(trait_ref.substs.iter()).all(
364-
// Here we'll have something like `[_, i32]` coming from our code
365-
// and `[Vec<_>, _]` from the probe. For cases with
366-
// inference variables we are left with ambiguous cases due to
367-
// trait bounds we couldn't evaluate, but we *can* filter out cases
368-
// like `[std::string::String, char]`, where we can `collect` a
369-
// `String` only if we have an `IntoIterator<Item = char>`, which
370-
// won't match the `i32` we have.
371-
|(l, r)| {
372-
// FIXME: ideally we would use `can_coerce` here instead, but `typeck`
373-
// comes *after* in the dependency graph.
374-
match (l.unpack(), r.unpack()) {
375-
(
376-
GenericArgKind::Type(left_ty),
377-
GenericArgKind::Type(right_ty),
378-
) => match (
379-
&left_ty.peel_refs().kind(),
380-
&right_ty.peel_refs().kind(),
381-
) {
382-
(Infer(_), _) | (_, Infer(_)) => true,
383-
(left_kind, right_kind) => left_kind == right_kind,
384-
},
385-
(
386-
GenericArgKind::Lifetime(_),
387-
GenericArgKind::Lifetime(_),
388-
)
389-
| (GenericArgKind::Const(_), GenericArgKind::Const(_)) => {
390-
true
391-
}
392-
_ => false,
393-
}
394-
},
395-
)
396-
&& !matches!(trait_ref.self_ty().kind(), ty::Infer(_))
397-
{
398-
turbofish_suggestions.insert(trait_ref.self_ty());
399-
}
400-
};
401-
}
366+
param_env,
367+
target_trait_ref.without_const().to_predicate(self.tcx),
368+
))
369+
.into_iter()
370+
.chain(obligations),
371+
) {
372+
debug!("get_turbofish_suggestions result {:?}", eval_result);
373+
if eval_result.must_apply_modulo_regions()
374+
&& !matches!(trait_ref.self_ty().kind(), ty::Infer(_))
375+
{
376+
turbofish_suggestions.insert(trait_ref.self_ty());
377+
}
378+
};
402379
})
403380
});
404381
// Sort types by always suggesting `Vec<_>` and `String` first, as they are the

compiler/rustc_trait_selection/src/traits/select/mod.rs

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -403,20 +403,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
403403
})
404404
}
405405

406+
crate fn evaluate_predicates(
407+
&mut self,
408+
predicates: impl Iterator<Item = PredicateObligation<'tcx>>,
409+
) -> Result<EvaluationResult, OverflowError> {
410+
self.evaluate_predicates_recursively(
411+
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
412+
predicates,
413+
)
414+
}
415+
406416
/// Evaluates the predicates in `predicates` recursively. Note that
407417
/// this applies projections in the predicates, and therefore
408418
/// is run within an inference probe.
409-
fn evaluate_predicates_recursively<'o, I>(
419+
fn evaluate_predicates_recursively<'o>(
410420
&mut self,
411421
stack: TraitObligationStackList<'o, 'tcx>,
412-
predicates: I,
413-
) -> Result<EvaluationResult, OverflowError>
414-
where
415-
I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug,
416-
{
422+
predicates: impl Iterator<Item = PredicateObligation<'tcx>>,
423+
) -> Result<EvaluationResult, OverflowError> {
417424
let mut result = EvaluatedToOk;
418-
debug!(?predicates, "evaluate_predicates_recursively");
419425
for obligation in predicates {
426+
debug!(?obligation, "evaluate_predicates_recursively obligation");
420427
let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
421428
if let EvaluatedToErr = eval {
422429
// fast-path - EvaluatedToErr is the top of the lattice,
@@ -484,7 +491,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
484491
) {
485492
Some(mut obligations) => {
486493
self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
487-
self.evaluate_predicates_recursively(previous_stack, obligations)
494+
self.evaluate_predicates_recursively(
495+
previous_stack,
496+
obligations.into_iter(),
497+
)
488498
}
489499
None => Ok(EvaluatedToAmbig),
490500
},
@@ -508,8 +518,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
508518
match project::poly_project_and_unify_type(self, &project_obligation) {
509519
Ok(Ok(Some(mut subobligations))) => {
510520
self.add_depth(subobligations.iter_mut(), obligation.recursion_depth);
511-
let result = self
512-
.evaluate_predicates_recursively(previous_stack, subobligations);
521+
let result = self.evaluate_predicates_recursively(
522+
previous_stack,
523+
subobligations.into_iter(),
524+
);
513525
if let Some(key) =
514526
ProjectionCacheKey::from_poly_projection_predicate(self, data)
515527
{
@@ -1245,7 +1257,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12451257
) -> Result<EvaluationResult, OverflowError> {
12461258
self.evaluation_probe(|this| {
12471259
match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
1248-
Ok(obligations) => this.evaluate_predicates_recursively(stack.list(), obligations),
1260+
Ok(obligations) => {
1261+
this.evaluate_predicates_recursively(stack.list(), obligations.into_iter())
1262+
}
12491263
Err(()) => Ok(EvaluatedToErr),
12501264
}
12511265
})

compiler/rustc_trait_selection/src/traits/specialize/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
176176
/// generics of `target_impl`, including both those needed to unify with
177177
/// `source_trait_ref` and those whose identity is determined via a where
178178
/// clause in the impl.
179-
fn fulfill_implication<'a, 'tcx>(
179+
crate fn fulfill_implication<'a, 'tcx>(
180180
infcx: &InferCtxt<'a, 'tcx>,
181181
param_env: ty::ParamEnv<'tcx>,
182182
source_trait_ref: ty::TraitRef<'tcx>,

compiler/rustc_typeck/src/check/check.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,11 @@ pub(super) fn check_fn<'a, 'tcx>(
131131
// for simple cases like `fn foo(x: Trait)`,
132132
// where we would error once on the parameter as a whole, and once on the binding `x`.
133133
if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals {
134-
fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
134+
fcx.require_type_is_sized_deferred(
135+
param_ty,
136+
param.pat.span,
137+
traits::SizedArgumentType(ty_span),
138+
);
135139
}
136140

137141
fcx.write_ty(param.hir_id, param_ty);

src/test/ui/closures/issue-41366.stderr

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,3 @@
1-
error[E0631]: type mismatch in closure arguments
2-
--> $DIR/issue-41366.rs:10:5
3-
|
4-
LL | (&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
5-
| ^^------^
6-
| | |
7-
| | found signature of `fn(u16) -> _`
8-
| expected signature of `fn(<u32 as T<'x>>::V) -> _`
9-
|
10-
= note: required for the cast to the object type `dyn for<'x> Fn(<u32 as T<'x>>::V)`
11-
121
error[E0277]: the size for values of type `<u32 as T<'_>>::V` cannot be known at compilation time
132
--> $DIR/issue-41366.rs:10:8
143
|
@@ -26,6 +15,17 @@ help: function arguments must have a statically known size, borrowed types alway
2615
LL | (&|&_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
2716
| ^
2817

18+
error[E0631]: type mismatch in closure arguments
19+
--> $DIR/issue-41366.rs:10:5
20+
|
21+
LL | (&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
22+
| ^^------^
23+
| | |
24+
| | found signature of `fn(u16) -> _`
25+
| expected signature of `fn(<u32 as T<'x>>::V) -> _`
26+
|
27+
= note: required for the cast to the object type `dyn for<'x> Fn(<u32 as T<'x>>::V)`
28+
2929
error: aborting due to 2 previous errors
3030

3131
Some errors have detailed explanations: E0277, E0631.

src/test/ui/question-mark-type-infer.stderr

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,8 @@ LL | l.iter().map(f).collect()?
88
= note: required by `into_result`
99
help: consider specifying the type argument in the method call
1010
|
11-
LL | l.iter().map(f).collect::<ControlFlow<_, _>>()?
12-
| ^^^^^^^^^^^^^^^^^^^^^
13-
LL | l.iter().map(f).collect::<Option<_>>()?
14-
| ^^^^^^^^^^^^^
15-
LL | l.iter().map(f).collect::<Poll<Option<std::result::Result<_, _>>>>()?
16-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17-
LL | l.iter().map(f).collect::<Poll<std::result::Result<_, _>>>()?
18-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
19-
and 1 other candidate
11+
LL | l.iter().map(f).collect::<B>()?
12+
| ^^^^^
2013

2114
error: aborting due to previous error
2215

src/test/ui/suggestions/appropriate-type-param-turbofish.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ mod c {
3636
trait T: Sized {
3737
fn new() -> Self;
3838
}
39+
3940
fn x<X: T>() -> X {
4041
T::new()
4142
}
@@ -46,6 +47,14 @@ impl T for S {
4647
}
4748
}
4849

50+
struct AAA<X> { x: X, }
51+
52+
impl<Z: std::fmt::Display> std::iter::FromIterator<Z> for AAA<Z> {
53+
fn from_iter<I: IntoIterator<Item = Z>>(_iter: I) -> AAA<Z> {
54+
panic!()
55+
}
56+
}
57+
4958
fn foo() {
5059
x(); //~ ERROR type annotations needed
5160
}
@@ -54,4 +63,34 @@ fn bar() {
5463
let _ = x(); //~ ERROR type annotations needed
5564
}
5665

57-
fn main() {}
66+
fn qux() {
67+
let x: Vec<&std::path::Path> = vec![];
68+
let y = x.into_iter().collect(); //~ ERROR type annotations needed
69+
}
70+
71+
trait Foo {
72+
fn foo<T: Bar<K>, K>(&self) -> T {
73+
panic!()
74+
}
75+
}
76+
77+
trait Bar<X> {}
78+
79+
struct R<X>(X);
80+
impl<X> Bar<X> for R<X> {}
81+
struct K<X>(X);
82+
impl Bar<i32> for K<i32> {}
83+
84+
struct I;
85+
86+
impl Foo for I {}
87+
88+
// These two cases do not have good suggestions yet:
89+
fn bat() {
90+
let _ = I.foo(); //~ ERROR type annotations needed
91+
}
92+
fn bak<T: Into<String>>() {}
93+
94+
fn main() {
95+
bak(); //~ ERROR type annotations needed
96+
}

0 commit comments

Comments
 (0)