Skip to content

nested RPIT and HRTB: unclear semantics and future incompatibility #96194

Closed

Description

@aliemjay

(Original post in internals forum)

Given the following code (stable sin 1.30!):

fn f() -> impl for<'a> Tr<'a, Assoc = impl Copy> {}

It is undocumented whether the inner existential type, impl Copy, is allowed to access 'a or not. In other words, it is equivalent to which of the following?

type Assoc = impl Copy;
fn f() -> impl for<'a> Tr<'a, Assoc = Assoc> {}

or,

type Assoc<'a> = impl Copy;
fn f() -> impl for<'a> Tr<'a, Assoc = Assoc<'a>> {}

On stable

The behavior in current stable is consistent with the first as shown by:

  • If Assoc uses the lifetime 'a, the compiler complains about Implementation is not general enough as expected.
  • The following test on the return type passes
fn assert_unique_assoc<Assoc>(_: impl for<'a> Tr<'a, Assoc = Assoc>) {}
fn main() { assert_unique_assoc(f()); }

It looks like this was unintentionally stabilized and changing that now would break the above test (unless we leak the fact that impl Copy captures 'a ??).

On beta

#94081 makes #88236 pass but that seems to be inconsistent with the behavior in stable:

  • If Assoc uses 'a, it gives ICE, see yet another ICE with HRTB and RPIT #95647.
  • Using the above test on the return type fails, which is quite surprising since removing the lifetime from impl Copy + 'a makes the test pass. playground. And I believe adding a lifetime bound shouldn't change the semantics in this regard.
  • It would be a backward compatibility risk if we ever want to reject the code in the future.

Meta

stable version: 1.60.0
beta version: 1.61.0-beta.3 2022-04-17 2431a974c2dcf82ba513)

@rustbot label +T-Lang +A-impl-Trait

Activity

  1. added
    T-langRelevant to the language team
    A-impl-traitArea: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch.
    on Apr 18, 2022
  2. aliemjay commented on Apr 20, 2022

    @aliemjay
    ContributorAuthor

    Just now found out that nested impl Trait in argument position are allowed 🙈

    fn test_argument_position(x: impl for<'a> Tr<'a, Assoc = impl Copy>)  {}

    and it actually desugars to

    T: for<'a> Tr<'a, Assoc = Assoc>,
    Assoc: Copy,

    instead of:

    for<'a> T: Tr<'a>, 
    for<'a> <T as Tr<'a>>::Assoc: Copy,

    Now I believe this is a strong argument to reject impl for<'a> Tr<'a, Assoc = impl Copy + 'a> in return position!

  3. aliemjay commented on May 10, 2022

    @aliemjay
    ContributorAuthor

    It would be unfortunate if it hits stable with such ambiguous semantics before the language team decides on the issue.

    Compiler team might want to intervene in this case.
    @rustbot label T-compiler I-prioritize

  4. added
    I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on May 10, 2022
  5. inquisitivecrystal commented on May 10, 2022

    @inquisitivecrystal
    Contributor

    @oli-obk: I just wanted to check, was this intended to be stabilized?

    Edit: sorry, I didn't see the internals link! That makes it clear that it was unintentional.

  6. Mark-Simulacrum commented on May 10, 2022

    @Mark-Simulacrum
    Member

    cc @nikomatsakis / @jackh726 for lack of better contacts in still-forming traits team, this is potentially another issue that is good to urgently-ish take a look at as an accidental stabilization.

  7. apiraino commented on May 11, 2022

    @apiraino
    Contributor

    Assigning priority as discussed in the Zulip thread of the Prioritization Working Group.

    @rustbot label -I-prioritize +P-critical

  8. added and removed
    I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
    on May 11, 2022
  9. oli-obk commented on May 12, 2022

    @oli-obk
    Contributor

    Summarizing the status:

    Given

    trait Tr<'a> {
    	type Assoc;
    }

    And the following impl

    impl<'a> Tr<'a> for () {
    	type Assoc = ();
    }

    Then f stack overflows on stable and is accepted on beta

    fn f() -> impl for<'a> Tr<'a, Assoc = impl Copy + 'a> {}

    while f1 stack works on stable and on beta

    fn f1() -> impl for<'a> Tr<'a, Assoc = impl Copy> {}

    but with (using the lifetime in the assoc type)

    impl<'a> Tr<'a> for i32 {
    	type Assoc = &'a ();
    }

    then f2 stack overflows on stable and ICEs on beta

    fn f2() -> impl for<'a> Tr<'a, Assoc = impl Copy + 'a> { 42_i32 }

    then f3 stack errors on stable and ICEs on beta

    fn f3() -> impl for<'a> Tr<'a, Assoc = impl Copy> { 42_i32 }

    In table form

    stable beta
    fn f() -> impl for<'a> Tr<'a, Assoc = impl Copy + 'a> {} stack overflow ✓
    fn f1() -> impl for<'a> Tr<'a, Assoc = impl Copy> {} ✓ ✓
    fn f2() -> impl for<'a> Tr<'a, Assoc = impl Copy + 'a> { 42_i32 } stack overflow 🧊
    fn f3() -> impl for<'a> Tr<'a, Assoc = impl Copy> { 42_i32 } error 🧊
  10. 5 remaining items

  11. added
    P-highHigh priority
    and removed on May 17, 2022
  12. Mark-Simulacrum commented on Jun 14, 2022

    @Mark-Simulacrum
    Member

    Dropping the lang nomination. It doesn't seem clear that there is an active need for lang feedback on this issue, or at least the question is unclear -- @oli-obk (as the nominator), if there is something pending here that needs lang action, can you provide a specific question? In general having short and succinct questions accompanying nominations rather than just nominating an issue expedites in-meeting review.

  13. pnkfelix commented on Nov 11, 2022

    @pnkfelix
    Contributor

    Discussed in P-high review meeting.

    This is no longer a stability hazard, because we removed support for the questionable syntax .

    @rustbot label -P-high

  14. pnkfelix commented on Nov 11, 2022

    @pnkfelix
    Contributor

    (Whoops, I didn't meant to close this; I'll let @oli-obk do that if they end up opening a separate tracking issue)

  15. oli-obk commented on Nov 11, 2022

    @oli-obk
    Contributor

    Closing in favour of #104288

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-impl-traitArea: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions