From c32adc2e66ab74b7eaafa1e6f54fed9b975269c6 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Fri, 2 Jun 2023 11:33:24 +0100 Subject: [PATCH] Avoid embedding SelectionProtos in Conversions --- .../dotty/tools/dotc/typer/Implicits.scala | 24 ++++++++++++++----- .../test/dotc/pos-test-pickling.blacklist | 1 + tests/pos/i15867.scala | 19 +++++++++++++++ 3 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 tests/pos/i15867.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index c6795ed25a0e..9c044207d4b3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -1122,17 +1122,29 @@ trait Implicits: adapt(generated, pt.widenExpr, locked) else { def untpdGenerated = untpd.TypedSplice(generated) - def producesConversion(info: Type): Boolean = info match - case info: PolyType => producesConversion(info.resType) - case info: MethodType if info.isImplicitMethod => producesConversion(info.resType) - case _ => info.derivesFrom(defn.ConversionClass) + def conversionResultType(info: Type): Type = info match + case info: PolyType => conversionResultType(info.resType) + case info: MethodType if info.isImplicitMethod => conversionResultType(info.resType) + case _ if info.derivesFrom(defn.ConversionClass) => pt match + case selProto: SelectionProto => + info.baseType(defn.ConversionClass) match + case AppliedType(_, List(_, restpe)) if selProto.isMatchedBy(restpe) => + // if we embed the SelectionProto as the Conversion result type + // it might end up within a GADT cast type + // so instead replace it with the targeted conversion type, if it matches + // see tests/pos/i15867.scala. + restpe + case _ => pt + case _ => pt + case _ => NoType def tryConversion(using Context) = { + val restpeConv = if ref.symbol.is(Given) then conversionResultType(ref.symbol.info) else NoType val untpdConv = - if ref.symbol.is(Given) && producesConversion(ref.symbol.info) then + if restpeConv.exists then untpd.Select( untpd.TypedSplice( adapt(generated, - defn.ConversionClass.typeRef.appliedTo(argument.tpe, pt), + defn.ConversionClass.typeRef.appliedTo(argument.tpe, restpeConv), locked)), nme.apply) else untpdGenerated diff --git a/compiler/test/dotc/pos-test-pickling.blacklist b/compiler/test/dotc/pos-test-pickling.blacklist index 81c0d3e35d3a..2ea2b045448f 100644 --- a/compiler/test/dotc/pos-test-pickling.blacklist +++ b/compiler/test/dotc/pos-test-pickling.blacklist @@ -94,6 +94,7 @@ i4176-gadt.scala # GADT difference i13974a.scala +i15867.scala java-inherited-type1 diff --git a/tests/pos/i15867.scala b/tests/pos/i15867.scala new file mode 100644 index 000000000000..2e62177ba590 --- /dev/null +++ b/tests/pos/i15867.scala @@ -0,0 +1,19 @@ +enum SUB[-A, +B]: + case Refl[S]() extends SUB[S, S] + +class Pow(self: Int): + def **(other: Int): Int = math.pow(self, other).toInt + +given fromList[T]: Conversion[List[T], Pow] = ??? + +given fromInt: Conversion[Int, Pow] = Pow(_) + +def foo[T](t1: T, ev: T SUB List[Int]) = + ev match { case SUB.Refl() => + t1 ** 2 // error + } + +def baz[T](t2: T, ev: T SUB Int) = + ev match { case SUB.Refl() => + t2 ** 2 // works + }