Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix expected/found order on impl trait projection mismatch error #80828

Merged
merged 2 commits into from
Apr 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -509,13 +509,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(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this to avoid losing a helpful suggestion in the impl-trait-return-missing-constraint test.

I wonder how much else of the expected_projection function makes sense to run in this case (when the projection type is found) as well.

db,
&msg,
body_owner_def_id,
proj_ty,
values.expected,
) {
)) {
db.help(&msg);
db.note(
"for more information, visit \
Expand Down Expand Up @@ -699,20 +704,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 @@ -750,6 +742,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 @@ -1190,10 +1190,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