-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Error on type inference #15864
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
I take some time to try to minimize at maximum the case : object Issue15864:
def op[O, P](ta: List[O], tb: List[P]): List[P] = ???
class Graph { class Node }
def outsQ(using g: Graph): List[List[g.Node]] = ???
object aGraph extends Graph
given aGraph.type = aGraph
val q1: List[List[aGraph.Node]] = op(outsQ, op(outsQ, outsQ))
implicitly[q1.type <:< List[List[aGraph.Node]]]
val q2 = op(outsQ, op(outsQ, outsQ))
implicitly[q2.type <:< List[List[aGraph.Node]]]
val q3: List[List[aGraph.Node]] = q2
end Issue15864 And the unexpected error is now Cannot prove that (asuivre.Issue15864.q2 : List[List[Any]]) <:< List[List[asuivre.Issue15864.aGraph.Node]].
implicitly[q2.type <:< List[List[aGraph.Node]]] I hope this can help |
I had a closer look at this. What goes on here is that a dependent type variable
We should instantiate the type variable to It does seem to have a lot to do with level checking and I see some code that uses a variable's name to decide interpolation direction in val fromBelow =
name.is(AvoidNameKind.UpperBound) ||
!name.is(AvoidNameKind.LowerBound) && tvar.hasLowerBound But the problem persists even if I turn Config.checkLevelsOnConstraints on. @smarter Do you have a suggestion how to proceed here? |
Maybe should bite the bullet and introduce reverse indices in constraints. By this I mean two maps val coDeps, contraDeps: Map[TypeVar, Set[TypeVar]]
The sets would have to be maintained in constraints. We can use these sets to make decisions about instantiation directions. |
We now keep track of reverse type variable dependencies in constraints. E.g. is a constraint contains a clause like A >: List[B] We associate with `B` info that A depends co-variantly on it. Or, if A <: B => C we associate with `B` that `A` depends co-variantly on it and with `C` that `A` depends contra-variantly on it. These dependencies are then used to guide type variable instantiation. If an eligible type variable does not appear in the type of a typed expression, we interpolate it to one of its bounds. Previously this was done in an ad-hoc manner where we minimized the type variable if it had a lower bound and maximized it otherwise. We now take reverse dependencies into account. If maximizing a type variable would narrow the remaining constraint we minimize, and if minimizing a type variable would narrow the remaining constraint we maximize. Only if the type variable is not referred to from the remaining constraint we resort to the old heuristic based on the lower bound. Fixes scala#15864 Todo: This could be generalized in several directions: - We could base the dependency tracking on type param refs instead of type variables. That could make the `replace` operation in a constraint more efficient. - We could base more interpolation decisions on dependencies. E.g. we could interpolate a type variable only if both the type an expression and the enclosing constraint agree in which direction this should be done.
We now keep track of reverse type variable dependencies in constraints. E.g. is a constraint contains a clause like A >: List[B] We associate with `B` info that A depends co-variantly on it. Or, if A <: B => C we associate with `B` that `A` depends co-variantly on it and with `C` that `A` depends contra-variantly on it. These dependencies are then used to guide type variable instantiation. If an eligible type variable does not appear in the type of a typed expression, we interpolate it to one of its bounds. Previously this was done in an ad-hoc manner where we minimized the type variable if it had a lower bound and maximized it otherwise. We now take reverse dependencies into account. If maximizing a type variable would narrow the remaining constraint we minimize, and if minimizing a type variable would narrow the remaining constraint we maximize. Only if the type variable is not referred to from the remaining constraint we resort to the old heuristic based on the lower bound. Fixes scala#15864 Todo: This could be generalized in several directions: - We could base the dependency tracking on type param refs instead of type variables. That could make the `replace` operation in a constraint more efficient. - We could base more interpolation decisions on dependencies. E.g. we could interpolate a type variable only if both the type an expression and the enclosing constraint agree in which direction this should be done.
We now keep track of reverse type variable dependencies in constraints. E.g. is a constraint contains a clause like A >: List[B] We associate with `B` info that A depends co-variantly on it. Or, if A <: B => C we associate with `B` that `A` depends co-variantly on it and with `C` that `A` depends contra-variantly on it. These dependencies are then used to guide type variable instantiation. If an eligible type variable does not appear in the type of a typed expression, we interpolate it to one of its bounds. Previously this was done in an ad-hoc manner where we minimized the type variable if it had a lower bound and maximized it otherwise. We now take reverse dependencies into account. If maximizing a type variable would narrow the remaining constraint we minimize, and if minimizing a type variable would narrow the remaining constraint we maximize. Only if the type variable is not referred to from the remaining constraint we resort to the old heuristic based on the lower bound. Fixes scala#15864 Todo: This could be generalized in several directions: - We could base the dependency tracking on type param refs instead of type variables. That could make the `replace` operation in a constraint more efficient. - We could base more interpolation decisions on dependencies. E.g. we could interpolate a type variable only if both the type an expression and the enclosing constraint agree in which direction this should be done.
We now keep track of reverse type variable dependencies in constraints. E.g. is a constraint contains a clause like A >: List[B] We associate with `B` info that A depends co-variantly on it. Or, if A <: B => C we associate with `B` that `A` depends co-variantly on it and with `C` that `A` depends contra-variantly on it. These dependencies are then used to guide type variable instantiation. If an eligible type variable does not appear in the type of a typed expression, we interpolate it to one of its bounds. Previously this was done in an ad-hoc manner where we minimized the type variable if it had a lower bound and maximized it otherwise. We now take reverse dependencies into account. If maximizing a type variable would narrow the remaining constraint we minimize, and if minimizing a type variable would narrow the remaining constraint we maximize. Only if the type variable is not referred to from the remaining constraint we resort to the old heuristic based on the lower bound. Fixes scala#15864
We now keep track of reverse type variable dependencies in constraints. E.g. is a constraint contains a clause like A >: List[B] We associate with `B` info that A depends co-variantly on it. Or, if A <: B => C we associate with `B` that `A` depends co-variantly on it and with `C` that `A` depends contra-variantly on it. These dependencies are then used to guide type variable instantiation. If an eligible type variable does not appear in the type of a typed expression, we interpolate it to one of its bounds. Previously this was done in an ad-hoc manner where we minimized the type variable if it had a lower bound and maximized it otherwise. We now take reverse dependencies into account. If maximizing a type variable would narrow the remaining constraint we minimize, and if minimizing a type variable would narrow the remaining constraint we maximize. Only if the type variable is not referred to from the remaining constraint we resort to the old heuristic based on the lower bound. Fixes scala#15864
…6042) We now keep track of reverse type variable dependencies in constraints. E.g. if a constraint contains a clause like A >: List[B] We associate with `B` info that `A` depends co-variantly on it. Or, if A <: B => C we associate with `B` that `A` depends co-variantly on it and with `C` that `A` depends contra-variantly on it. Here, co-variant means that the allowable range of `A` narrows if the referred-to variable `B` grows, and contra-variant means that the allowable range of `A` narrows if the referred-to variable `C` shrinks. If there's an invariant reference such as A <: Array[B] Then `A` depends both co- and contra-variantly on `B`. These dependencies are then used to guide type variable instantiation. If an eligible type variable does not appear in the type of a typed expression, we interpolate it to one of its bounds. Previously this was done in an ad-hoc manner where we minimized the type variable if it had a lower bound and maximized it otherwise. We now take reverse dependencies into account. If maximizing a type variable would narrow the remaining constraint we minimize, and if minimizing a type variable would narrow the remaining constraint we maximize. Only if the type variable is not referred to from the remaining constraint we resort to the old heuristic based on the lower bound. Fixes #15864 Todo: This could be generalized in several directions: - We could base the dependency tracking on type param refs instead of type variables. That could make the `replace` operation in a constraint more efficient. - We could base more interpolation decisions on dependencies. E.g. we could interpolate a type variable only if both the type of an expression and the enclosing constraint agree in which direction this should be done.
We now keep track of reverse type variable dependencies in constraints. E.g. is a constraint contains a clause like A >: List[B] We associate with `B` info that A depends co-variantly on it. Or, if A <: B => C we associate with `B` that `A` depends co-variantly on it and with `C` that `A` depends contra-variantly on it. These dependencies are then used to guide type variable instantiation. If an eligible type variable does not appear in the type of a typed expression, we interpolate it to one of its bounds. Previously this was done in an ad-hoc manner where we minimized the type variable if it had a lower bound and maximized it otherwise. We now take reverse dependencies into account. If maximizing a type variable would narrow the remaining constraint we minimize, and if minimizing a type variable would narrow the remaining constraint we maximize. Only if the type variable is not referred to from the remaining constraint we resort to the old heuristic based on the lower bound. Fixes scala#15864
Compiler version
3.1.3
Minimized code
A similar issue (#11556) was already corrected several month ago (#12847)
Output
Expectation
Supposed to compile without error.
The text was updated successfully, but these errors were encountered: