Skip to content

Replace symbol traversal with tree traversal when finding top level experimentals #21827

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -804,20 +804,20 @@ 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(): List[Symbol] =
new TreeAccumulator[List[Symbol]] {
override def apply(x: List[Symbol], tree: tpd.Tree)(using Context): List[Symbol] =
def addIfNotExperimental(sym: Symbol) =
if !sym.isExperimental then sym :: x
else x
tree match {
case tpd.PackageDef(_, contents) => apply(x, contents)
case typeDef @ tpd.TypeDef(_, temp: Template) if typeDef.symbol.isPackageObject =>
apply(x, temp.body)
case mdef: tpd.MemberDef => addIfNotExperimental(mdef.symbol)
case _ => x
}
}.apply(Nil, ctx.compilationUnit.tpdTree)

def unitExperimentalLanguageImports =
def isAllowedImport(sel: untpd.ImportSelector) =
Expand All @@ -835,7 +835,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
Expand Down
15 changes: 15 additions & 0 deletions tests/pos-macros/i21802/Macro.scala
Original file line number Diff line number Diff line change
@@ -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] }
13 changes: 13 additions & 0 deletions tests/pos-macros/i21802/Test.scala
Original file line number Diff line number Diff line change
@@ -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]