From f3c2b1df6a1e7de896ea7be3461032cc3387024d Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Tue, 27 Jun 2023 14:21:41 +0200 Subject: [PATCH 1/2] Fix StaleSymbol for path dependent result type in macro context The reason for the stale symbols was the fact that they were derived from the previous (suspended) run (by calling a method from that run), and path depended types seem to use an optimized path utilizing initial designator, unlike the other kinds of types, which seem to either not need calculating denotation or the denotation there is able to update it's own validity. Since that is impossible to do for those path dependent types, if they are invalid in the run recaluclate the Symbol, otherwise use `currentSymbol` as before. --- .../src/dotty/tools/dotc/core/Types.scala | 5 +- tests/neg-macros/i17152/DFBits.scala | 82 +++++++++++++++++++ tests/neg-macros/i17152/DFVal.scala | 25 ++++++ tests/neg-macros/i17294/DFVal.scala | 3 + tests/neg-macros/i17294/Width.scala | 12 +++ 5 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 tests/neg-macros/i17152/DFBits.scala create mode 100644 tests/neg-macros/i17152/DFVal.scala create mode 100644 tests/neg-macros/i17294/DFVal.scala create mode 100644 tests/neg-macros/i17294/Width.scala diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 7555ba41e58d..b2304087ccb4 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2677,7 +2677,10 @@ object Types { else { if (isType) { val res = - if (currentSymbol.isAllOf(ClassTypeParam)) argForParam(prefix) + val sym = + if (currentSymbol.isValidInCurrentRun) currentSymbol + else computeSymbol + if (sym.isAllOf(ClassTypeParam)) argForParam(prefix) else prefix.lookupRefined(name) if (res.exists) return res if (Config.splitProjections) diff --git a/tests/neg-macros/i17152/DFBits.scala b/tests/neg-macros/i17152/DFBits.scala new file mode 100644 index 000000000000..dd0e8b88a962 --- /dev/null +++ b/tests/neg-macros/i17152/DFBits.scala @@ -0,0 +1,82 @@ +// nopos-error +package crash + +import scala.quoted.* + +class IRDFType +class IRDFBoolOrBit extends IRDFType +class IRDFDecimal extends IRDFType +class IRDFBits extends IRDFType + +final class DFType[+T <: IRDFType, +A] +type DFTypeAny = DFType[IRDFType, Any] + +trait Baz + +trait Width[T]: + type Out <: Int +object Width: + given fromDFBoolOrBit[T <: DFBoolOrBit]: Width[T] with + type Out = 1 + transparent inline given [T]: Width[T] = ${ getWidthMacro[T] } + def getWidthMacro[T](using Quotes, Type[T]): Expr[Width[T]] = + '{ + new Width[T]: + type Out = 1 + } +end Width + +extension [T](t: T)(using baz: Baz) def width: 1 = ??? + +trait Check[T1 <: Int, T2 <: Int] + +type DFBits[W <: Int] = DFType[IRDFBits, Tuple1[W]] + +private object CompanionsDFBits: + object Val: + trait Candidate[R]: + type OutW <: Int + def apply(value: R): DFValOf[DFBits[OutW]] + object Candidate: + given fromDFUInt[W <: Int, R <: DFValOf[DFDecimal]]: Candidate[R] with + type OutW = W + def apply(value: R): DFValOf[DFBits[W]] = + import DFVal.Ops.bits + value.bits + ??? + end Candidate + + object TC: + import DFVal.TC + given DFBitsFromCandidate[ + LW <: Int, + V + ](using candidate: Candidate[V])(using + check: Check[LW, candidate.OutW] + ): TC[DFBits[LW], V] with + def conv(dfType: DFBits[LW], value: V): DFValOf[DFBits[LW]] = + val dfVal = candidate(value) + ??? + end TC + end Val + +end CompanionsDFBits + +type DFBoolOrBit = DFType[IRDFBoolOrBit, Any] +type DFDecimal = DFType[IRDFDecimal, Any] +object DFDecimal: + def foo(arg1: Int, arg2: Int): Unit = ??? + + object Val: + object TC: + import DFVal.TC + given [R]: TC[DFDecimal, R] = ??? + def apply( + dfType: DFDecimal, + dfVal: DFValOf[DFDecimal] + ): DFValOf[DFDecimal] = + foo(dfType.width, dfVal.width) + dfVal + end TC + end Val +end DFDecimal \ No newline at end of file diff --git a/tests/neg-macros/i17152/DFVal.scala b/tests/neg-macros/i17152/DFVal.scala new file mode 100644 index 000000000000..08da551c1072 --- /dev/null +++ b/tests/neg-macros/i17152/DFVal.scala @@ -0,0 +1,25 @@ +package crash + +trait TCConv[T <: DFTypeAny, V, O]: + type Out <: O + def conv(dfType: T, value: V): Out + +class DFVal[+T <: DFTypeAny] +type DFValAny = DFVal[DFTypeAny] +type DFValOf[+T <: DFTypeAny] = DFVal[T] + +object DFVal: + trait TC[T <: DFTypeAny, R] extends TCConv[T, R, DFValAny]: + type Out = DFValOf[T] + final def apply(dfType: T, value: R): Out = ??? + + object TC: + export CompanionsDFBits.Val.TC.given + end TC + + object Ops: + extension [T <: DFTypeAny, A, C, I](dfVal: DFVal[T]) + def bits(using w: Width[T]): DFValOf[DFBits[w.Out]] = ??? + end extension + end Ops +end DFVal \ No newline at end of file diff --git a/tests/neg-macros/i17294/DFVal.scala b/tests/neg-macros/i17294/DFVal.scala new file mode 100644 index 000000000000..268ad4e188b3 --- /dev/null +++ b/tests/neg-macros/i17294/DFVal.scala @@ -0,0 +1,3 @@ +package crash + +def bits[T](t: T)(using w: Width[T]): w.Out = ??? diff --git a/tests/neg-macros/i17294/Width.scala b/tests/neg-macros/i17294/Width.scala new file mode 100644 index 000000000000..255f4799c32c --- /dev/null +++ b/tests/neg-macros/i17294/Width.scala @@ -0,0 +1,12 @@ +// nopos-error +package crash +import scala.quoted.* + +trait Width[T]: + type Out +object Width: + transparent inline given [T]: Width[T] = ${ getWidthMacro[T] } + def getWidthMacro[T](using Quotes, Type[T]): Expr[Width[T]] = '{ new Width[T] {} } +end Width + +val x = bits(1) \ No newline at end of file From 576d44875072111a2708f26b253c20f360bd3fd8 Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Tue, 27 Jun 2023 14:40:07 +0200 Subject: [PATCH 2/2] Fix StaleSymbol for path dependent argument type in macro context To fix we recalculate the symbol from directly from NamedType when from invalid run, instead of updating it's validity (which is impossible, as its owners do not include it in their decls). --- compiler/src/dotty/tools/dotc/core/Types.scala | 14 ++++++++------ tests/pos-macros/i17294/Bar.scala | 6 ++++++ tests/pos-macros/i17294/Foo.scala | 3 +++ 3 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 tests/pos-macros/i17294/Bar.scala create mode 100644 tests/pos-macros/i17294/Foo.scala diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index b2304087ccb4..858b6c4883ec 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2754,14 +2754,16 @@ object Types { /** A reference like this one, but with the given prefix. */ final def withPrefix(prefix: Type)(using Context): Type = { def reload(): NamedType = { - val lastSym = lastSymbol.nn - val allowPrivate = !lastSym.exists || lastSym.is(Private) + val sym = + if lastSymbol.nn.isValidInCurrentRun then lastSymbol.nn + else computeSymbol + val allowPrivate = !sym.exists || sym.is(Private) var d = memberDenot(prefix, name, allowPrivate) - if (d.isOverloaded && lastSym.exists) + if (d.isOverloaded && sym.exists) d = disambiguate(d, - if (lastSym.signature == Signature.NotAMethod) Signature.NotAMethod - else lastSym.asSeenFrom(prefix).signature, - lastSym.targetName) + if (sym.signature == Signature.NotAMethod) Signature.NotAMethod + else sym.asSeenFrom(prefix).signature, + sym.targetName) NamedType(prefix, name, d) } if (prefix eq this.prefix) this diff --git a/tests/pos-macros/i17294/Bar.scala b/tests/pos-macros/i17294/Bar.scala new file mode 100644 index 000000000000..8c99b69b50c7 --- /dev/null +++ b/tests/pos-macros/i17294/Bar.scala @@ -0,0 +1,6 @@ +import scala.quoted.* + +class Bar[T] +object Bar: + transparent inline def bar[T](a: Foo, b: a.Out): Bar[T] = ${ getBarMacro[T] } + def getBarMacro[T](using Quotes, Type[T]): Expr[Bar[T]] = '{ new Bar[T] } \ No newline at end of file diff --git a/tests/pos-macros/i17294/Foo.scala b/tests/pos-macros/i17294/Foo.scala new file mode 100644 index 000000000000..b25d6416727e --- /dev/null +++ b/tests/pos-macros/i17294/Foo.scala @@ -0,0 +1,3 @@ +class Foo: + type Out = Int +val a = Bar.bar(new Foo(), 0) \ No newline at end of file