From df0d9eadf789b1315a1c73522c5642127cdbdeff Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 17 Nov 2022 15:51:15 +0100 Subject: [PATCH 1/2] Disallow local term references in staged types Fixes #16355 Fixes #15917 --- .../dotc/transform/PCPCheckAndHeal.scala | 8 +++-- tests/neg-macros/i15917.scala | 6 ++++ tests/neg-macros/i16355a.scala | 35 +++++++++++++++++++ tests/neg-macros/i16355b.scala | 4 +++ 4 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 tests/neg-macros/i15917.scala create mode 100644 tests/neg-macros/i16355a.scala create mode 100644 tests/neg-macros/i16355b.scala diff --git a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala index 1d0ed035df09..4669dc86982d 100644 --- a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala +++ b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala @@ -176,8 +176,10 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages( /** If the type refers to a locally defined symbol (either directly, or in a pickled type), * check that its staging level matches the current level. * - Static types and term are allowed at any level. - * - If a type reference is used a higher level, then it is inconsistent. Will attempt to heal before failing. - * - If a term reference is used a different level, then it is inconsistent. + * - If a type reference is used a higher level, then it is inconsistent. + * Will attempt to heal before failing. + * - If a term reference is used a higher level, then it is inconsistent. + * It can not be healed because the term will not exists in the any future stage. * * If `T` is a reference to a type at the wrong level, try to heal it by replacing it with * a type tag of type `quoted.Type[T]`. @@ -206,6 +208,8 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages( tryHeal(prefix.symbol, tp, pos) case _ => mapOver(tp) + case tp @ TermRef(NoPrefix, _) if !tp.symbol.isStatic && level > levelOf(tp.symbol) => + levelError(tp.symbol, tp, pos) case tp: ThisType if level != -1 && level != levelOf(tp.cls) => levelError(tp.cls, tp, pos) case tp: AnnotatedType => diff --git a/tests/neg-macros/i15917.scala b/tests/neg-macros/i15917.scala new file mode 100644 index 000000000000..3eecc38b21f9 --- /dev/null +++ b/tests/neg-macros/i15917.scala @@ -0,0 +1,6 @@ +import scala.quoted.* + +def m(using Quotes): Expr[Option[_]] = + val s = 3 + type st = s.type + '{ Some(${ Expr(s) }: st) } // error diff --git a/tests/neg-macros/i16355a.scala b/tests/neg-macros/i16355a.scala new file mode 100644 index 000000000000..8870b7777263 --- /dev/null +++ b/tests/neg-macros/i16355a.scala @@ -0,0 +1,35 @@ +//> using scala "3.2.1" +import scala.quoted.Expr +import scala.quoted.Type +import scala.quoted.quotes +import scala.quoted.Quotes + +object macros { + + inline transparent def mkNames[A]: List[Any] = ${ mkNamesImpl[A] } + + def mkNamesImpl[A: Type](using Quotes): Expr[List[Any]] = { + import quotes.reflect._ + + val fieldNames = TypeRepr.of[A].typeSymbol.declaredFields.map(_.name) + + val types = fieldNames + .map { f => + val t1 = ConstantType(StringConstant(f)) + t1.asType match { + case '[t1Type] => TypeRepr.of[(t1Type, "aa")] + } + } + .reduceLeft[TypeRepr](OrType(_, _)) + + types.asType match { + case '[ttt] => + Expr.ofList[ttt]( + fieldNames.map { v => + Expr[(v.type, "aa")](v -> "aa").asExprOf[ttt] // error + } + ) + } + } + +} diff --git a/tests/neg-macros/i16355b.scala b/tests/neg-macros/i16355b.scala new file mode 100644 index 000000000000..763810979ddf --- /dev/null +++ b/tests/neg-macros/i16355b.scala @@ -0,0 +1,4 @@ +import scala.quoted._ +def test(v: String)(using Quotes): Any = + Type.of : Type[v.type] // error + Type.of[v.type] // error From 4e4bf207fd521f16d743d4bbe64d11f7cf076c9e Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 23 Jan 2023 17:18:16 +0100 Subject: [PATCH 2/2] Update compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala Co-authored-by: Guillaume Martres --- compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala index 4669dc86982d..e2e494a95074 100644 --- a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala +++ b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala @@ -179,7 +179,7 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages( * - If a type reference is used a higher level, then it is inconsistent. * Will attempt to heal before failing. * - If a term reference is used a higher level, then it is inconsistent. - * It can not be healed because the term will not exists in the any future stage. + * It cannot be healed because the term will not exist in any future stage. * * If `T` is a reference to a type at the wrong level, try to heal it by replacing it with * a type tag of type `quoted.Type[T]`.