From 11393384db3ca0c6234340439d3ee682d33697d5 Mon Sep 17 00:00:00 2001 From: Georgi Krastev Date: Fri, 26 Nov 2021 01:34:24 +0100 Subject: [PATCH] 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. --- .../src/dotty/tools/dotc/core/TypeOps.scala | 7 +++++ .../dotty/tools/dotc/typer/Synthesizer.scala | 17 +++------- tests/pos/i13859.scala | 31 +++++++++++++++++++ 3 files changed, 42 insertions(+), 13 deletions(-) create mode 100644 tests/pos/i13859.scala diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 6a5145ffd202..451b567dc771 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -829,4 +829,11 @@ object TypeOps: def nestedPairs(ts: List[Type])(using Context): Type = ts.foldRight(defn.EmptyTupleModule.termRef: Type)(defn.PairClass.typeRef.appliedTo(_, _)) + class StripTypeVarsMap(using Context) extends TypeMap: + def apply(tp: Type) = mapOver(tp).stripTypeVar + + /** Apply [[Type.stripTypeVar]] recursively. */ + def stripTypeVars(tp: Type)(using Context): Type = + new StripTypeVarsMap().apply(tp) + end TypeOps diff --git a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala index 44351b9a213c..31694c23a8e0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala @@ -249,21 +249,12 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): val cls = mirroredType.classSymbol val accessors = cls.caseAccessors.filterNot(_.isAllOf(PrivateLocal)) val elemLabels = accessors.map(acc => ConstantType(Constant(acc.name.toString))) + val nestedPairs = TypeOps.nestedPairs(accessors.map(mirroredType.resultType.memberInfo(_).widenExpr)) val (monoType, elemsType) = mirroredType match case mirroredType: HKTypeLambda => - def accessorType(acc: Symbol) = - if cls.typeParams.hasSameLengthAs(mirroredType.paramRefs) then - acc.info.subst(cls.typeParams, mirroredType.paramRefs) - else - acc.info - val elems = - mirroredType.derivedLambdaType( - resType = TypeOps.nestedPairs(accessors.map(accessorType)) - ) - (mkMirroredMonoType(mirroredType), elems) + (mkMirroredMonoType(mirroredType), mirroredType.derivedLambdaType(resType = nestedPairs)) case _ => - val elems = TypeOps.nestedPairs(accessors.map(mirroredType.memberInfo(_).widenExpr)) - (mirroredType, elems) + (mirroredType, nestedPairs) val elemsLabels = TypeOps.nestedPairs(elemLabels) checkRefinement(formal, tpnme.MirroredElemTypes, elemsType, span) checkRefinement(formal, tpnme.MirroredElemLabels, elemsLabels, span) @@ -344,7 +335,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): (using Context): Tree = if checkFormal(formal) then formal.member(tpnme.MirroredType).info match - case TypeBounds(mirroredType, _) => synth(mirroredType.stripTypeVar, formal, span) + case TypeBounds(mirroredType, _) => synth(TypeOps.stripTypeVars(mirroredType), formal, span) case other => EmptyTree else EmptyTree diff --git a/tests/pos/i13859.scala b/tests/pos/i13859.scala new file mode 100644 index 000000000000..4092de52fd94 --- /dev/null +++ b/tests/pos/i13859.scala @@ -0,0 +1,31 @@ +import scala.deriving.* + +object Test: + type Kind1[C, O[_]] = C { + type MirroredType[X] = O[X] + type MirroredMonoType = O[Any] + type MirroredElemTypes[_] <: Tuple + } + + type Kind2[C, O[_, _]] = C { + type MirroredType[X, Y] = O[X, Y] + type MirroredMonoType = O[Any, Any] + type MirroredElemTypes[_, _] <: Tuple + } + + type Test[X] = (X, Boolean) + type Swap[X, Y] = (Y, X) + + locally { + val x = summon[Kind1[Mirror.Product, Test]] + x: Mirror.Product { + type MirroredElemTypes[X] = (X, Boolean) + } + } + + locally { + val x = summon[Kind2[Mirror.Product, Swap]] + x: Mirror.Product { + type MirroredElemTypes[X, Y] = (Y, X) + } + }