-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
HRTB bounds not resolving correctly (take 3, lifetimes on the RHS) #90950
Comments
😔 always another HRTB issue Based on |
@jackh726 yeah, sorry 😅 But that diagnosis makes sense |
I think I just ran into this issue: trait SomeOtherTrait<'a> {
fn create(string: &'a mut str) -> Self;
}
trait SomeTrait<'a> {
type Associated;
fn do_stuff(&self, other: &mut Self::Associated);
}
fn something_else<T>(v: T)
where
for<'b> T: SomeTrait<'b>,
for<'b> <T as SomeTrait<'b>>::Associated: SomeOtherTrait<'b>,
{
let mut message = "Hello".to_string();
{
let evil_borrow = <T::Associated as SomeOtherTrait<'_>>::create(message.as_mut_str());
}
}
struct FooAssociated<'a> {
blah: &'a str,
}
impl<'a> SomeOtherTrait<'a> for FooAssociated<'a> {
fn create(string: &'a mut str) -> Self {
Self { blah: string }
}
}
struct Foo {}
impl<'a> SomeTrait<'a> for Foo {
type Associated = FooAssociated<'a>;
fn do_stuff(&self, other: &mut Self::Associated) {
// ...
}
}
fn foo(x: Foo) {
something_else(x);
} For those who stumble upon this, I found this workaround that may or may not be applicable to your situation: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=f4b1074af9207306222d37d2ed5a317f (create another trait with the desired associated type bounds and a blanket impl) trait SomeTraitWithOtherAssociated<'a> {
type Associated: SomeOtherTrait<'a>;
}
impl<'a, T: SomeTrait<'a>> SomeTraitWithOtherAssociated<'a> for T
where
for<'b> <T as SomeTrait<'b>>::Associated: SomeOtherTrait<'b>,
{
type Associated = <T as SomeTrait<'a>>::Associated;
}
fn something_else<T>(v: T)
where
for<'b> T: SomeTraitWithOtherAssociated<'b>,
{
// ... |
I'd like to mention another use-case where this issue (as I understand it) comes up. Sometimes, people want to write a HRTB for fn choose_randomly<It>(
game: &mut GameState,
generator: impl FnOnce(&GameState) -> It,
) -> Option<It::Item>
where
It: Iterator, But this doesn't work because fn choose_randomly<G, Item>(
game: &mut GameState,
generator: G,
) -> Option<Item>
where
for<'any> G: GeneratesIterator<'any, Item=Item>, Conceptually, you shouldn't need this, because the outputs of the fn choose_randomly<G, Item>(
game: &mut GameState,
generator: G,
) -> Option<Item>
where
for<'any> G: FnOnce<(&'any GameState,)>,
for<'any> <G as FnOnce<(&'any GameState,)>>::Output: Iterator<Item = Item> + 'any, ➡️
You can't name closures or function items, so the workaround of being explicit about the type is not ideal. I didn't keep the playground handy, but with the stable workaround, if you don't thread enough associated types like |
Current output
|
…imulacrum Add a few known-bug tests The labels of these tests should be changed from `S-bug-has-mcve` to `S-bug-has-test` once this is merged. cc: rust-lang#101518 rust-lang#99492 rust-lang#90950 rust-lang#89196 rust-lang#104034 rust-lang#101350 rust-lang#103705 rust-lang#103899 I couldn't reproduce the failures in rust-lang#101962 and rust-lang#100772 (so either these have started passing, or I didn't repro properly), so leaving those out for now. rust-lang#102065 was a bit more complicated, since it uses `rustc_private` and I didn't want to mess with that.
I’ve only tested the first two examples, but this hasn’t been mentioned here yet – the code examples compile successfully if the type argument is specified explicitly, e.g. calling |
That code fails to compile: struct Opaque;
trait FromRef<'r>: 'r {
fn from_ref(_: &'r Opaque) -> Self;
}
struct Bar<'r>(&'r Opaque);
impl<'r> FromRef<'r> for Bar<'r> {
fn from_ref(op: &'r Opaque) -> Self {
Bar(op)
}
}
trait Foo<I, O> {
fn call_foo(&self, op: &Opaque);
}
impl<I: for<'r> FromRef<'r>, O, H: Fn(I) -> O> Foo<I, O> for H {
fn call_foo(&self, op: &Opaque) {
let i = I::from_ref(op);
let _: O = self(i);
}
}
struct FooImpl;
impl<I: for<'r> FromRef<'r>> Foo<I, ()> for FooImpl {
fn call_foo(&self, op: &Opaque) {
let _ = I::from_ref(op);
}
}
fn asserted<'r>(_: Bar<'r>) {}
fn main() {
let op = Opaque;
// fails:
asserted.call_foo(&op);
// also fails:
FooImpl.call_foo(&op);
} While working on another code from picoserve I got such note, which guided me here. If this is not the right place, please guide me to elsewhere |
This is a new version of #85636 and #89196 . When reporting it I first hit an ICE which got fixed in #90638.
The basic idea is that bounds of the form
for<'a> <Type as Trait<'a>>::AssocType: OtherTrait<'a>
don't work. #85636, which has since been fixed, is about this same issue without a lifetime on the right side of the bound. This will likely also be a problem for GATs.The commented out code is not necessary for it to work, but it gives an idea of why such a bound might be necessary.
(playpen)
The error shown is:
which is incorrect, that bound is satisfied here.
I'm currently working on rustc master (d914f17) so that I can have the fix for #90638, though that fix is not necessary for the commented-out version of my code to work. This should be available on nightly soon.
cc @jackh726 @eddyb
The text was updated successfully, but these errors were encountered: