lampepfl / dotty-feature-requests

Historical feature requests. Please create new feature requests at https://github.com/lampepfl/dotty/discussions/new?category=feature-requests
31 stars 2 forks source link

should expected type stop singleton widening of nested expressions #198

Closed hmf closed 1 year ago

hmf commented 3 years ago

Compiler version

3.0.0-RC1

Minimized code

    val s1: Tuple3[Int, Int, Double] = Tuple3(28, 28, 1.0)
    val s2: Tuple3[28, 28, 1.0] = Tuple3(28, 28, 1.0)
    val s3: Tuple3[28, 28, 1.0] = (28, 28, 1.0)
    val s4: (28, 28, 1.0) = (28, 28, 1.0)
    val s5: (Int, Int, Double) = (28, 28, 1.0)

    import scala.Tuple$package.EmptyTuple

    val s10: (Int, Int, Double) = 28 *: 28 *: 1.0 *: Tuple()
    val s11: Tuple3[Int, Int, Double] = 28 *: 28 *: 1.0 *: Tuple()
    val s12: Tuple3[28, Int, Double] = 28 *: 28 *: 1.0 *: Tuple()
    val s13: Tuple3[28, 28, 1.0] = 28 *: 28 *: 1.0 *: Tuple()

Output

[error] -- [E007] Type Mismatch Error: /home/hmf/VSCodeProjects/pdm_toyadmos/dcase2020/src/examples/djl/autoencoder/SparseEncoder.scala:164:35 
[error] 164 |    val s13: Tuple3[28, 28, 1.0] = 28 *: 28 *: 1.0 *: Tuple()
[error]     |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
[error]     |                    Found:    (Int, Int, Double)
[error]     |                    Required: ((28 : Int), (28 : Int), (1.0 : Double))
[error] one error found

Expectation

I am assuming that Tuples with arity > 22 will be typed just as they are for lower arity. From the example above it seems like the tail of the HList is lost. Is this the expected behavior?

bishabosha commented 3 years ago

I am skeptical to call this a bug, but asking for @smarter opinion on if expected type should prevent widening here

bishabosha commented 3 years ago

i think this is also a duplicate, will need to find the previous issue

hmf commented 3 years ago

@bishabosha Just to make sure: aren't s4 and s13 equivalent?

bishabosha commented 3 years ago

@bishabosha Just to make sure: aren't s4 and s13 equivalent?

maybe conceptually, but (28, 28, 1.0) is still Tuple3.apply(28, 28, 1.0) whereas a chain of *: still looks like 3 calls to scala.runtime.Tuples.cons in the bytecode, I thought there was meant to be an optimisation for this :/

hmf commented 3 years ago

maybe conceptually, but (28, 28, 1.0) is still Tuple3.apply(28, 28, 1.0) whereas a chain of *: still looks like 3 calls to ...

I think I may be misleading you here. I don't think its is just an issue of equivalence between Tuples and HLists (cons). More concretely, this also fails:

    val s14: *:[28, *:[28, *:[1.0, EmptyTuple]]] = 28 *: 28 *: 1.0 *: EmptyTuple

I get:

[error] 243 |    val s14: *:[28, *:[28, *:[1.0, EmptyTuple]]] = 28 *: 28 *: 1.0 *: EmptyTuple
[error]     |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error]     |    Found:    (Int, Int, Double)
[error]     |    Required: (28 : Int) *: (28 : Int) *: (1.0 : Double) *: EmptyTuple
[error] one error found

Shouldn't that also work? Maybe it is another issue?

Notice also how in s12 in the previous example (shown below again) works. And so does its equivalent s15:

val s12: Tuple3[28, Int, Double] = 28 *: 28 *: 1.0 *: Tuple()
val s15: *:[28, *:[Int, *:[Double, EmptyTuple]]] = 28 *: 28 *: 1.0 *: EmptyTuple

We are able to get the first value type 28 but not the rest. Looks like the value type of the tail is lost.

And in s14 we get all the standard types but not the value types. Seems inconsistent. At the very least s14 should work even if we don't consider equivalence with the Tuples. Maybe this is another problem?

EDIT: value type should be singleton type.

bishabosha commented 3 years ago

you can replicate the issue with your own definition:

sealed trait Tpl {
  inline def **:[H, This >: this.type <: Tpl](h: H): H **: This = null.asInstanceOf[H **: This]
}
sealed trait NonEmptyTpl extends Tpl
case object EmpT extends Tpl
class **:[+H, +T <: Tpl] extends NonEmptyTpl

scala> val m: 1 **: 2 **: EmpT.type = 1 **: 2 **: EmpT                                                                  
1 |val m: 1 **: 2 **: EmpT.type = 1 **: 2 **: EmpT
  |                               ^^^^^^^^^^^^^^^^
  |                           Found:    Int **: Int **: EmpT.type
  |                           Required: (1 : Int) **: (2 : Int) **: EmpT.type
bishabosha commented 3 years ago

so this is not really an issue with tuples

hmf commented 3 years ago

Maybe a change the issue title?

odersky commented 3 years ago

Singletons are only inferred as type arguments if the type parameter is bounded by Singleton. So the behavior here looks as expected to me.

bishabosha commented 3 years ago

I guess in my intuition, expected type would unify more deeply in expressions rather than only the top level. Moved to feature-requests if this is as expected