Skip to content

Commit 19695df

Browse files
Check built-in operator obligation before the method's WF obligations so as to not incompletely guide inference
1 parent f45d4ac commit 19695df

File tree

5 files changed

+54
-22
lines changed

5 files changed

+54
-22
lines changed

compiler/rustc_hir_typeck/src/method/mod.rs

+14-12
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
359359

360360
let obligation = traits::Obligation::new(
361361
self.tcx,
362-
cause,
362+
cause.clone(),
363363
self.param_env,
364364
ty::TraitRef::new_from_args(self.tcx, trait_def_id, args),
365365
);
@@ -385,6 +385,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
385385

386386
debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
387387
let mut obligations = PredicateObligations::new();
388+
// Register the operator's obligation first to constrain the "rhs" argument (or inputs
389+
// for a fn-like operator). This would happen coincidentally as part of normalizing the
390+
// signature below if the output type is constrained but a param-env predicate, but for
391+
// `AsyncFn*`, the output type doesn't actually show up in the signature, so we end up
392+
// trying to prove other WF predicates first which incompletely constrains the type.
393+
obligations.push(obligation);
388394

389395
// Instantiate late-bound regions and instantiate the trait
390396
// parameters into the method type to get the actual method type.
@@ -393,11 +399,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
393399
// function signature so that normalization does not need to deal
394400
// with bound regions.
395401
let fn_sig = tcx.fn_sig(def_id).instantiate(self.tcx, args);
396-
let fn_sig =
397-
self.instantiate_binder_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig);
402+
let fn_sig = self.instantiate_binder_with_fresh_vars(cause.span, infer::FnCall, fn_sig);
398403

399404
let InferOk { value: fn_sig, obligations: o } =
400-
self.at(&obligation.cause, self.param_env).normalize(fn_sig);
405+
self.at(&cause, self.param_env).normalize(fn_sig);
401406
obligations.extend(o);
402407

403408
// Register obligations for the parameters. This will include the
@@ -411,26 +416,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
411416
let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, args);
412417

413418
let InferOk { value: bounds, obligations: o } =
414-
self.at(&obligation.cause, self.param_env).normalize(bounds);
419+
self.at(&cause, self.param_env).normalize(bounds);
415420
obligations.extend(o);
416421
assert!(!bounds.has_escaping_bound_vars());
417422

418-
let predicates_cause = obligation.cause.clone();
419423
obligations.extend(traits::predicates_for_generics(
420-
move |_, _| predicates_cause.clone(),
424+
|_, _| cause.clone(),
421425
self.param_env,
422426
bounds,
423427
));
424428

425429
// Also add an obligation for the method type being well-formed.
426430
let method_ty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(fn_sig));
427-
debug!(
428-
"lookup_method_in_trait: matched method method_ty={:?} obligation={:?}",
429-
method_ty, obligation
430-
);
431+
debug!("lookup_method_in_trait: matched method method_ty={:?}", method_ty);
432+
431433
obligations.push(traits::Obligation::new(
432434
tcx,
433-
obligation.cause,
435+
cause.clone(),
434436
self.param_env,
435437
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
436438
method_ty.into(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//@ check-pass
2+
3+
// Ensure that a param-env predicate like `(T,): Sized` doesn't get in the way of us
4+
// confirming the built-in call operator for `AsyncFnOnce`. This happens because we
5+
// end up with a signature like:
6+
//
7+
// `<F as AsyncFnOnce<(?0,)>>::async_call_once(self) -> <F as AsyncFnOnce<(?0,)>>::CallOnceFuture`
8+
//
9+
// (where we use fresh infer vars for each arg since we haven't actually typeck'd the args yet).
10+
// But normalizing that signature keeps the associated type rigid, so we don't end up
11+
// constraining `?0` like we would if we were normalizing the analogous `FnOnce` call...
12+
// Then we were checking that the method signature was WF, which would incompletely constrain
13+
// `(?0,) == (T,)` via the param-env, leading to us later failing on `F: AsyncFnOnce<(T,)>`.
14+
15+
fn run<F, T>(f: F)
16+
where
17+
F: AsyncFnOnce(i32),
18+
(T,): Sized,
19+
{
20+
f(1i32);
21+
}
22+
23+
fn main() {}

tests/ui/inference/issue-70082.stderr

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
error[E0284]: type annotations needed
1+
error[E0283]: type annotations needed
22
--> $DIR/issue-70082.rs:7:33
33
|
44
LL | let y: f64 = 0.01f64 * 1i16.into();
55
| - ^^^^
66
| |
77
| type must be known at this point
88
|
9-
= note: cannot satisfy `<f64 as Mul<_>>::Output == f64`
9+
= note: multiple `impl`s satisfying `f64: Mul<_>` found in the `core` crate:
10+
- impl Mul for f64;
11+
- impl Mul<&f64> for f64;
1012
help: try using a fully qualified path to specify the expected types
1113
|
1214
LL - let y: f64 = 0.01f64 * 1i16.into();
@@ -15,4 +17,4 @@ LL + let y: f64 = 0.01f64 * <i16 as Into<T>>::into(1i16);
1517

1618
error: aborting due to 1 previous error
1719

18-
For more information about this error, try `rustc --explain E0284`.
20+
For more information about this error, try `rustc --explain E0283`.

tests/ui/inference/issue-71584.stderr

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
error[E0284]: type annotations needed
1+
error[E0283]: type annotations needed
22
--> $DIR/issue-71584.rs:5:15
33
|
44
LL | d = d % n.into();
55
| - ^^^^
66
| |
77
| type must be known at this point
88
|
9-
= note: cannot satisfy `<u64 as Rem<_>>::Output == u64`
9+
= note: multiple `impl`s satisfying `u64: Rem<_>` found in the `core` crate:
10+
- impl Rem for u64;
11+
- impl Rem<&u64> for u64;
12+
- impl Rem<NonZero<u64>> for u64;
1013
help: try using a fully qualified path to specify the expected types
1114
|
1215
LL - d = d % n.into();
@@ -15,4 +18,4 @@ LL + d = d % <u32 as Into<T>>::into(n);
1518

1619
error: aborting due to 1 previous error
1720

18-
For more information about this error, try `rustc --explain E0284`.
21+
For more information about this error, try `rustc --explain E0283`.

tests/ui/issues/issue-24036.stderr

+6-4
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,21 @@ LL | x = |c| c + 1;
1111
= note: no two closures, even if identical, have the same type
1212
= help: consider boxing your closure and/or using it as a trait object
1313

14-
error[E0284]: type annotations needed
14+
error[E0283]: type annotations needed
1515
--> $DIR/issue-24036.rs:9:15
1616
|
1717
LL | 1 => |c| c + 1,
1818
| ^ - type must be known at this point
1919
|
20-
= note: cannot satisfy `<_ as Add<i32>>::Output == _`
20+
= note: multiple `impl`s satisfying `_: Add<i32>` found in the `core` crate:
21+
- impl Add for i32;
22+
- impl<'a> Add<i32> for &'a i32;
2123
help: consider giving this closure parameter an explicit type
2224
|
2325
LL | 1 => |c: /* Type */| c + 1,
2426
| ++++++++++++
2527

2628
error: aborting due to 2 previous errors
2729

28-
Some errors have detailed explanations: E0284, E0308.
29-
For more information about an error, try `rustc --explain E0284`.
30+
Some errors have detailed explanations: E0283, E0308.
31+
For more information about an error, try `rustc --explain E0283`.

0 commit comments

Comments
 (0)