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

Weak Least Upper Bound is not Correctly Calculated in Some Conditional Expressions #9338

Closed
scabug opened this issue Jun 1, 2015 · 7 comments

Comments

@scabug
Copy link

scabug commented Jun 1, 2015

According to SLS 6.15:

The type of the conditional expression is the weak least upper bound of the types of e2 and e3.

However, it seems that the result of following code (conditional expression is included) is not correct:

scala> val x: Any = if(true) 1 else 1.0
x: Any = 1

scala> val x: Double = if(true) 1 else 1.0
x: Double = 1.0

because weak least upper bounds of Int (type of 1) and Double (type of 1.0) is Double, 1 should be converted 1.0 regardless of the expected type.

@scabug
Copy link
Author

scabug commented Jun 1, 2015

Imported From: https://issues.scala-lang.org/browse/SI-9338?orig=1
Reporter: Kota Mizushima (kmizushima)
Affected Versions: 2.11.6

@SethTisue
Copy link
Member

SethTisue commented Feb 23, 2023

I would agree it's a bug, and it's still present in 2.13.10.

I'm going to mark it as "fixed in Scala 3" not because the bug was addressed directly, even though the behavior is the same:

Welcome to Scala 3.3.1-RC1-bin-20230221-847eccc-NIGHTLY-git-847eccc (17.0.6, Java OpenJDK 64-Bit Server VM).

scala> val x: Any = if(true) 1 else 1.0
val x: Any = 1

because in Scala 3 it's behaving as spec'ed, as per https://docs.scala-lang.org/scala3/reference/dropped-features/weak-conformance.html :

Scala 3 drops the general notion of weak conformance, and instead keeps one rule: Int literals are adapted to other numeric types if necessary.

and when the expected type is Any, no adaptation is needed.

@SethTisue
Copy link
Member

Regardless, I'm going to close this ticket as "not planned", since I think that the benefit of fixing it would be exceeded, at this late stage in Scala 2's evolution, by the cost of introducing a Scala 2 vs 3 behavior difference that doesn't currently exist.

@SethTisue SethTisue closed this as not planned Won't fix, can't repro, duplicate, stale Feb 23, 2023
@SethTisue SethTisue removed this from the Backlog milestone Feb 23, 2023
@som-snytt
Copy link

som-snytt commented Feb 24, 2023

It's not a bug because the spec says each expr must conform to the expected type of the conditional.

That is why the following works. Otherwise the type of the conditional is AnyRef instead of D.

The ticket example is more special because 42 is not an Int if the expected type is Short. Cf #12722

scala> class C; class D
class C
class D

scala> implicit def cv0(c: C): D = new D
def cv0(c: C): D

scala> def b = true
def b: Boolean

scala> val x: D = if (b) new C else new D // print
                                                             private[this] val `x `: D = if (b)
  cv0(new C())
else
  new D()

A similar example:

scala> val d: Double = if (b) (42: Short) else (17: Byte) // print

private[this] val `d `: scala.Double = if (b)
  ((42): scala.Short).toDouble
else
  ((17): scala.Byte).toDouble

If the RHS were typed as Short, the conditional result would be converted in turn toDouble.

I think the same principle applies in Scala 3, which still has numeric widening. I don't know how they describe the type of a conditional without recourse to weak LUB; "harmonization" applies only to literals.

Edit, union for the inferred case, harmonized for the harmonized literals:

val i = if (b) (42: Short) else (17: Byte)
val j = if (b) 42 else 17.134
val k: Any = if (b) 42 else 17.134

val i: Short | Byte = if this.b then 42:Short else 17:Byte
val j: Double = if this.b then 42.0d else 17.134d
val k: Any = if this.b then 42 else 17.134d

@SethTisue
Copy link
Member

It's not a bug because the spec says each expr must conform to the expected type of the conditional

It does say that, but 1 and 1.0 both conform to Any, so we're good.

But then the spec also says:

The type of the conditional expression is the weak least upper bound of the types of e2 and e3

I don't see how you've made an argument that this wording somehow doesn't apply here?

@SethTisue
Copy link
Member

If we're reading the spec differently, maybe the bug is that the spec ought to be clearer.

@som-snytt
Copy link

The code says the spec should say "The inferred type of the conditional...".

So a branch body might be typed with the explicit expected type, or subsequently adapted to the inferred type.

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

No branches or pull requests

3 participants