Open
Description
related to rust-lang/trait-system-refactor-initiative#173, see added tests in #139789
trait Trait {
// desugars to
// type Assoc: Sized + Send;
// fn foo(b: bool) -> Self::Assoc;
fn foo(b: bool) -> impl Sized + Send;
}
impl Trait for u32 {
// desugars to
// type Assoc = impl_rpit::<Self>;
// fn foo(b: bool) -> Self::Assoc { .. }
fn foo(b: bool) -> impl Sized {
if b {
u32::foo(false)
} else {
1u32
}
}
}
This currently results in a query cycle:
type_of(impl::Assoc)
collect_return_position_impl_trait_in_trait_tys
impl_rpit: Send
type_of(impl_rpit)
// auto trait leakagetypeck(impl::foo)
normalize(<u32 as Trait>::Assoc)
type_of(impl::Assoc)
I believe that this query cycle should not be there and can be avoided.
collect_return_position_impl_trait_in_trait_tys
currently adds the item bounds of the RPITIT when replacing it with fresh infer vars. I believe this is not necessary to guide inference as the method signature is fully concrete.
We could therefore split this in two:
collect_return_position_impl_trait_in_trait_tys
instantiates RPITIT with infer vars but does not check the item bounds of the RPITIT trait assoc typecompare_type_predicate_entailment
(or a separate query, idk and idc :3) then usescollect_return_position_impl_trait_in_trait_tys
and actually checks the item bounds
This means normalizing impl::Assoc
no longer has to prove the item bounds of the RPITIT, allowing the above example to compile and fixing rust-lang/trait-system-refactor-initiative#173
Metadata
Metadata
Assignees
Labels
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
compiler-errors commentedon Apr 14, 2025
I'm confused here: we use the item bounds not just to enforce that the hidden types implement their bounds, but also in order to collect the hidden type of inner RPITITs, for example, so we at least need to keep around projection bounds, unless I'm missing something from the write-up above.
I believe the example I use throughout the documentation to motivate this is something like an RPITIT
impl Deref<Assoc = impl Sized>
being equated against an impl signature of&String
so that we inferimpl Sized := String
.I'm not certain I see how this scheme manages to compute the type of the inner
impl Sized
-- can you elaborate?lcnr commentedon Apr 14, 2025
It does not '^^ I did not consider that we need this for nested RPITIT. We could filter the required item bounds to only prove bounds which may constrain nested RPITITs. But with this requirement changing the approach feels less obviously desirable to me 🤔 these projection bounds could still require leaking auto traits:
otoh, we could add yet another
TypingMode::ComputeSyntheticAssocItems
which treats allimpl Trait: AutoTrait
bounds as trivially true (so it's unsound by itself) which we use to incollect_return_position_impl_trait_in_trait_tys
and then recheck inTypingMode::Analysis
proper while leaking auto traits as normalcompiler-errors commentedon Apr 14, 2025
Yes, though stylistically it feels a bit different than other candidate assembly special casing because it would need to happen before we try to normalize the self type of the trait bound.
I'm personally not very keen to fix this cycle, since to me it feels qualitiatively different than the one I'm trying to fix in rust-lang/trait-system-refactor-initiative#173, which can be justified much more simply by "rigid projections should never be projected in the first place".
Rollup merge of rust-lang#139789 - lcnr:opaques-auto-trait-leakage, r…
Rollup merge of rust-lang#139789 - lcnr:opaques-auto-trait-leakage, r…
Rollup merge of rust-lang#139789 - lcnr:opaques-auto-trait-leakage, r…
Unrolled build for rust-lang#139789