opaque type needlessly inferred to be recursive · Issue #115017 · rust-lang/rust (original) (raw)

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 = impl Sized; fn test<A, B>( arg: Vec<(Opaque, u8)>, ) -> impl IntoIterator<Item = (Opaque, Opaque)> { 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,
);