-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Strange type inference for recursive RPIT #139406
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
Comments
Let me explain what's going on. I would like us to definitely break
|
if !self.fcx.next_trait_solver() { | |
if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind() | |
&& alias_ty.def_id == opaque_type_key.def_id.to_def_id() | |
&& alias_ty.args == opaque_type_key.args | |
{ | |
continue; | |
} | |
} |
If there are no constraints for an RPIT, we explicitly fall back to Ty::new_diverging_default(tcx)
rust/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
Lines 248 to 266 in b9856b6
DefiningScopeKind::HirTypeck => { | |
let tables = tcx.typeck(owner_def_id); | |
if let Some(guar) = tables.tainted_by_errors { | |
Ty::new_error(tcx, guar) | |
} else if let Some(hidden_ty) = tables.concrete_opaque_types.get(&def_id) { | |
hidden_ty.ty | |
} else { | |
// FIXME(-Znext-solver): This should not be necessary and we should | |
// instead rely on inference variable fallback inside of typeck itself. | |
// We failed to resolve the opaque type or it | |
// resolves to itself. We interpret this as the | |
// no values of the hidden type ever being constructed, | |
// so we can just make the hidden type be `!`. | |
// For backwards compatibility reasons, we fall back to | |
// `()` until we the diverging default is changed. | |
Ty::new_diverging_default(tcx) | |
} | |
} |
what2
HIR typeck eagerly replaces the return type with an infer var, ending up with RPIT<T> = RPIT<RPIT<T>>
in the storage. While we return this in the TypeckResults
, it's never actually used anywhere.
MIR building then results in the following statement
let _0: impl RPIT<T> /* the return place */ = build<RPIT<T>>(_some_local);
Unlike HIR typeck MIR typeck now directly equates RPIT<T>
with RPIT<RPIT<T>>
. This does not try to define RPIT
but instead relates its generic arguments
rust/compiler/rustc_infer/src/infer/relate/type_relating.rs
Lines 185 to 190 in b9856b6
( | |
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), | |
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), | |
) if a_def_id == b_def_id => { | |
super_combine_tys(infcx, self, a, b)?; | |
} |
This means we relate T
with RPIT<T>
, which results in a defining use RPIT<T> = T
what3
same as what2
except that we relate RPIT<T>
with RPIT<RPIT<RPIT<T>>>
which means we get a non-universal defining use RPIT<RPIT<T>> = T
.
I tried this code:
I compiled the above code in edition 2024, and got the output:
Also, the following code gives a compile error:
(See also #139350)
I think that both
what1
andwhat2
should not compile, but I'm not sure. And if it does compiles, they should both return!
. However, they return()
andi32
, respectively. (This happens despite the edition 2024 never type fallback change.) The current behavior doesn't make any sense to me.Discovered while experimenting with #139402.
@rustbot labels +A-impl-trait
Meta
Reproducible on the playground with nightly rust
1.88.0-nightly (2025-04-04 17ffbc81a30c09419383)
The text was updated successfully, but these errors were encountered: