Skip to content

Commit d8aab99

Browse files
authored
Merge pull request #10987 from dotty-staging/fix-10958
Fix #11061: stop accidentally supported auto-tupling for case classes
2 parents 6750f0e + 3602d40 commit d8aab99

File tree

5 files changed

+27
-18
lines changed

5 files changed

+27
-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.widenExpr.dealias 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
@@ -31,7 +31,7 @@ import TypeComparer.CompareResult
3131
import util.Spans._
3232
import util.common._
3333
import util.{Property, SimpleIdentityMap, SrcPos}
34-
import Applications.{productSelectorTypes, wrapDefs, defaultArgument}
34+
import Applications.{tupleComponentTypes, wrapDefs, defaultArgument}
3535

3636
import collection.mutable
3737
import annotation.tailrec
@@ -1273,8 +1273,8 @@ class Typer extends Namer
12731273
/** Is `formal` a product type which is elementwise compatible with `params`? */
12741274
def ptIsCorrectProduct(formal: Type) =
12751275
isFullyDefined(formal, ForceDegree.flipBottom) &&
1276-
(defn.isProductSubType(formal) || formal.derivesFrom(defn.PairClass)) &&
1277-
productSelectorTypes(formal, tree.srcPos).corresponds(params) {
1276+
defn.isProductSubType(formal) &&
1277+
tupleComponentTypes(formal).corresponds(params) {
12781278
(argType, param) =>
12791279
param.tpt.isEmpty || argType.widenExpr <:< typedAheadType(param.tpt).tpe
12801280
}

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/neg/i11061.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
case class Foo(a: Int, b: Int)
2+
3+
object Test {
4+
def foo(x: Foo) = List(x).map(_ + _) // error
5+
6+
def main(args: Array[String]): Unit = println(foo(Foo(3, 4)))
7+
}

tests/pos/i6199a.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ case class ValueWithEncoder[T](value: T, encoder: Encoder[T])
33

44
object Test {
55
val a: Seq[ValueWithEncoder[_]] = Seq.empty
6-
val b = a.map((value, encoder) => encoder.encode(value))
6+
val b = a.map(ve => ve.encoder.encode(ve.value))
77
val c: Seq[String] = b
88
}

0 commit comments

Comments
 (0)