---
# System prepended metadata

title: alias handling hangs

---

# new solver hangs

## rigid alias as potentially non-rigid

https://github.com/rust-lang/trait-system-refactor-initiative/issues/109

two ideas:

#### eagerly reject definitely rigid aliases in normalizes-to

https://github.com/rust-lang/rust/pull/125334

does not work for rayon as rayon has a blanket impl whose nested goals fail instead

```rust
pub trait ParallelIterator {
    type Item;
}

trait Trait {}

macro_rules! multizip_impl {
    ($($T:ident),+) => {
        impl<$( $T, )+> Trait for ($( $T, )+)
        where
            $(
                $T: ParallelIterator,
                $T::Item: ParallelIterator<Item = u32>,
            )+
        {}
    }
}

multizip_impl! { A, B, C, D, E, F, G, H, I, J, K, L }

fn main() {}
```

how this proceeds...

* proving `A: ParallelIterator`...
    * we try `A::Item: ParallelIterator` and normalize `A::Item -> A`
        * to do that normalization we look to show that `A: ParallelIterator`
            * direct cycle
    * we try `B::Item: ParallelIterator` and normalize `B::Item -> A`
        * to do that normalization we look to show that `B: ParallelIterator`
            * in the environment we find `B: ParallelIterator` but also `A::Item: ParallelIterator`, `C`, .. `L`
    * same for `C`

...so we do `O(n!)` work.

Note that in original version there was no `Item = u32`.

in old solver:

* we do param-env normalization
    * at each step, we assume that the existing where-clauses are rigid

where is it fruitful

```rust
// very easy

fn foo<A, B>()
where
    A: Iterator<Item = B>,
    A::Item: Iterator,
{}

// ---

// indirect, requires combining blanket impl with environment

fn foo<A, B>()
where
    A: Iterator<Item = B>,
    <A as IntoIterator>::Item: Iterator,
{}

impl<I: Iterator> IntoIterator for I {
    type Item = <I as Iterator>::Item;
}

// ---

trait IteratorWithUnusedArg<T: ?Sized> {
    type Item: ?Sized;
}

trait IntoIterator {
    type Item: ?Sized;
}

fn foo<A, B>()
where
    A: IteratorWithUnusedArg<<A as IntoIterator>::Item, Item = B>,
    <A as IntoIterator>::Item: IteratorWithUnusedArg<u32>,
{}

impl<I: ?Sized + IteratorWithUnusedArg<<I as IntoIterator>::Item>> IntoIterator for I {
    type Item = <I as IteratorWithUnusedArg<<I as IntoIterator>::Item>>::Item;
}
```

Hypothesis:

* The only way that normalizing `T = <P0 as Iterator<P1..Pn>>::Foo` can yield `Q` (where `Q` not free in `T`) is if there is some other thing in the environment that normalizes to a type `U` including `Q` ?
    * this is what is impl'd in #124852
    * but it cannot rule out `P0::Item = P0::OtherItem`, as in the impl in https://github.com/rust-lang/rust/issues/125269 (even if the cause of that hang is different)
        * would be helped by the "is_rigid_alias" test described at first
    * concern: currently have `for<'a> fn(&'a <?x as Subtrait<'a>>::Assoc)` will be `for<'a> where { ?x: Subtrait<'a> } fn(&'a <?x as Subtrait<'a>>::Assoc)`, with where-clauses on binders we end up putting `?x: Subtrait<'a>` into the environment inside of this function pointer, elaborating that could put `?x: Supertrait<Assoc = ?x>` into the env?
        * Prolly not an issue in practice, have bigger issues with that anyways :3

#### eagerly fail "rigid-ty alias-relate alias" if the rigid type contains a placeholder not nameable by the alias

https://github.com/rust-lang/rust/pull/124852

Both fix some, but not all issues of this kind

## ambig alias != infer var weakens cycle detection

https://github.com/rust-lang/rust/issues/125269

- can be fixed by eagerly normalizing before evaluating nested goals: https://github.com/rust-lang/rust/pull/125343

## separate: highly involved cycles requiring >1 fixpoint iterations

- most notably fuchsia

Currently working on a search graph PR. Found another issue :<

*edit: 2 minutes ago I ended up questioning whether this is sound at all :3*

- `?t: Trait` with 2 candidates
    - `impl<T> Trait for Vec<T> where T: Trait`
        - first iteration, inductive cycle -> error
    - `impl Trait for u32 {}`
        - ok: `?t = u32`
    - result of first iteration: `OK: ?t = u32`
    - `impl<T> Trait for Vec<T> where T: Trait`
        - first iteration, inductive cycle -> ok `?t: u32`
        - result `?t = Vec<u32>`
    - `impl Trait for u32 {}`
        - ok: `?t = u32`
    - result of second iteration `Ambig`

constraints from fixpoints aren't monotonically increasing :skull: 
