-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Type parameter inference is too eager to widen union types #4867
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
@smarter I'd be interested in learning a bit about the type parameter inference. If this bug seems somewhat accessible, can you point me to where in the code I should be looking at for this change? Thanks! |
The current logic is here: https://github.com/lampepfl/dotty/blob/34baac4b69ef9bc764c8a6d0d4c8cd458759a5e4/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala#L297-L301 To give some context: we avoid inferring union types for the same reason we avoid inferring singleton types, because sometimes they're "too precise". E.g.: scala> List(1, "")
val res0: List[Any] = List(1, )
scala> List(if (true) 1 else "")
val res1: List[Any] = List(1) The problem is that we do not distinguish between an inferred union type and a union type actually written down by the user: scala> val x: Int | String = 1
val x: Int | String = 1
scala> List(x)
val res2: List[Any] = List(1) This is tricky to fix since we'd need to have a way to distinguish (If you're looking for issues related to type inference, I've left a sketch of how to fix things in #4742, but it's not super easy either) |
Thanks! I'll take a look at #4742 |
I fell into a similar case with class Expr[+T]
def foo(): Char | String = bar/*[Char | String]*/(impl())
def bar[T](expr: Expr[T]): T = ???
def impl(): Expr[Char | String] = ??? Which fails with 8 | def foo(): Char | String = bar/*[Char | String]*/(impl())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| Found: Any
| Required: Char | String |
Currently type inference for `Expr` of union types is not precise enough as reported in scala#4867. This implies that currently we cannot have macros of the form ```scala inline def foo(x: T) <: X | Y = ${ ... } ``` but we can always default back to the less informative alternative ```scala inline def foo(x: T) <: Any = ${ ... } ``` Both form will refine the type to the type of the expression returned by the macro.
Currently type inference for `Expr` of union types is not precise enough as reported in scala#4867. This implies that currently we cannot have macros of the form ```scala inline def foo(x: T) <: X | Y = ${ ... } ``` but we can always default back to the less informative alternative ```scala inline def foo(x: T) <: Any = ${ ... } ``` Both form will refine the type to the type of the expression returned by the macro.
Currently type inference for `Expr` of union types is not precise enough as reported in scala#4867. This implies that currently we cannot have macros of the form ```scala inline def foo(x: T) <: X | Y = ${ ... } ``` but we can always default back to the less informative alternative ```scala inline def foo(x: T) <: Any = ${ ... } ``` Both form will refine the type to the type of the expression returned by the macro.
Currently type inference for `Expr` of union types is not precise enough as reported in scala#4867. This implies that currently we cannot have macros of the form ```scala inline def foo(x: T) <: X | Y = ${ ... } ``` but we can always default back to the less informative alternative ```scala inline def foo(x: T) <: Any = ${ ... } ``` Both form will refine the type to the type of the expression returned by the macro.
Currently type inference for `Expr` of union types is not precise enough as reported in scala#4867. This implies that currently we cannot have macros of the form ```scala inline def foo(x: T) <: X | Y = ${ ... } ``` but we can always default back to the less informative alternative ```scala inline def foo(x: T) <: Any = ${ ... } ``` Both form will refine the type to the type of the expression returned by the macro.
I'm encountering this issue as well : https://scastie.scala-lang.org/GW8xTsFARp22lzpTI7nb5Q |
Improves the inference of union types by preserving the union when there is a type ascription with an union. If the term has not been explicity ascribed with an union then the existing semantics of joining the orType is maintained. To determine whether an explicit union ascription exists, a lexical check on the untyped tree is performed.
Splits union.scala test from negative to negative and positive tests, exhibiting the preservation of the union when the union has been explicitly ascribed as per fix scala#4867.
I have a PR for this union inference issue: #7829 |
Improves the inference of union types by preserving the union when there is a type ascription with an union. If the term has not been explicity ascribed with an union then the existing semantics of joining the orType is maintained. To determine whether an explicit union ascription exists, a lexical check on the untyped tree is performed.
Splits union.scala test from negative to negative and positive tests, exhibiting the preservation of the union when the union has been explicitly ascribed as per fix scala#4867.
Splits union.scala test from negative to negative and positive tests, exhibiting the preservation of the union when the union has been explicitly ascribed as per fix scala#4867.
Splits union.scala test from negative to negative and positive tests, exhibiting the preservation of the union when the union has been explicitly ascribed as per fix scala#4867.
Improves the inference of union types by preserving the union when there is a type ascription with an union. If the term has not been explicity ascribed with an union then the existing semantics of joining the orType is maintained. To determine whether an explicit union ascription exists, a lexical check on the untyped tree is performed.
Splits union.scala test from negative to negative and positive tests, exhibiting the preservation of the union when the union has been explicitly ascribed as per fix scala#4867.
Improves the inference of union types by preserving the union when there is a type ascription with an union. If the term has not been explicity ascribed with an union then the existing semantics of joining the orType is maintained. To determine whether an explicit union ascription exists, a lexical check on the untyped tree is performed.
Splits union.scala test from negative to negative and positive tests, exhibiting the preservation of the union when the union has been explicitly ascribed as per fix scala#4867.
Improves the inference of union types by preserving the union when there is a type ascription with an union. If the term has not been explicity ascribed with an union then the existing semantics of joining the orType is maintained. To determine whether an explicit union ascription exists, a lexical check on the untyped tree is performed.
Splits union.scala test from negative to negative and positive tests, exhibiting the preservation of the union when the union has been explicitly ascribed as per fix scala#4867.
Improves the inference of union types by preserving the union when there is a type ascription with an union. If the term has not been explicity ascribed with an union then the existing semantics of joining the orType is maintained. To determine whether an explicit union ascription exists, a lexical check on the untyped tree is performed.
Splits union.scala test from negative to negative and positive tests, exhibiting the preservation of the union when the union has been explicitly ascribed as per fix scala#4867.
This works by now. |
From https://stackoverflow.com/questions/51575183/dotty-seq-mapping-to-union:
There's enough hints here that type inference should be able to do the right thing and not widen
Int | Double
toAnyVal
.The text was updated successfully, but these errors were encountered: