Skip to content
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

ICE: cannot infer substitution during normalization #829

Open
ranjitjhala opened this issue Oct 1, 2024 · 8 comments · Fixed by #830
Open

ICE: cannot infer substitution during normalization #829

ranjitjhala opened this issue Oct 1, 2024 · 8 comments · Fixed by #830

Comments

@ranjitjhala
Copy link
Contributor

(Creating a separate issue from #808 FTR)

@ranjitjhala This is a bit tricky. When we normalize <MyType<...> as MyTrait<...>>::Assoc we get back an impl of the form

impl<T1, ..., Tn> MyTrait<...> for MyType<..> { 
    type Assoc = ...
}

Where T1,...,Tn are used as args for Trait and Type. To proceed with the normalization we need to find a substitution for the T1,...,Tn based on the refinements we have. For example, if we have

impl<T> MyTrait for MyType<T> {
    type Assoc = T;
}

And we are trying to normalize <MyType<Nat> as MyTrait>::Assoc we get the substitution T -> Nat by matching MyType<Nat> against MyType<T>. This step is important because with this substitution we can infer that <MyType<Nat> as MyTrait>::Assoc normalizes to Nat.

Now, the implementation of Iterator for FilterMap looks like:

impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
where
    F: FnMut(I::Item) -> Option<B>,
{
    type Item = B;
    ...
}

The B is not used in Iterator or in FilterMap<I, F> so we can't find a substitution for it when doing the matching. The B appears to be unconstrained but it's actually constrained by the bound F: FnMut(I::Item) -> Option<B>. This bounds desugars to the bounds

F: FnMut<I::Item>,
F::Output == Option<B>   

The second equality bound is constraining B

Originally posted by @nilehmann in #808 (comment)

@ranjitjhala
Copy link
Contributor Author

[ see other commentary in #808 ]

@ranjitjhala
Copy link
Contributor Author

Good point! Can you make a small mock for the real thing with FnOnce ?

@nilehmann
Copy link
Member

This is a minimal example that should trigger the original behavior in #808

trait Trait {
    type Assoc;
}

struct S<T> {
    fld: T,
}

impl<T1, T2> Trait for S<T1>
where
    T1: FnOnce() -> T2,
{
    type Assoc = T1;
}

fn test(x: <S<fn()> as Trait>::Assoc) {}

@nilehmann
Copy link
Member

nilehmann commented Oct 1, 2024

Even simpler. The following triggers the normalization for function pointers which is orthogonal to the ambiguous substitution part of this issue

fn test01<F: FnOnce() -> i32>(f: F) -> F::Output {
    f()
}

fn test02(f: fn() -> i32) -> i32 {
    test01(f)
}

It turns out it's "working" thanks to this (unsound) hack

let ty = self.normalize_projection_ty_with_rustc(obligation)?;

@ranjitjhala
Copy link
Contributor Author

Reopening to make sure we actually fix the issue described in #808 re: FnOnce and FnPtr

@ranjitjhala ranjitjhala reopened this Oct 1, 2024
@ranjitjhala
Copy link
Contributor Author

btw the hack is only unsound once we allow refinements on fnptrs, yes?

@nilehmann
Copy link
Member

nilehmann commented Oct 1, 2024

btw the hack is only unsound once we allow refinements on fnptrs, yes?

The hack is unsound if:

  1. The type being normalized has refinements
  2. The normalization candidate has refinements (e.g., a projection predicate with refinements on a type parameter)

So yes, it's not unsound for fn ptrs unless we allow refinements on them because 2. doesn't apply here.

@ranjitjhala
Copy link
Contributor Author

indeed the above don't trigger the ICE... probably should fix at the same time as #803

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants