Skip to content

opaque type needlessly inferred to be recursive #115017

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

Open
aliemjay opened this issue Aug 20, 2023 · 2 comments
Open

opaque type needlessly inferred to be recursive #115017

aliemjay opened this issue Aug 20, 2023 · 2 comments
Assignees
Labels
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

@aliemjay
Copy link
Member

aliemjay commented Aug 20, 2023

The following code should compile. However we infer two conflicting hidden types, Opaque<A> := Opaque<A> and Opaque<B> := u8, causing an error:

#![feature(type_alias_impl_trait)]
type Opaque<T> = impl Sized;
fn test<A, B>(
    arg: Vec<(Opaque<A>, u8)>,
) -> impl IntoIterator<Item = (Opaque<A>, Opaque<B>)> {
    arg
    //~^ ERROR concrete type differs from previous defining opaque type use
    //~| expected `Opaque<T>`, got `u8`
}

Another case to show that it is not enough to naively ignore the recursive definition, as it may have different arguments (Opaque<'a, 'b> := Opaque<'static, 'static>).

#![feature(type_alias_impl_trait)]

type Opaque<'a, 'b> = impl Sized + 'a + 'b;
//~^ ERROR concrete type differs from previous defining opaque type use
//~| expected `Opaque<'static, 'static>`, got `()`

// `Opaque<'a, 'b> := ()`
fn get_one<'a, 'b>() -> Opaque<'a, 'b> {}

// `Opaque<'a, 'b> := Opaque<'static, 'static>`
fn get_iter<'a, 'b>() -> impl IntoIterator<Item = Opaque<'a, 'b>> {
    Some(get_one())
}

Normally when we encounter an equality Opaque<A> == Opaque<A>, we equate substs and never register a hidden type.

The only way we infer an opaque type to be recursive in borrowck is through replace_opaque_types_with_inference_vars here:

// For an example where this is necessary see tests/ui/impl-trait/nested-return-type2.rs
// This allows users to omit re-mentioning all bounds on an associated type and just use an
// `impl Trait` for the assoc type to add more bounds.
let InferOk { value: actual, obligations: new } =
selcx.infcx.replace_opaque_types_with_inference_vars(
actual,
obligation.cause.body_id,
obligation.cause.span,
obligation.param_env,
);

@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Aug 20, 2023
@aliemjay aliemjay added 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. and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Aug 20, 2023
@aliemjay
Copy link
Member Author

A related ICE. TODO report in a separate issue:

#![feature(type_alias_impl_trait)]

trait IsU8 {}
impl IsU8 for u8 {}

struct IterOfU8<T>(T);

trait Iter {
    type Item;
}
impl<T, I> Iter for IterOfU8<T>
where
    T: IntoIterator<Item = I>,
    I: IsU8,
{
    type Item = I;
}

type Opaque<A> = impl Sized;
fn iter_of_opaque<A, T: Iter<Item = Opaque<A>>>() {}
fn test<A>() -> Opaque<A> {
    iter_of_opaque::<A, IterOfU8<Vec<u8>>>();
    0u8
}

@oli-obk
Copy link
Contributor

oli-obk commented Mar 25, 2024

The first example compiles on master

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
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.
Development

No branches or pull requests

3 participants