Skip to content
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

Explain how to fix “no field on type” on a TAIT / ATPIT typed value #113581

Open
kpreid opened this issue Jul 11, 2023 · 1 comment
Open

Explain how to fix “no field on type” on a TAIT / ATPIT typed value #113581

kpreid opened this issue Jul 11, 2023 · 1 comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. F-impl_trait_in_assoc_type `#![feature(impl_trait_in_assoc_type)]` F-type_alias_impl_trait `#[feature(type_alias_impl_trait)]` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@kpreid
Copy link
Contributor

kpreid commented Jul 11, 2023

Code

#![feature(impl_trait_in_assoc_type)]

pub trait Transaction {
    type Check: 'static;
    fn check(&self) -> Self::Check;
    fn commit(&self, check: Self::Check);
}

pub mod foo {
    pub struct Foo;

    struct FooC {
        field: (),
    }

    impl super::Transaction for Foo {
        type Check = impl Sized;

        fn check(&self) -> Self::Check {
            FooC { field: () }
        }

        fn commit(&self, check: Self::Check) {
            assert_eq!(check.field, ());
        }
    }
}

Current output

error[E0609]: no field `field` on type `<Foo as Transaction>::Check`
  --> src/lib.rs:24:30
   |
24 |             assert_eq!(check.field, ());
   |                              ^^^^^

For more information about this error, try `rustc --explain E0609`.
error: could not compile `playground` (lib) due to previous error

Desired output

help: to access fields of the underlying type `FooC`, coerce the value to it:
      `(check as FooC).field`

Rationale and extra context

If users are not given this advice, it will not be obvious how to proceed; they may think that it is not even possible. For me at least, it is obvious only in hindsight that

  • the incoming check argument is of a different type than the outgoing return value, and
  • a type coercion would solve the problem here.

The alternate mental model I was working with before I understood the problem was something like:

  • Self::Check is an alias for a particular impl Sized
  • which, only this impl or module knows (being in the defining scope of the impl Trait), is an alias for FooC

so check should be of type FooC already. Now that I understand what's actually going on, it makes much more sense that the compiler would work this way (scope-dependent type equality would be a nightmare), but it wasn't obvious when I started.

Other cases

No response

Anything else?

This exact same problem happens with TAIT; I just think it's just a little less clear and more important for associated types in traits.

Another detail to consider is what the output should be when the underlying type does not have such a field (or method). I think there should still be a similar hint, but phrased differently — in general, this hint should show up whenever

  • an opaque type is used,
  • in a place where the coercion would be allowed,
  • at a use site which does not itself cause a coercion already (e.g. a generic rather than concrete function parameter).

@rustbot label +A-impl-trait +F-type_alias_impl_trait

@kpreid kpreid added A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jul 11, 2023
@rustbot rustbot added needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. F-type_alias_impl_trait `#[feature(type_alias_impl_trait)]` labels Jul 11, 2023
@kpreid
Copy link
Contributor Author

kpreid commented Jul 11, 2023

A solution that might be more elegant in particular code is to destructure the argument — let FooC { field } = check;. That's harder to suggest automatically, however, since it involves introducing a new statement and variables.

@Noratrieb Noratrieb removed the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Jul 13, 2023
@workingjubilee workingjubilee added the F-impl_trait_in_assoc_type `#![feature(impl_trait_in_assoc_type)]` label Nov 8, 2023
@fmease fmease added the D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. label Dec 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. F-impl_trait_in_assoc_type `#![feature(impl_trait_in_assoc_type)]` F-type_alias_impl_trait `#[feature(type_alias_impl_trait)]` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants