Skip to content

opaque type needlessly inferred to be recursive #115017

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

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

# for free to join this conversation on GitHub. Already have an account? # 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