diff --git a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala index 399d411dd64f..fc5fcaa62cca 100644 --- a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala +++ b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala @@ -117,7 +117,8 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages( // Replace it with a properly encoded type splice. This is the normal for expected for type splices. tp.prefix.select(tpnme.splice) case tp: NamedType => - checkSymLevel(tp.symbol, tp, pos) match { + if (tp.prefix.isInstanceOf[TermRef] && tp.prefix.isStable) tp + else checkSymLevel(tp.symbol, tp, pos) match { case Some(tpRef) => tpRef.tpe case _ => if (tp.symbol.is(Param)) tp diff --git a/tests/neg/i5954b.scala b/tests/neg/i5954b.scala new file mode 100644 index 000000000000..f1bd7f8e8f6e --- /dev/null +++ b/tests/neg/i5954b.scala @@ -0,0 +1,11 @@ +abstract class MatcherFactory1[A] { + class AndNotWord +} + +object MatcherFactory1 { + import scala.quoted._ + + def impl[T](self: Expr[MatcherFactory1[T]#AndNotWord]) given QuoteContext = + '{ val a: Any = $self } // error: access to type T from wrong staging level + +} diff --git a/tests/neg/i5954c.scala b/tests/neg/i5954c.scala new file mode 100644 index 000000000000..50ae4d351974 --- /dev/null +++ b/tests/neg/i5954c.scala @@ -0,0 +1,11 @@ +abstract class MatcherFactory1 { + class AndNotWord[A] +} + +object MatcherFactory1 { + import scala.quoted._ + + def impl[T](self: Expr[MatcherFactory1#AndNotWord[T]]) given QuoteContext = + '{ val a: Any = $self } // error: access to type T from wrong staging level + +} diff --git a/tests/pos/i5954b.scala b/tests/pos/i5954b.scala new file mode 100644 index 000000000000..f4ea7cf08afa --- /dev/null +++ b/tests/pos/i5954b.scala @@ -0,0 +1,15 @@ +abstract class MatcherFactory1 { + class AndNotWord[A] +} + +object MatcherFactory1 { + import scala.quoted._ + + def impl(self: Expr[MatcherFactory1#AndNotWord[Int]]) given QuoteContext = + '{ val a: Any = $self } + + + def impl[T: Type](self: Expr[MatcherFactory1#AndNotWord[T]]) given QuoteContext = + '{ val a: Any = $self } + +} diff --git a/tests/pos/i5954c.scala b/tests/pos/i5954c.scala new file mode 100644 index 000000000000..9587beac7e16 --- /dev/null +++ b/tests/pos/i5954c.scala @@ -0,0 +1,15 @@ +abstract class MatcherFactory1[A] { + class AndNotWord +} + +object MatcherFactory1 { + import scala.quoted._ + + def impl(self: Expr[MatcherFactory1[Int]#AndNotWord]) given QuoteContext = + '{ val a: Any = $self } + + + def impl[T: Type](self: Expr[MatcherFactory1[T]#AndNotWord]) given QuoteContext = + '{ val a: Any = $self } + +} diff --git a/tests/pos/i5954d.scala b/tests/pos/i5954d.scala new file mode 100644 index 000000000000..60f6aeb46297 --- /dev/null +++ b/tests/pos/i5954d.scala @@ -0,0 +1,15 @@ +abstract class MatcherFactory1 { + type AndNotWord +} + +object MatcherFactory1 { + import scala.quoted._ + + def impl(self: Expr[MatcherFactory1#AndNotWord]) given QuoteContext = + '{ val a: Any = $self } + + + def impl2[T: Type](a: MatcherFactory1)(self: Expr[T])(implicit ev: T =:= a.AndNotWord, qctx: QuoteContext) = + '{ val a: Any = $self } + +} diff --git a/tests/pos/i7048.scala b/tests/pos/i7048.scala new file mode 100644 index 000000000000..f4797e5d675a --- /dev/null +++ b/tests/pos/i7048.scala @@ -0,0 +1,13 @@ +import scala.quoted._ + +trait IsExpr[T] { + type Underlying + def expr: Expr[Underlying] +} + +def f(x: Any): String = x.toString + +def g[T] given (e: IsExpr[T], tu: Type[e.Underlying]): given QuoteContext => Expr[String] = { + val underlying: Expr[e.Underlying] = e.expr + '{f($underlying)} +} diff --git a/tests/pos/i7048b.scala b/tests/pos/i7048b.scala new file mode 100644 index 000000000000..0600f9c1fa9b --- /dev/null +++ b/tests/pos/i7048b.scala @@ -0,0 +1,12 @@ +import scala.quoted._ + +trait IsExpr { + type Underlying +} + +val foo: IsExpr = ??? + +def g() given QuoteContext: Unit = { + val a = '[foo.Underlying] + () +} diff --git a/tests/pos/i7048c.scala b/tests/pos/i7048c.scala new file mode 100644 index 000000000000..ed03eb9adbb1 --- /dev/null +++ b/tests/pos/i7048c.scala @@ -0,0 +1,13 @@ +import scala.quoted._ + +trait IsExpr { + type Underlying +} + +val foo: IsExpr = ??? + +def g(e: IsExpr) given (tu: Type[e.Underlying]): Unit = ??? + +def mcrImpl given QuoteContext: Unit = { + g(foo) +} diff --git a/tests/pos/i7048d.scala b/tests/pos/i7048d.scala new file mode 100644 index 000000000000..cdf54020b172 --- /dev/null +++ b/tests/pos/i7048d.scala @@ -0,0 +1,13 @@ +import scala.quoted._ + +trait IsExpr { + class Underlying +} + +val foo: IsExpr = ??? + +def g(e: IsExpr) given (tu: Type[e.Underlying]): Unit = ??? + +def mcrImpl given QuoteContext: Unit = { + g(foo) +} diff --git a/tests/run-macros/i7048/Lib_1.scala b/tests/run-macros/i7048/Lib_1.scala new file mode 100644 index 000000000000..4ba8e6e76240 --- /dev/null +++ b/tests/run-macros/i7048/Lib_1.scala @@ -0,0 +1,24 @@ +import scala.quoted._ + +trait IsExpr[T] { + type Underlying + def toExpr(x: T): Expr[Underlying] +} + +given [U] as IsExpr[Expr[U]] = new IsExpr[Expr[U]] { + type Underlying = U + def toExpr(x: Expr[U]): Expr[U] = x +} + +def f(x: Any): String = x.toString + +def g[T](x: T) given (e: IsExpr[T], tu: Type[e.Underlying]): given QuoteContext => Expr[String] = { + val underlying: Expr[e.Underlying] = e.toExpr(x) + '{f($underlying)} +} + +inline def mcr(): Any = ${mcrImpl} +def mcrImpl given QuoteContext: Expr[Any] = { + val x = '{1} + g(x) +} diff --git a/tests/run-macros/i7048/Test_2.scala b/tests/run-macros/i7048/Test_2.scala new file mode 100644 index 000000000000..d29e6be42f64 --- /dev/null +++ b/tests/run-macros/i7048/Test_2.scala @@ -0,0 +1,5 @@ +object Test { + def main(args: Array[String]): Unit = { + mcr() + } +}