diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala b/compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala index 3779f59d33b0..6331913049c2 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala @@ -292,7 +292,7 @@ trait BCodeHelpers extends BCodeIdiomatic { } case Ident(nme.WILDCARD) => // An underscore argument indicates that we want to use the default value for this parameter, so do not emit anything - case t: tpd.RefTree if t.symbol.owner.linkedClass.isAllOf(JavaEnumTrait) => + case t: tpd.RefTree if t.symbol.owner.linkedClass.isAllOf(JavaEnum) => val edesc = innerClasesStore.typeDescriptor(t.tpe) // the class descriptor of the enumeration class. val evalue = t.symbol.javaSimpleName // value the actual enumeration value. av.visitEnum(name, edesc, evalue) diff --git a/compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala b/compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala index 55619f31ec32..b8d7ee04c870 100644 --- a/compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala +++ b/compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala @@ -304,7 +304,7 @@ class BTypesFromSymbols[I <: DottyBackendInterface](val int: I, val frontendAcce .addFlagIf(sym.is(Bridge), ACC_BRIDGE | ACC_SYNTHETIC) .addFlagIf(sym.is(Artifact), ACC_SYNTHETIC) .addFlagIf(sym.isClass && !sym.isInterface, ACC_SUPER) - .addFlagIf(sym.isAllOf(JavaEnumTrait), ACC_ENUM) + .addFlagIf(sym.isAllOf(JavaEnum), ACC_ENUM) .addFlagIf(sym.is(JavaVarargs), ACC_VARARGS) .addFlagIf(sym.is(Synchronized), ACC_SYNCHRONIZED) .addFlagIf(sym.isDeprecated, ACC_DEPRECATED) diff --git a/compiler/src/dotty/tools/dotc/CompilationUnit.scala b/compiler/src/dotty/tools/dotc/CompilationUnit.scala index 62f62a3c6dc6..78773a518b67 100644 --- a/compiler/src/dotty/tools/dotc/CompilationUnit.scala +++ b/compiler/src/dotty/tools/dotc/CompilationUnit.scala @@ -19,7 +19,7 @@ import scala.annotation.internal.sharable import scala.util.control.NoStackTrace import transform.MacroAnnotations -class CompilationUnit protected (val source: SourceFile) { +class CompilationUnit protected (val source: SourceFile, val info: CompilationUnitInfo | Null) { override def toString: String = source.toString @@ -30,6 +30,13 @@ class CompilationUnit protected (val source: SourceFile) { /** Is this the compilation unit of a Java file */ def isJava: Boolean = source.file.name.endsWith(".java") + /** Is this the compilation unit of a Java file, or TASTy derived from a Java file */ + def typedAsJava = isJava || { + val infoNN = info + infoNN != null && infoNN.tastyInfo.exists(_.attributes.isJava) + } + + /** The source version for this unit, as determined by a language import */ var sourceVersion: Option[SourceVersion] = None @@ -106,7 +113,7 @@ class CompilationUnit protected (val source: SourceFile) { myAssignmentSpans.nn } -@sharable object NoCompilationUnit extends CompilationUnit(NoSource) { +@sharable object NoCompilationUnit extends CompilationUnit(NoSource, info = null) { override def isJava: Boolean = false @@ -122,13 +129,14 @@ object CompilationUnit { /** Make a compilation unit for top class `clsd` with the contents of the `unpickled` tree */ def apply(clsd: ClassDenotation, unpickled: Tree, forceTrees: Boolean)(using Context): CompilationUnit = - val file = clsd.symbol.associatedFile.nn - apply(SourceFile(file, Array.empty[Char]), unpickled, forceTrees) + val compilationUnitInfo = clsd.symbol.compilationUnitInfo.nn + val file = compilationUnitInfo.associatedFile + apply(SourceFile(file, Array.empty[Char]), unpickled, forceTrees, compilationUnitInfo) /** Make a compilation unit, given picked bytes and unpickled tree */ - def apply(source: SourceFile, unpickled: Tree, forceTrees: Boolean)(using Context): CompilationUnit = { + def apply(source: SourceFile, unpickled: Tree, forceTrees: Boolean, info: CompilationUnitInfo)(using Context): CompilationUnit = { assert(!unpickled.isEmpty, unpickled) - val unit1 = new CompilationUnit(source) + val unit1 = new CompilationUnit(source, info) unit1.tpdTree = unpickled if (forceTrees) { val force = new Force @@ -156,7 +164,8 @@ object CompilationUnit { NoSource } else source - new CompilationUnit(src) + val info = if src.exists then CompilationUnitInfo(src.file) else null + new CompilationUnit(src, info) } /** Force the tree to be loaded */ diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index a08d6da650c9..3386dc7d7a6c 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -17,6 +17,7 @@ import reporting.* import annotation.constructorOnly import printing.Formatting.hl import config.Printers +import parsing.Parsers import scala.annotation.internal.sharable import scala.annotation.threadUnsafe @@ -143,8 +144,13 @@ object desugar { /** A value definition copied from `vdef` with a tpt typetree derived from it */ def derivedTermParam(vdef: ValDef)(using Context): ValDef = + derivedTermParam(vdef, vdef.unforcedRhs) + + def derivedTermParam(vdef: ValDef, rhs: LazyTree)(using Context): ValDef = cpy.ValDef(vdef)( - tpt = DerivedFromParamTree().withSpan(vdef.tpt.span).watching(vdef)) + tpt = DerivedFromParamTree().withSpan(vdef.tpt.span).watching(vdef), + rhs = rhs + ) // ----- Desugar methods ------------------------------------------------- @@ -544,8 +550,11 @@ object desugar { constrTparams.zipWithConserve(impliedTparams)((tparam, impliedParam) => derivedTypeParam(tparam).withAnnotations(impliedParam.mods.annotations)) val derivedVparamss = - constrVparamss.nestedMap(vparam => - derivedTermParam(vparam).withAnnotations(Nil)) + constrVparamss.nestedMap: vparam => + val derived = + if ctx.compilationUnit.isJava then derivedTermParam(vparam, Parsers.unimplementedExpr) + else derivedTermParam(vparam) + derived.withAnnotations(Nil) val constr = cpy.DefDef(constr1)(paramss = joinParams(constrTparams, constrVparamss)) diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 68c68e48caaf..a71f28f49410 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -8,7 +8,7 @@ import dotty.tools.dotc.config.Settings.{Setting, SettingGroup} import dotty.tools.dotc.config.SourceVersion import dotty.tools.dotc.core.Contexts.* import dotty.tools.dotc.rewrites.Rewrites -import dotty.tools.io.{AbstractFile, Directory, JDK9Reflectors, PlainDirectory} +import dotty.tools.io.{AbstractFile, Directory, JDK9Reflectors, PlainDirectory, NoAbstractFile} import Setting.ChoiceWithHelp import scala.util.chaining.* @@ -433,4 +433,9 @@ private sealed trait YSettings: val YforceInlineWhileTyping: Setting[Boolean] = BooleanSetting("-Yforce-inline-while-typing", "Make non-transparent inline methods inline when typing. Emulates the old inlining behavior of 3.0.0-M3.") val YdebugMacros: Setting[Boolean] = BooleanSetting("-Ydebug-macros", "Show debug info when quote pattern match fails") + + // Pipeline compilation options + val YjavaTasty: Setting[Boolean] = BooleanSetting("-Yjava-tasty", "Pickler phase should compute pickles for .java defined symbols for use by build tools") + val YjavaTastyOutput: Setting[AbstractFile] = OutputSetting("-Yjava-tasty-output", "directory|jar", "(Internal use only!) destination for generated .tasty files containing Java type signatures.", NoAbstractFile) + val YallowOutlineFromTasty: Setting[Boolean] = BooleanSetting("-Yallow-outline-from-tasty", "Allow outline TASTy to be loaded with the -from-tasty option.") end YSettings diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index c3de3ab69519..3d86b0271e02 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -996,6 +996,7 @@ class Definitions { @tu lazy val AnnotationClass: ClassSymbol = requiredClass("scala.annotation.Annotation") @tu lazy val StaticAnnotationClass: ClassSymbol = requiredClass("scala.annotation.StaticAnnotation") @tu lazy val RefiningAnnotationClass: ClassSymbol = requiredClass("scala.annotation.RefiningAnnotation") + @tu lazy val JavaAnnotationClass: ClassSymbol = requiredClass("java.lang.annotation.Annotation") // Annotation classes @tu lazy val AllowConversionsAnnot: ClassSymbol = requiredClass("scala.annotation.allowConversions") diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 6ae9541a327f..8c1b715e3e30 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -576,7 +576,7 @@ object Flags { val InlineMethod: FlagSet = Inline | Method val InlineParam: FlagSet = Inline | Param val InlineByNameProxy: FlagSet = InlineProxy | Method - val JavaEnumTrait: FlagSet = JavaDefined | Enum // A Java enum trait + val JavaEnum: FlagSet = JavaDefined | Enum // A Java enum trait val JavaEnumValue: FlagSet = JavaDefined | EnumValue // A Java enum value val StaticProtected: FlagSet = JavaDefined | JavaStatic | Protected // Java symbol which is `protected` and `static` val JavaModule: FlagSet = JavaDefined | Module // A Java companion object diff --git a/compiler/src/dotty/tools/dotc/core/Phases.scala b/compiler/src/dotty/tools/dotc/core/Phases.scala index e04d829d1e60..c704846a82da 100644 --- a/compiler/src/dotty/tools/dotc/core/Phases.scala +++ b/compiler/src/dotty/tools/dotc/core/Phases.scala @@ -333,16 +333,25 @@ object Phases { def subPhases: List[Run.SubPhase] = Nil final def traversals: Int = if subPhases.isEmpty then 1 else subPhases.length + /** skip the phase for a Java compilation unit, may depend on -Yjava-tasty */ + def skipIfJava(using Context): Boolean = true + /** @pre `isRunnable` returns true */ def run(using Context): Unit /** @pre `isRunnable` returns true */ def runOn(units: List[CompilationUnit])(using runCtx: Context): List[CompilationUnit] = val buf = List.newBuilder[CompilationUnit] + // factor out typedAsJava check when not needed + val doSkipJava = ctx.settings.YjavaTasty.value && this <= picklerPhase && skipIfJava for unit <- units do given unitCtx: Context = runCtx.fresh.setPhase(this.start).setCompilationUnit(unit).withRootImports if ctx.run.enterUnit(unit) then - try run + try + if doSkipJava && unit.typedAsJava then + () + else + run catch case ex: Throwable if !ctx.run.enrichedErrorMessage => println(ctx.run.enrichErrorMessage(s"unhandled exception while running $phaseName on $unit")) throw ex diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 5fa9afbcd171..83362897e5e3 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1695,7 +1695,7 @@ object SymDenotations { c.ensureCompleted() end completeChildrenIn - if is(Sealed) || isAllOf(JavaEnumTrait) then + if is(Sealed) || isAllOf(JavaEnum) && isClass then if !is(ChildrenQueried) then // Make sure all visible children are completed, so that // they show up in Child annotations. A possible child is visible if it diff --git a/compiler/src/dotty/tools/dotc/core/tasty/Attributes.scala b/compiler/src/dotty/tools/dotc/core/tasty/Attributes.scala index 7f87b7f4f2b7..0697f39f6dab 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/Attributes.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/Attributes.scala @@ -11,6 +11,8 @@ class Attributes private[tasty]( def explicitNulls: Boolean = booleanTags(EXPLICITNULLSattr) def captureChecked: Boolean = booleanTags(CAPTURECHECKEDattr) def withPureFuns: Boolean = booleanTags(WITHPUREFUNSattr) + def isJava: Boolean = booleanTags(JAVAattr) + def isOutline: Boolean = booleanTags(OUTLINEattr) } object Attributes: @@ -19,12 +21,16 @@ object Attributes: explicitNulls: Boolean, captureChecked: Boolean, withPureFuns: Boolean, + isJava: Boolean, + isOutline: Boolean, ): Attributes = val booleanTags = BitSet.newBuilder if scala2StandardLibrary then booleanTags += SCALA2STANDARDLIBRARYattr if explicitNulls then booleanTags += EXPLICITNULLSattr if captureChecked then booleanTags += CAPTURECHECKEDattr if withPureFuns then booleanTags += WITHPUREFUNSattr + if isJava then booleanTags += JAVAattr + if isOutline then booleanTags += OUTLINEattr new Attributes(booleanTags.result()) end apply diff --git a/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala index 033d8cd40c1f..8753017cc82f 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala @@ -36,6 +36,7 @@ object DottyUnpickler { def unpickle(reader: TastyReader, nameAtRef: NameTable): CommentUnpickler = new CommentUnpickler(reader) } + class AttributesSectionUnpickler extends SectionUnpickler[AttributeUnpickler](AttributesSection) { def unpickle(reader: TastyReader, nameAtRef: NameTable): AttributeUnpickler = new AttributeUnpickler(reader) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index b4ba58c55c93..dafd6c2e8daa 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -23,7 +23,7 @@ import quoted.QuotePatterns object TreePickler: class StackSizeExceeded(val mdef: tpd.MemberDef) extends Exception -class TreePickler(pickler: TastyPickler) { +class TreePickler(pickler: TastyPickler, attributes: Attributes) { val buf: TreeBuffer = new TreeBuffer pickler.newSection(ASTsSection, buf) import buf.* @@ -322,6 +322,11 @@ class TreePickler(pickler: TastyPickler) { if (!tree.isEmpty) pickleTree(tree) } + def pickleElidedUnlessEmpty(tree: Tree, tp: Type)(using Context): Unit = + if !tree.isEmpty then + writeByte(ELIDED) + pickleType(tp) + def pickleDef(tag: Int, mdef: MemberDef, tpt: Tree, rhs: Tree = EmptyTree, pickleParams: => Unit = ())(using Context): Unit = { val sym = mdef.symbol @@ -337,7 +342,12 @@ class TreePickler(pickler: TastyPickler) { case _: Template | _: Hole => pickleTree(tpt) case _ if tpt.isType => pickleTpt(tpt) } - pickleTreeUnlessEmpty(rhs) + if attributes.isOutline && sym.isTerm && attributes.isJava then + // TODO: if we introduce outline typing for Scala definitions + // then we will need to update the check here + pickleElidedUnlessEmpty(rhs, tpt.tpe) + else + pickleTreeUnlessEmpty(rhs) pickleModifiers(sym, mdef) } catch diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 1f551028c415..d4271d5bffaf 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -104,6 +104,11 @@ class TreeUnpickler(reader: TastyReader, private val explicitNulls = attributeUnpicklerOpt.exists(_.attributes.explicitNulls) + private val unpicklingJava = + attributeUnpicklerOpt.exists(_.attributes.isJava) + + private val isOutline = attributeUnpicklerOpt.exists(_.attributes.isOutline) + private def registerSym(addr: Addr, sym: Symbol) = symAtAddr(addr) = sym @@ -609,7 +614,10 @@ class TreeUnpickler(reader: TastyReader, val rhsIsEmpty = nothingButMods(end) if (!rhsIsEmpty) skipTree() val (givenFlags0, annotFns, privateWithin) = readModifiers(end) - val givenFlags = if isClass && unpicklingScala2Library then givenFlags0 | Scala2x | Scala2Tasty else givenFlags0 + val givenFlags = + if isClass && unpicklingScala2Library then givenFlags0 | Scala2x | Scala2Tasty + else if unpicklingJava then givenFlags0 | JavaDefined + else givenFlags0 pickling.println(i"creating symbol $name at $start with flags ${givenFlags.flagsString}, isAbsType = $isAbsType, $ttag") val flags = normalizeFlags(tag, givenFlags, name, isAbsType, rhsIsEmpty) def adjustIfModule(completer: LazyType) = @@ -1037,6 +1045,8 @@ class TreeUnpickler(reader: TastyReader, val parentReader = fork val parents = readParents(withArgs = false)(using parentCtx) val parentTypes = parents.map(_.tpe.dealias) + if cls.is(JavaDefined) && parentTypes.exists(_.derivesFrom(defn.JavaAnnotationClass)) then + cls.setFlag(JavaAnnotation) val self = if (nextByte == SELFDEF) { readByte() @@ -1197,7 +1207,12 @@ class TreeUnpickler(reader: TastyReader, def completeSelect(name: Name, sig: Signature, target: Name): Select = val qual = readTree() - val denot = accessibleDenot(qual.tpe.widenIfUnstable, name, sig, target) + val denot0 = accessibleDenot(qual.tpe.widenIfUnstable, name, sig, target) + val denot = + if unpicklingJava && name == tpnme.Object && denot0.symbol == defn.ObjectClass then + defn.FromJavaObjectType.denot + else + denot0 makeSelect(qual, name, denot) def readQualId(): (untpd.Ident, TypeRef) = @@ -1216,6 +1231,11 @@ class TreeUnpickler(reader: TastyReader, forkAt(readAddr()).readTree() case IDENT => untpd.Ident(readName()).withType(readType()) + case ELIDED => + if !isOutline then + report.error( + s"Illegal elided tree in unpickler without ${attributeTagToString(OUTLINEattr)}, ${ctx.source}") + untpd.Ident(nme.WILDCARD).withType(readType()) case IDENTtpt => untpd.Ident(readName().toTypeName).withType(readType()) case SELECT => diff --git a/compiler/src/dotty/tools/dotc/fromtasty/AlreadyLoadedCompilationUnit.scala b/compiler/src/dotty/tools/dotc/fromtasty/AlreadyLoadedCompilationUnit.scala index 74c680bda1b7..8700cb730e91 100644 --- a/compiler/src/dotty/tools/dotc/fromtasty/AlreadyLoadedCompilationUnit.scala +++ b/compiler/src/dotty/tools/dotc/fromtasty/AlreadyLoadedCompilationUnit.scala @@ -7,4 +7,4 @@ import dotty.tools.dotc.util.NoSource * encountered, and attempted to inspect, something that has already been loaded, for example a Scala primitive or a * library class like Option. */ -class AlreadyLoadedCompilationUnit(val className: String) extends CompilationUnit(NoSource) +class AlreadyLoadedCompilationUnit(val className: String) extends CompilationUnit(NoSource, null) diff --git a/compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala b/compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala index 4969882b7766..9cf2421c3bda 100644 --- a/compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala +++ b/compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala @@ -46,9 +46,16 @@ class ReadTasty extends Phase { case unpickler: tasty.DottyUnpickler => if (cls.rootTree.isEmpty) None else { - val unit = CompilationUnit(cls, cls.rootTree, forceTrees = true) - unit.pickled += (cls -> (() => unpickler.unpickler.bytes)) - Some(unit) + val attributes = unpickler.tastyAttributes + if attributes.isJava && !ctx.settings.YjavaTasty.value then + // filter out Java compilation units if -Yjava-tasty is not set + None + else if attributes.isOutline && !ctx.settings.YallowOutlineFromTasty.value then + cannotUnpickle("it contains outline signatures and -Yallow-outline-from-tasty is not set.") + else + val unit = CompilationUnit(cls, cls.rootTree, forceTrees = true) + unit.pickled += (cls -> (() => unpickler.unpickler.bytes)) + Some(unit) } case tree: Tree[?] => // TODO handle correctly this case correctly to get the tree or avoid it completely. diff --git a/compiler/src/dotty/tools/dotc/fromtasty/TASTYCompilationUnit.scala b/compiler/src/dotty/tools/dotc/fromtasty/TASTYCompilationUnit.scala index 77021efa3050..1d4daff510e7 100644 --- a/compiler/src/dotty/tools/dotc/fromtasty/TASTYCompilationUnit.scala +++ b/compiler/src/dotty/tools/dotc/fromtasty/TASTYCompilationUnit.scala @@ -3,6 +3,6 @@ package dotty.tools.dotc.fromtasty import dotty.tools.dotc.CompilationUnit import dotty.tools.dotc.util.NoSource -class TASTYCompilationUnit(val className: String) extends CompilationUnit(NoSource) { +class TASTYCompilationUnit(val className: String) extends CompilationUnit(NoSource, null) { override def toString: String = s"class file $className" } diff --git a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala index 8e075acdf5e3..bdd29d9ec0ef 100644 --- a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -136,7 +136,7 @@ object JavaParsers { ValDef(name, tpt, EmptyTree).withMods(Modifiers(Flags.JavaDefined | Flags.Param)) def makeConstructor(formals: List[Tree], tparams: List[TypeDef], flags: FlagSet = Flags.JavaDefined): DefDef = { - val vparams = formals.zipWithIndex.map { case (p, i) => makeSyntheticParam(i + 1, p) } + val vparams = formals.zipWithIndex.map { case (p, i) => makeSyntheticParam(i + 1, p).withMods(Modifiers(flags)) } DefDef(nme.CONSTRUCTOR, joinParams(tparams, List(vparams)), TypeTree(), EmptyTree).withMods(Modifiers(flags)) } @@ -992,7 +992,7 @@ object JavaParsers { Select(New(javaLangDot(tpnme.Enum)), nme.CONSTRUCTOR), List(enumType)), Nil) val enumclazz = atSpan(start, nameOffset) { TypeDef(name, - makeTemplate(superclazz :: interfaces, body, List(), true)).withMods(mods | Flags.JavaEnumTrait) + makeTemplate(superclazz :: interfaces, body, List(), true)).withMods(mods | Flags.JavaEnum) } addCompanionObject(consts ::: statics ::: predefs, enumclazz) } @@ -1011,7 +1011,7 @@ object JavaParsers { skipAhead() accept(RBRACE) } - ValDef(name.toTermName, enumType, unimplementedExpr).withMods(Modifiers(Flags.JavaEnumTrait | Flags.StableRealizable | Flags.JavaDefined | Flags.JavaStatic)) + ValDef(name.toTermName, enumType, unimplementedExpr).withMods(Modifiers(Flags.JavaEnumValue | Flags.JavaStatic)) } } diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 306656b137c8..f3a2300913ec 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -97,6 +97,9 @@ object Parsers { private val InCond: Region => Region = Scanners.InParens(LPAREN, _) private val InFor : Region => Region = Scanners.InBraces(_) + def unimplementedExpr(using Context): Select = + Select(scalaDot(nme.Predef), nme.???) + abstract class ParserCommon(val source: SourceFile)(using Context) { val in: ScannerCommon @@ -164,9 +167,6 @@ object Parsers { */ def syntaxError(msg: Message, span: Span): Unit = report.error(msg, source.atSpan(span)) - - def unimplementedExpr(using Context): Select = - Select(scalaDot(nme.Predef), nme.???) } trait OutlineParserCommon extends ParserCommon { diff --git a/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala b/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala index a9b66fc056e2..6a030c424f08 100644 --- a/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala +++ b/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala @@ -9,7 +9,7 @@ import dotty.tools.dotc.core.Flags.* import dotty.tools.dotc.core.Mode import dotty.tools.dotc.core.Symbols.* import dotty.tools.dotc.core.Types.* -import dotty.tools.dotc.core.tasty.{ PositionPickler, TastyPickler, TastyPrinter, TreePickler } +import dotty.tools.dotc.core.tasty.{ PositionPickler, TastyPickler, TastyPrinter, TreePickler, Attributes } import dotty.tools.dotc.core.tasty.DottyUnpickler import dotty.tools.dotc.core.tasty.TreeUnpickler.UnpickleMode import dotty.tools.dotc.report @@ -217,7 +217,7 @@ object PickledQuotes { private def pickle(tree: Tree)(using Context): Array[Byte] = { quotePickling.println(i"**** pickling quote of\n$tree") val pickler = new TastyPickler(defn.RootClass) - val treePkl = new TreePickler(pickler) + val treePkl = new TreePickler(pickler, Attributes.empty) treePkl.pickle(tree :: Nil) treePkl.compactify() if tree.span.exists then diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala index bb1d2afd04d6..dafb44d525e4 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala @@ -54,6 +54,9 @@ class ExtractAPI extends Phase { // Check no needed. Does not transform trees override def isCheckable: Boolean = false + // when `-Yjava-tasty` is set we actually want to run this phase on Java sources + override def skipIfJava(using Context): Boolean = false + // SuperAccessors need to be part of the API (see the scripted test // `trait-super` for an example where this matters), this is only the case // after `PostTyper` (unlike `ExtractDependencies`, the simplication to trees diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala index 36982633e881..a35628dc52e4 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala @@ -64,6 +64,9 @@ class ExtractDependencies extends Phase { // Check no needed. Does not transform trees override def isCheckable: Boolean = false + // when `-Yjava-tasty` is set we actually want to run this phase on Java sources + override def skipIfJava(using Context): Boolean = false + // This phase should be run directly after `Frontend`, if it is run after // `PostTyper`, some dependencies will be lost because trees get simplified. // See the scripted test `constants` for an example where this matters. diff --git a/compiler/src/dotty/tools/dotc/transform/Pickler.scala b/compiler/src/dotty/tools/dotc/transform/Pickler.scala index c361b50af819..2dc1599365cd 100644 --- a/compiler/src/dotty/tools/dotc/transform/Pickler.scala +++ b/compiler/src/dotty/tools/dotc/transform/Pickler.scala @@ -9,6 +9,8 @@ import tasty.* import config.Printers.{noPrinter, pickling} import config.Feature import java.io.PrintStream +import io.ClassfileWriterOps +import StdNames.str import Periods.* import Phases.* import Symbols.* @@ -17,6 +19,7 @@ import reporting.{ThrowingReporter, Profile, Message} import collection.mutable import util.concurrent.{Executor, Future} import compiletime.uninitialized +import dotty.tools.io.JarArchive object Pickler { val name: String = "pickler" @@ -27,6 +30,9 @@ object Pickler { * only in backend. */ inline val ParallelPickling = true + + class EarlyFileWriter(writer: ClassfileWriterOps): + export writer.{writeTasty, close} } /** This phase pickles trees */ @@ -39,7 +45,10 @@ class Pickler extends Phase { // No need to repickle trees coming from TASTY override def isRunnable(using Context): Boolean = - super.isRunnable && !ctx.settings.fromTasty.value + super.isRunnable && (!ctx.settings.fromTasty.value || ctx.settings.YjavaTasty.value) + + // when `-Yjava-tasty` is set we actually want to run this phase on Java sources + override def skipIfJava(using Context): Boolean = false private def output(name: String, msg: String) = { val s = new PrintStream(name) @@ -74,7 +83,8 @@ class Pickler extends Phase { private val executor = Executor[Array[Byte]]() private def useExecutor(using Context) = - Pickler.ParallelPickling && !ctx.settings.YtestPickler.value + Pickler.ParallelPickling && !ctx.settings.YtestPickler.value && + !ctx.settings.YjavaTasty.value // disable parallel pickling when `-Yjava-tasty` is set (internal testing only) override def run(using Context): Unit = { val unit = ctx.compilationUnit @@ -86,8 +96,22 @@ class Pickler extends Phase { do if ctx.settings.YtestPickler.value then beforePickling(cls) = tree.show + val isJavaAttr = unit.isJava // we must always set JAVAattr when pickling Java sources + if isJavaAttr then + // assert that Java sources didn't reach Pickler without `-Yjava-tasty`. + assert(ctx.settings.YjavaTasty.value, "unexpected Java source file without -Yjava-tasty") + val isOutline = isJavaAttr // TODO: later we may want outline for Scala sources too + val attributes = Attributes( + scala2StandardLibrary = ctx.settings.YcompileScala2Library.value, + explicitNulls = ctx.settings.YexplicitNulls.value, + captureChecked = Feature.ccEnabled, + withPureFuns = Feature.pureFunsEnabled, + isJava = isJavaAttr, + isOutline = isOutline + ) + val pickler = new TastyPickler(cls) - val treePkl = new TreePickler(pickler) + val treePkl = new TreePickler(pickler, attributes) treePkl.pickle(tree :: Nil) Profile.current.recordTasty(treePkl.buf.length) @@ -109,12 +133,6 @@ class Pickler extends Phase { pickler, treePkl.buf.addrOfTree, treePkl.docString, tree, scratch.commentBuffer) - val attributes = Attributes( - scala2StandardLibrary = ctx.settings.YcompileScala2Library.value, - explicitNulls = ctx.settings.YexplicitNulls.value, - captureChecked = Feature.ccEnabled, - withPureFuns = Feature.pureFunsEnabled, - ) AttributePickler.pickleAttributes(attributes, pickler, scratch.attributeBuffer) val pickled = pickler.assembleParts() @@ -154,13 +172,22 @@ class Pickler extends Phase { } override def runOn(units: List[CompilationUnit])(using Context): List[CompilationUnit] = { - val result = - if useExecutor then - executor.start() - try super.runOn(units) - finally executor.close() + val sigWriter: Option[Pickler.EarlyFileWriter] = ctx.settings.YjavaTastyOutput.value match + case jar: JarArchive if jar.exists => + Some(Pickler.EarlyFileWriter(ClassfileWriterOps(jar))) + case _ => + None + val units0 = + if ctx.settings.fromTasty.value then + // we still run the phase for the side effect of writing the pipeline tasty files + units else - super.runOn(units) + if useExecutor then + executor.start() + try super.runOn(units) + finally executor.close() + else + super.runOn(units) if ctx.settings.YtestPickler.value then val ctx2 = ctx.fresh .setSetting(ctx.settings.YreadComments, true) @@ -171,9 +198,34 @@ class Pickler extends Phase { .setReporter(new ThrowingReporter(ctx.reporter)) .addMode(Mode.ReadPositions) ) + val result = + if ctx.settings.YjavaTasty.value then + sigWriter.foreach(writeJavaSigFiles(units0, _)) + units0.filterNot(_.typedAsJava) // remove java sources, this is the terminal phase when `-Yjava-tasty` is set + else + units0 result } + private def writeJavaSigFiles(units: List[CompilationUnit], writer: Pickler.EarlyFileWriter)(using Context): Unit = { + var count = 0 + try + for + unit <- units if unit.typedAsJava + (cls, pickled) <- unit.pickled + if cls.isDefinedInCurrentRun + do + val binaryName = cls.binaryClassName.replace('.', java.io.File.separatorChar).nn + val binaryClassName = if (cls.is(Module)) binaryName.stripSuffix(str.MODULE_SUFFIX).nn else binaryName + writer.writeTasty(binaryClassName, pickled()) + count += 1 + finally + writer.close() + if ctx.settings.verbose.value then + report.echo(s"[$count java sig files written]") + end try + } + private def testUnpickler(using Context): Unit = pickling.println(i"testing unpickler at run ${ctx.runId}") ctx.initialize() diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index f3a883df9e4f..beb4119775d0 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -626,7 +626,7 @@ object SpaceEngine { case tp if tp.isRef(defn.UnitClass) => ConstantType(Constant(())) :: Nil case tp @ NamedType(Parts(parts), _) => parts.map(tp.derivedSelect) case _: SingletonType => ListOfNoType - case tp if tp.classSymbol.isAllOf(JavaEnumTrait) => tp.classSymbol.children.map(_.termRef) + case tp if tp.classSymbol.isAllOf(JavaEnum) => tp.classSymbol.children.map(_.termRef) // the class of a java enum value is the enum class, so this must follow SingletonType to not loop infinitely case tp @ AppliedType(Parts(parts), targs) if tp.classSymbol.children.isEmpty => @@ -843,7 +843,7 @@ object SpaceEngine { isCheckable(and.tp1) || isCheckable(and.tp2) }) || tpw.isRef(defn.BooleanClass) || - classSym.isAllOf(JavaEnumTrait) || + classSym.isAllOf(JavaEnum) || classSym.is(Case) && { if seen.add(tpw) then productSelectorTypes(tpw, sel.srcPos).exists(isCheckable(_)) else true // recursive case class: return true and other members can still fail the check diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 5697fcdfc98f..f8ced1c6599a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -248,7 +248,7 @@ class Namer { typer: Typer => val cls = createOrRefine[ClassSymbol](tree, name, flags, ctx.owner, cls => adjustIfModule(new ClassCompleter(cls, tree)(ctx), tree), - newClassSymbol(ctx.owner, name, _, _, _, tree.nameSpan, CompilationUnitInfo(ctx.source.file))) + newClassSymbol(ctx.owner, name, _, _, _, tree.nameSpan, ctx.compilationUnit.info)) cls.completer.asInstanceOf[ClassCompleter].init() cls case tree: MemberDef => diff --git a/compiler/src/dotty/tools/dotc/typer/TyperPhase.scala b/compiler/src/dotty/tools/dotc/typer/TyperPhase.scala index b79235f4f819..b16447ecb15b 100644 --- a/compiler/src/dotty/tools/dotc/typer/TyperPhase.scala +++ b/compiler/src/dotty/tools/dotc/typer/TyperPhase.scala @@ -57,7 +57,7 @@ class TyperPhase(addRootImports: Boolean = true) extends Phase { } protected def discardAfterTyper(unit: CompilationUnit)(using Context): Boolean = - unit.isJava || unit.suspended + (unit.isJava && !ctx.settings.YjavaTasty.value) || unit.suspended override val subPhases: List[SubPhase] = List( SubPhase("indexing"), SubPhase("typechecking"), SubPhase("checkingJava")) diff --git a/compiler/src/dotty/tools/io/ClassfileWriterOps.scala b/compiler/src/dotty/tools/io/ClassfileWriterOps.scala new file mode 100644 index 000000000000..c2107ded6f51 --- /dev/null +++ b/compiler/src/dotty/tools/io/ClassfileWriterOps.scala @@ -0,0 +1,50 @@ +package dotty.tools.io + +import dotty.tools.io.* +import dotty.tools.dotc.core.Decorators.* +import dotty.tools.dotc.core.Contexts.* +import dotty.tools.dotc.report +import scala.language.unsafeNulls +import scala.annotation.constructorOnly + + +/** Experimental usage - writes bytes to JarArchives */ +class ClassfileWriterOps(outputDir: JarArchive)(using @constructorOnly ictx: Context) { + + type InternalName = String + + // if non-null, classfiles are written to a jar instead of the output directory + private val jarWriter: JarWriter | Null = + val localCtx = ictx + outputDir.underlyingSource.map { source => + if outputDir.isEmpty then + new Jar(source.file).jarWriter() + else inContext(localCtx) { + // Writing to non-empty JAR might be an undefined behaviour, e.g. in case if other files where + // created using `AbstractFile.bufferedOutputStream`instead of JarWriter + report.warning(em"Tried to write to non-empty JAR: $source") + null + } + }.getOrElse( + inContext(localCtx) { + report.warning(em"tried to create a file writer for $outputDir, but it had no underlying source.") + null + } + ) + + def writeTasty(className: InternalName, bytes: Array[Byte]): Unit = + writeToJar(className, bytes, ".tasty") + + private def writeToJar(className: InternalName, bytes: Array[Byte], suffix: String): Unit = { + if (jarWriter == null) return + val path = className + suffix + val out = jarWriter.newOutputStream(path) + try out.write(bytes, 0, bytes.length) + finally out.flush() + } + + def close(): Unit = { + if (jarWriter != null) jarWriter.close() + outputDir.close() + } +} diff --git a/compiler/src/dotty/tools/io/JarArchive.scala b/compiler/src/dotty/tools/io/JarArchive.scala index 49b743e83074..f42f68e745ed 100644 --- a/compiler/src/dotty/tools/io/JarArchive.scala +++ b/compiler/src/dotty/tools/io/JarArchive.scala @@ -12,6 +12,7 @@ import scala.jdk.CollectionConverters.* */ class JarArchive private (root: Directory) extends PlainDirectory(root) { def close(): Unit = jpath.getFileSystem().close() + override def exists: Boolean = jpath.getFileSystem().isOpen() && super.exists def allFileNames(): Iterator[String] = java.nio.file.Files.walk(jpath).iterator().asScala.map(_.toString) } diff --git a/compiler/src/dotty/tools/repl/ReplCompiler.scala b/compiler/src/dotty/tools/repl/ReplCompiler.scala index af3fb32c3e86..d69173cb6d88 100644 --- a/compiler/src/dotty/tools/repl/ReplCompiler.scala +++ b/compiler/src/dotty/tools/repl/ReplCompiler.scala @@ -4,6 +4,7 @@ import dotty.tools.dotc.ast.Trees.* import dotty.tools.dotc.ast.{tpd, untpd} import dotty.tools.dotc.ast.tpd.TreeOps import dotty.tools.dotc.core.Contexts.* +import dotty.tools.dotc.core.CompilationUnitInfo import dotty.tools.dotc.core.Decorators.* import dotty.tools.dotc.core.Flags.* import dotty.tools.dotc.core.Names.* @@ -233,7 +234,7 @@ object ReplCompiler: val objectNames = mutable.Map.empty[Int, TermName] end ReplCompiler -class ReplCompilationUnit(source: SourceFile) extends CompilationUnit(source): +class ReplCompilationUnit(source: SourceFile) extends CompilationUnit(source, CompilationUnitInfo(source.file)): override def isSuspendable: Boolean = false /** A placeholder phase that receives parse trees.. diff --git a/compiler/test/dotty/tools/dotc/core/SealedDescendantsTest.scala b/compiler/test/dotty/tools/dotc/core/SealedDescendantsTest.scala index 0ae9069c03d1..4726596c0428 100644 --- a/compiler/test/dotty/tools/dotc/core/SealedDescendantsTest.scala +++ b/compiler/test/dotty/tools/dotc/core/SealedDescendantsTest.scala @@ -47,6 +47,19 @@ class SealedDescendantsTest extends DottyTest { ) end enumOpt + @Test + def javaEnum: Unit = + expectedDescendents("java.util.concurrent.TimeUnit", + "TimeUnit" :: + "NANOSECONDS.type" :: + "MICROSECONDS.type" :: + "MILLISECONDS.type" :: + "SECONDS.type" :: + "MINUTES.type" :: + "HOURS.type" :: + "DAYS.type" :: Nil + ) + @Test def hierarchicalSharedChildren: Unit = // Q is a child of both Z and A and should appear once @@ -91,10 +104,22 @@ class SealedDescendantsTest extends DottyTest { ) end hierarchicalSharedChildrenB - def expectedDescendents(source: String, root: String, expected: List[String]) = - exploreRoot(source, root) { rootCls => - val descendents = rootCls.sealedDescendants.map(sym => s"${sym.name}${if (sym.isTerm) ".type" else ""}") - assertEquals(expected.toString, descendents.toString) + def assertMatchingDescenants(rootCls: Symbol, expected: List[String])(using Context): Unit = + val descendents = rootCls.sealedDescendants.map(sym => s"${sym.name}${if (sym.isTerm) ".type" else ""}") + assertEquals(expected.toString, descendents.toString) + + def expectedDescendents(root: String, expected: List[String]): Unit = + exploreRootNoSource(root)(assertMatchingDescenants(_, expected)) + + def expectedDescendents(source: String, root: String, expected: List[String]): Unit = + exploreRoot(source, root)(assertMatchingDescenants(_, expected)) + + def exploreRootNoSource(root: String)(op: Context ?=> ClassSymbol => Unit) = + val source1 = s"""package testsealeddescendants + |object Foo { def foo: $root = ??? }""".stripMargin + checkCompile("typer", source1) { (_, context) => + given Context = context + op(requiredClass(root)) } def exploreRoot(source: String, root: String)(op: Context ?=> ClassSymbol => Unit) = diff --git a/presentation-compiler/src/main/dotty/tools/pc/completions/MatchCaseCompletions.scala b/presentation-compiler/src/main/dotty/tools/pc/completions/MatchCaseCompletions.scala index fe9a73655835..a3d5d8814c48 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/completions/MatchCaseCompletions.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/completions/MatchCaseCompletions.scala @@ -349,11 +349,7 @@ object CaseKeywordCompletion: symTpe <:< tpe val parents = getParentTypes(tpe, List.empty) - parents.toList.map { parent => - // There is an issue in Dotty, `sealedStrictDescendants` ends in an exception for java enums. https://github.com/lampepfl/dotty/issues/15908 - if parent.isAllOf(JavaEnumTrait) then parent.children - else sealedStrictDescendants(parent) - } match + parents.toList.map(sealedStrictDescendants) match case Nil => Nil case subcls :: Nil => subcls case subcls => @@ -409,9 +405,7 @@ class CompletionValueGenerator( Context ): Option[String] = val isModuleLike = - sym.is(Flags.Module) || sym.isOneOf(JavaEnumTrait) || sym.isOneOf( - JavaEnumValue - ) || sym.isAllOf(EnumCase) + sym.is(Flags.Module) || sym.isOneOf(JavaEnum) || sym.isOneOf(JavaEnumValue) || sym.isAllOf(EnumCase) if isModuleLike && hasBind then None else val pattern = diff --git a/sbt-test/pipelining/Yjava-tasty-annotation/a/src/main/scala/a/A.java b/sbt-test/pipelining/Yjava-tasty-annotation/a/src/main/scala/a/A.java new file mode 100644 index 000000000000..49c55a7c4d9c --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-annotation/a/src/main/scala/a/A.java @@ -0,0 +1,11 @@ +// this test ensures that it is possible to read a java annotation from TASTy. +package a; + +import java.lang.annotation.*; + + +@Documented +@Retention(RetentionPolicy.CLASS) +@Target({ ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.TYPE, ElementType.PACKAGE }) +public @interface A { +} diff --git a/sbt-test/pipelining/Yjava-tasty-annotation/a/src/main/scala/a/package.scala b/sbt-test/pipelining/Yjava-tasty-annotation/a/src/main/scala/a/package.scala new file mode 100644 index 000000000000..93f99e9892fe --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-annotation/a/src/main/scala/a/package.scala @@ -0,0 +1,2 @@ +// THIS FILE EXISTS SO THAT `A.java` WILL BE COMPILED BY SCALAC +package a diff --git a/sbt-test/pipelining/Yjava-tasty-annotation/b/src/main/scala/b/B.scala b/sbt-test/pipelining/Yjava-tasty-annotation/b/src/main/scala/b/B.scala new file mode 100644 index 000000000000..51c7322bf264 --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-annotation/b/src/main/scala/b/B.scala @@ -0,0 +1,9 @@ +package b + +import a.A + +object B { + @A + val foo = 23 +} + diff --git a/sbt-test/pipelining/Yjava-tasty-annotation/build.sbt b/sbt-test/pipelining/Yjava-tasty-annotation/build.sbt new file mode 100644 index 000000000000..9299d94c060d --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-annotation/build.sbt @@ -0,0 +1,13 @@ +lazy val a = project.in(file("a")) + .settings( + scalacOptions += "-Yjava-tasty", // enable pickling of java signatures + scalacOptions ++= Seq("-Yjava-tasty-output", ((ThisBuild / baseDirectory).value / "a-annotation-java-tasty.jar").toString), + scalacOptions += "-Ycheck:all", + Compile / classDirectory := ((ThisBuild / baseDirectory).value / "a-annotation-classes"), // send classfiles to a different directory + ) + +lazy val b = project.in(file("b")) + .settings( + Compile / unmanagedClasspath := Seq(Attributed.blank((ThisBuild / baseDirectory).value / "a-annotation-java-tasty.jar")), + scalacOptions += "-Ycheck:all", + ) diff --git a/sbt-test/pipelining/Yjava-tasty-annotation/project/DottyInjectedPlugin.scala b/sbt-test/pipelining/Yjava-tasty-annotation/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..69f15d168bfc --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-annotation/project/DottyInjectedPlugin.scala @@ -0,0 +1,12 @@ +import sbt._ +import Keys._ + +object DottyInjectedPlugin extends AutoPlugin { + override def requires = plugins.JvmPlugin + override def trigger = allRequirements + + override val projectSettings = Seq( + scalaVersion := sys.props("plugin.scalaVersion"), + scalacOptions += "-source:3.0-migration" + ) +} diff --git a/sbt-test/pipelining/Yjava-tasty-annotation/test b/sbt-test/pipelining/Yjava-tasty-annotation/test new file mode 100644 index 000000000000..6105296d455b --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-annotation/test @@ -0,0 +1,3 @@ +> a/compile +# Test depending on a java compiled annotation through TASTy +> b/compile diff --git a/sbt-test/pipelining/Yjava-tasty-enum/a/src/main/scala/a/A.java b/sbt-test/pipelining/Yjava-tasty-enum/a/src/main/scala/a/A.java new file mode 100644 index 000000000000..26bf8a246774 --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-enum/a/src/main/scala/a/A.java @@ -0,0 +1,7 @@ +// this test ensures that ExtractAPI does not cause a crash +// when looking at sealedDescendants of a Java enum. +package a; + +public enum A { + X, Y, Z; +} diff --git a/sbt-test/pipelining/Yjava-tasty-enum/a/src/main/scala/a/package.scala b/sbt-test/pipelining/Yjava-tasty-enum/a/src/main/scala/a/package.scala new file mode 100644 index 000000000000..93f99e9892fe --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-enum/a/src/main/scala/a/package.scala @@ -0,0 +1,2 @@ +// THIS FILE EXISTS SO THAT `A.java` WILL BE COMPILED BY SCALAC +package a diff --git a/sbt-test/pipelining/Yjava-tasty-enum/b/src/main/scala/b/B.scala b/sbt-test/pipelining/Yjava-tasty-enum/b/src/main/scala/b/B.scala new file mode 100644 index 000000000000..a648bb4e83d6 --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-enum/b/src/main/scala/b/B.scala @@ -0,0 +1,17 @@ +package b + +import a.A + +object B { + + def formattedEnum(e: A): String = e match { + case A.X => "X" + case A.Y => "Y" + case A.Z => "Z" + } + + @main def test = + assert(A.values.toList == List(A.X, A.Y, A.Z)) + assert(A.values.toList.map(formattedEnum) == List("X", "Y", "Z")) +} + diff --git a/sbt-test/pipelining/Yjava-tasty-enum/build.sbt b/sbt-test/pipelining/Yjava-tasty-enum/build.sbt new file mode 100644 index 000000000000..0c95d8318913 --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-enum/build.sbt @@ -0,0 +1,19 @@ +lazy val a = project.in(file("a")) + .settings( + compileOrder := CompileOrder.Mixed, // ensure we send java sources to Scala compiler + scalacOptions += "-Yjava-tasty", // enable pickling of java signatures + scalacOptions ++= Seq("-Yjava-tasty-output", ((ThisBuild / baseDirectory).value / "a-enum-java-tasty.jar").toString), + scalacOptions += "-Ycheck:all", + Compile / classDirectory := ((ThisBuild / baseDirectory).value / "a-enum-classes"), // send classfiles to a different directory + ) + + +lazy val b = project.in(file("b")) + .settings( + Compile / unmanagedClasspath := Seq(Attributed.blank((ThisBuild / baseDirectory).value / "a-enum-java-tasty.jar")), + scalacOptions += "-Ycheck:all", + ) + .settings( + fork := true, // we have to fork the JVM if we actually want to run the code with correct failure semantics + Runtime / unmanagedClasspath += Attributed.blank((ThisBuild / baseDirectory).value / "a-enum-classes"), // make sure the java classes are visible at runtime + ) diff --git a/sbt-test/pipelining/Yjava-tasty-enum/project/DottyInjectedPlugin.scala b/sbt-test/pipelining/Yjava-tasty-enum/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..69f15d168bfc --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-enum/project/DottyInjectedPlugin.scala @@ -0,0 +1,12 @@ +import sbt._ +import Keys._ + +object DottyInjectedPlugin extends AutoPlugin { + override def requires = plugins.JvmPlugin + override def trigger = allRequirements + + override val projectSettings = Seq( + scalaVersion := sys.props("plugin.scalaVersion"), + scalacOptions += "-source:3.0-migration" + ) +} diff --git a/sbt-test/pipelining/Yjava-tasty-enum/test b/sbt-test/pipelining/Yjava-tasty-enum/test new file mode 100644 index 000000000000..fe04b1a7c7ea --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-enum/test @@ -0,0 +1,3 @@ +> a/compile +# test depending on a java compiled enum through TASTy +> b/run diff --git a/sbt-test/pipelining/Yjava-tasty-from-tasty/a/src/main/scala/a/A.java b/sbt-test/pipelining/Yjava-tasty-from-tasty/a/src/main/scala/a/A.java new file mode 100644 index 000000000000..381da612df90 --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-from-tasty/a/src/main/scala/a/A.java @@ -0,0 +1,5 @@ +package a; + +public class A { + public String VALUE = "A"; +} diff --git a/sbt-test/pipelining/Yjava-tasty-from-tasty/a/src/main/scala/a/package.scala b/sbt-test/pipelining/Yjava-tasty-from-tasty/a/src/main/scala/a/package.scala new file mode 100644 index 000000000000..8cfc7fa44d87 --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-from-tasty/a/src/main/scala/a/package.scala @@ -0,0 +1,2 @@ +// THE PURPOSE OF THIS FILE IS TO MAKE SBT SEND A.java TO THE SCALA COMPILER +package a diff --git a/sbt-test/pipelining/Yjava-tasty-from-tasty/a_from_tasty/.keep b/sbt-test/pipelining/Yjava-tasty-from-tasty/a_from_tasty/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/sbt-test/pipelining/Yjava-tasty-from-tasty/b/src/main/scala/b/B.scala b/sbt-test/pipelining/Yjava-tasty-from-tasty/b/src/main/scala/b/B.scala new file mode 100644 index 000000000000..43a45ae53ce2 --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-from-tasty/b/src/main/scala/b/B.scala @@ -0,0 +1,9 @@ +package b + +object B { + val A_VALUE = (new a.A).VALUE + + @main def test = { + assert(A_VALUE == "A", s"actually was $A_VALUE") + } +} diff --git a/sbt-test/pipelining/Yjava-tasty-from-tasty/build.sbt b/sbt-test/pipelining/Yjava-tasty-from-tasty/build.sbt new file mode 100644 index 000000000000..570e72a40c1b --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-from-tasty/build.sbt @@ -0,0 +1,35 @@ +// `a` contains mixed java/scala sources so sbt will send java sources to Scala compiler. +lazy val a = project.in(file("a")) + .settings( + compileOrder := CompileOrder.Mixed, // ensure we send java sources to Scala compiler + scalacOptions += "-Yjava-tasty", // enable pickling of java signatures + scalacOptions ++= Seq("-Yjava-tasty-output", ((ThisBuild / baseDirectory).value / "a-pre-java-tasty.jar").toString), + scalacOptions += "-Ycheck:all", + Compile / classDirectory := ((ThisBuild / baseDirectory).value / "a-pre-classes"), // send classfiles to a different directory + ) + +// recompile `a` with `-from-tasty` flag to test idempotent read/write java signatures. +// Requires -Yjava-tasty to be set in order to read them. +lazy val a_from_tasty = project.in(file("a_from_tasty")) + .settings( + Compile / sources := Seq((ThisBuild / baseDirectory).value / "a-pre-java-tasty.jar"), + Compile / unmanagedClasspath := Seq(Attributed.blank((ThisBuild / baseDirectory).value / "a-pre-java-tasty.jar")), + scalacOptions += "-from-tasty", // read the jar file tasties as the source files + scalacOptions += "-Yjava-tasty", + scalacOptions += "-Yallow-outline-from-tasty", // allow outline signatures to be read with -from-tasty + scalacOptions ++= Seq("-Yjava-tasty-output", ((ThisBuild / baseDirectory).value / "a_from_tasty-java-tasty.jar").toString), + scalacOptions += "-Ycheck:all", + Compile / classDirectory := ((ThisBuild / baseDirectory).value / "a_from_tasty-classes"), // send classfiles to a different directory + ) + +lazy val b = project.in(file("b")) + .settings( + scalacOptions += "-Ycheck:all", + Compile / unmanagedClasspath := Seq(Attributed.blank((ThisBuild / baseDirectory).value / "a_from_tasty-java-tasty.jar")), + ) + .settings( + // we have to fork the JVM if we actually want to run the code with correct failure semantics + fork := true, + // make sure the java classes are visible at runtime + Runtime / unmanagedClasspath += Attributed.blank((ThisBuild / baseDirectory).value / "a-pre-classes"), + ) diff --git a/sbt-test/pipelining/Yjava-tasty-from-tasty/project/DottyInjectedPlugin.scala b/sbt-test/pipelining/Yjava-tasty-from-tasty/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..69f15d168bfc --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-from-tasty/project/DottyInjectedPlugin.scala @@ -0,0 +1,12 @@ +import sbt._ +import Keys._ + +object DottyInjectedPlugin extends AutoPlugin { + override def requires = plugins.JvmPlugin + override def trigger = allRequirements + + override val projectSettings = Seq( + scalaVersion := sys.props("plugin.scalaVersion"), + scalacOptions += "-source:3.0-migration" + ) +} diff --git a/sbt-test/pipelining/Yjava-tasty-from-tasty/test b/sbt-test/pipelining/Yjava-tasty-from-tasty/test new file mode 100644 index 000000000000..5c08ed4c4458 --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-from-tasty/test @@ -0,0 +1,5 @@ +> a/compile +# test reading java tasty with -from-tasty +> a_from_tasty/compile +# test java tasty is still written even with -from-tasty +> b/run diff --git a/sbt-test/pipelining/Yjava-tasty-generic/a/src/main/scala/a/A.java b/sbt-test/pipelining/Yjava-tasty-generic/a/src/main/scala/a/A.java new file mode 100644 index 000000000000..1fcb7e78ae3d --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-generic/a/src/main/scala/a/A.java @@ -0,0 +1,14 @@ +// this test ensures that it is possible to read a generic java class from TASTy. +package a; + +public abstract class A { + private final int _value; + + protected A(final int value) { + this._value = value; + } + + public int value() { + return _value; + } +} diff --git a/sbt-test/pipelining/Yjava-tasty-generic/a/src/main/scala/a/package.scala b/sbt-test/pipelining/Yjava-tasty-generic/a/src/main/scala/a/package.scala new file mode 100644 index 000000000000..93f99e9892fe --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-generic/a/src/main/scala/a/package.scala @@ -0,0 +1,2 @@ +// THIS FILE EXISTS SO THAT `A.java` WILL BE COMPILED BY SCALAC +package a diff --git a/sbt-test/pipelining/Yjava-tasty-generic/b/src/main/scala/b/B.scala b/sbt-test/pipelining/Yjava-tasty-generic/b/src/main/scala/b/B.scala new file mode 100644 index 000000000000..f132e012a5fc --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-generic/b/src/main/scala/b/B.scala @@ -0,0 +1,15 @@ +package b + +import a.A + +class B[T] { + val inner = new A[T](23) {} +} + +object B { + @main def test = { + val derived: Int = (new B[Int]).inner.value + assert(derived == 23, s"actually was $derived") + } +} + diff --git a/sbt-test/pipelining/Yjava-tasty-generic/build.sbt b/sbt-test/pipelining/Yjava-tasty-generic/build.sbt new file mode 100644 index 000000000000..0c8a5c55fe7e --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-generic/build.sbt @@ -0,0 +1,17 @@ +lazy val a = project.in(file("a")) + .settings( + scalacOptions += "-Yjava-tasty", // enable pickling of java signatures + scalacOptions ++= Seq("-Yjava-tasty-output", ((ThisBuild / baseDirectory).value / "a-generic-java-tasty.jar").toString), + scalacOptions += "-Ycheck:all", + Compile / classDirectory := ((ThisBuild / baseDirectory).value / "a-generic-classes"), // send classfiles to a different directory + ) + +lazy val b = project.in(file("b")) + .settings( + Compile / unmanagedClasspath := Seq(Attributed.blank((ThisBuild / baseDirectory).value / "a-generic-java-tasty.jar")), + scalacOptions += "-Ycheck:all", + ) + .settings( + fork := true, // we have to fork the JVM if we actually want to run the code with correct failure semantics + Runtime / unmanagedClasspath += Attributed.blank((ThisBuild / baseDirectory).value / "a-generic-classes"), // make sure the java classes are visible at runtime + ) diff --git a/sbt-test/pipelining/Yjava-tasty-generic/project/DottyInjectedPlugin.scala b/sbt-test/pipelining/Yjava-tasty-generic/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..69f15d168bfc --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-generic/project/DottyInjectedPlugin.scala @@ -0,0 +1,12 @@ +import sbt._ +import Keys._ + +object DottyInjectedPlugin extends AutoPlugin { + override def requires = plugins.JvmPlugin + override def trigger = allRequirements + + override val projectSettings = Seq( + scalaVersion := sys.props("plugin.scalaVersion"), + scalacOptions += "-source:3.0-migration" + ) +} diff --git a/sbt-test/pipelining/Yjava-tasty-generic/test b/sbt-test/pipelining/Yjava-tasty-generic/test new file mode 100644 index 000000000000..cbe3e14572a8 --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-generic/test @@ -0,0 +1,3 @@ +> a/compile +# Test depending on a java generic class through TASTy +> b/run diff --git a/sbt-test/pipelining/Yjava-tasty-result-types/a/src/main/scala/a/A.java b/sbt-test/pipelining/Yjava-tasty-result-types/a/src/main/scala/a/A.java new file mode 100644 index 000000000000..c48f149849a6 --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-result-types/a/src/main/scala/a/A.java @@ -0,0 +1,9 @@ +package a; + +public class A { + public static final String VALUE = "A"; + + public String add(T t) { + return VALUE + t.toString(); + } +} diff --git a/sbt-test/pipelining/Yjava-tasty-result-types/a/src/main/scala/a/package.scala b/sbt-test/pipelining/Yjava-tasty-result-types/a/src/main/scala/a/package.scala new file mode 100644 index 000000000000..93f99e9892fe --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-result-types/a/src/main/scala/a/package.scala @@ -0,0 +1,2 @@ +// THIS FILE EXISTS SO THAT `A.java` WILL BE COMPILED BY SCALAC +package a diff --git a/sbt-test/pipelining/Yjava-tasty-result-types/b/src/main/scala/b/B.scala b/sbt-test/pipelining/Yjava-tasty-result-types/b/src/main/scala/b/B.scala new file mode 100644 index 000000000000..32d001075d40 --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-result-types/b/src/main/scala/b/B.scala @@ -0,0 +1,17 @@ +package b + +import a.A + +object B { + val finalResult: "A" = A.VALUE + + val a_B: String = (new A()).add("B") + val a_true: String = (new A()).add(true) + + @main def test = { + assert(finalResult == "A", s"actually was $finalResult") + assert(a_B == "AB", s"actually was $a_B") + assert(a_true == "Atrue", s"actually was $a_true") + } +} + diff --git a/sbt-test/pipelining/Yjava-tasty-result-types/build.sbt b/sbt-test/pipelining/Yjava-tasty-result-types/build.sbt new file mode 100644 index 000000000000..8f9e782f8810 --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-result-types/build.sbt @@ -0,0 +1,17 @@ +lazy val a = project.in(file("a")) + .settings( + scalacOptions += "-Yjava-tasty", // enable pickling of java signatures + scalacOptions ++= Seq("-Yjava-tasty-output", ((ThisBuild / baseDirectory).value / "a-result-types-java-tasty.jar").toString), + scalacOptions += "-Ycheck:all", + Compile / classDirectory := ((ThisBuild / baseDirectory).value / "a-result-types-classes"), // send classfiles to a different directory + ) + +lazy val b = project.in(file("b")) + .settings( + Compile / unmanagedClasspath := Seq(Attributed.blank((ThisBuild / baseDirectory).value / "a-result-types-java-tasty.jar")), + scalacOptions += "-Ycheck:all", + ) + .settings( + fork := true, // we have to fork the JVM if we actually want to run the code with correct failure semantics + Runtime / unmanagedClasspath += Attributed.blank((ThisBuild / baseDirectory).value / "a-result-types-classes"), // make sure the java classes are visible at runtime + ) diff --git a/sbt-test/pipelining/Yjava-tasty-result-types/project/DottyInjectedPlugin.scala b/sbt-test/pipelining/Yjava-tasty-result-types/project/DottyInjectedPlugin.scala new file mode 100644 index 000000000000..69f15d168bfc --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-result-types/project/DottyInjectedPlugin.scala @@ -0,0 +1,12 @@ +import sbt._ +import Keys._ + +object DottyInjectedPlugin extends AutoPlugin { + override def requires = plugins.JvmPlugin + override def trigger = allRequirements + + override val projectSettings = Seq( + scalaVersion := sys.props("plugin.scalaVersion"), + scalacOptions += "-source:3.0-migration" + ) +} diff --git a/sbt-test/pipelining/Yjava-tasty-result-types/test b/sbt-test/pipelining/Yjava-tasty-result-types/test new file mode 100644 index 000000000000..c1cbbb1f2fe5 --- /dev/null +++ b/sbt-test/pipelining/Yjava-tasty-result-types/test @@ -0,0 +1,3 @@ +> a/compile +# Test depending on a java static final result, and method result through TASTy +> b/run diff --git a/staging/src/scala/quoted/staging/ExprCompilationUnit.scala b/staging/src/scala/quoted/staging/ExprCompilationUnit.scala index ea1456527c8b..2f91f4bc4ef1 100644 --- a/staging/src/scala/quoted/staging/ExprCompilationUnit.scala +++ b/staging/src/scala/quoted/staging/ExprCompilationUnit.scala @@ -5,4 +5,4 @@ import dotty.tools.dotc.CompilationUnit import dotty.tools.dotc.util.NoSource /** Compilation unit containing the contents of a quoted expression */ -private class ExprCompilationUnit(val exprBuilder: Quotes => Expr[?]) extends CompilationUnit(NoSource) +private class ExprCompilationUnit(val exprBuilder: Quotes => Expr[?]) extends CompilationUnit(NoSource, null) diff --git a/staging/src/scala/quoted/staging/QuoteCompiler.scala b/staging/src/scala/quoted/staging/QuoteCompiler.scala index d10eab321bae..cf24b1de369a 100644 --- a/staging/src/scala/quoted/staging/QuoteCompiler.scala +++ b/staging/src/scala/quoted/staging/QuoteCompiler.scala @@ -95,8 +95,9 @@ private class QuoteCompiler extends Compiler: val classTree = ClassDef(cls, DefDef(cls.primaryConstructor.asTerm), run :: Nil) val tree = PackageDef(ref(defn.RootPackage).asInstanceOf[Ident], classTree :: Nil).withSpan(pos) val source = SourceFile.virtual("", "") + val unitInfo = CompilationUnitInfo(source.file, tastyInfo = None) result = Left(outputClassName.toString) - Some(CompilationUnit(source, tree, forceTrees = true)) + Some(CompilationUnit(source, tree, forceTrees = true, unitInfo)) } /** Get the literal value if this tree only contains a literal tree */ diff --git a/tasty/src/dotty/tools/tasty/TastyFormat.scala b/tasty/src/dotty/tools/tasty/TastyFormat.scala index ebe94cc0a76c..6ceb82f011f4 100644 --- a/tasty/src/dotty/tools/tasty/TastyFormat.scala +++ b/tasty/src/dotty/tools/tasty/TastyFormat.scala @@ -89,6 +89,7 @@ Standard-Section: "ASTs" TopLevelStat* SELECTin Length possiblySigned_NameRef qual_Term owner_Type -- qual.name, referring to a symbol declared in owner that has the given signature (see note below) QUALTHIS typeIdent_Tree -- id.this, different from THIS in that it contains a qualifier ident with position. NEW clsType_Term -- new cls + ELIDED exprType_Type -- elided expression of the given type THROW throwableExpr_Term -- throw throwableExpr NAMEDARG paramName_NameRef arg_Term -- paramName = arg APPLY Length fn_Term arg_Term* -- fn(args) @@ -275,6 +276,8 @@ Standard Section: "Attributes" Attribute* EXPLICITNULLSattr CAPTURECHECKEDattr WITHPUREFUNSattr + JAVAattr + OUTLINEattr ``` **************************************************************************************/ @@ -525,6 +528,7 @@ object TastyFormat { final val SINGLETONtpt = 101 final val BOUNDED = 102 final val EXPLICITtpt = 103 + final val ELIDED = 104 // Cat. 4: tag Nat AST @@ -615,6 +619,8 @@ object TastyFormat { final val EXPLICITNULLSattr = 2 final val CAPTURECHECKEDattr = 3 final val WITHPUREFUNSattr = 4 + final val JAVAattr = 5 + final val OUTLINEattr = 6 /** Useful for debugging */ def isLegalTag(tag: Int): Boolean = @@ -622,7 +628,7 @@ object TastyFormat { firstNatTreeTag <= tag && tag <= RENAMED || firstASTTreeTag <= tag && tag <= BOUNDED || firstNatASTTreeTag <= tag && tag <= NAMEDARG || - firstLengthTreeTag <= tag && tag <= MATCHtpt || + firstLengthTreeTag <= tag && tag <= MATCHCASEtype || tag == HOLE def isParamTag(tag: Int): Boolean = tag == PARAM || tag == TYPEPARAM @@ -828,6 +834,7 @@ object TastyFormat { case PRIVATEqualified => "PRIVATEqualified" case PROTECTEDqualified => "PROTECTEDqualified" case EXPLICITtpt => "EXPLICITtpt" + case ELIDED => "ELIDED" case HOLE => "HOLE" } @@ -836,6 +843,8 @@ object TastyFormat { case EXPLICITNULLSattr => "EXPLICITNULLSattr" case CAPTURECHECKEDattr => "CAPTURECHECKEDattr" case WITHPUREFUNSattr => "WITHPUREFUNSattr" + case JAVAattr => "JAVAattr" + case OUTLINEattr => "OUTLINEattr" } /** @return If non-negative, the number of leading references (represented as nats) of a length/trees entry. diff --git a/tests/pos-with-compiler-cc/backend/jvm/BCodeHelpers.scala b/tests/pos-with-compiler-cc/backend/jvm/BCodeHelpers.scala index 3ab75bda787e..2454bca9d653 100644 --- a/tests/pos-with-compiler-cc/backend/jvm/BCodeHelpers.scala +++ b/tests/pos-with-compiler-cc/backend/jvm/BCodeHelpers.scala @@ -374,7 +374,7 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters { } case Ident(nme.WILDCARD) => // An underscore argument indicates that we want to use the default value for this parameter, so do not emit anything - case t: tpd.RefTree if t.symbol.owner.linkedClass.isAllOf(JavaEnumTrait) => + case t: tpd.RefTree if t.symbol.owner.linkedClass.isAllOf(JavaEnum) => val edesc = innerClasesStore.typeDescriptor(t.tpe) // the class descriptor of the enumeration class. val evalue = t.symbol.javaSimpleName // value the actual enumeration value. av.visitEnum(name, edesc, evalue) diff --git a/tests/pos-with-compiler-cc/backend/jvm/BTypesFromSymbols.scala b/tests/pos-with-compiler-cc/backend/jvm/BTypesFromSymbols.scala index 54dafe6f0032..d78008d65cc6 100644 --- a/tests/pos-with-compiler-cc/backend/jvm/BTypesFromSymbols.scala +++ b/tests/pos-with-compiler-cc/backend/jvm/BTypesFromSymbols.scala @@ -330,7 +330,7 @@ class BTypesFromSymbols[I <: DottyBackendInterface](val int: I) extends BTypes { .addFlagIf(sym.is(Bridge), ACC_BRIDGE | ACC_SYNTHETIC) .addFlagIf(sym.is(Artifact), ACC_SYNTHETIC) .addFlagIf(sym.isClass && !sym.isInterface, ACC_SUPER) - .addFlagIf(sym.isAllOf(JavaEnumTrait), ACC_ENUM) + .addFlagIf(sym.isAllOf(JavaEnum), ACC_ENUM) .addFlagIf(sym.is(JavaVarargs), ACC_VARARGS) .addFlagIf(sym.is(Synchronized), ACC_SYNCHRONIZED) .addFlagIf(sym.isDeprecated, ACC_DEPRECATED)