From cfe29d61ee8ef41ef79e7ff787e4bfb484a325f7 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. [Cherry-picked f3c2b1df6a1e7de896ea7be3461032cc3387024d] --- .../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 54f8ca02eb4a..23348fe103fd 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 e5239236b4ddfa2250c4c7ca3caa8605ab36f045 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). [Cherry-picked 576d44875072111a2708f26b253c20f360bd3fd8] --- 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 23348fe103fd..5d43ebd25319 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