Skip to content

Commit

Permalink
Adapt generic tuples to be able to access members
Browse files Browse the repository at this point in the history
Fixes #14215
  • Loading branch information
nicolasstucki committed Jan 10, 2022
1 parent ec43a19 commit 584c05b
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 0 deletions.
6 changes: 6 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Expand Up @@ -3854,6 +3854,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
gadts.println(i"Member selection healed by GADT approximation")
tree.cast(gadtApprox)
else tree
else if tree.tpe.derivesFrom(defn.PairClass) && !defn.isTupleNType(tree.tpe.widenDealias) then
// If this is a generic tuple we need to cast it to make the TupleN/ members accessible.
// This only works for generic tuples of know size up to 22.
defn.tupleTypes(tree.tpe.widenTermRefExpr, Definitions.MaxTupleArity) match
case Some(elems) => tree.cast(defn.tupleType(elems))
case None => tree
else tree // other adaptations for selections are handled in typedSelect
case _ if ctx.mode.is(Mode.ImplicitsEnabled) && tree.tpe.isValueType =>
checkConversionsSpecific(pt, tree.srcPos)
Expand Down
38 changes: 38 additions & 0 deletions tests/neg/genericTupleMembers.scala
@@ -0,0 +1,38 @@
def Test: Unit =
val tup1 = 1 *: EmptyTuple
val tup2 = 1 *: 2 *: EmptyTuple
val tup3 = 1 *: 2 *: 3 *: EmptyTuple
val tup4 = 1 *: 2 *: 3 *: 4 *: EmptyTuple
val tup5 = 1 *: 2 *: 3 *: 4 *: 5 *: EmptyTuple
val tup22 = 1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: 22 *: EmptyTuple
val tup23 = 1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: 22 *: 23 *: EmptyTuple

tup1._2 // error

tup2._3 // error

tup22._23 // error

tup23._1 // error
tup23._2 // error
tup23._3 // error
tup23._4 // error
tup23._5 // error
tup23._6 // error
tup23._7 // error
tup23._8 // error
tup23._9 // error
tup23._10 // error
tup23._11 // error
tup23._12 // error
tup23._13 // error
tup23._14 // error
tup23._15 // error
tup23._16 // error
tup23._17 // error
tup23._18 // error
tup23._19 // error
tup23._20 // error
tup23._21 // error
tup23._22 // error
tup23._23 // error
46 changes: 46 additions & 0 deletions tests/run/genericTupleMembers.scala
@@ -0,0 +1,46 @@

@main def Test: Unit =
val tup1 = 1 *: EmptyTuple
val tup2 = 1 *: 2 *: EmptyTuple
val tup3 = 1 *: 2 *: 3 *: EmptyTuple
val tup4 = 1 *: 2 *: 3 *: 4 *: EmptyTuple
val tup5 = 1 *: 2 *: 3 *: 4 *: 5 *: EmptyTuple
val tup22 = 1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: 22 *: EmptyTuple

tup1._1

tup2._1
tup2._2
tup2.swap

tup3._1
tup3._2
tup3._3

tup4._1
tup4._2
tup4._3
tup4._4

tup22._1
tup22._2
tup22._3
tup22._4
tup22._5
tup22._6
tup22._7
tup22._8
tup22._9
tup22._10
tup22._11
tup22._12
tup22._13
tup22._14
tup22._15
tup22._16
tup22._17
tup22._18
tup22._19
tup22._20
tup22._21
tup22._22
12 changes: 12 additions & 0 deletions tests/run/i14215.scala
@@ -0,0 +1,12 @@
def f[T <: Tuple2[Int, Int]](tup: T): T = tup

@main def Test: Unit =
(1, 2)._1
f((1, 2))._1

(1 *: 2 *: EmptyTuple)._1
f(1 *: 2 *: EmptyTuple)._1
f[Int *: Int *: EmptyTuple](1 *: 2 *: EmptyTuple)._1

f[Int *: Int *: EmptyTuple]((1, 2))._1
f[Tuple2[Int, Int]](1 *: 2 *: EmptyTuple)._1

0 comments on commit 584c05b

Please sign in to comment.