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, |
); |