Skip to content

Commit 1139338

Browse files
committed
Fix Mirror.Product for type lambdas
We don't need to guess how the type parameters should be substituted. Instead we can use the result type directly to obtain the member type. This exposed another issue - the mirrored type contained type variables. To get rid of them we apply `Type.stripTypeVar` recursively.
1 parent 1f48de1 commit 1139338

File tree

3 files changed

+42
-13
lines changed

3 files changed

+42
-13
lines changed

compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -829,4 +829,11 @@ object TypeOps:
829829
def nestedPairs(ts: List[Type])(using Context): Type =
830830
ts.foldRight(defn.EmptyTupleModule.termRef: Type)(defn.PairClass.typeRef.appliedTo(_, _))
831831

832+
class StripTypeVarsMap(using Context) extends TypeMap:
833+
def apply(tp: Type) = mapOver(tp).stripTypeVar
834+
835+
/** Apply [[Type.stripTypeVar]] recursively. */
836+
def stripTypeVars(tp: Type)(using Context): Type =
837+
new StripTypeVarsMap().apply(tp)
838+
832839
end TypeOps

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

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -249,21 +249,12 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
249249
val cls = mirroredType.classSymbol
250250
val accessors = cls.caseAccessors.filterNot(_.isAllOf(PrivateLocal))
251251
val elemLabels = accessors.map(acc => ConstantType(Constant(acc.name.toString)))
252+
val nestedPairs = TypeOps.nestedPairs(accessors.map(mirroredType.resultType.memberInfo(_).widenExpr))
252253
val (monoType, elemsType) = mirroredType match
253254
case mirroredType: HKTypeLambda =>
254-
def accessorType(acc: Symbol) =
255-
if cls.typeParams.hasSameLengthAs(mirroredType.paramRefs) then
256-
acc.info.subst(cls.typeParams, mirroredType.paramRefs)
257-
else
258-
acc.info
259-
val elems =
260-
mirroredType.derivedLambdaType(
261-
resType = TypeOps.nestedPairs(accessors.map(accessorType))
262-
)
263-
(mkMirroredMonoType(mirroredType), elems)
255+
(mkMirroredMonoType(mirroredType), mirroredType.derivedLambdaType(resType = nestedPairs))
264256
case _ =>
265-
val elems = TypeOps.nestedPairs(accessors.map(mirroredType.memberInfo(_).widenExpr))
266-
(mirroredType, elems)
257+
(mirroredType, nestedPairs)
267258
val elemsLabels = TypeOps.nestedPairs(elemLabels)
268259
checkRefinement(formal, tpnme.MirroredElemTypes, elemsType, span)
269260
checkRefinement(formal, tpnme.MirroredElemLabels, elemsLabels, span)
@@ -344,7 +335,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
344335
(using Context): Tree =
345336
if checkFormal(formal) then
346337
formal.member(tpnme.MirroredType).info match
347-
case TypeBounds(mirroredType, _) => synth(mirroredType.stripTypeVar, formal, span)
338+
case TypeBounds(mirroredType, _) => synth(TypeOps.stripTypeVars(mirroredType), formal, span)
348339
case other => EmptyTree
349340
else EmptyTree
350341

tests/pos/i13859.scala

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import scala.deriving.*
2+
3+
object Test:
4+
type Kind1[C, O[_]] = C {
5+
type MirroredType[X] = O[X]
6+
type MirroredMonoType = O[Any]
7+
type MirroredElemTypes[_] <: Tuple
8+
}
9+
10+
type Kind2[C, O[_, _]] = C {
11+
type MirroredType[X, Y] = O[X, Y]
12+
type MirroredMonoType = O[Any, Any]
13+
type MirroredElemTypes[_, _] <: Tuple
14+
}
15+
16+
type Test[X] = (X, Boolean)
17+
type Swap[X, Y] = (Y, X)
18+
19+
locally {
20+
val x = summon[Kind1[Mirror.Product, Test]]
21+
x: Mirror.Product {
22+
type MirroredElemTypes[X] = (X, Boolean)
23+
}
24+
}
25+
26+
locally {
27+
val x = summon[Kind2[Mirror.Product, Swap]]
28+
x: Mirror.Product {
29+
type MirroredElemTypes[X, Y] = (Y, X)
30+
}
31+
}

0 commit comments

Comments
 (0)