Skip to content

Rust is overflowing on recursive trait evaluation where it didn't before #34260

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

Open
sgrif opened this issue Jun 13, 2016 · 5 comments
Open

Rust is overflowing on recursive trait evaluation where it didn't before #34260

sgrif opened this issue Jun 13, 2016 · 5 comments
Assignees
Labels
A-type-system Area: Type system C-bug Category: This is a bug. P-medium Medium priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@sgrif
Copy link
Contributor

sgrif commented Jun 13, 2016

This can be simplified down to the following:

trait MyTrait {
    type Output;
}

impl<T: MyTrait> MyTrait for T {
    type Output = <T as MyTrait>::Output;
}

trait SomeOtherTrait {}

impl<T> SomeOtherTrait for T where T: MyTrait, T::Output: Send {}

fn main() {}

When compiling that program, rust will overflow when it did not on older versions.. Of course that example is contrived, and attempting to use any concrete type there will always overflow. It is simplified from the slightly more realistic example in https://is.gd/XSHLG2, which is simplified from the real world case where I encountered this, which was trying to pull https://github.com/diesel-rs/diesel/blob/f0a75bb/diesel/src/query_dsl/load_dsl.rs#L23-L29 into a separate trait.

The important distinction is that we're now overflowing in a generic context, in cases where there are some concrete types which are valid. Specifically this causes confusing differing behavior between where clauses on methods and where clauses on trait impls. The above code is fine if the where clause is instead on some trait method, as it's no longer evaluated until there's a concrete type that the method is being called on.

I'd actually think that rustc could always avoid overflow here, and instead detect that it's evaluating the same trait impl def for the same type and answer no. The code implies that was the intention. But that's aside the point, this is about a concrete change in behavior.

The issue was first introduced in nightly-2015-08-15. On nightlies prior to that, https://is.gd/vrEvFN would compile successfully. It manifested as an actual stack overflow until nightly-2015-10-29, where it became a proper error (hilariously giving a warning that this warning would become a hard error due to RFC 1214, when it was already hard erroring). I believe this was an unintentional side effect of implementing RFC 1214, as that was merged in on the nightly that introduced the issue.

@Mark-Simulacrum Mark-Simulacrum added A-type-system Area: Type system T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 23, 2017
@Mark-Simulacrum Mark-Simulacrum added the C-bug Category: This is a bug. label Jul 25, 2017
@sgrif
Copy link
Contributor Author

sgrif commented Dec 3, 2017

It's been over a year, and there's been no reply to this. Some of Diesel's worst error messages result from this issue. It's even become a meme that if you forget an & in the wrong place, you get a pyramid of checking &[[[[[[_]]]]]].

This case has come up again, in a recent Diesel PR. However, we're seeing overflow in cases where it's checking a concrete type, for which the recursive impl should definitively not apply. I've simplified it down to this: https://gist.github.com/sgrif/48bf08a27b3da35a44ac085cada0622c, which should fail to compile with E0277, not an overflow.

The code today has a comment which says "it is important that overflow never be masked". What's especially frustrating here is that it is masked in places that it's convenient for rustc. If the overflow occurred as a result of checking x.method_from_trait(), Rust just assumes "well clearly that trait wasn't meant to apply here". I feel pretty strongly that if it occurs on a trait bound or from UFCS, the same logic of "well clearly that impl wasn't meant to apply to this type" should apply.

@sgrif
Copy link
Contributor Author

sgrif commented Dec 4, 2017

@nikomatsakis If you have some time this week is there any chance I could get you to take a look at this?

@nikomatsakis
Copy link
Contributor

triage: P-medium

@sgrif and I are working on this a bit =)

@steveklabnik
Copy link
Member

Triage: no change

weiznich added a commit to weiznich/diesel that referenced this issue Nov 26, 2020
Instead of producing an overflowing trait bound error show a concrete
error message what's wrong for certain query combination. This requires
to workaround rust-lang/rust#34260 in our
single method query dsl implementations:
* `GroupByDsl`
* `BoxedDsl`
* `DistinctDsl`
* `DistinctOnDsl`
* `LockingDsl`
@Spoonbender
Copy link

Triage: @sgrif 's examples in the original post (markdown code + https://is.gd/XSHLG2 + https://is.gd/vrEvFN) do not reproduce on 2021 edition, tested on rustc 1.59.0 (9d1b2106e 2022-02-23).

@sgrif do you know if there still an issue which can be reproduced?

@fmease fmease added A-type-system Area: Type system T-types Relevant to the types team, which will review and decide on the PR/issue. and removed A-type-system Area: Type system labels Dec 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-type-system Area: Type system C-bug Category: This is a bug. P-medium Medium priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

7 participants