Skip to content

<Box<T> as Deref>::Target is not equivalent to T in this case. #76956

New issue

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

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

Already on GitHub? # to your account

Closed
someguynamedjosh opened this issue Sep 20, 2020 · 6 comments · Fixed by #90017
Closed

<Box<T> as Deref>::Target is not equivalent to T in this case. #76956

someguynamedjosh opened this issue Sep 20, 2020 · 6 comments · Fixed by #90017
Labels
A-associated-items Area: Associated items (types, constants & functions) C-bug Category: This is a bug. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added.

Comments

@someguynamedjosh
Copy link

This code compiles correctly:

struct Data {
    boxed: Box<&'static i32>
}

impl Data {
    fn use_data(&self, user: impl for <'a> FnOnce(&'a i32)) {
        user(*self.boxed)
    }
}

However, this code does not:

use std::ops::Deref;

struct Data {
    boxed: Box<&'static i32>
}

impl Data {
    fn use_data(&self, user: impl for <'a> FnOnce(<Box<&'a i32> as Deref>::Target)) {
        user(*self.boxed)
    }
}

The only change was effectively replacing T with <Box<T> as Deref>::Target. My understanding is that these are supposed to be equivalent as it is defined that way in the standard library. The exact compile error is as follows:

error[E0308]: mismatched types
 --> src/main.rs:9:14
  |
9 |         user(*self.boxed)
  |              ^^^^^^^^^^^ expected associated type, found `&i32`
  |
  = note: expected associated type `<std::boxed::Box<&i32> as std::ops::Deref>::Target`
                   found reference `&'static i32`
  = help: consider constraining the associated type `<std::boxed::Box<&i32> as std::ops::Deref>::Target` to `&'static i32` or calling a method that returns `<std::boxed::Box<&i32> as std::ops::Deref>::Target`
  = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

error[E0277]: expected a `std::ops::FnOnce<(&i32,)>` closure, found `impl for<'a> FnOnce(<Box<&'a i32> as Deref>::Target)`
 --> src/main.rs:9:9
  |
9 |         user(*self.boxed)
  |         ^^^^^^^^^^^^^^^^^ expected an `FnOnce<(&i32,)>` closure, found `impl for<'a> FnOnce(<Box<&'a i32> as Deref>::Target)`
  |
  = help: the trait `std::ops::FnOnce<(&i32,)>` is not implemented for `impl for<'a> FnOnce(<Box<&'a i32> as Deref>::Target)`
help: consider further restricting this bound
  |
8 |     fn use_data(&self, user: impl for <'a> FnOnce(<Box<&'a i32> as Deref>::Target) + std::ops::FnOnce<(&i32,)>) {
  |                                                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.

Meta

The error also occurs on the Nightly compiler.

@someguynamedjosh someguynamedjosh added the C-bug Category: This is a bug. label Sep 20, 2020
@lcnr lcnr added the A-associated-items Area: Associated items (types, constants & functions) label Sep 21, 2020
@lcnr
Copy link
Contributor

lcnr commented Sep 21, 2020

We currently do not normalize projections <Ty as Trait>::AssociatedType if they contain unbound variables (stuff which is introduced using a for qualifier, 'a in your example). This means that we never actually see that <Box<&'a i32> as Deref>::Target is equal to &'a i32.

cc @eddyb @nikomatsakis but I don't think we can do much about cases like this for now.

@smmalis37
Copy link
Contributor

Is this the same underlying issue as #74736 and possibly #72582?

@lcnr
Copy link
Contributor

lcnr commented Sep 28, 2020

I think #74736 has a similar cause. #72582 is caused by something different, probably related to #41756

@lcnr
Copy link
Contributor

lcnr commented Oct 28, 2020

Using trait objects instead of impl Trait has the same issue

use std::ops::Deref;

fn use_data(v: &'static i32, user: &dyn for<'a> Fn(<Box<&'a i32> as Deref>::Target)) {
    user(v)
}

@smmalis37
Copy link
Contributor

Came up with another interesting version. This will fail to typecheck:

struct Container<'a>(std::marker::PhantomData<&'a ()>);

struct Empty;

trait Trait {
    type Assoc;
}

impl<'a> Trait for Container<'a> {
    type Assoc = Empty;
}

fn foo(x: impl for <'a> FnOnce(<Container<'a> as Trait>::Assoc)) {
    x(Empty);
}

Replacing the header of foo with this will successfully typecheck:

fn foo<'a>(x: impl FnOnce(<Container<'a> as Trait>::Assoc)) {

Might be useful for diffing.

bors added a commit to rust-lang-ci/rust that referenced this issue Aug 25, 2021
…komatsakis

Normalize projections under binders

Fixes rust-lang#70243
Fixes rust-lang#70120
Fixes rust-lang#62529
Fixes rust-lang#87219

Issues to followup on after (probably fixed, but no test added here):
rust-lang#76956
rust-lang#56556
rust-lang#79207
rust-lang#85636

r? `@nikomatsakis`
@jackh726
Copy link
Member

Fixed by #85499. Not going to close this because this is a simple example that didn't ICE, but still failed to compile.

@jackh726 jackh726 added the E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. label Aug 26, 2021
GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this issue Oct 25, 2021
Add a couple tests for normalize under binder issues

Closes rust-lang#56556
Closes rust-lang#76956

r? `@nikomatsakis`
@bors bors closed this as completed in 2d85c7e Oct 25, 2021
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
A-associated-items Area: Associated items (types, constants & functions) C-bug Category: This is a bug. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants