Skip to content

Commit a0d8ea4

Browse files
authored
Rollup merge of rust-lang#80828 - SNCPlay42:opaque-projections, r=estebank
Fix expected/found order on impl trait projection mismatch error fixes rust-lang#68561 This PR adds a new `ObligationCauseCode` used when checking the concrete type of an impl trait satisfies its bounds, and checks for that cause code in the existing test to see if a projection's normalized type should be the "expected" or "found" type. The second commit adds a `peel_derives` to that test, which appears to be necessary in some cases (see projection-mismatch-in-impl-where-clause.rs, which would still give expected/found in the wrong order otherwise). This caused some other changes in diagnostics not involving impl trait, but they look correct to me.
2 parents d474075 + 525e23a commit a0d8ea4

18 files changed

+109
-55
lines changed

compiler/rustc_middle/src/traits/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,9 @@ pub enum ObligationCauseCode<'tcx> {
323323

324324
/// #[feature(trivial_bounds)] is not enabled
325325
TrivialBound,
326+
327+
/// If `X` is the concrete type of an opaque type `impl Y`, then `X` must implement `Y`
328+
OpaqueType,
326329
}
327330

328331
impl ObligationCauseCode<'_> {

compiler/rustc_middle/src/ty/error.rs

+32-16
Original file line numberDiff line numberDiff line change
@@ -511,13 +511,18 @@ impl<T> Trait<T> for X {
511511
"consider constraining the associated type `{}` to `{}`",
512512
values.found, values.expected,
513513
);
514-
if !self.suggest_constraint(
514+
if !(self.suggest_constraining_opaque_associated_type(
515+
db,
516+
&msg,
517+
proj_ty,
518+
values.expected,
519+
) || self.suggest_constraint(
515520
db,
516521
&msg,
517522
body_owner_def_id,
518523
proj_ty,
519524
values.expected,
520-
) {
525+
)) {
521526
db.help(&msg);
522527
db.note(
523528
"for more information, visit \
@@ -701,20 +706,7 @@ impl<T> Trait<T> for X {
701706
}
702707
}
703708

704-
if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() {
705-
// When the expected `impl Trait` is not defined in the current item, it will come from
706-
// a return type. This can occur when dealing with `TryStream` (#71035).
707-
if self.constrain_associated_type_structured_suggestion(
708-
db,
709-
self.def_span(def_id),
710-
&assoc,
711-
proj_ty.trait_ref_and_own_substs(self).1,
712-
values.found,
713-
&msg,
714-
) {
715-
return;
716-
}
717-
}
709+
self.suggest_constraining_opaque_associated_type(db, &msg, proj_ty, values.found);
718710

719711
if self.point_at_associated_type(db, body_owner_def_id, values.found) {
720712
return;
@@ -752,6 +744,30 @@ fn foo(&self) -> Self::T { String::new() }
752744
}
753745
}
754746

747+
/// When the expected `impl Trait` is not defined in the current item, it will come from
748+
/// a return type. This can occur when dealing with `TryStream` (#71035).
749+
fn suggest_constraining_opaque_associated_type(
750+
self,
751+
db: &mut DiagnosticBuilder<'_>,
752+
msg: &str,
753+
proj_ty: &ty::ProjectionTy<'tcx>,
754+
ty: Ty<'tcx>,
755+
) -> bool {
756+
let assoc = self.associated_item(proj_ty.item_def_id);
757+
if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() {
758+
self.constrain_associated_type_structured_suggestion(
759+
db,
760+
self.def_span(def_id),
761+
&assoc,
762+
proj_ty.trait_ref_and_own_substs(self).1,
763+
ty,
764+
&msg,
765+
)
766+
} else {
767+
false
768+
}
769+
}
770+
755771
fn point_at_methods_that_satisfy_associated_type(
756772
self,
757773
db: &mut DiagnosticBuilder<'_>,

compiler/rustc_trait_selection/src/opaque_types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1171,7 +1171,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
11711171
// This also instantiates nested instances of `impl Trait`.
11721172
let predicate = self.instantiate_opaque_types_in_map(predicate);
11731173

1174-
let cause = traits::ObligationCause::new(span, self.body_id, traits::MiscObligation);
1174+
let cause = traits::ObligationCause::new(span, self.body_id, traits::OpaqueType);
11751175

11761176
// Require that the predicate holds for the concrete type.
11771177
debug!("instantiate_opaque_types: predicate={:?}", predicate);

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -1226,10 +1226,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
12261226
);
12271227

12281228
let is_normalized_ty_expected = !matches!(
1229-
obligation.cause.code,
1229+
obligation.cause.code.peel_derives(),
12301230
ObligationCauseCode::ItemObligation(_)
12311231
| ObligationCauseCode::BindingObligation(_, _)
12321232
| ObligationCauseCode::ObjectCastObligation(_)
1233+
| ObligationCauseCode::OpaqueType
12331234
);
12341235

12351236
if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp(

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

+1
Original file line numberDiff line numberDiff line change
@@ -1840,6 +1840,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
18401840
| ObligationCauseCode::MethodReceiver
18411841
| ObligationCauseCode::ReturnNoExpression
18421842
| ObligationCauseCode::UnifyReceiver(..)
1843+
| ObligationCauseCode::OpaqueType
18431844
| ObligationCauseCode::MiscObligation => {}
18441845
ObligationCauseCode::SliceOrArrayElem => {
18451846
err.note("slice and array elements must have `Sized` type");

src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ error[E0271]: type mismatch resolving `<impl Bar as Foo>::Item == i32`
22
--> $DIR/impl-trait-return-missing-constraint.rs:25:13
33
|
44
LL | fn bar() -> impl Bar {
5-
| -------- the expected opaque type
5+
| -------- the found opaque type
66
...
77
LL | fn baz() -> impl Bar<Item = i32> {
8-
| ^^^^^^^^^^^^^^^^^^^^ expected associated type, found `i32`
8+
| ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found associated type
99
|
10-
= note: expected associated type `<impl Bar as Foo>::Item`
11-
found type `i32`
10+
= note: expected type `i32`
11+
found associated type `<impl Bar as Foo>::Item`
1212
help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32`
1313
|
1414
LL | fn bar() -> impl Bar<Item = i32> {

src/test/ui/associated-types/issue-44153.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | fn visit() {}
55
| ---------- required by `Visit::visit`
66
...
77
LL | <() as Visit>::visit();
8-
| ^^^^^^^^^^^^^^^^^^^^ expected `()`, found `&()`
8+
| ^^^^^^^^^^^^^^^^^^^^ expected `&()`, found `()`
99
|
1010
= note: required because of the requirements on the impl of `Visit` for `()`
1111

src/test/ui/generator/type-mismatch-signature-deduction.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-
1616
--> $DIR/type-mismatch-signature-deduction.rs:5:13
1717
|
1818
LL | fn foo() -> impl Generator<Return = i32> {
19-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Result`, found `i32`
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found enum `Result`
2020
|
21-
= note: expected enum `Result<{integer}, _>`
22-
found type `i32`
21+
= note: expected type `i32`
22+
found enum `Result<{integer}, _>`
2323

2424
error: aborting due to 2 previous errors
2525

src/test/ui/impl-trait/bound-normalization-fail.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as imp
1111
--> $DIR/bound-normalization-fail.rs:27:32
1212
|
1313
LL | fn foo_fail<T: Trait>() -> impl FooLike<Output=T::Assoc> {
14-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found `()`
1515
|
16-
= note: expected type `()`
17-
found associated type `<T as impl_trait::Trait>::Assoc`
16+
= note: expected associated type `<T as impl_trait::Trait>::Assoc`
17+
found type `()`
1818
help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc` to `()`
1919
|
2020
LL | fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output=T::Assoc> {
@@ -30,10 +30,10 @@ error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lif
3030
--> $DIR/bound-normalization-fail.rs:43:41
3131
|
3232
LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output=T::Assoc> {
33-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
33+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found `()`
3434
|
35-
= note: expected type `()`
36-
found associated type `<T as lifetimes::Trait<'static>>::Assoc`
35+
= note: expected associated type `<T as lifetimes::Trait<'static>>::Assoc`
36+
found type `()`
3737
help: consider constraining the associated type `<T as lifetimes::Trait<'static>>::Assoc` to `()`
3838
|
3939
LL | fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output=T::Assoc> {

src/test/ui/impl-trait/equality2.stderr

+4-2
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@ LL | let _: i32 = Leak::leak(hide(0_i32));
3535
|
3636
= note: expected type `i32`
3737
found associated type `<impl Foo as Leak>::T`
38-
= help: consider constraining the associated type `<impl Foo as Leak>::T` to `i32`
39-
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
38+
help: consider constraining the associated type `<impl Foo as Leak>::T` to `i32`
39+
|
40+
LL | fn hide<T: Foo>(x: T) -> impl Foo<T = i32> {
41+
| ^^^^^^^^^
4042

4143
error[E0308]: mismatched types
4244
--> $DIR/equality2.rs:38:10

src/test/ui/impl-trait/issues/issue-70877.full_tait.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ error[E0271]: type mismatch resolving `<Bar as Iterator>::Item == Box<(dyn for<'
22
--> $DIR/issue-70877.rs:11:12
33
|
44
LL | type FooRet = impl std::fmt::Debug;
5-
| -------------------- the expected opaque type
5+
| -------------------- the found opaque type
66
...
77
LL | type Foo = impl Iterator<Item = FooItem>;
8-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found enum `Option`
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Option`, found opaque type
99
|
10-
= note: expected struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> impl Debug + 'static)>`
11-
found struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
10+
= note: expected struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
11+
found struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> impl Debug + 'static)>`
1212

1313
error: aborting due to previous error
1414

src/test/ui/impl-trait/issues/issue-70877.min_tait.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ error[E0271]: type mismatch resolving `<Bar as Iterator>::Item == Box<(dyn for<'
22
--> $DIR/issue-70877.rs:11:12
33
|
44
LL | type FooRet = impl std::fmt::Debug;
5-
| -------------------- the expected opaque type
5+
| -------------------- the found opaque type
66
...
77
LL | type Foo = impl Iterator<Item = FooItem>;
8-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found enum `Option`
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Option`, found opaque type
99
|
10-
= note: expected struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> impl Debug + 'static)>`
11-
found struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
10+
= note: expected struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
11+
found struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> impl Debug + 'static)>`
1212

1313
error: aborting due to previous error
1414

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
pub trait Super {
2+
type Assoc;
3+
}
4+
5+
impl Super for () {
6+
type Assoc = u8;
7+
}
8+
9+
pub trait Test {}
10+
11+
impl<T> Test for T where T: Super<Assoc = ()> {}
12+
13+
fn test() -> impl Test {
14+
//~^ERROR type mismatch resolving `<() as Super>::Assoc == ()`
15+
()
16+
}
17+
18+
fn main() {
19+
let a = test();
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0271]: type mismatch resolving `<() as Super>::Assoc == ()`
2+
--> $DIR/projection-mismatch-in-impl-where-clause.rs:13:14
3+
|
4+
LL | fn test() -> impl Test {
5+
| ^^^^^^^^^ expected `()`, found `u8`
6+
|
7+
= note: required because of the requirements on the impl of `Test` for `()`
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0271`.

src/test/ui/issues/issue-33941.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _,
1111
--> $DIR/issue-33941.rs:4:14
1212
|
1313
LL | for _ in HashMap::new().iter().cloned() {}
14-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found tuple
1515
|
16-
= note: expected tuple `(&_, &_)`
17-
found reference `&_`
16+
= note: expected reference `&_`
17+
found tuple `(&_, &_)`
1818
= note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
1919
= note: required because of the requirements on the impl of `IntoIterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
2020
= note: required by `into_iter`
@@ -23,10 +23,10 @@ error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _,
2323
--> $DIR/issue-33941.rs:4:14
2424
|
2525
LL | for _ in HashMap::new().iter().cloned() {}
26-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference
26+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found tuple
2727
|
28-
= note: expected tuple `(&_, &_)`
29-
found reference `&_`
28+
= note: expected reference `&_`
29+
found tuple `(&_, &_)`
3030
= note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
3131
= note: required by `std::iter::Iterator::next`
3232

src/test/ui/issues/issue-39970.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | fn visit() {}
55
| ---------- required by `Visit::visit`
66
...
77
LL | <() as Visit>::visit();
8-
| ^^^^^^^^^^^^^^^^^^^^ expected `&()`, found `()`
8+
| ^^^^^^^^^^^^^^^^^^^^ expected `()`, found `&()`
99
|
1010
= note: required because of the requirements on the impl of `Visit` for `()`
1111

src/test/ui/type-alias-impl-trait/issue-63279.full_tait.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ error[E0271]: type mismatch resolving `<[closure@$DIR/issue-63279.rs:11:5: 11:28
1111
--> $DIR/issue-63279.rs:8:16
1212
|
1313
LL | type Closure = impl FnOnce();
14-
| ^^^^^^^^^^^^^ expected opaque type, found `()`
14+
| ^^^^^^^^^^^^^ expected `()`, found opaque type
1515
|
16-
= note: expected opaque type `impl FnOnce<()>`
17-
found unit type `()`
16+
= note: expected unit type `()`
17+
found opaque type `impl FnOnce<()>`
1818

1919
error: aborting due to previous error; 1 warning emitted
2020

src/test/ui/type-alias-impl-trait/issue-63279.min_tait.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ error[E0271]: type mismatch resolving `<[closure@$DIR/issue-63279.rs:11:5: 11:28
1111
--> $DIR/issue-63279.rs:8:16
1212
|
1313
LL | type Closure = impl FnOnce();
14-
| ^^^^^^^^^^^^^ expected opaque type, found `()`
14+
| ^^^^^^^^^^^^^ expected `()`, found opaque type
1515
|
16-
= note: expected opaque type `impl FnOnce<()>`
17-
found unit type `()`
16+
= note: expected unit type `()`
17+
found opaque type `impl FnOnce<()>`
1818

1919
error: aborting due to 2 previous errors
2020

0 commit comments

Comments
 (0)