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

higher ranked lifetimes not recognized by type alias impl trait #96146

Open
oli-obk opened this issue Apr 17, 2022 · 5 comments
Open

higher ranked lifetimes not recognized by type alias impl trait #96146

oli-obk opened this issue Apr 17, 2022 · 5 comments
Assignees
Labels
A-higher-ranked Area: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs) A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. C-bug Category: This is a bug. F-type_alias_impl_trait `#[feature(type_alias_impl_trait)]` T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@oli-obk
Copy link
Contributor

oli-obk commented Apr 17, 2022

The following snippet fails

#![feature(type_alias_impl_trait)]
trait Trait<'a> { type Out: 'a;}
impl<'a> Trait<'a> for i32 { type Out = String;}
type A = impl for<'a> Trait<'a, Out = impl Sized + 'a>;
fn foo() -> A {
    0_i32
}

The error is

error: non-defining opaque type use in defining scope
 --> src/lib.rs:6:5
  |
6 |     0_i32
  |     ^^^^^
  |
note: used non-generic lifetime `'a` for generic parameter
 --> src/lib.rs:4:52
  |
4 | type A = impl for<'a> Trait<'a, Out = impl Sized + 'a>;
  |                                                    ^^

Originally posted by @oli-obk in #96094 (comment)

@oli-obk oli-obk added C-bug Category: This is a bug. F-type_alias_impl_trait `#[feature(type_alias_impl_trait)]` labels Apr 17, 2022
@oli-obk
Copy link
Contributor Author

oli-obk commented Apr 17, 2022

Amusingly you get a different error if the associated type actually uses the lifetime:

#![feature(type_alias_impl_trait)]
trait Trait<'a> { type Out: 'a;}
impl<'a> Trait<'a> for i32 { type Out = &'a String;}
type A = impl for<'a> Trait<'a, Out = impl Sized + 'a>;
fn foo() -> A {
    0_i32
}

Fails with

error: implementation of `Trait` is not general enough
 --> src/lib.rs:6:5
  |
6 |     0_i32
  |     ^^^^^ implementation of `Trait` is not general enough
  |
  = note: `i32` must implement `Trait<'0>`, for any lifetime `'0`...
  = note: ...but it actually implements `Trait<'1>`, for some specific lifetime `'1`

@aliemjay
Copy link
Member

Amusingly you get a different error if the associated type actually uses the lifetime:

I think this the right behavior. I started a thread on internals forum to discuss this.

@jyn514
Copy link
Member

jyn514 commented Apr 19, 2022

cc #96194

@aliemjay
Copy link
Member

aliemjay commented Apr 20, 2022

To rule out the ambiguity of nested impls as shown in #96194, I tried splitting the opaque type into two, inner and outer, and that showed an interesting pattern.


If the inner type has a lifetime paramter <'a>, but it's not used by the associated type:

#![feature(type_alias_impl_trait)]
trait Trait<'a> { type Out; }
impl<'a> Trait<'a> for () { type Out = (); }

type Inner<'a> = impl Sized;
fn outer_impl() -> impl for<'a> Trait<'a, Out = Inner<'a>> {}

This yields the same error of this issue: error: non-defining opaque type use in defining scope

And when the lifetime is used by the associated type:

impl<'a> Trait<'a> for () { type Out = &'a (); }

the compiler produces the same ICE in #95647 .

This behavior is consistent regardless of of whether the inner impl have a lifetime bound impl Sized + 'a or whether the outer impl appears in type alias or in return position.


Surprisingly, if Fn traits are used for the outer impl, both cases work fine:

#![feature(type_alias_impl_trait)]
type Inner<'a> = impl Sized;
fn outer_impl() -> impl for<'a> Fn(&'a ()) -> Inner<'a> { |x| x }

If the Inner type has NO lifetime paramter <'a>, but the associated type actually captures one:

#![feature(type_alias_impl_trait)]
trait Trait<'a> { type Out; }
impl<'a> Trait<'a> for () { type Out = &'a (); }

type Inner = impl Sized;
fn outer_impl() -> impl for<'a> Trait<'a, Out = Inner> {}

This is rejected, but but behavior depends on the outer impl:

  • if outer impl is in return position: implementation not general enough error.
  • if outer impl is in type alias: same ICE as yet another ICE with HRTB and RPIT #95647 .
  • if outer impl is an Fn trait: a nice error 'impl Trait' captures lifetime that does not appear in bounds

@rustbot claim

@lcnr
Copy link
Contributor

lcnr commented Feb 15, 2024

this has been changed to explicitly forbid nested opaques from referencing higher ranked lifetimes:

#![feature(type_alias_impl_trait)]
trait Trait<'a> { type Out: 'a;}
impl<'a> Trait<'a> for i32 { type Out = String;}
type A = impl for<'a> Trait<'a, Out = impl Sized + 'a>;
fn foo() -> A {
    0_i32
}

results in

error: cannot capture late-bound lifetime in type alias impl trait
 --> src/lib.rs:4:52
  |
4 | type A = impl for<'a> Trait<'a, Out = impl Sized + 'a>;
  |                   -- lifetime defined here         ^^

we get a different error when using the Fn-trait sugar

#![feature(type_alias_impl_trait)]
type Inner<'a> = impl Sized;
fn outer_impl() -> impl for<'a> Fn(&'a ()) -> Inner<'a> { |x| x }
error[E0792]: expected generic lifetime parameter, found `'a`
 --> src/lib.rs:3:59
  |
2 | type Inner<'a> = impl Sized;
  |            -- this generic parameter must be used with a generic lifetime parameter
3 | fn outer_impl() -> impl for<'a> Fn(&'a ()) -> Inner<'a> { |x| x }
  |                                                           ^^^^^

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Feb 22, 2024
…r=lcnr

test that we do not support higher-ranked regions in opaque type inference

We already do all the right checks in `check_opaque_type_parameter_valid`, and we have done so since at least 2 years.

I collected the tests from rust-lang#116935 and rust-lang#100503 and added some more

cc rust-lang#96146

r? `@lcnr`
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Feb 22, 2024
…r=lcnr

test that we do not support higher-ranked regions in opaque type inference

We already do all the right checks in `check_opaque_type_parameter_valid`, and we have done so since at least 2 years.

I collected the tests from rust-lang#116935 and rust-lang#100503 and added some more

cc rust-lang#96146

r? `@lcnr`
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Feb 22, 2024
Rollup merge of rust-lang#121386 - oli-obk:no_higher_ranked_opaques, r=lcnr

test that we do not support higher-ranked regions in opaque type inference

We already do all the right checks in `check_opaque_type_parameter_valid`, and we have done so since at least 2 years.

I collected the tests from rust-lang#116935 and rust-lang#100503 and added some more

cc rust-lang#96146

r? `@lcnr`
@traviscross traviscross changed the title higher kinded lifetimes not recognized by type alias impl trait higher ranked lifetimes not recognized by type alias impl trait Mar 19, 2024
@fmease fmease added A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. T-types Relevant to the types team, which will review and decide on the PR/issue. A-higher-ranked Area: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs) labels Sep 24, 2024
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
A-higher-ranked Area: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs) A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. C-bug Category: This is a bug. F-type_alias_impl_trait `#[feature(type_alias_impl_trait)]` T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
Status: Can do after stabilization
Development

Successfully merging a pull request may close this issue.

5 participants