-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Implicit resolution with type bound for intersection type fails #4562
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
Since |
I think you're right, you cannot actually construct a value of type |
I suspect that's due to the incompleteness of the constraint solver; a complete solution would require backtracking, which could make typechecking exponentially slower. Relation[?T, ?U] <: Relation[Wrapper[A] & Wrapper[B], B]
?T <: Wrapper[?U]
// hence
?T = Wrapper[A] & Wrapper[B] <: Wrapper[?U]
?U = B but at some point, That's internally documented in https://github.com/lampepfl/dotty/blob/master/compiler/src/dotty/tools/dotc/core/TypeComparer.scala#L643-L658 |
Okay, thanks for the explanation. That makes sense indeed. And I see the point in avoiding the need for backtracking during typechecking. But from a programming perspective, it's a bit strange that it makes a difference whether you write Otherwise, it might be good to at least augment the "no implicit argument found" warning with a hint that a branch of the search space was cut off due to an intersection type |
I don't know if this is ok for your usecase, but note that your example can be made to compile by making |
Good point, thanks! In the simplified example here this is a solution. But unfortunately, in my specific use case, I cannot easily make |
TLDR: constraints in this example can be reordered to help Dotty, I wonder if Dotty's heuristics could be improved to handle this case by instantiating ?U first, and I agree that logging cuts during constraint solving could be useful (also for #4029).
I totally agree — but at long as nobody implements and benchmarks backtracking and shows it's fine, we risk this sort of trouble. In this case backtracking might not be necessary tho. I must say: I expect instantiating Meanwhile, maybe one could also tune the method signature somehow to help inference — here, one could try something like: implicit def relation[T, U](/* erased? */ implicit ev: T <:< Wrapper[U]): Relation[T, U] = ??? which apparently just works (surprising, since it was the first attempt)! object test {
trait A
trait B
trait Wrapper[T]
trait Relation[T, U]
implicit def relation[T, U](/* erased? */ implicit ev: T <:< Wrapper[U]): Relation[T, U] = ???
def test(implicit ev: Relation[Wrapper[A] with Wrapper[B], B]) = ???
test
}
I agree such warnings might be very useful, and we have other reasons why being able to detect incomplete search might be useful (#4029). It'd also be useful to have a debugger for type inference (à la https://infoscience.epfl.ch/record/179877/files/typedebugger-applc2012.pdf), but the amount of effort required for last attempt was very significant. |
That would of course be the best solution. But I understand that you don't want to risk the slowdown as long as there is no evidence that this kind of backtracking does not come at a significant performance cost. Issuing a more meaningful warning is maybe a more practical solution. Since it seems it would be good to detect an incomplete search anyway.
Interesting; that might already catch quite some problematic cases without backtracking.
Thanks! That seems to help type inference for my case indeed. |
Closing since this has been inactive for a long time, and there are no clear directives what should be done. |
Since you forgot to close. |
The following code compiles using Scala:
Dotty produces the following compiler error:
Notably, using
instead of
works fine (i.e., the implicit value is successfully resolved).
The text was updated successfully, but these errors were encountered: