Open lcnr opened 1 month ago
cc https://hackmd.io/N0rzMn94QZOfbaAVOl4f6A#finite-size-is-good-actually
one solution would be to attempt to eagerly detect associated type definitions which may expand to infinite types. This is already allowed on stable and would therefore require a breaking change. One such example is the following:
trait Trait {
type Assoc;
}
impl<T: Trait> Trait for Vec<T> {
type Assoc = T::Assoc;
}
trait Indir {
type IndirAssoc<T: Trait>: Trait;
}
struct Map<T>(T);
impl<T: Indir> Trait for Map<T> {
type Assoc = <T::IndirAssoc<Self> as Trait>::Assoc;
}
// in a downstream crate
struct Local;
impl Indir for Local {
type IndirAssoc<T: Trait> = Vec<T>;
}
// `<Map<Local> as Trait>::Assoc` is now infinite,
// all impls are
// fine by itself.
Conclusion: we are going to ignore this for now. We don't know of a concrete problem. We do know of various solutions (noted below) all of which seem unappealing but also largely orthogonal to other issues we have to address so we prefer to ignore this problem for now.
Options include:
<T::IndirAssoc<Self> as Trait>::Assoc;
) -- breaking change but soundness justified, unclear impact.Self
(and make sure that we fully normalize everywhere we need to)
for
type Alias = Vec<Alias>;
, equatingAlias
withVec<Alias>
may succeed:normalizes-to(Alias, Vec<Alias>) -> Vec<Alias>
equate(Vec<Alias>, Vec<Alias>)
ok via structural equality fast-pathThis would cause the occurs check to be incomplete as
?0 eq Vec<?0>
can be proven by instantiating?0
withAlias
. The occurs check is strictly required:This issue is pretty much purely theoretical as we're eagerly replacing all aliases inside of the normalized type with infer vars when equating it with the expected term. I don't necessarily believe we need to handle this until somebody crafts an example where this causes 'overlap' of impls allowed due to the occurs check.