From bd52edfa32afa26cc3b8b19a15f8c85561331fde Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 29 Sep 2020 13:28:01 +0200 Subject: [PATCH] Fix #8521: Remove PackageDef and use Symbol directly PackageDef was originally added to try to encode trees in the API without the use of symbols. Now that we have symbols all the package def logic is redundant. At the time we assumed that we would be able to have a tree for all Symbol, but this has not been the case since the introduction of NoSymbol. Now we handle the `tree` of a package def the same way we did the one of a NoSymbol. * Remove `PackageDef` * Add `members` method on `Symbol` * Disallow package symbols in `Symbol.tree` as done with `NoSymbol` --- .../tools/dotc/quoted/QuoteContextImpl.scala | 35 +++----------- .../dotc/quoted/reflect/FromSymbol.scala | 8 ++-- .../tools/dotc/quoted/reflect/package.scala | 22 --------- library/src/scala/tasty/Reflection.scala | 47 +++++-------------- .../tasty/reflect/ExtractorsPrinter.scala | 2 - .../tasty/reflect/SourceCodePrinter.scala | 3 +- tests/pos-macros/i8521/Macro_1.scala | 26 ++++++++++ tests/pos-macros/i8521/Tes_2.scala | 5 ++ 8 files changed, 54 insertions(+), 94 deletions(-) delete mode 100644 compiler/src/dotty/tools/dotc/quoted/reflect/package.scala create mode 100644 tests/pos-macros/i8521/Macro_1.scala create mode 100644 tests/pos-macros/i8521/Tes_2.scala diff --git a/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala b/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala index 7c64df6e0e69..922c70cb31f6 100644 --- a/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala +++ b/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala @@ -11,7 +11,6 @@ import dotty.tools.dotc.core.NameKinds import dotty.tools.dotc.core.StdNames._ import dotty.tools.dotc.quoted.reflect._ import dotty.tools.dotc.core.Decorators._ -import dotty.tools.dotc.quoted.reflect.FromSymbol.{definitionFromSym, packageDefFromSym} import dotty.tools.dotc.typer.Implicits import scala.quoted.QuoteContext @@ -154,13 +153,12 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext: case _ => None end StatementTypeTest - type Definition = tpd.Tree + type Definition = tpd.MemberDef object DefinitionTypeTest extends TypeTest[Tree, Definition]: def runtimeClass: Class[?] = classOf[Definition] override def unapply(x: Any): Option[Definition] = x match case x: tpd.MemberDef @unchecked => Some(x) - case x: PackageDefinition @unchecked => Some(x) case _ => None end DefinitionTypeTest @@ -170,7 +168,6 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext: extension (self: Definition): def name: String = self match case self: tpd.MemberDef => self.name.toString - case self: PackageDefinition => self.symbol.name.toString // TODO make PackageDefinition a MemberDef or NameTree end extension end DefinitionMethodsImpl @@ -284,29 +281,6 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext: end extension end TypeDefMethodsImpl - type PackageDef = PackageDefinition - - object PackageDefTypeTest extends TypeTest[Tree, PackageDef]: - def runtimeClass: Class[?] = classOf[PackageDef] - override def unapply(x: Any): Option[PackageDef] = x match - case x: PackageDefinition @unchecked => Some(x) - case _ => None - end PackageDefTypeTest - - object PackageDef extends PackageDefModule: - def unapply(tree: PackageDef): Option[(String, PackageDef)] = - Some((tree.name, tree.owner)) - end PackageDef - - object PackageDefMethodsImpl extends PackageDefMethods: - extension (self: PackageDef): - def owner: PackageDef = packageDefFromSym(self.symbol.owner) - def members: List[Statement] = - if (self.symbol.is(JavaDefined)) Nil // FIXME should also support java packages - else self.symbol.info.decls.iterator.map(definitionFromSym).toList - end extension - end PackageDefMethodsImpl - type Term = tpd.Tree object TermTypeTest extends TypeTest[Tree, Term]: @@ -1137,13 +1111,13 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext: def copy(original: Tree)(tpt: TypeTree, refinements: List[Definition]): Refined = tpd.cpy.RefinedTypeTree(original)(tpt, refinements) def unapply(x: Refined): Option[(TypeTree, List[Definition])] = - Some((x.tpt, x.refinements)) + Some((x.tpt, x.refinements.asInstanceOf[List[Definition]])) end Refined object RefinedMethodsImpl extends RefinedMethods: extension (self: Refined): def tpt: TypeTree = self.tpt - def refinements: List[Definition] = self.refinements + def refinements: List[Definition] = self.refinements.asInstanceOf[List[Definition]] end extension end RefinedMethodsImpl @@ -2288,6 +2262,9 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext: case sym if isMethod(sym) => sym.asTerm }.toList + def members: List[Symbol] = + self.typeRef.info.decls.toList + def typeMembers: List[Symbol] = self.unforcedDecls.filter(_.isType) diff --git a/compiler/src/dotty/tools/dotc/quoted/reflect/FromSymbol.scala b/compiler/src/dotty/tools/dotc/quoted/reflect/FromSymbol.scala index 7f90ecabfd09..97079e0d343b 100644 --- a/compiler/src/dotty/tools/dotc/quoted/reflect/FromSymbol.scala +++ b/compiler/src/dotty/tools/dotc/quoted/reflect/FromSymbol.scala @@ -12,9 +12,9 @@ import dotty.tools.dotc.core.Types._ object FromSymbol { def definitionFromSym(sym: Symbol)(using Context): tpd.Tree = { - assert(sym.exists) - if (sym.is(Package)) packageDefFromSym(sym) - else if (sym.isClass) classDef(sym.asClass) + assert(sym.exists, "Cannot get tree of no symbol") + assert(!sym.is(Package), "Cannot get tree of package symbol") + if (sym.isClass) classDef(sym.asClass) else if (sym.isType && sym.is(Case)) typeBindFromSym(sym.asType) else if (sym.isType) typeDefFromSym(sym.asType) else if (sym.is(Method)) defDefFromSym(sym.asTerm) @@ -22,8 +22,6 @@ object FromSymbol { else valDefFromSym(sym.asTerm) } - def packageDefFromSym(sym: Symbol)(using Context): PackageDefinition = PackageDefinitionImpl(sym) - def classDef(cls: ClassSymbol)(using Context): tpd.TypeDef = cls.defTree match { case tree: tpd.TypeDef => tree case tpd.EmptyTree => diff --git a/compiler/src/dotty/tools/dotc/quoted/reflect/package.scala b/compiler/src/dotty/tools/dotc/quoted/reflect/package.scala deleted file mode 100644 index 4f8475bfce6a..000000000000 --- a/compiler/src/dotty/tools/dotc/quoted/reflect/package.scala +++ /dev/null @@ -1,22 +0,0 @@ -package dotty.tools.dotc.quoted - -import dotty.tools.dotc.ast.Trees.{Tree, Untyped} -import dotty.tools.dotc.core.Contexts._ -import dotty.tools.dotc.core.Symbols.Symbol -import dotty.tools.dotc.core.Types.Type -import dotty.tools.dotc.util.SourceFile -import dotty.tools.dotc.core.SymDenotations.SymDenotation -import scala.annotation.constructorOnly - -package object reflect { - - type PackageDefinition = PackageDefinitionImpl[Type] - - /** Represents the symbol of a definition in tree form */ - case class PackageDefinitionImpl[-T >: Untyped] private[reflect] (sym: Symbol)(implicit @constructorOnly src: SourceFile) extends Tree[T] { - type ThisTree[-T >: Untyped] = PackageDefinitionImpl[T] - - override def denot(using Context): SymDenotation = sym.denot - } -} - diff --git a/library/src/scala/tasty/Reflection.scala b/library/src/scala/tasty/Reflection.scala index 8f721b7b7d19..de8df6033c03 100644 --- a/library/src/scala/tasty/Reflection.scala +++ b/library/src/scala/tasty/Reflection.scala @@ -20,8 +20,7 @@ import scala.tasty.reflect._ * * +- Tree -+- PackageClause * +- Import - * +- Statement -+- Definition --+- PackageDef - * | | +- ClassDef + * +- Statement -+- Definition --+- ClassDef * | | +- TypeDef * | | +- DefDef * | | +- ValDef @@ -225,7 +224,7 @@ trait Reflection { reflection => // ----- Definitions ---------------------------------------------- - /** Tree representing a definition in the source code. It can be `PackageDef`, `ClassDef`, `TypeDef`, `DefDef` or `ValDef` */ + /** Tree representing a definition in the source code. It can be `ClassDef`, `TypeDef`, `DefDef` or `ValDef` */ type Definition <: Statement given TypeTest[Tree, Definition] = DefinitionTypeTest @@ -352,29 +351,6 @@ trait Reflection { reflection => end extension end TypeDefMethods - // PackageDef - - /** Tree representing a package definition. This includes definitions in all source files */ - type PackageDef <: Definition - - given TypeTest[Tree, PackageDef] = PackageDefTypeTest - protected val PackageDefTypeTest: TypeTest[Tree, PackageDef] - - val PackageDef: PackageDefModule - - trait PackageDefModule { this: PackageDef.type => - def unapply(tree: PackageDef): Option[(String, PackageDef)] - } - - given PackageDefMethods as PackageDefMethods = PackageDefMethodsImpl - protected val PackageDefMethodsImpl: PackageDefMethods - - trait PackageDefMethods: - extension (self: PackageDef): - def owner: PackageDef - def members: List[Statement] - end extension - end PackageDefMethods // ----- Terms ---------------------------------------------------- @@ -2555,14 +2531,14 @@ trait Reflection { reflection => def comment: Option[Comment] /** Tree of this definition - * - * if this symbol `isPackageDef` it will return a `PackageDef`, - * if this symbol `isClassDef` it will return a `ClassDef`, - * if this symbol `isTypeDef` it will return a `TypeDef`, - * if this symbol `isValDef` it will return a `ValDef`, - * if this symbol `isDefDef` it will return a `DefDef` - * if this symbol `isBind` it will return a `Bind` - */ + * + * If this symbol `isClassDef` it will return `a `ClassDef`, + * if this symbol `isTypeDef` it will return `a `TypeDef`, + * if this symbol `isValDef` it will return `a `ValDef`, + * if this symbol `isDefDef` it will return `a `DefDef` + * if this symbol `isBind` it will return `a `Bind`, + * else will throw + */ def tree: Tree /** Annotations attached to this symbol */ @@ -2626,6 +2602,9 @@ trait Reflection { reflection => /** Type member with the given name directly declared in the class */ def typeMember(name: String): Symbol + /** All members directly declared in the class */ + def members: List[Symbol] + /** Get named non-private methods declared or inherited */ def method(name: String): List[Symbol] diff --git a/library/src/scala/tasty/reflect/ExtractorsPrinter.scala b/library/src/scala/tasty/reflect/ExtractorsPrinter.scala index 464e7a4f63be..216c161a37e1 100644 --- a/library/src/scala/tasty/reflect/ExtractorsPrinter.scala +++ b/library/src/scala/tasty/reflect/ExtractorsPrinter.scala @@ -118,8 +118,6 @@ class ExtractorsPrinter[R <: Reflection & Singleton](val tasty: R) extends Print this += ", " visitList[TypeTree](derived, visitTree) this += ", " += self += ", " ++= body += ")" - case PackageDef(name, owner) => - this += "PackageDef(\"" += name += "\", " += owner += ")" case Import(expr, selectors) => this += "Import(" += expr += ", " ++= selectors += ")" case PackageClause(pid, stats) => diff --git a/library/src/scala/tasty/reflect/SourceCodePrinter.scala b/library/src/scala/tasty/reflect/SourceCodePrinter.scala index 54d13d6dd0ed..d19293b80ec5 100644 --- a/library/src/scala/tasty/reflect/SourceCodePrinter.scala +++ b/library/src/scala/tasty/reflect/SourceCodePrinter.scala @@ -1228,12 +1228,11 @@ class SourceCodePrinter[R <: Reflection & Singleton](val tasty: R)(syntaxHighlig case RenameSelector(name, newName) => this += name += " => " += newName } - def printDefinitionName(sym: Definition): Buffer = sym match { + def printDefinitionName(tree: Definition): Buffer = tree match { case ValDef(name, _, _) => this += highlightValDef(name) case DefDef(name, _, _, _, _) => this += highlightValDef(name) case ClassDef(name, _, _, _, _, _) => this += highlightTypeDef(name.stripSuffix("$")) case TypeDef(name, _) => this += highlightTypeDef(name) - case PackageDef(name, _) => this += highlightTypeDef(name) } def printAnnotation(annot: Term)(using elideThis: Option[Symbol]): Buffer = { diff --git a/tests/pos-macros/i8521/Macro_1.scala b/tests/pos-macros/i8521/Macro_1.scala new file mode 100644 index 000000000000..7488ef448816 --- /dev/null +++ b/tests/pos-macros/i8521/Macro_1.scala @@ -0,0 +1,26 @@ +import scala.quoted._ + +object Foo { + inline def foo[T <: AnyKind]: String = ${ bar[T] } + + def bar[T <: AnyKind : Type](using qctx: QuoteContext): Expr[String] = { + import qctx.tasty.{Type => _, _} + + def packageToName(sym: Symbol): Unit = { + if sym.isPackageDef then + packageToName(sym.owner) + } + + val sym = implicitly[Type[T]].unseal.symbol + if (!sym.isNoSymbol) { + sym.tree match { + case c: ClassDef => + if (!sym.maybeOwner.isNoSymbol) { + if sym.maybeOwner.isPackageDef then + packageToName(sym.maybeOwner) + } + } + } + Expr("") + } +} diff --git a/tests/pos-macros/i8521/Tes_2.scala b/tests/pos-macros/i8521/Tes_2.scala new file mode 100644 index 000000000000..ac223dc68e0f --- /dev/null +++ b/tests/pos-macros/i8521/Tes_2.scala @@ -0,0 +1,5 @@ +class A + +object Test { + def test = Foo.foo[A] +}