Skip to content

Commit 70319b4

Browse files
committed
Fix #10958: handle tupling for generic tuples without affecting patmat
This commit refactor the PR #5259 so that it will not impact pattern matching code. The phase patternMatcher requires members `_N` for to generate correct code. #5259
1 parent c9bf740 commit 70319b4

File tree

5 files changed

+28
-18
lines changed

5 files changed

+28
-18
lines changed

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -111,21 +111,23 @@ object Applications {
111111
}
112112

113113
def productSelectorTypes(tp: Type, errorPos: SrcPos)(using Context): List[Type] = {
114-
def tupleSelectors(n: Int, tp: Type): List[Type] = {
115-
val sel = extractorMemberType(tp, nme.selectorName(n), errorPos)
116-
// extractorMemberType will return NoType if this is the tail of tuple with an unknown tail
117-
// such as `Int *: T` where `T <: Tuple`.
118-
if (sel.exists) sel :: tupleSelectors(n + 1, tp) else Nil
119-
}
120-
def genTupleSelectors(n: Int, tp: Type): List[Type] = tp match {
121-
case tp: AppliedType if !defn.isTupleClass(tp.tycon.typeSymbol) && tp.derivesFrom(defn.PairClass) =>
122-
val List(head, tail) = tp.args
123-
head :: genTupleSelectors(n, tail)
124-
case _ => tupleSelectors(n, tp)
125-
}
126-
genTupleSelectors(0, tp)
114+
val sels = for (n <- Iterator.from(0)) yield extractorMemberType(tp, nme.selectorName(n), errorPos)
115+
sels.takeWhile(_.exists).toList
127116
}
128117

118+
def tupleComponentTypes(tp: Type)(using Context): List[Type] =
119+
tp match
120+
case tp: AppliedType =>
121+
if defn.isTupleClass(tp.tycon.typeSymbol) then
122+
tp.args
123+
else if tp.tycon.derivesFrom(defn.PairClass) then
124+
val List(head, tail) = tp.args
125+
head :: tupleComponentTypes(tail)
126+
else
127+
Nil
128+
case _ =>
129+
Nil
130+
129131
def productArity(tp: Type, errorPos: SrcPos = NoSourcePosition)(using Context): Int =
130132
if (defn.isProductSubType(tp)) productSelectorTypes(tp, errorPos).size else -1
131133

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import TypeComparer.CompareResult
3030
import util.Spans._
3131
import util.common._
3232
import util.{Property, SimpleIdentityMap, SrcPos}
33-
import Applications.{ExtMethodApply, IntegratedTypeArgs, productSelectorTypes, wrapDefs}
33+
import Applications.{ExtMethodApply, IntegratedTypeArgs, tupleComponentTypes, wrapDefs}
3434

3535
import collection.mutable
3636
import annotation.tailrec
@@ -1257,8 +1257,8 @@ class Typer extends Namer
12571257
/** Is `formal` a product type which is elementwise compatible with `params`? */
12581258
def ptIsCorrectProduct(formal: Type) =
12591259
isFullyDefined(formal, ForceDegree.flipBottom) &&
1260-
(defn.isProductSubType(formal) || formal.derivesFrom(defn.PairClass)) &&
1261-
productSelectorTypes(formal, tree.srcPos).corresponds(params) {
1260+
defn.isProductSubType(formal) &&
1261+
tupleComponentTypes(formal).corresponds(params) {
12621262
(argType, param) =>
12631263
param.tpt.isEmpty || argType.widenExpr <:< typedAheadType(param.tpt).tpe
12641264
}

library/src-non-bootstrapped/scala/Tuple.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ object Tuple {
199199
def apply(): EmptyTuple = EmptyTuple
200200

201201
/** Tuple with one element */
202-
def apply[T](x: T): T *: EmptyTuple = Tuple1(x)
202+
def apply[T](x: T): Tuple1[T] = Tuple1(x)
203203

204204
/** Matches an empty tuple. */
205205
def unapply(x: EmptyTuple): true = true

scala3doc/src/dotty/renderers/MemberRenderer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class MemberRenderer(signatureRenderer: SignatureRenderer, buildNode: ContentNod
3333
case Origin.Overrides(defs) =>
3434
def renderDef(d: Overriden): Seq[TagArg] =
3535
Seq(" -> ", signatureRenderer.renderLink(d.name, d.dri))
36-
val headNode = m.inheritedFrom.map(signatureRenderer.renderLink(_, _))
36+
val headNode = m.inheritedFrom.map(form => signatureRenderer.renderLink(form.name, form.dri))
3737
val tailNodes = defs.flatMap(renderDef)
3838
val nodes = headNode.fold(tailNodes.drop(1))(_ +: tailNodes)
3939
tableRow("Definition Classes", div(nodes:_*))

tests/run/i10958.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
object U:
2+
def unapply(s:String) = Tuple(s) // specifying the type :Tuple1[String] fixes the issue
3+
4+
@main
5+
def Test =
6+
"" match
7+
case s"${U(u)})" =>
8+
val x: String = u

0 commit comments

Comments
 (0)