-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Tasty Reader with Simple Trees in Annotations [ci: last-only] #8865
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
Conversation
| * @param end The position one greater than the last byte to be read | ||
| * @param base The index referenced by the logical zero address Addr(0) | ||
| */ | ||
| class TastyReader(val bytes: Array[Byte], start: Int, end: Int, val base: Int = 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These classes are duplicated from the tasty-core project in dotty https://github.com/lampepfl/dotty/tree/master/tasty/src/dotty/tools/tasty I hoped we could depend on it, but its compiled with scala 2.13.1, so probably not allowed
| nameAtRef: NameRef => TastyName, | ||
| splices: Seq[Any])(implicit | ||
| val tasty: Tasty) { self => | ||
| import tasty._, FlagSets._ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
main aim here is that tasty provides some type aliases and we don't directly select from tasty.symbolTable, not yet converted to abstract types due to directly selecting on symbols here
| import scala.tools.nsc.tasty.TastyName | ||
| import scala.tools.nsc.tasty.TastyModes._ | ||
|
|
||
| trait ContextOps { self: TastyUniverse => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
once TreeUnpickler can only see abstract types, then all the FooOps traits will still see the concrete types of symbolTable
| import nsc.symtab, nsc.tasty.TastyUniverse | ||
|
|
||
| abstract class TastyCore { self: TastyUniverse => | ||
| import self.{symbolTable => u} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally this should extend some version where all the types and operations are abstract and thats what TreeUnpickler sees, but perhaps that would be useless, depending on what shared API is extracted for reading TASTy.
| import annotation.unchecked.uncheckedVariance | ||
|
|
||
| package object tasty { | ||
| implicit final class SafeEq[-T](private val t: T @uncheckedVariance) extends AnyVal { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert rhs is subtype of lhs
| * and a method for re-use elsewhere, because nobody will get this right without | ||
| * some higher level facilities. | ||
| */ | ||
| def extensionMethInfo(extensionMeth: Symbol, origInfo: Type, clazz: Symbol): Type = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved this to internal.Types as I was not sure how to transform symbols coming from tasty as ExtensionMethods only works on trees, and there is no flag to detect if a symbol of a tree is from tasty
|
This is ready for review now |
Great - it'll take me a week or two to get to, and through it. |
|
Be sure to try out the flag |
|
The last three commits were important bug fixes but I'll stop pushing to this branch now |
lrytz
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some feedback before i forget:
- Unpickler class names:
ScalacUnpickleris maybe not the best name - put Tasty in it somewhere? SectionUnpickler, TreeSectionUnpickler: do we need those small wrapper classes? - The explanations you wrote in the PR description are really excellent and should make their way into the source code.
- Maybe you can extend
tastyreader.mdortastytest.md(side-note: merge the two?) with some workflow advice how to effectively work on the tasty rader code.
| unpickler.unpickle(bytes, 0, clazz, staticModule, file.name) | ||
| } else if (isTASTY) { | ||
|
|
||
| def parseTASTYFile(): Array[Byte] = file.underlyingSource match { // TODO: simplify when #3552 is fixed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| def parseTASTYFile(): Array[Byte] = file.underlyingSource match { // TODO: simplify when #3552 is fixed | |
| def parseTASTYFile(): Array[Byte] = file.underlyingSource match { // TODO: simplify when lampepfl/dotty#3552 is fixed |
in case that comment applies here
| for (decl <- cls.info.decls if decl.isMethod) { | ||
| if (decl.isParamAccessor) decl.makeNotPrivate(cls) | ||
| if (!decl.isClassConstructor) { | ||
| val extensionMeth = decl.newExtensionMethodSymbol(cls.companion, u.NoPosition) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just a question: is cls.companion guaranteed to be defined?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dotty manually defines equals$extension and hashCode$extension in the companion so I assume so
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, this seems to be false, so I should guard that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually the companion object is still made even for a basic class Box(val a: Any) extends AnyVal, just not the extension methods for equals and hashCode
|
@lrytz The organisation of |
| bounds | ||
| } | ||
|
|
||
| private[bridge] def resolveErasedTypeRef(ref: ErasedTypeRef)(implicit ctx: Context): Type = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not correct for converting an ErasedTypeRef of an inner class of a class, in another branch I instead convert Type => ErasedTypeRef
c88224c to
d42d672
Compare
|
This has been rebased for scala 2.13.3 |
|
I don't have the compiler knowledge to review this, and I don't have the capacity to obtain the relevant knowledge right now. sorry |
|
@NthPortal sorry, I forced pushed some code and GitHub requested a review |
|
no worries 💜 |
lrytz
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks really great!
As discussed offline, let's try to assign the children of sealed types more early. Doing it late (patmat) causes sym.children to be incomplete if someone (a macro, compiler plugin) happens to call it early, and it's also a bit ad-hoc.
Ideally it would happen already during tasty-unpickling, similar to what's done in ordinary unpickling. If that fails because completing annotation arguments causes cycles, I can implement what was discussed here: #9023 (comment), which we should do anyway.
I don't know why the travis build failed... On jenkins it's green. Do you have an idea?
compiling sources in /home/travis/build/scala/scala/test/tasty/pos/src-3 with dotc.
exception occurred while compiling /home/travis/build/scala/scala/test/tasty/pos/src-3/dotty_i3816.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/IO.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/Defaults.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/Reader.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/Functor.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/Monad.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/Annotated.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/printing/printers.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/rootAnnot.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/HelloWorld.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/DelayedParameterised.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/AnythingIsPossible.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/Delayed.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/TraitWithSideEffects.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/symbolicAnnot.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/DelayedInternal.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest_>>>/package.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/InEmpty.scala
java.lang.AssertionError: assertion failed: no extension method found for:
method ->:[B](y: B): (A, B) with signature Signature(List(1, java.lang.Object),scala.Tuple2) in <none>
Candidates:
Candidates (signatures normalized):
while compiling /home/travis/build/scala/scala/test/tasty/pos/src-3/dotty_i3816.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/IO.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/Defaults.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/Reader.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/Functor.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/Monad.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/Annotated.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/printing/printers.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/rootAnnot.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/HelloWorld.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/DelayedParameterised.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/AnythingIsPossible.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/Delayed.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/TraitWithSideEffects.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/symbolicAnnot.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest/DelayedInternal.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/tastytest_>>>/package.scala, /home/travis/build/scala/scala/test/tasty/pos/src-3/InEmpty.scala
[error] Test scala.tools.tastytest.TastyTestJUnit.pos failed: java.lang.reflect.InvocationTargetException: null, took 2.296 sec
[error] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[error] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[error] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[error] at java.lang.reflect.Method.invoke(Method.java:498)
[error] at scala.tools.tastytest.Dotc$.$anonfun$processMethod$3(Dotc.scala:19)
[error] at scala.tools.tastytest.Dotc$.$anonfun$processMethod$2(Dotc.scala:18)
[error] at scala.tools.tastytest.Dotc$.dotc(Dotc.scala:38)
[error] at scala.tools.tastytest.TastyTest$.dotcPos(TastyTest.scala:145)
[error] at scala.tools.tastytest.TastyTest$.$anonfun$posSuite$8(TastyTest.scala:141)
[error] at scala.util.Success.flatMap(Try.scala:258)
[error] at scala.tools.tastytest.TastyTest$.$anonfun$posSuite$7(TastyTest.scala:32)
[error] at scala.util.Success.flatMap(Try.scala:258)
[error] at scala.tools.tastytest.TastyTest$.$anonfun$posSuite$4(TastyTest.scala:31)
[error] at scala.util.Success.flatMap(Try.scala:258)
[error] at scala.tools.tastytest.TastyTest$.posSuite(TastyTest.scala:29)
[error] at scala.tools.tastytest.TastyTestJUnit.pos(TastyTestJUnit.scala:23)
[error] ...
[error] Caused by: java.lang.AssertionError: assertion failed: no extension method found for:
[error]
[error] method ->:[B](y: B): (A, B) with signature Signature(List(1, java.lang.Object),scala.Tuple2) in <none>
[error]
[error] Candidates:
[error]
[error]
[error]
[error] Candidates (signatures normalized):
[error]
[error]
[error] at dotty.DottyPredef$.assertFail(DottyPredef.scala:17)
[error] at dotty.tools.dotc.transform.ExtensionMethods$.extensionMethod$$anonfun$1(ExtensionMethods.scala:195)
[error] at dotty.tools.dotc.core.Phases.atPhase$$anonfun$1(Phases.scala:35)
[error] at dotty.tools.dotc.core.Periods.atPhase(Periods.scala:25)
[error] at dotty.tools.dotc.core.Phases.atPhase(Phases.scala:35)
[error] at dotty.tools.dotc.core.Contexts$Context.atPhase(Contexts.scala:75)
[error] at dotty.tools.dotc.transform.ExtensionMethods$.extensionMethod(ExtensionMethods.scala:208)
[error] at dotty.tools.dotc.transform.VCInlineMethods.rewire(VCInlineMethods.scala:69)
[error] at dotty.tools.dotc.transform.VCInlineMethods.rewireIfNeeded(VCInlineMethods.scala:96)
[error] at dotty.tools.dotc.transform.VCInlineMethods.transformApply(VCInlineMethods.scala:106)
[error] at dotty.tools.dotc.transform.MegaPhase.goApply(MegaPhase.scala:611)
[error] at dotty.tools.dotc.transform.MegaPhase.goApply(MegaPhase.scala:612)
[error] at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:272)
[error] at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:396)
[error] at dotty.tools.dotc.transform.MegaPhase.transformTrees$$anonfun$1(MegaPhase.scala:420)
[error] at scala.collection.immutable.List.mapConserve(List.scala:472)
[error] at dotty.tools.dotc.transform.MegaPhase.transformTrees(MegaPhase.scala:420)
[error] at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:328)
[error] at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:396)
[error] at dotty.tools.dotc.transform.MegaPhase.transformTrees$$anonfun$1(MegaPhase.scala:420)
[error] at scala.collection.immutable.List.mapConserve(List.scala:472)
[error] at dotty.tools.dotc.transform.MegaPhase.transformTrees(MegaPhase.scala:420)
[error] at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:271)
[error] at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:396)
[error] at dotty.tools.dotc.transform.MegaPhase.mapValDef$1(MegaPhase.scala:234)
[error] at dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:238)
[error] at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:394)
[error] at dotty.tools.dotc.transform.MegaPhase.transformStat$2(MegaPhase.scala:404)
[error] at dotty.tools.dotc.transform.MegaPhase.$anonfun$1(MegaPhase.scala:409)
[error] at scala.collection.immutable.List.mapConserve(List.scala:472)
[error] at dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:409)
[error] at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:339)
[error] at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:396)
[error] at dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:251)
[error] at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:394)
[error] at dotty.tools.dotc.transform.MegaPhase.transformStat$2(MegaPhase.scala:404)
[error] at dotty.tools.dotc.transform.MegaPhase.$anonfun$1(MegaPhase.scala:409)
[error] at scala.collection.immutable.List.mapConserve(List.scala:472)
[error] at dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:409)
[error] at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:286)
[error] at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:396)
[error] at dotty.tools.dotc.transform.MegaPhase.mapDefDef$1(MegaPhase.scala:245)
[error] at dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:248)
[error] at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:394)
[error] at dotty.tools.dotc.transform.MegaPhase.transformStat$2(MegaPhase.scala:404)
[error] at dotty.tools.dotc.transform.MegaPhase.$anonfun$1(MegaPhase.scala:409)
[error] at scala.collection.immutable.List.mapConserve(List.scala:472)
[error] at dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:409)
[error] at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:339)
[error] at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:396)
[error] at dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:251)
[error] at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:394)
[error] at dotty.tools.dotc.transform.MegaPhase.transformStat$2(MegaPhase.scala:404)
[error] at dotty.tools.dotc.transform.MegaPhase.$anonfun$1(MegaPhase.scala:409)
[error] at scala.collection.immutable.List.mapConserve(List.scala:472)
[error] at dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:409)
[error] at dotty.tools.dotc.transform.MegaPhase.mapPackage$1(MegaPhase.scala:356)
[error] at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:359)
[error] at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:396)
[error] at dotty.tools.dotc.transform.MegaPhase.transformUnit(MegaPhase.scala:415)
[error] at dotty.tools.dotc.transform.MegaPhase.run(MegaPhase.scala:427)
[error] at dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:318)
[error] at scala.collection.immutable.List.map(List.scala:250)
[error] at dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:319)
[error] at dotty.tools.dotc.Run.runPhases$4$$anonfun$4(Run.scala:167)
[error] at dotty.runtime.function.JProcedure1.apply(JProcedure1.java:15)
[error] at dotty.runtime.function.JProcedure1.apply(JProcedure1.java:10)
[error] at scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1323)
[error] at dotty.tools.dotc.Run.runPhases$5(Run.scala:177)
[error] at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:185)
[error] at dotty.runtime.function.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
[error] at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:64)
[error] at dotty.tools.dotc.Run.compileUnits(Run.scala:192)
[error] at dotty.tools.dotc.Run.compileSources(Run.scala:129)
[error] at dotty.tools.dotc.Run.compile(Run.scala:112)
[error] at dotty.tools.dotc.Driver.doCompile(Driver.scala:36)
[error] at dotty.tools.dotc.Driver.process(Driver.scala:189)
[error] at dotty.tools.dotc.Driver.process(Driver.scala:158)
[error] at dotty.tools.dotc.Driver.process(Driver.scala:170)
[error] at dotty.tools.dotc.Main.process(Main.scala)
[error] ... 49 more
src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
Outdated
Show resolved
Hide resolved
src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
Outdated
Show resolved
Hide resolved
|
so I now force the sealed children annotations as soon as all definitions are seen in a scope |
|
//object DefAnnots {
//
// def withAnnotatedAnnot(@Wrapper.annotatedAnnot arg: Any): Any = arg
//
// object Wrapper {
// class annot extends StaticAnnotation
// @annot class annotatedAnnot extends StaticAnnotation
// }
//
//}EDIT: resolved in commit |
63fa421 to
7ae768b
Compare
This commit is a squash of several commits to atomically add the feature: When indexing a scope for the first time to set up completers, add lazy annotations to symbols. At the end of the indexing, force the annotations and if one is scala.annotation.internal.Child[T], add the symbol of T as a sealed child. If we are not indexing statements, such as completing the a method and reading its parameters, force annotations as soon as each symbol is initialised, this is ok because the owner tree for the definition is also initialised so forward references can be safely accessed. force sealed children after indexing scope cache RepeatedAnnot force all annotations early, catching more errors Also force annotations for lookahead contexts. It would be good to see if perhaps we can share a single annotation cache per tasty file and force from one place. Force annotations for each new symbol Additionally, when sequencing statements, only force after the whole sequence is indexed. Forceable annotations are now stored in and forced from the initial context. Made it more lazy to print parents of a class. If a LambdaPolyType is in a New tree, unwrap it. force annotations at end of createMemberSymbol only make lazy annotation if we delay its evaluation
… class info. Before this, inherited members may not be visible at the point of forcing the annotation on a definition in the template. Also moved symbol cache to the initial context so that child contexts all pass to the same cache.
Inner classes can not be found with Mirror getRequiredClass, so we should have another way to compare types to signatures, this proposes to instead convert method signatures to Signature[ErasedTypeRef]
Read inner classes in signatures, force annotations after template parents
Fix JavaUniverseForce
This pull request adds the ability for the SymbolTable to be populated from a classfile that is linked to a TASTy file by reading its contents. Similar to how Pickles provide symbols. The TASTy reader is not a tree provider, however there is limited support for reading expressions, enough to read annotation trees with constants and paths. Future work would be to add full support for creating trees for defs, vals, templates etc.
I would greatly appreciate feedback on a few things that I will point out in the diffs, but mainly how I handle adaption of value class extension methods, and dotty's enum constants.
Steps to Review
i. Be sure to try out the flag
-Ydebug-tastywhich gives a lot of information which you can use to trace where in a tasty file you are currently traversingsrc/compiler/scala/tools/tasty/- these classes provide machinery for reading bytes from TASTy, and some simple data structures that represent static data in TASTy:TastyFormat.scala,TastyHeaderUnpickler.scala,TastyRefs.scala,UnpickleException.scala,TastyReader.scala- these are duplicates of sources from the dotty repo, unchanged except to remove dead code. These purely deal with traversing TASTy bytesTastyFlags.scala: A static type representing a bitset of flags that are encoded in a TASTy file, along with some standard flags inferred from context, such asMethodandDeferred.TastyName.scala: This is a data structure representing semantic names.TastyNameis the interface that TASTy uses to select members from a type, providing more information than simple strings, such as selecting a Types over Terms, companion module instead of a class, or if a term is a default getter. Names can also be paired with aMethodSignature[ErasedTypeRef], which is used to select an overloaded method.ErasedTypeRef.scala: This is a wrapper around aTastyName.TypeNamethat adds a count of the number of array dimensions the referenced type has. It carries the invariant that it references the erasure of a fully qualified class or module, and never any other definition.Signature.scala: Currently only encodesMethodSignature, which represents the erased signature of a method, along with any interspersed type parameter listssrc/compiler/scala/tools/nsc/tastyare compiler specific definitions for reading tasty:TastyModes.scala: A static type representing a bitset of modes that affect the interpretation of a TASTy file, such as distinguishing between reading the parents of a class, or an annotation tree.package.scala: providesSafeEq, which is a implicit value class adding equality operators asserting at compiletime that the rhs is a subtype of the lhs.TastyUniverse.scala: provides a wrapper aroundscala.tools.nsc.symbtab.SymbolTableadapting it to the API TASTy requires to resolve types and symbols and create trees. Uses a cake with dependent types from symbolTable.ScalacUnpickler.scala: the entry point to TASTy unpickling fornsc, initialises aTastyUniverse#Contextwith the root symbols of a top level class, then delegates toTastyUnpicklerto parse names from a TASTy file and divide it into sections, before entering symbols from theASTssection withTreeUnpicklerTastyUnpickler.scala: Divides a TASTy file into sections, reading names into a cache ofTastyName. Responsible for providing aTastyReaderassociated with a section to aSectionUnpickler.TreeUnpickler.scala: Responsible for traversing all trees in a TASTy file, representing the definitions inside the classfile associated with the root class/module and extracting the public API into the symbolTable. Public API includes annotations where they are simple trees. Where possible,TreeUnpicklershould not directly manipulate values created by thesymbolTable, but use operations provided byTastyUniversesrc/compiler/scala/tools/nsc/tasty/bridge/are the sources that make up theTastyUniversecake, divided by responsibility:TastyCore.scala: the base of the cake, provides aliases to types fromscala.reflectat the same import level as new TASTy specific types.ContextOps.scala: This is the most important trait, this contains the definition forContext, which is used to maintain state through traversal of a TASTy file, such as the current owner - the container of the current definition; the traversal mode; and the root owners and source path for the TASTy file. It also provides operations for manipulation of the symbol table, such as creating/updating symbols and finding fully qualified classes/modules. the file also provides some standard error throwing capabilities with formatted errors that depend on the context mode.AnnotationOps.scala: adds support for creating annotations from treesFlagOps.scala: Handles encoding ofTastyFlagstoscala.reflectflags and witnessing which flags do not map directly from TASTy.NameOps.scala: This layer handles encoding ofTastyNametosymbolTable.Name, escaping any specially handled names. Also contains definitions of names for handling special dotty internal symbols withinTreeUnpickler.SymbolOps.scala: This layer deals with selecting a member symbol from a type using aTastyName, also adds factories for making type references to symbolsTreeOps.scala: This layer adds factories that construct typedscala.reflectTrees in the shapes that TASTy expectsTypeOps.scalaThis layer adds factories that constructscala.reflectTypes in the shapes that TASTy expects. Additionally provides operations to select a type from a prefix, or a type with an additional prefix, using aTastyName.tastypackagessrc/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala: Adds logic to look for the TASTY attribute in a classfile and then delegate toScalacUnpickler, similar to what is done forUnPicklersrc/compiler/scala/tools/nsc/transform/ExtensionMethods.scala: Moved logic for creating extension method symbols tointernal.Types, as it needs to be triggered from within theTreeUnpickler. I believe it would be too inefficient to modifyExtensionMethods.scalato inspect all select nodes to check if the symbol owner is a value class. Perhaps there is another efficient way to generate extension methods for value classes from TASTy.src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala: Added logic that checks the selector of a match if it has the annotationscala.annotation.internal.Child, which is the dotty encoding of sealed children. This has potential to be moved to be driven from withinTreeUnpicklerbut there is the problem of forcing the annotation at the correct time to prevent errors from reading a forward reference, and forcing each annotation to ensure exhaustivity.- this change has been reversed.src/reflect/scala/reflect/internal/Constants.scala: Added a newDottyEnumTagwhich is used to give a precise type to a dotty enum constant before erasure. After erasure these should be treated the same as a java enum. If dotty enum constants are not typed with a constant type then pattern match warnings use a wildcard pattern and not the constants name - perhaps pattern match logic could be adjusted rather than adding a new constant kind. This change also affectsBCodeBodyBuilder.scala,internal/Definitions.scalaandinternal/Importers.scala.src/reflect/scala/reflect/internal/transform/Erasure.scala: added a check that when a dotty enum singleton is erased, it is no longer a module class, but erased like the intersection of its parents. This is matched by a change tosrc/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scalawhich is modified to that accesses to Dotty enum singletons are to a field in the wrapping object, not a field within the module class of the symbolTastyTest, has been added insrc/tastytest/scala/tools/tastytest/which recreates (pos/neg/run) scenarios which the tasty reader is intended to be used for: typically, compiling some Scala 3 code with dotc and using the Dotty library, then depending on it from Scala 2 code. the modes are explained indoc/internal/tastytest.md.TastyTestalso has test kinds to force dependencies compiled with dotc to not be available on the classpath from scala 2. Alternative: Partest could be adopted to integrate these new workflows, or perhaps it already has a mode for dependent compilations using a different compiler between stages.build.sbtseveral task keys have been added to assist with testing individual scenarios in thetasty_reader, perhaps these pollute the build?test/tastyThis directory consists exclusively of test sources to be compiled byTastyTest, which is automated by aJUnitsuite:test/tasty/test/scala/tools/tastytest/TastyTestJUnit.scala, which wrapsTastyTestsuites with customised options.Dotty Support:
There is an attempt to provide some more information, when possible, about unsupported dotty features, (currently, union types can not be pretty printed, with more work it is possible to flatten nested union types for the purpose of better error messages)