From 50fd96b86756010281fc2a402501dc551fb25b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pa=C5=82ka?= Date: Wed, 20 Nov 2024 10:50:51 +0100 Subject: [PATCH 1/9] Drop normalization of applied match alias arguments Delay their normalization until it is needed. Avoids overflows from infinite match types that did not need to normalize. Also improves MatchTypeTraces as a side effect. It appears to have been added to avoid some separate issue, which seems to have been fixed. It is no longer needed since the previous fix with constant folding in disjointnessBoundary. [Cherry-picked 32752e28e898473a9f78f1ca8a8a019decd3f665][modified] --- compiler/src/dotty/tools/dotc/core/Types.scala | 9 ++++++++- tests/neg/i12049d.check | 14 ++++++++++++++ tests/neg/i12049d.scala | 14 ++++++++++++++ tests/pos/matchtype-unusedArg/A_1.scala | 8 ++++++++ tests/pos/matchtype-unusedArg/B_2.scala | 2 ++ 5 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 tests/neg/i12049d.check create mode 100644 tests/neg/i12049d.scala create mode 100644 tests/pos/matchtype-unusedArg/A_1.scala create mode 100644 tests/pos/matchtype-unusedArg/B_2.scala diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 4be905beefcc..20b3fcb43b7a 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -4517,7 +4517,14 @@ object Types extends TypeUtils { case MatchAlias(alias) => trace(i"normalize $this", typr, show = true) { MatchTypeTrace.recurseWith(this) { - alias.applyIfParameterized(args.map(_.normalized)).tryNormalize + alias.applyIfParameterized(args).tryNormalize + /* `applyIfParameterized` may reduce several HKTypeLambda applications + * before the underlying MatchType is reached. + * Even if they do not involve any match type normalizations yet, + * we still want to record these reductions in the MatchTypeTrace. + * They should however only be attempted if they eventually expand + * to a match type, which is ensured by the `isMatchAlias` guard. + */ } } case _ => diff --git a/tests/neg/i12049d.check b/tests/neg/i12049d.check new file mode 100644 index 000000000000..fdb13aae4e43 --- /dev/null +++ b/tests/neg/i12049d.check @@ -0,0 +1,14 @@ +-- [E007] Type Mismatch Error: tests/neg/i12049d.scala:14:52 ----------------------------------------------------------- +14 |val x: M[NotRelevant[Nothing], Relevant[Nothing]] = 2 // error + | ^ + | Found: (2 : Int) + | Required: M[NotRelevant[Nothing], Relevant[Nothing]] + | + | Note: a match type could not be fully reduced: + | + | trying to reduce M[NotRelevant[Nothing], Relevant[Nothing]] + | trying to reduce Relevant[Nothing] + | failed since selector Nothing + | is uninhabited (there are no values of that type). + | + | longer explanation available when compiling with `-explain` diff --git a/tests/neg/i12049d.scala b/tests/neg/i12049d.scala new file mode 100644 index 000000000000..0011ec1f00b1 --- /dev/null +++ b/tests/neg/i12049d.scala @@ -0,0 +1,14 @@ + +trait A +trait B + +type M[X, Y] = Y match + case A => Int + case B => String + +type Relevant[Z] = Z match + case A => B +type NotRelevant[Z] = Z match + case B => A + +val x: M[NotRelevant[Nothing], Relevant[Nothing]] = 2 // error diff --git a/tests/pos/matchtype-unusedArg/A_1.scala b/tests/pos/matchtype-unusedArg/A_1.scala new file mode 100644 index 000000000000..4364a812f12c --- /dev/null +++ b/tests/pos/matchtype-unusedArg/A_1.scala @@ -0,0 +1,8 @@ + +type Rec[X] = X match + case Int => Rec[X] + +type M[Unused, Y] = Y match + case String => Double + +def foo[X](d: M[Rec[X], "hi"]) = ??? diff --git a/tests/pos/matchtype-unusedArg/B_2.scala b/tests/pos/matchtype-unusedArg/B_2.scala new file mode 100644 index 000000000000..437e53a1691d --- /dev/null +++ b/tests/pos/matchtype-unusedArg/B_2.scala @@ -0,0 +1,2 @@ + +def Test = foo[Int](3d) // crash before changes From acaaeb3ab6d626edd4398ee4bb457da39fd11ea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pa=C5=82ka?= Date: Wed, 20 Nov 2024 15:33:52 +0100 Subject: [PATCH 2/9] Use cached underlyingMatchType when normalizing applied match aliases Also fixes underlyingMatchType to not use the resType of HKTypeLambdas It should only be in `isMatch` used for `AliasingBounds`, not `isMatchAlias` [Cherry-picked ac980239a55d496f9c35f74e0dd6cc9879d1bb01][modified] --- .../src/dotty/tools/dotc/core/Types.scala | 51 +++++++++---------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 20b3fcb43b7a..b98d3809791a 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -456,12 +456,10 @@ object Types extends TypeUtils { */ def isMatch(using Context): Boolean = underlyingMatchType.exists - def underlyingMatchType(using Context): Type = stripped match { + def underlyingMatchType(using Context): Type = stripped match case tp: MatchType => tp - case tp: HKTypeLambda => tp.resType.underlyingMatchType - case tp: AppliedType if tp.isMatchAlias => tp.superType.underlyingMatchType + case tp: AppliedType => tp.underlyingMatchType case _ => NoType - } /** Is this a higher-kinded type lambda with given parameter variances? * These lambdas are used as the RHS of higher-kinded abstract types or @@ -4455,6 +4453,9 @@ object Types extends TypeUtils { private var myEvalRunId: RunId = NoRunId private var myEvalued: Type = uninitialized + private var validUnderlyingMatch: Period = Nowhere + private var cachedUnderlyingMatch: Type = uninitialized + def isGround(acc: TypeAccumulator[Boolean])(using Context): Boolean = if myGround == 0 then myGround = if acc.foldOver(true, this) then 1 else -1 myGround > 0 @@ -4511,29 +4512,25 @@ object Types extends TypeUtils { case nil => x foldArgs(op(x, tycon), args) - override def tryNormalize(using Context): Type = tycon.stripTypeVar match { - case tycon: TypeRef => - def tryMatchAlias = tycon.info match { - case MatchAlias(alias) => - trace(i"normalize $this", typr, show = true) { - MatchTypeTrace.recurseWith(this) { - alias.applyIfParameterized(args).tryNormalize - /* `applyIfParameterized` may reduce several HKTypeLambda applications - * before the underlying MatchType is reached. - * Even if they do not involve any match type normalizations yet, - * we still want to record these reductions in the MatchTypeTrace. - * They should however only be attempted if they eventually expand - * to a match type, which is ensured by the `isMatchAlias` guard. - */ - } - } - case _ => - NoType - } - tryCompiletimeConstantFold.orElse(tryMatchAlias) - case _ => - NoType - } + /** Exists if the tycon is a TypeRef of an alias with an underlying match type. + * Anything else should have already been reduced in `appliedTo` by the TypeAssigner. + * May reduce several HKTypeLambda applications before the underlying MatchType is reached. + */ + override def underlyingMatchType(using Context): Type = + if ctx.period != validUnderlyingMatch then + cachedUnderlyingMatch = superType.underlyingMatchType + validUnderlyingMatch = validSuper + cachedUnderlyingMatch + + override def tryNormalize(using Context): Type = + def tryMatchAlias = + if isMatchAlias then trace(i"normalize $this", typr, show = true): + if MatchTypeTrace.isRecording then + MatchTypeTrace.recurseWith(this)(superType.tryNormalize) + else + underlyingMatchType.tryNormalize + else NoType + tryCompiletimeConstantFold.orElse(tryMatchAlias) /** Does this application expand to a match type? */ def isMatchAlias(using Context): Boolean = tycon.stripTypeVar match From cda1d403c83300bb2ef634dcd27cda1c2b2abd9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pa=C5=82ka?= Date: Wed, 20 Nov 2024 15:49:53 +0100 Subject: [PATCH 3/9] Cache underlying applied compiletime.ops [Cherry-picked 68ca883017888203a59341f7bd0e1d9c69b45e3a][modified] --- .../src/dotty/tools/dotc/core/Types.scala | 50 +++++++++---------- .../src/dotty/tools/dotc/typer/Typer.scala | 2 +- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index b98d3809791a..60eb5a0fea12 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -452,13 +452,18 @@ object Types extends TypeUtils { /** Is this a MethodType for which the parameters will not be used? */ def hasErasedParams(using Context): Boolean = false - /** Is this a match type or a higher-kinded abstraction of one? - */ - def isMatch(using Context): Boolean = underlyingMatchType.exists + /** Is this a match type or a higher-kinded abstraction of one? */ + def isMatch(using Context): Boolean = stripped match + case tp: MatchType => true + case tp: HKTypeLambda => tp.resType.isMatch + case _ => false + + /** Does this application expand to a match type? */ + def isMatchAlias(using Context): Boolean = underlyingNormalizable.isMatch - def underlyingMatchType(using Context): Type = stripped match + def underlyingNormalizable(using Context): Type = stripped match case tp: MatchType => tp - case tp: AppliedType => tp.underlyingMatchType + case tp: AppliedType => tp.underlyingNormalizable case _ => NoType /** Is this a higher-kinded type lambda with given parameter variances? @@ -4453,8 +4458,8 @@ object Types extends TypeUtils { private var myEvalRunId: RunId = NoRunId private var myEvalued: Type = uninitialized - private var validUnderlyingMatch: Period = Nowhere - private var cachedUnderlyingMatch: Type = uninitialized + private var validUnderlyingNormalizable: Period = Nowhere + private var cachedUnderlyingNormalizable: Type = uninitialized def isGround(acc: TypeAccumulator[Boolean])(using Context): Boolean = if myGround == 0 then myGround = if acc.foldOver(true, this) then 1 else -1 @@ -4516,11 +4521,15 @@ object Types extends TypeUtils { * Anything else should have already been reduced in `appliedTo` by the TypeAssigner. * May reduce several HKTypeLambda applications before the underlying MatchType is reached. */ - override def underlyingMatchType(using Context): Type = - if ctx.period != validUnderlyingMatch then - cachedUnderlyingMatch = superType.underlyingMatchType - validUnderlyingMatch = validSuper - cachedUnderlyingMatch + override def underlyingNormalizable(using Context): Type = + if ctx.period != validUnderlyingNormalizable then tycon match + case tycon: TypeRef if defn.isCompiletimeAppliedType(tycon.symbol) => + cachedUnderlyingNormalizable = this + validUnderlyingNormalizable = ctx.period + case _ => + cachedUnderlyingNormalizable = superType.underlyingNormalizable + validUnderlyingNormalizable = validSuper + cachedUnderlyingNormalizable override def tryNormalize(using Context): Type = def tryMatchAlias = @@ -4528,18 +4537,10 @@ object Types extends TypeUtils { if MatchTypeTrace.isRecording then MatchTypeTrace.recurseWith(this)(superType.tryNormalize) else - underlyingMatchType.tryNormalize + underlyingNormalizable.tryNormalize else NoType tryCompiletimeConstantFold.orElse(tryMatchAlias) - /** Does this application expand to a match type? */ - def isMatchAlias(using Context): Boolean = tycon.stripTypeVar match - case tycon: TypeRef => - tycon.info match - case _: MatchAlias => true - case _ => false - case _ => false - /** Is this an unreducible application to wildcard arguments? * This is the case if tycon is higher-kinded. This means * it is a subtype of a hk-lambda, but not a match alias. @@ -5041,10 +5042,9 @@ object Types extends TypeUtils { def apply(bound: Type, scrutinee: Type, cases: List[Type])(using Context): MatchType = unique(new CachedMatchType(bound, scrutinee, cases)) - def thatReducesUsingGadt(tp: Type)(using Context): Boolean = tp match - case MatchType.InDisguise(mt) => mt.reducesUsingGadt - case mt: MatchType => mt.reducesUsingGadt - case _ => false + def thatReducesUsingGadt(tp: Type)(using Context): Boolean = tp.underlyingNormalizable match + case mt: MatchType => mt.reducesUsingGadt + case _ => false /** Extractor for match types hidden behind an AppliedType/MatchAlias. */ object InDisguise: diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index ecbcb7b2efda..827df499f470 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1789,7 +1789,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer case _ => false } - val result = pt match { + val result = pt.underlyingNormalizable match { case mt: MatchType if isMatchTypeShaped(mt) => typedDependentMatchFinish(tree, sel1, selType, tree.cases, mt) case MatchType.InDisguise(mt) if isMatchTypeShaped(mt) => From 8621dc48cc0cfcc0fa59af605ea40d5fb433ad94 Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Tue, 30 Apr 2024 13:44:54 +0200 Subject: [PATCH 4/9] Use `underlyingNormalizable` in `Type#tryNormalize` [Cherry-picked a6cadec56e92412b2866895f6fbfc6149193f32b] --- .../src/dotty/tools/dotc/core/Types.scala | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 60eb5a0fea12..2b6c9c5b9acc 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1488,11 +1488,13 @@ object Types extends TypeUtils { if (normed.exists) normed else this } - /** If this type can be normalized at the top-level by rewriting match types - * of S[n] types, the result after applying all toplevel normalizations, - * otherwise NoType + /** If this type has an underlying match type or applied compiletime.ops, + * then the result after applying all toplevel normalizations, otherwise NoType. */ - def tryNormalize(using Context): Type = NoType + def tryNormalize(using Context): Type = underlyingNormalizable match + case mt: MatchType => mt.tryNormalize + case tp: AppliedType => tp.tryCompiletimeConstantFold + case _ => NoType private def widenDealias1(keep: AnnotatedType => Context ?=> Boolean)(using Context): Type = { val res = this.widen.dealias1(keep, keepOpaques = false) @@ -4532,14 +4534,9 @@ object Types extends TypeUtils { cachedUnderlyingNormalizable override def tryNormalize(using Context): Type = - def tryMatchAlias = - if isMatchAlias then trace(i"normalize $this", typr, show = true): - if MatchTypeTrace.isRecording then - MatchTypeTrace.recurseWith(this)(superType.tryNormalize) - else - underlyingNormalizable.tryNormalize - else NoType - tryCompiletimeConstantFold.orElse(tryMatchAlias) + if isMatchAlias && MatchTypeTrace.isRecording then + MatchTypeTrace.recurseWith(this)(superType.tryNormalize) + else super.tryNormalize /** Is this an unreducible application to wildcard arguments? * This is the case if tycon is higher-kinded. This means From ea961618711a9ea6325a233d85d19402fd92e7b2 Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Tue, 30 Apr 2024 13:45:54 +0200 Subject: [PATCH 5/9] `stripLazyRef` for `underlyingNormalizable` [Cherry-picked 4fbba66ec6376e2d7f4f936cf79738fa86a49f23] --- compiler/src/dotty/tools/dotc/core/Types.scala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 2b6c9c5b9acc..6e2596b33c98 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -461,7 +461,7 @@ object Types extends TypeUtils { /** Does this application expand to a match type? */ def isMatchAlias(using Context): Boolean = underlyingNormalizable.isMatch - def underlyingNormalizable(using Context): Type = stripped match + def underlyingNormalizable(using Context): Type = stripped.stripLazyRef match case tp: MatchType => tp case tp: AppliedType => tp.underlyingNormalizable case _ => NoType @@ -3111,8 +3111,6 @@ object Types extends TypeUtils { private var myRef: Type | Null = null private var computed = false - override def tryNormalize(using Context): Type = ref.tryNormalize - def ref(using Context): Type = if computed then if myRef == null then From dc2d31bdddaeca24f497c533b2caef20ae1c13b2 Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Tue, 30 Apr 2024 13:57:30 +0200 Subject: [PATCH 6/9] Drop `handleRecursive` from `MatchType#tryNormalize` There is already a `handleRecursive` in `reduced` Having the two makes error messages undeterministic, see #20269 [Cherry-picked 309b1cfceeb812c589f932e16dbd50b09c11a5f4] --- compiler/src/dotty/tools/dotc/core/Types.scala | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 6e2596b33c98..980c096ed001 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -4958,11 +4958,7 @@ object Types extends TypeUtils { private var reductionContext: util.MutableMap[Type, Type] = _ override def tryNormalize(using Context): Type = - try - reduced.normalized - catch - case ex: Throwable => - handleRecursive("normalizing", s"${scrutinee.show} match ..." , ex) + reduced.normalized def reduced(using Context): Type = atPhaseNoLater(elimOpaquePhase) { From 08967f6e0c810b6dacee06d39c49768f63658e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pa=C5=82ka?= Date: Wed, 20 Nov 2024 15:56:56 +0100 Subject: [PATCH 7/9] Regroup `tryNormalize` logic [Cherry-picked 0b87d7fcdb40808226bf79857fe06246f2840e7a][modified] --- .../src/dotty/tools/dotc/core/Types.scala | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 980c096ed001..a0018d2e4abd 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -461,11 +461,6 @@ object Types extends TypeUtils { /** Does this application expand to a match type? */ def isMatchAlias(using Context): Boolean = underlyingNormalizable.isMatch - def underlyingNormalizable(using Context): Type = stripped.stripLazyRef match - case tp: MatchType => tp - case tp: AppliedType => tp.underlyingNormalizable - case _ => NoType - /** Is this a higher-kinded type lambda with given parameter variances? * These lambdas are used as the RHS of higher-kinded abstract types or * type aliases. The variance info is strictly needed only for abstract types. @@ -1480,22 +1475,25 @@ object Types extends TypeUtils { } deskolemizer(this) - /** The result of normalization using `tryNormalize`, or the type itself if - * tryNormlize yields NoType - */ - final def normalized(using Context): Type = { - val normed = tryNormalize - if (normed.exists) normed else this - } + /** The result of normalization, or the type itself if none apply. */ + final def normalized(using Context): Type = tryNormalize.orElse(this) /** If this type has an underlying match type or applied compiletime.ops, * then the result after applying all toplevel normalizations, otherwise NoType. */ def tryNormalize(using Context): Type = underlyingNormalizable match - case mt: MatchType => mt.tryNormalize + case mt: MatchType => mt.reduced.normalized case tp: AppliedType => tp.tryCompiletimeConstantFold case _ => NoType + /** Perform successive strippings, and beta-reductions of applied types until + * a match type or applied compiletime.ops is reached, if any, otherwise NoType. + */ + def underlyingNormalizable(using Context): Type = stripped.stripLazyRef match + case tp: MatchType => tp + case tp: AppliedType => tp.underlyingNormalizable + case _ => NoType + private def widenDealias1(keep: AnnotatedType => Context ?=> Boolean)(using Context): Type = { val res = this.widen.dealias1(keep, keepOpaques = false) if (res eq this) res else res.widenDealias1(keep) @@ -4517,9 +4515,10 @@ object Types extends TypeUtils { case nil => x foldArgs(op(x, tycon), args) - /** Exists if the tycon is a TypeRef of an alias with an underlying match type. - * Anything else should have already been reduced in `appliedTo` by the TypeAssigner. - * May reduce several HKTypeLambda applications before the underlying MatchType is reached. + /** Exists if the tycon is a TypeRef of an alias with an underlying match type, + * or a compiletime applied type. Anything else should have already been + * reduced in `appliedTo` by the TypeAssigner. This may reduce several + * HKTypeLambda applications before the underlying normalizable type is reached. */ override def underlyingNormalizable(using Context): Type = if ctx.period != validUnderlyingNormalizable then tycon match @@ -4957,8 +4956,6 @@ object Types extends TypeUtils { private var myReduced: Type | Null = null private var reductionContext: util.MutableMap[Type, Type] = _ - override def tryNormalize(using Context): Type = - reduced.normalized def reduced(using Context): Type = atPhaseNoLater(elimOpaquePhase) { From 1bc6fc812055e4e52e2c3306ba2b168d047272fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pa=C5=82ka?= Date: Wed, 20 Nov 2024 15:58:31 +0100 Subject: [PATCH 8/9] Add i974.scala to neg-best-effort-pickling.blacklist [Cherry-picked 9df3942d63513acd28bc5fcbe87c29e879c9d1fd][modified] --- .../dotc/neg-best-effort-pickling.blacklist | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 compiler/test/dotc/neg-best-effort-pickling.blacklist diff --git a/compiler/test/dotc/neg-best-effort-pickling.blacklist b/compiler/test/dotc/neg-best-effort-pickling.blacklist new file mode 100644 index 000000000000..a582f085dd30 --- /dev/null +++ b/compiler/test/dotc/neg-best-effort-pickling.blacklist @@ -0,0 +1,22 @@ +export-in-extension.scala +i12456.scala +i8623.scala +i1642.scala +i16696.scala +constructor-proxy-values.scala +i9328.scala +i15414.scala +i6796.scala +i14013.scala +toplevel-cyclic +curried-dependent-ift.scala +i17121.scala +illegal-match-types.scala +i13780-1.scala +i20317a.scala +i11226.scala +i974.scala + +# semantic db generation fails in the first compilation +i1642.scala +i15158.scala From ad6eb2b847cea18dfca9463db8ab026027498812 Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Mon, 3 Jun 2024 16:51:07 +0200 Subject: [PATCH 9/9] Add test for #20482 tryNormalize used to not recursively check if tycon of applied type was normalizable, this may be necessary in the case of an applied type dealiasing to a type lambda. Fixes #20482 [Cherry-picked 9465d65e185236353811e3cada62b91df61a1076] --- tests/pos/i20482.scala | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/pos/i20482.scala diff --git a/tests/pos/i20482.scala b/tests/pos/i20482.scala new file mode 100644 index 000000000000..2a7680df054d --- /dev/null +++ b/tests/pos/i20482.scala @@ -0,0 +1,16 @@ +trait WrapperType[A] + +case class Foo[A]() + +case class Bar[A]() + +type FooToBar[D[_]] = [A] =>> D[Unit] match { + case Foo[Unit] => Bar[A] +} + +case class Test() +object Test { + implicit val wrapperType: WrapperType[Bar[Test]] = new WrapperType[Bar[Test]] {} +} + +val test = summon[WrapperType[FooToBar[Foo][Test]]]