-
-
Notifications
You must be signed in to change notification settings - Fork 139
fix regression with the next-generation trait solver #787
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
Conversation
|
I was already expecting this to be a bit hacky since I managed to trigger some internal compiler logs in some error conditions. Unfortunately it looks like some crates are stuck on a really old version with slightly different interfaces. I'll have a look though if I can backport this though. |
|
Leaving it open for now until it's in a mergeable state. |
|
This is great. Since I still can't push to this, could you run |
Co-authored-by: Armin Ronacher <[email protected]>
Co-authored-by: Armin Ronacher <[email protected]>
|
Alright, as stated in #788 (comment) proving goals via item bounds - i.e. the fact that We can solve this by hiding the goal we want to prove via an item bound inside of another impl. This means there's now a normalization call between instantiating the binder and proving the goal, meaning that the associated type has already been normalized when we try to prove it by using the item bound of the opaque type. It's a bit annoying that we can't just do Isn't Rust beautiful :3 |
|
Well I consider this generally a step in the right direction because it hides some of that lifetime mess away from the more public interfaces (unless someone looks closer at the blanket impls of |
|
wrote |
Hi there 👋 unfortunately minijinja currently relies on a type system bug. This code will break with the
-Znext-solver.Let's look at the relevant section of the minimization in rust-lang/trait-system-refactor-initiative#195 (comment) [godbolt]:
The call to
inspect_valuesstarts out withAandFbeing unconstrained inference variables, let's call them?aand?f.?fthen gets constrained to theFparameter fromgeneric_caller. This leaves us with the following trait bounds:?a: for<'a> Arg<'a>F: for<'a> Filter<<?a as Arg<'a>>::Output>F: Filter<?a>One of these bounds has to constrain
?ato theAparameter for this to compile.?a: for<'a> Arg<'a>certainly cannot do so, so we're left with theF: Filterbounds.F: Filter<?a>can be proven by either using theF: for<'a> Filter<<A as Arg<'a>>::Output>or theF: Filter<A>where-bound ofgeneric_caller. The first instantiates?awith<<A as Arg<'a>>::Output, the second withA. As both where-bounds are valid, this remains ambiguous.F: for<'a> Filter<<?a as Arg<'a>>::Output>can in theory also be proven by using both where-bounds ofgeneric_caller. The fact thatF: for<'a> Filter<<A as Arg<'a>>::Output>may apply should be clear, butF: Filter<A>is also totally valid. We'd just need to instantiate?awith some typeTfor which<T as Arg<'a>>::Outputnormalizes toA.What's even more subtle is that even if we use the
F: for<'a> Filter<<A as Arg<'a>>::Output>where-bound to to proveF: for<'a> Filter<<?a as Arg<'a>>::Output>, this does not necessarily have to constrain?atoA. It would also be valid to instantiate?awith some typeT != Afor which<T as Arg<'a>>::Outputnormalizes to<A as Arg<'a>>::Output>.The current type system implementation incorrectly relates associated types structurally, i.e. by simply checking that their generic arguments are equal, if these associated types reference higher ranked regions, the
'afromfor<'a>. This can result in a lot of weird errors and questionable inference behavior, see rust-lang/trait-system-refactor-initiative#9 for an example. Trying to support this behavior with the new implementation is pretty much impossible without adding explicit hacks for each individual breakage.See rust-lang/trait-system-refactor-initiative#195 and rust-lang/trait-system-refactor-initiative#168 for more details about the breakage.
What this PR is doing
To avoid the ambiguity errors with
-Znext-solver, I am moving the duplicate where-bounds into theFunctionimpl so that generic functions have a singleF: Functionwhere-bound which referencesAdirectly.I don't believe this to be a breaking change unless people try to use the
Functiontrait for functions whose signature is not higher ranked, i.e.fn(&'a str)for some early-bound lifetime'a. However, given thatfn invokeis#[doc(hidden)]and all uses of the trait inside ofminijinjaalready had a higher-ranked bound, this should not be an issue.If you think this change is acceptable, it would be awesome to also backport this change to older versions as the crater run in rust-lang/rust#133502 discovered quite a few projects which depend on older versions of this crate.
I am sorry for the inconvenience and please ask any questions if you would like some additional clarification. Thanks :>