Skip to content

[experiment] fulfill diagnostics: do not look into T: IntoIterator #99719

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

Closed
wants to merge 1 commit into from
Closed
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
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1412,6 +1412,10 @@ rustc_queries! {
separate_provide_extern
}

query is_general_impl(def_id: DefId) -> bool {
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if this needs to use a qualifier like "fully" or "maximally" to apply to "general" (I suppose "general" is better than "blanket"? at least a doc comment here could explain the connection).

desc { |tcx| "looking up whether `{}` is a general impl", tcx.def_path_str(def_id) }
}

query check_well_formed(key: LocalDefId) -> () {
desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// candidate which assumes $0 == int, one that assumes `$0 ==
// usize`, etc. This spells an ambiguity.

let mut candidates = self.filter_impls(candidates, stack.obligation);

let candidates = self.filter_impls(candidates, stack.obligation);
let mut candidates = candidates
.into_iter()
.map(|c| match c {
ImplCandidate(impl_def) if self.tcx().is_general_impl(impl_def) => {
match self.evaluate_candidate(stack, &c) {
Ok(eval) if eval.may_apply() => Ok(Some(c)),
Ok(_) => Ok(None),
Err(OverflowError::Canonical) => Err(Overflow(OverflowError::Canonical)),
Err(OverflowError::ErrorReporting) => Err(ErrorReporting),
Err(OverflowError::Error(e)) => Err(Overflow(OverflowError::Error(e))),
}
}
_ => Ok(Some(c)),
})
.flat_map(Result::transpose)
.collect::<Result<Vec<_>, _>>()?;
Comment on lines +143 to +154
Copy link
Member

Choose a reason for hiding this comment

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

Hmm, I see, this is a copy of the winnowing code below. What about making if candidates.len() == 1 { below additionally check that "this candidate isn't a fully-blanket impl", and just not return early?

It could be framed as "only early-succeed when the candidate is a refinement of the obligation", where e.g. "$0: Iterator is not a refinement of $0: IntoIterator".

Then such candidates would hit the winnowing step, which already exists and wouldn't need duplication.

// If there is more than one candidate, first winnow them down
// by considering extra conditions (nested obligations and so
// forth). We don't winnow if there is exactly one
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_ty_utils/src/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::util::IgnoreRegions;
use rustc_middle::ty::{
self, Binder, EarlyBinder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt,
};
Expand Down Expand Up @@ -460,6 +461,13 @@ pub fn conservative_is_privately_uninhabited_raw<'tcx>(
}
}

fn is_general_impl(tcx: TyCtxt<'_>, id: DefId) -> bool {
let Some(trait_ref) = tcx.impl_trait_ref(id) else {
span_bug!(tcx.def_span(id), "expected impl, found `{:?} for `{:?}`", tcx.def_kind(id), id);
};
tcx.uses_unique_generic_params(trait_ref.substs, IgnoreRegions::No).is_ok()
Copy link
Member

Choose a reason for hiding this comment

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

Huh, fascinating, never seen this before.

}

pub fn provide(providers: &mut ty::query::Providers) {
*providers = ty::query::Providers {
asyncness,
Expand All @@ -469,6 +477,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
instance_def_size_estimate,
issue33140_self_ty,
impl_defaultness,
is_general_impl,
conservative_is_privately_uninhabited: conservative_is_privately_uninhabited_raw,
..*providers
};
Expand Down
5 changes: 5 additions & 0 deletions library/core/src/future/into_future.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ use crate::future::Future;
/// }
/// ```
#[stable(feature = "into_future", since = "1.64.0")]
#[rustc_on_unimplemented(
label = "`{Self}` cannot be converted to a future",
message = "`{Self}` cannot be converted to a future",
note = "{Self} must be a future or must implement `IntoFuture` to be awaited"
)]
pub trait IntoFuture {
/// The output that the future will produce on completion.
#[stable(feature = "into_future", since = "1.64.0")]
Expand Down
29 changes: 29 additions & 0 deletions library/core/src/iter/traits/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,35 @@ pub trait FromIterator<A>: Sized {
/// ```
#[rustc_diagnostic_item = "IntoIterator"]
#[rustc_skip_array_during_method_dispatch]
#[rustc_on_unimplemented(
on(
_Self = "std::ops::RangeTo<Idx>",
label = "if you meant to iterate until a value, add a starting value",
note = "`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \
bounded `Range`: `0..end`"
),
on(
_Self = "std::ops::RangeToInclusive<Idx>",
label = "if you meant to iterate until a value (including it), add a starting value",
note = "`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \
to have a bounded `RangeInclusive`: `0..=end`"
),
on(
_Self = "&str",
label = "cannot implicitly convert `{Self}` to an iterator; try calling `.chars()` or `.bytes()`"
),
on(
_Self = "std::string::String",
label = "cannot implicitly convert `{Self}` to an iterator; try calling `.chars()` or `.bytes()`"
),
on(
_Self = "{integral}",
note = "if you want to iterate between `start` until a value `end`, use the exclusive range \
syntax `start..end` or the inclusive range syntax `start..=end`"
),
label = "`{Self}` cannot be converted to an iterator",
message = "`{Self}` cannot be converted to an iterator"
)]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait IntoIterator {
/// The type of the elements being iterated over.
Expand Down
11 changes: 2 additions & 9 deletions src/test/ui/associated-types/substs-ppaux.normal.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,11 @@ help: use parentheses to call this function
LL | let x: () = foo::<'static>();
| ++

error[E0277]: the size for values of type `str` cannot be known at compilation time
error[E0277]: the trait bound `str: Foo<'_, '_, u8>` is not satisfied
--> $DIR/substs-ppaux.rs:49:5
|
LL | <str as Foo<u8>>::bar;
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `str`
note: required because of the requirements on the impl of `Foo<'_, '_, u8>` for `str`
--> $DIR/substs-ppaux.rs:11:17
|
LL | impl<'a,'b,T,S> Foo<'a, 'b, S> for T {}
| ^^^^^^^^^^^^^^ ^
Comment on lines -80 to -84
Copy link
Contributor

Choose a reason for hiding this comment

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

🤔 should we be pointing at blanket impls always, if any, on E0277s?

| ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo<'_, '_, u8>` is not implemented for `str`

error: aborting due to 5 previous errors

Expand Down
11 changes: 2 additions & 9 deletions src/test/ui/associated-types/substs-ppaux.verbose.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,11 @@ help: use parentheses to call this function
LL | let x: () = foo::<'static>();
| ++

error[E0277]: the size for values of type `str` cannot be known at compilation time
error[E0277]: the trait bound `str: Foo<'_#0r, '_#1r, u8>` is not satisfied
--> $DIR/substs-ppaux.rs:49:5
|
LL | <str as Foo<u8>>::bar;
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `str`
note: required because of the requirements on the impl of `Foo<'_#0r, '_#1r, u8>` for `str`
--> $DIR/substs-ppaux.rs:11:17
|
LL | impl<'a,'b,T,S> Foo<'a, 'b, S> for T {}
| ^^^^^^^^^^^^^^ ^
| ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo<'_#0r, '_#1r, u8>` is not implemented for `str`

error: aborting due to 5 previous errors

Expand Down
7 changes: 3 additions & 4 deletions src/test/ui/async-await/issue-70594.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,14 @@ error[E0744]: `.await` is not allowed in a `const`
LL | [1; ().await];
| ^^^^^^

error[E0277]: `()` is not a future
error[E0277]: `()` cannot be converted to a future
--> $DIR/issue-70594.rs:4:11
|
LL | [1; ().await];
| ^^^^^^ `()` is not a future
| ^^^^^^ `()` cannot be converted to a future
|
= help: the trait `Future` is not implemented for `()`
= help: the trait `IntoFuture` is not implemented for `()`
= note: () must be a future or must implement `IntoFuture` to be awaited
= note: required because of the requirements on the impl of `IntoFuture` for `()`
help: remove the `.await`
|
LL - [1; ().await];
Expand Down
7 changes: 3 additions & 4 deletions src/test/ui/async-await/issues/issue-62009-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,14 @@ LL | fn main() {
LL | (|_| 2333).await;
| ^^^^^^ only allowed inside `async` functions and blocks

error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` is not a future
error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` cannot be converted to a future
--> $DIR/issue-62009-1.rs:12:15
|
LL | (|_| 2333).await;
| ^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` is not a future
| ^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` cannot be converted to a future
Copy link
Contributor

Choose a reason for hiding this comment

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

I really hate how we display closures 😩

Ideally we should number them and display a span label naming all the ones that are involved, but this will require handling that on every error independently :-/

Copy link
Contributor

Choose a reason for hiding this comment

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

related discussion on irlo wants to display fn items more like closures, specifically so they don't look like fn pointers.

Perhaps lying and calling the closure impl FnOnce(_) -> {integer} would work? Or not abusing impl trait, {closure}: FnOnce(_) -> {integer}.

There is a potential way to number closures automatically, but it would still require touching every location that's naming types; roughly one of:

  • fn DiagnosticBuilder::name_type(ty: &Ty) -> impl Display; provides an indexed name for {closure#0} and registers to show a map of indexed to the normal display formatting.
  • Add functionality to Print/PrettyPrinter to do this numbering, require printing types to use Print instead of Display (e.g. here using DiagnosticBuilder as the printing context), and do the name_type stuff through the existing Print/PrettyPrinter machinery.

Either way it seems reasonable to add a PrettyPrinter::pretty_print_closure or similar.

|
= help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]`
= help: the trait `IntoFuture` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]`
= note: [closure@$DIR/issue-62009-1.rs:12:6: 12:9] must be a future or must implement `IntoFuture` to be awaited
= note: required because of the requirements on the impl of `IntoFuture` for `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]`
help: remove the `.await`
|
LL - (|_| 2333).await;
Expand Down
7 changes: 3 additions & 4 deletions src/test/ui/async-await/unnecessary-await.stderr
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
error[E0277]: `()` is not a future
error[E0277]: `()` cannot be converted to a future
--> $DIR/unnecessary-await.rs:9:10
|
LL | boo().await;
| -----^^^^^^ `()` is not a future
| -----^^^^^^ `()` cannot be converted to a future
| |
| this call returns `()`
|
= help: the trait `Future` is not implemented for `()`
= help: the trait `IntoFuture` is not implemented for `()`
= note: () must be a future or must implement `IntoFuture` to be awaited
= note: required because of the requirements on the impl of `IntoFuture` for `()`
help: remove the `.await`
|
LL - boo().await;
Expand Down
53 changes: 4 additions & 49 deletions src/test/ui/const-generics/generic_const_exprs/issue-85848.stderr
Original file line number Diff line number Diff line change
@@ -1,63 +1,18 @@
error[E0277]: the trait bound `(): _Contains<&C>` is not satisfied
error[E0277]: the trait bound `&C: Delegates<()>` is not satisfied
--> $DIR/issue-85848.rs:24:29
|
LL | writes_to_specific_path(&cap);
| ----------------------- ^^^^ the trait `_Contains<&C>` is not implemented for `()`
| ----------------------- ^^^^ the trait `Delegates<()>` is not implemented for `&C`
| |
| required by a bound introduced by this call
|
= help: the trait `Delegates<U>` is implemented for `T`
note: required because of the requirements on the impl of `Contains<(), true>` for `&C`
--> $DIR/issue-85848.rs:21:12
|
LL | impl<T, U> Contains<T, { contains::<T, U>() }> for U where T: _Contains<U> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^
note: required because of the requirements on the impl of `Delegates<()>` for `&C`
--> $DIR/issue-85848.rs:12:12
|
LL | impl<T, U> Delegates<U> for T where T: Contains<U, true> {}
| ^^^^^^^^^^^^ ^
note: required by a bound in `writes_to_specific_path`
--> $DIR/issue-85848.rs:30:31
|
LL | fn writes_to_specific_path<C: Delegates<()>>(cap: &C) {}
| ^^^^^^^^^^^^^ required by this bound in `writes_to_specific_path`

error: unconstrained generic constant
--> $DIR/issue-85848.rs:24:29
|
LL | writes_to_specific_path(&cap);
| ----------------------- ^^^^
| |
| required by a bound introduced by this call
|
= help: try adding a `where` bound using this expression: `where [(); { contains::<T, U>() }]:`
note: required because of the requirements on the impl of `Contains<(), true>` for `&C`
--> $DIR/issue-85848.rs:21:12
|
LL | impl<T, U> Contains<T, { contains::<T, U>() }> for U where T: _Contains<U> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^
note: required because of the requirements on the impl of `Delegates<()>` for `&C`
--> $DIR/issue-85848.rs:12:12
|
LL | impl<T, U> Delegates<U> for T where T: Contains<U, true> {}
| ^^^^^^^^^^^^ ^
note: required by a bound in `writes_to_specific_path`
--> $DIR/issue-85848.rs:30:31
|
LL | fn writes_to_specific_path<C: Delegates<()>>(cap: &C) {}
| ^^^^^^^^^^^^^ required by this bound in `writes_to_specific_path`

error[E0308]: mismatched types
--> $DIR/issue-85848.rs:24:5
|
LL | writes_to_specific_path(&cap);
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `true`, found `{ contains::<T, U>() }`
|
= note: expected type `true`
found type `{ contains::<T, U>() }`

error: aborting due to 3 previous errors
error: aborting due to previous error

Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
For more information about this error, try `rustc --explain E0277`.
10 changes: 5 additions & 5 deletions src/test/ui/error-codes/E0275.stderr
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
error[E0275]: overflow evaluating the requirement `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo`
--> $DIR/E0275.rs:5:33
error[E0275]: overflow evaluating the requirement `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo`
--> $DIR/E0275.rs:5:9
|
LL | impl<T> Foo for T where Bar<T>: Foo {}
| ^^^
| ^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`E0275`)
note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
--> $DIR/E0275.rs:5:9
|
LL | impl<T> Foo for T where Bar<T>: Foo {}
| ^^^ ^
= note: 127 redundant requirements hidden
= note: required because of the requirements on the impl of `Foo` for `Bar<T>`
= note: required because of the requirements on the impl of `Foo` for `T`

error: aborting due to previous error

Expand Down
7 changes: 3 additions & 4 deletions src/test/ui/for/for-c-in-str.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
error[E0277]: `&str` is not an iterator
error[E0277]: `&str` cannot be converted to an iterator
--> $DIR/for-c-in-str.rs:4:14
|
LL | for c in "asdf" {
| ^^^^^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()`
| ^^^^^^ cannot implicitly convert `&str` to an iterator; try calling `.chars()` or `.bytes()`
|
= help: the trait `Iterator` is not implemented for `&str`
= note: required because of the requirements on the impl of `IntoIterator` for `&str`
= help: the trait `IntoIterator` is not implemented for `&str`

error: aborting due to previous error

Expand Down
7 changes: 3 additions & 4 deletions src/test/ui/for/for-loop-bogosity.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
error[E0277]: `MyStruct` is not an iterator
error[E0277]: `MyStruct` cannot be converted to an iterator
--> $DIR/for-loop-bogosity.rs:17:14
|
LL | for x in bogus {
| ^^^^^ `MyStruct` is not an iterator
| ^^^^^ `MyStruct` cannot be converted to an iterator
|
= help: the trait `Iterator` is not implemented for `MyStruct`
= note: required because of the requirements on the impl of `IntoIterator` for `MyStruct`
= help: the trait `IntoIterator` is not implemented for `MyStruct`

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ error[E0627]: yield expression outside of generator literal
LL | yield || for i in 0 { }
| ^^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: `{integer}` is not an iterator
error[E0277]: `{integer}` cannot be converted to an iterator
--> $DIR/yield-outside-generator-issue-78653.rs:4:23
|
LL | yield || for i in 0 { }
| ^ `{integer}` is not an iterator
| ^ `{integer}` cannot be converted to an iterator
|
= help: the trait `Iterator` is not implemented for `{integer}`
= help: the trait `IntoIterator` is not implemented for `{integer}`
= note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
= note: required because of the requirements on the impl of `IntoIterator` for `{integer}`

error: aborting due to 2 previous errors

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
error[E0599]: the method `f` exists for struct `S`, but its trait bounds were not satisfied
error[E0599]: no method named `f` found for struct `S` in the current scope
--> $DIR/method-unsatified-assoc-type-predicate.rs:30:7
|
LL | struct S;
| --------
| |
| method `f` not found for this struct
| doesn't satisfy `<S as X>::Y<i32> = i32`
| doesn't satisfy `S: M`
| -------- method `f` not found for this struct
...
LL | a.f();
| ^ method cannot be called on `S` due to unsatisfied trait bounds
| ^ method not found in `S`
|
note: trait bound `<S as X>::Y<i32> = i32` was not satisfied
--> $DIR/method-unsatified-assoc-type-predicate.rs:14:11
= help: items from traits can only be used if the trait is implemented and in scope
note: `M` defines an item `f`, perhaps you need to implement it
--> $DIR/method-unsatified-assoc-type-predicate.rs:10:1
|
LL | impl<T: X<Y<i32> = i32>> M for T {}
| ^^^^^^^^^^^^ - -
| |
| unsatisfied trait bound introduced here
Comment on lines -1 to -20
Copy link
Contributor

@estebank estebank Jul 25, 2022

Choose a reason for hiding this comment

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

This would qualify as a regression, right? Maybe we need a two-step mechanism, where we create the error first and then we try to resolve without accounting for trait bounds?

Copy link
Member

Choose a reason for hiding this comment

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

IMO this suggests that it's the right error:

note: `M` defines an item `f`, perhaps you need to implement it

At most we could show the impl as "hey btw this M impl exists but doesn't apply here" (which I think we do sometimes? maybe not for blanket impls? or is it for an error that's unambiguous about which trait is, and just not method call resolution failures?)

Copy link
Contributor

Choose a reason for hiding this comment

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

But in this case it is a blanket impl, which means that the user can't impl M themselves due to orphan rules, right?

Copy link
Member

@eddyb eddyb Jul 26, 2022

Choose a reason for hiding this comment

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

As an analogy (to avoid the M/X names here), you can implement IntoIterator yourself on your own types, the only time it's disallowed is if you also implemented Iterator (in which case you have IntoIterator already handled by the blanket impl so the error isn't a concern).

If the type wasn't a locally-defined struct S;, maybe I could see "perhaps you need to implement it" being suboptimal, but it's fine here.

LL | trait M {
| ^^^^^^^

error: aborting due to previous error

Expand Down
Loading