From b92251dfbc8d09444cee08df168b57b62585cac7 Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Tue, 22 Oct 2024 19:12:35 +0200 Subject: [PATCH] Replace symbol travelsal with tree traversal when finding top level experimentals --- .../src/dotty/tools/dotc/typer/Checking.scala | 32 ++++++++++--------- tests/pos-macros/i21802/Macro.scala | 15 +++++++++ tests/pos-macros/i21802/Test.scala | 13 ++++++++ 3 files changed, 45 insertions(+), 15 deletions(-) create mode 100644 tests/pos-macros/i21802/Macro.scala create mode 100644 tests/pos-macros/i21802/Test.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 700bd483ff38..27b9e8e8498a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -804,20 +804,22 @@ object Checking { * */ def checkAndAdaptExperimentalImports(trees: List[Tree])(using Context): Unit = - def nonExperimentalTopLevelDefs(pack: Symbol): Iterator[Symbol] = - def isNonExperimentalTopLevelDefinition(sym: Symbol) = - sym.isDefinedInCurrentRun - && sym.source == ctx.compilationUnit.source - && !sym.isConstructor // not constructor of package object - && !sym.is(Package) && !sym.name.isPackageObjectName - && !sym.isExperimental - - pack.info.decls.toList.iterator.flatMap: sym => - if sym.isClass && (sym.is(Package) || sym.isPackageObject) then - nonExperimentalTopLevelDefs(sym) - else if isNonExperimentalTopLevelDefinition(sym) then - sym :: Nil - else Nil + def nonExperimentalTopLevelDefs(): Iterator[Symbol] = + new TreeAccumulator[List[Symbol]] { + override def apply(x: List[Symbol], tree: tpd.Tree)(using Context): List[Symbol] = + tree match { + case tpd.PackageDef(_, contents) => + super.apply(x, contents) + case a @ tpd.TypeDef(_, temp: Template) if a.symbol.isPackageObject => + super.apply(x, temp.body) + case a @ tpd.TypeDef(_, Template(_, _, _, _)) => + val sym = a.symbol + if !sym.isExperimental then + sym :: x + else x + case _ => x + } + }.apply(Nil, ctx.compilationUnit.tpdTree).iterator def unitExperimentalLanguageImports = def isAllowedImport(sel: untpd.ImportSelector) = @@ -835,7 +837,7 @@ object Checking { if ctx.owner.is(Package) || ctx.owner.name.startsWith(str.REPL_SESSION_LINE) then def markTopLevelDefsAsExperimental(why: String): Unit = - for sym <- nonExperimentalTopLevelDefs(ctx.owner) do + for sym <- nonExperimentalTopLevelDefs() do sym.addAnnotation(ExperimentalAnnotation(s"Added by $why", sym.span)) unitExperimentalLanguageImports match diff --git a/tests/pos-macros/i21802/Macro.scala b/tests/pos-macros/i21802/Macro.scala new file mode 100644 index 000000000000..e2eb1287c727 --- /dev/null +++ b/tests/pos-macros/i21802/Macro.scala @@ -0,0 +1,15 @@ +class MetricsGroup[A] +object MetricsGroup: + import scala.quoted.* + + transparent inline final def refine[A]: MetricsGroup[A] = + ${ refineImpl[A] } + + private def refineImpl[A](using qctx: Quotes, tpe: Type[A]): Expr[MetricsGroup[A]] = + import qctx.reflect.* + + val mt = MethodType(Nil)(_ => Nil, _ => TypeRepr.of[A]) + val tpe = Refinement(TypeRepr.of[MetricsGroup[A]], "apply", mt).asType + tpe match + case '[tpe] => + '{ MetricsGroup[A]().asInstanceOf[MetricsGroup[A] & tpe] } diff --git a/tests/pos-macros/i21802/Test.scala b/tests/pos-macros/i21802/Test.scala new file mode 100644 index 000000000000..70063653c43c --- /dev/null +++ b/tests/pos-macros/i21802/Test.scala @@ -0,0 +1,13 @@ +//> using options -experimental -Ydebug + +class ProbeFailedException(cause: Exception) extends Exception(cause) +trait Probing: + self: Metrics => + val probeFailureCounter: MetricsGroup[Counter] = + counters("ustats_probe_failures_count").labelled + + +trait Counter +class Metrics: + class counters(name: String): + transparent inline final def labelled: MetricsGroup[Counter] = MetricsGroup.refine[Counter]