Skip to content

Commit

Permalink
Rollup merge of rust-lang#80828 - SNCPlay42:opaque-projections, r=est…
Browse files Browse the repository at this point in the history
…ebank

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.
  • Loading branch information
Dylan-DPC authored Apr 1, 2021
2 parents d474075 + 525e23a commit a0d8ea4
Show file tree
Hide file tree
Showing 18 changed files with 109 additions and 55 deletions.
3 changes: 3 additions & 0 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,9 @@ pub enum ObligationCauseCode<'tcx> {

/// #[feature(trivial_bounds)] is not enabled
TrivialBound,

/// If `X` is the concrete type of an opaque type `impl Y`, then `X` must implement `Y`
OpaqueType,
}

impl ObligationCauseCode<'_> {
Expand Down
48 changes: 32 additions & 16 deletions compiler/rustc_middle/src/ty/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,13 +511,18 @@ impl<T> Trait<T> for X {
"consider constraining the associated type `{}` to `{}`",
values.found, values.expected,
);
if !self.suggest_constraint(
if !(self.suggest_constraining_opaque_associated_type(
db,
&msg,
proj_ty,
values.expected,
) || self.suggest_constraint(
db,
&msg,
body_owner_def_id,
proj_ty,
values.expected,
) {
)) {
db.help(&msg);
db.note(
"for more information, visit \
Expand Down Expand Up @@ -701,20 +706,7 @@ impl<T> Trait<T> for X {
}
}

if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() {
// When the expected `impl Trait` is not defined in the current item, it will come from
// a return type. This can occur when dealing with `TryStream` (#71035).
if self.constrain_associated_type_structured_suggestion(
db,
self.def_span(def_id),
&assoc,
proj_ty.trait_ref_and_own_substs(self).1,
values.found,
&msg,
) {
return;
}
}
self.suggest_constraining_opaque_associated_type(db, &msg, proj_ty, values.found);

if self.point_at_associated_type(db, body_owner_def_id, values.found) {
return;
Expand Down Expand Up @@ -752,6 +744,30 @@ fn foo(&self) -> Self::T { String::new() }
}
}

/// When the expected `impl Trait` is not defined in the current item, it will come from
/// a return type. This can occur when dealing with `TryStream` (#71035).
fn suggest_constraining_opaque_associated_type(
self,
db: &mut DiagnosticBuilder<'_>,
msg: &str,
proj_ty: &ty::ProjectionTy<'tcx>,
ty: Ty<'tcx>,
) -> bool {
let assoc = self.associated_item(proj_ty.item_def_id);
if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() {
self.constrain_associated_type_structured_suggestion(
db,
self.def_span(def_id),
&assoc,
proj_ty.trait_ref_and_own_substs(self).1,
ty,
&msg,
)
} else {
false
}
}

fn point_at_methods_that_satisfy_associated_type(
self,
db: &mut DiagnosticBuilder<'_>,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1171,7 +1171,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
// This also instantiates nested instances of `impl Trait`.
let predicate = self.instantiate_opaque_types_in_map(predicate);

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

// Require that the predicate holds for the concrete type.
debug!("instantiate_opaque_types: predicate={:?}", predicate);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1226,10 +1226,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
);

let is_normalized_ty_expected = !matches!(
obligation.cause.code,
obligation.cause.code.peel_derives(),
ObligationCauseCode::ItemObligation(_)
| ObligationCauseCode::BindingObligation(_, _)
| ObligationCauseCode::ObjectCastObligation(_)
| ObligationCauseCode::OpaqueType
);

if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1840,6 +1840,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
| ObligationCauseCode::MethodReceiver
| ObligationCauseCode::ReturnNoExpression
| ObligationCauseCode::UnifyReceiver(..)
| ObligationCauseCode::OpaqueType
| ObligationCauseCode::MiscObligation => {}
ObligationCauseCode::SliceOrArrayElem => {
err.note("slice and array elements must have `Sized` type");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ error[E0271]: type mismatch resolving `<impl Bar as Foo>::Item == i32`
--> $DIR/impl-trait-return-missing-constraint.rs:25:13
|
LL | fn bar() -> impl Bar {
| -------- the expected opaque type
| -------- the found opaque type
...
LL | fn baz() -> impl Bar<Item = i32> {
| ^^^^^^^^^^^^^^^^^^^^ expected associated type, found `i32`
| ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found associated type
|
= note: expected associated type `<impl Bar as Foo>::Item`
found type `i32`
= note: expected type `i32`
found associated type `<impl Bar as Foo>::Item`
help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32`
|
LL | fn bar() -> impl Bar<Item = i32> {
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/associated-types/issue-44153.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ LL | fn visit() {}
| ---------- required by `Visit::visit`
...
LL | <() as Visit>::visit();
| ^^^^^^^^^^^^^^^^^^^^ expected `()`, found `&()`
| ^^^^^^^^^^^^^^^^^^^^ expected `&()`, found `()`
|
= note: required because of the requirements on the impl of `Visit` for `()`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-
--> $DIR/type-mismatch-signature-deduction.rs:5:13
|
LL | fn foo() -> impl Generator<Return = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Result`, found `i32`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found enum `Result`
|
= note: expected enum `Result<{integer}, _>`
found type `i32`
= note: expected type `i32`
found enum `Result<{integer}, _>`

error: aborting due to 2 previous errors

Expand Down
12 changes: 6 additions & 6 deletions src/test/ui/impl-trait/bound-normalization-fail.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as imp
--> $DIR/bound-normalization-fail.rs:27:32
|
LL | fn foo_fail<T: Trait>() -> impl FooLike<Output=T::Assoc> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found `()`
|
= note: expected type `()`
found associated type `<T as impl_trait::Trait>::Assoc`
= note: expected associated type `<T as impl_trait::Trait>::Assoc`
found type `()`
help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc` to `()`
|
LL | fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output=T::Assoc> {
Expand All @@ -30,10 +30,10 @@ error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lif
--> $DIR/bound-normalization-fail.rs:43:41
|
LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output=T::Assoc> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found `()`
|
= note: expected type `()`
found associated type `<T as lifetimes::Trait<'static>>::Assoc`
= note: expected associated type `<T as lifetimes::Trait<'static>>::Assoc`
found type `()`
help: consider constraining the associated type `<T as lifetimes::Trait<'static>>::Assoc` to `()`
|
LL | fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output=T::Assoc> {
Expand Down
6 changes: 4 additions & 2 deletions src/test/ui/impl-trait/equality2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ LL | let _: i32 = Leak::leak(hide(0_i32));
|
= note: expected type `i32`
found associated type `<impl Foo as Leak>::T`
= help: consider constraining the associated type `<impl Foo as Leak>::T` to `i32`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
help: consider constraining the associated type `<impl Foo as Leak>::T` to `i32`
|
LL | fn hide<T: Foo>(x: T) -> impl Foo<T = i32> {
| ^^^^^^^^^

error[E0308]: mismatched types
--> $DIR/equality2.rs:38:10
Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/impl-trait/issues/issue-70877.full_tait.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ error[E0271]: type mismatch resolving `<Bar as Iterator>::Item == Box<(dyn for<'
--> $DIR/issue-70877.rs:11:12
|
LL | type FooRet = impl std::fmt::Debug;
| -------------------- the expected opaque type
| -------------------- the found opaque type
...
LL | type Foo = impl Iterator<Item = FooItem>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found enum `Option`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Option`, found opaque type
|
= note: expected struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> impl Debug + 'static)>`
found struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
= note: expected struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
found struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> impl Debug + 'static)>`

error: aborting due to previous error

Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/impl-trait/issues/issue-70877.min_tait.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ error[E0271]: type mismatch resolving `<Bar as Iterator>::Item == Box<(dyn for<'
--> $DIR/issue-70877.rs:11:12
|
LL | type FooRet = impl std::fmt::Debug;
| -------------------- the expected opaque type
| -------------------- the found opaque type
...
LL | type Foo = impl Iterator<Item = FooItem>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found enum `Option`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Option`, found opaque type
|
= note: expected struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> impl Debug + 'static)>`
found struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
= note: expected struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
found struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> impl Debug + 'static)>`

error: aborting due to previous error

Expand Down
20 changes: 20 additions & 0 deletions src/test/ui/impl-trait/projection-mismatch-in-impl-where-clause.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
pub trait Super {
type Assoc;
}

impl Super for () {
type Assoc = u8;
}

pub trait Test {}

impl<T> Test for T where T: Super<Assoc = ()> {}

fn test() -> impl Test {
//~^ERROR type mismatch resolving `<() as Super>::Assoc == ()`
()
}

fn main() {
let a = test();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0271]: type mismatch resolving `<() as Super>::Assoc == ()`
--> $DIR/projection-mismatch-in-impl-where-clause.rs:13:14
|
LL | fn test() -> impl Test {
| ^^^^^^^^^ expected `()`, found `u8`
|
= note: required because of the requirements on the impl of `Test` for `()`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0271`.
12 changes: 6 additions & 6 deletions src/test/ui/issues/issue-33941.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _,
--> $DIR/issue-33941.rs:4:14
|
LL | for _ in HashMap::new().iter().cloned() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found tuple
|
= note: expected tuple `(&_, &_)`
found reference `&_`
= note: expected reference `&_`
found tuple `(&_, &_)`
= note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
= note: required because of the requirements on the impl of `IntoIterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
= note: required by `into_iter`
Expand All @@ -23,10 +23,10 @@ error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _,
--> $DIR/issue-33941.rs:4:14
|
LL | for _ in HashMap::new().iter().cloned() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found tuple
|
= note: expected tuple `(&_, &_)`
found reference `&_`
= note: expected reference `&_`
found tuple `(&_, &_)`
= note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
= note: required by `std::iter::Iterator::next`

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-39970.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ LL | fn visit() {}
| ---------- required by `Visit::visit`
...
LL | <() as Visit>::visit();
| ^^^^^^^^^^^^^^^^^^^^ expected `&()`, found `()`
| ^^^^^^^^^^^^^^^^^^^^ expected `()`, found `&()`
|
= note: required because of the requirements on the impl of `Visit` for `()`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ error[E0271]: type mismatch resolving `<[closure@$DIR/issue-63279.rs:11:5: 11:28
--> $DIR/issue-63279.rs:8:16
|
LL | type Closure = impl FnOnce();
| ^^^^^^^^^^^^^ expected opaque type, found `()`
| ^^^^^^^^^^^^^ expected `()`, found opaque type
|
= note: expected opaque type `impl FnOnce<()>`
found unit type `()`
= note: expected unit type `()`
found opaque type `impl FnOnce<()>`

error: aborting due to previous error; 1 warning emitted

Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/type-alias-impl-trait/issue-63279.min_tait.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ error[E0271]: type mismatch resolving `<[closure@$DIR/issue-63279.rs:11:5: 11:28
--> $DIR/issue-63279.rs:8:16
|
LL | type Closure = impl FnOnce();
| ^^^^^^^^^^^^^ expected opaque type, found `()`
| ^^^^^^^^^^^^^ expected `()`, found opaque type
|
= note: expected opaque type `impl FnOnce<()>`
found unit type `()`
= note: expected unit type `()`
found opaque type `impl FnOnce<()>`

error: aborting due to 2 previous errors

Expand Down

0 comments on commit a0d8ea4

Please sign in to comment.