diff options
author | Felix Mulder <felix.mulder@gmail.com> | 2016-11-02 11:08:28 +0100 |
---|---|---|
committer | Guillaume Martres <smarter@ubuntu.com> | 2016-11-22 01:35:07 +0100 |
commit | 8a61ff432543a29234193cd1f7c14abd3f3d31a0 (patch) | |
tree | a8147561d307af862c295cfc8100d271063bb0dd /compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala | |
parent | 6a455fe6da5ff9c741d91279a2dc6fe2fb1b472f (diff) | |
download | dotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.tar.gz dotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.tar.bz2 dotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.zip |
Move compiler and compiler tests to compiler dir
Diffstat (limited to 'compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala')
-rw-r--r-- | compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala | 1102 |
1 files changed, 1102 insertions, 0 deletions
diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala new file mode 100644 index 000000000..a7c449947 --- /dev/null +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -0,0 +1,1102 @@ +package dotty.tools.backend.jvm + +import dotty.tools.dotc.ast.tpd +import dotty.tools.dotc +import dotty.tools.dotc.backend.jvm.DottyPrimitives +import dotty.tools.dotc.core.Flags.FlagSet +import dotty.tools.dotc.transform.Erasure +import dotty.tools.dotc.transform.SymUtils._ +import java.io.{File => JFile} + +import scala.collection.generic.Clearable +import scala.collection.mutable +import scala.reflect.ClassTag +import scala.reflect.internal.util.WeakHashSet +import scala.reflect.io.{AbstractFile, Directory, PlainDirectory} +import scala.tools.asm.{AnnotationVisitor, ClassVisitor, FieldVisitor, MethodVisitor} +import scala.tools.nsc.backend.jvm.{BCodeHelpers, BackendInterface} +import dotty.tools.dotc.core._ +import Periods._ +import SymDenotations._ +import Contexts._ +import Types._ +import Symbols._ +import Denotations._ +import Phases._ +import java.lang.AssertionError + +import dotty.tools.dotc.util.{DotClass, Positions} +import Decorators._ +import tpd._ + +import scala.tools.asm +import NameOps._ +import StdNames.nme +import NameOps._ +import dotty.tools.dotc.core +import dotty.tools.dotc.core.Names.TypeName + +import scala.annotation.tailrec + +class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Map[Symbol, Set[ClassSymbol]])(implicit ctx: Context) extends BackendInterface{ + type Symbol = Symbols.Symbol + type Type = Types.Type + type Tree = tpd.Tree + type CompilationUnit = dotc.CompilationUnit + type Constant = Constants.Constant + type Literal = tpd.Literal + type Position = Positions.Position + type Name = Names.Name + type ClassDef = tpd.TypeDef + type TypeDef = tpd.TypeDef + type Apply = tpd.Apply + type TypeApply = tpd.TypeApply + type Try = tpd.Try + type Assign = tpd.Assign + type Ident = tpd.Ident + type If = tpd.If + type ValDef = tpd.ValDef + type Throw = tpd.Apply + type Return = tpd.Return + type Block = tpd.Block + type Typed = tpd.Typed + type Match = tpd.Match + type This = tpd.This + type CaseDef = tpd.CaseDef + type Alternative = tpd.Alternative + type DefDef = tpd.DefDef + type Template = tpd.Template + type Select = tpd.Tree // Actually tpd.Select || tpd.Ident + type Bind = tpd.Bind + type New = tpd.New + type Super = tpd.Super + type Modifiers = Null + type Annotation = Annotations.Annotation + type ArrayValue = tpd.JavaSeqLiteral + type ApplyDynamic = Null + type ModuleDef = Null + type LabelDef = tpd.DefDef + type Closure = tpd.Closure + + val NoSymbol = Symbols.NoSymbol + val NoPosition: Position = Positions.NoPosition + val EmptyTree: Tree = tpd.EmptyTree + + + val UnitTag: ConstantTag = Constants.UnitTag + val IntTag: ConstantTag = Constants.IntTag + val FloatTag: ConstantTag = Constants.FloatTag + val NullTag: ConstantTag = Constants.NullTag + val BooleanTag: ConstantTag = Constants.BooleanTag + val ByteTag: ConstantTag = Constants.ByteTag + val ShortTag: ConstantTag = Constants.ShortTag + val CharTag: ConstantTag = Constants.CharTag + val DoubleTag: ConstantTag = Constants.DoubleTag + val LongTag: ConstantTag = Constants.LongTag + val StringTag: ConstantTag = Constants.StringTag + val ClazzTag: ConstantTag = Constants.ClazzTag + val EnumTag: ConstantTag = Constants.EnumTag + + val nme_This: Name = StdNames.nme.This + val nme_EMPTY_PACKAGE_NAME: Name = StdNames.nme.EMPTY_PACKAGE + val nme_CONSTRUCTOR: Name = StdNames.nme.CONSTRUCTOR + val nme_WILDCARD: Name = StdNames.nme.WILDCARD + val nme_THIS: Name = StdNames.nme.THIS + val nme_PACKAGE: Name = StdNames.nme.PACKAGE + val nme_EQEQ_LOCAL_VAR: Name = StdNames.nme.EQEQ_LOCAL_VAR + + // require LambdaMetafactory: scalac uses getClassIfDefined, but we need those always. + override lazy val LambdaMetaFactory = ctx.requiredClass("java.lang.invoke.LambdaMetafactory") + override lazy val MethodHandle = ctx.requiredClass("java.lang.invoke.MethodHandle") + + val nme_valueOf: Name = StdNames.nme.valueOf + val nme_apply = StdNames.nme.apply + val NothingClass: Symbol = defn.NothingClass + val NullClass: Symbol = defn.NullClass + val ObjectClass: Symbol = defn.ObjectClass + val Object_Type: Type = defn.ObjectType + val Throwable_Type: Type = defn.ThrowableType + val Object_isInstanceOf: Symbol = defn.Any_isInstanceOf + val Object_asInstanceOf: Symbol = defn.Any_asInstanceOf + val Object_equals: Symbol = defn.Any_equals + val ArrayClass: Symbol = defn.ArrayClass + val UnitClass: Symbol = defn.UnitClass + val BooleanClass: Symbol = defn.BooleanClass + val CharClass: Symbol = defn.CharClass + val ShortClass: Symbol = defn.ShortClass + val ClassClass: Symbol = defn.ClassClass + val ByteClass: Symbol = defn.ByteClass + val IntClass: Symbol = defn.IntClass + val LongClass: Symbol = defn.LongClass + val FloatClass: Symbol = defn.FloatClass + val DoubleClass: Symbol = defn.DoubleClass + def isArrayClone(tree: Tree) = tree match { + case Select(qual, StdNames.nme.clone_) if qual.tpe.widen.isInstanceOf[JavaArrayType] => true + case _ => false + } + + val hashMethodSym: Symbol = NoSymbol // used to dispatch ## on primitives to ScalaRuntime.hash. Should be implemented by a miniphase + val externalEqualsNumNum: Symbol = defn.BoxesRunTimeModule.requiredMethod(nme.equalsNumNum) + val externalEqualsNumChar: Symbol = NoSymbol // ctx.requiredMethod(BoxesRunTimeTypeRef, nme.equalsNumChar) // this method is private + val externalEqualsNumObject: Symbol = defn.BoxesRunTimeModule.requiredMethod(nme.equalsNumObject) + val externalEquals: Symbol = defn.BoxesRunTimeClass.info.decl(nme.equals_).suchThat(toDenot(_).info.firstParamTypes.size == 2).symbol + val MaxFunctionArity: Int = Definitions.MaxFunctionArity + val FunctionClass: Array[Symbol] = defn.FunctionClassPerRun() + val AbstractFunctionClass: Array[Symbol] = defn.AbstractFunctionClassPerRun() + val PartialFunctionClass: Symbol = defn.PartialFunctionClass + val AbstractPartialFunctionClass: Symbol = defn.AbstractPartialFunctionClass + val String_valueOf: Symbol = defn.String_valueOf_Object + lazy val Predef_classOf: Symbol = defn.ScalaPredefModule.requiredMethod(nme.classOf) + + lazy val AnnotationRetentionAttr = ctx.requiredClass("java.lang.annotation.Retention") + lazy val AnnotationRetentionSourceAttr = ctx.requiredClass("java.lang.annotation.RetentionPolicy").linkedClass.requiredValue("SOURCE") + lazy val AnnotationRetentionClassAttr = ctx.requiredClass("java.lang.annotation.RetentionPolicy").linkedClass.requiredValue("CLASS") + lazy val AnnotationRetentionRuntimeAttr = ctx.requiredClass("java.lang.annotation.RetentionPolicy").linkedClass.requiredValue("RUNTIME") + lazy val JavaAnnotationClass = ctx.requiredClass("java.lang.annotation.Annotation") + + def boxMethods: Map[Symbol, Symbol] = defn.ScalaValueClasses().map{x => // @darkdimius Are you sure this should be a def? + (x, Erasure.Boxing.boxMethod(x.asClass)) + }.toMap + def unboxMethods: Map[Symbol, Symbol] = defn.ScalaValueClasses().map(x => (x, Erasure.Boxing.unboxMethod(x.asClass))).toMap + + override def isSyntheticArrayConstructor(s: Symbol) = { + s eq defn.newArrayMethod + } + + def isBox(sym: Symbol): Boolean = Erasure.Boxing.isBox(sym) + def isUnbox(sym: Symbol): Boolean = Erasure.Boxing.isUnbox(sym) + + val primitives: Primitives = new Primitives { + val primitives = new DottyPrimitives(ctx) + def getPrimitive(app: Apply, reciever: Type): Int = primitives.getPrimitive(app, reciever) + + def getPrimitive(sym: Symbol): Int = primitives.getPrimitive(sym) + + def isPrimitive(fun: Tree): Boolean = primitives.isPrimitive(fun) + } + implicit val TypeDefTag: ClassTag[TypeDef] = ClassTag[TypeDef](classOf[TypeDef]) + implicit val ApplyTag: ClassTag[Apply] = ClassTag[Apply](classOf[Apply]) + implicit val SelectTag: ClassTag[Select] = ClassTag[Select](classOf[Select]) + implicit val TypeApplyTag: ClassTag[TypeApply] = ClassTag[TypeApply](classOf[TypeApply]) + implicit val ClassDefTag: ClassTag[ClassDef] = ClassTag[TypeDef](classOf[TypeDef]) + implicit val TryTag: ClassTag[Try] = ClassTag[Try](classOf[Try]) + implicit val AssignTag: ClassTag[Assign] = ClassTag[Assign](classOf[Assign]) + implicit val IdentTag: ClassTag[Ident] = ClassTag[Ident](classOf[Ident]) + implicit val IfTag: ClassTag[If] = ClassTag[If](classOf[If]) + implicit val LabelDefTag: ClassTag[LabelDef] = ClassTag[LabelDef](classOf[LabelDef]) + implicit val ValDefTag: ClassTag[ValDef] = ClassTag[ValDef](classOf[ValDef]) + implicit val ThrowTag: ClassTag[Throw] = ClassTag[Throw](classOf[Throw]) + implicit val ReturnTag: ClassTag[Return] = ClassTag[Return](classOf[Return]) + implicit val LiteralTag: ClassTag[Literal] = ClassTag[Literal](classOf[Literal]) + implicit val BlockTag: ClassTag[Block] = ClassTag[Block](classOf[Block]) + implicit val TypedTag: ClassTag[Typed] = ClassTag[Typed](classOf[Typed]) + implicit val ArrayValueTag: ClassTag[ArrayValue] = ClassTag[ArrayValue](classOf[ArrayValue]) + implicit val MatchTag: ClassTag[Match] = ClassTag[Match](classOf[Match]) + implicit val CaseDefTag: ClassTag[CaseDef] = ClassTag[CaseDef](classOf[CaseDef]) + implicit val ThisTag: ClassTag[This] = ClassTag[This](classOf[This]) + implicit val AlternativeTag: ClassTag[Alternative] = ClassTag[Alternative](classOf[Alternative]) + implicit val DefDefTag: ClassTag[DefDef] = ClassTag[DefDef](classOf[DefDef]) + implicit val ModuleDefTag: ClassTag[ModuleDef] = ClassTag[ModuleDef](classOf[ModuleDef]) + implicit val NameTag: ClassTag[Name] = ClassTag[Name](classOf[Name]) + implicit val TemplateTag: ClassTag[Template] = ClassTag[Template](classOf[Template]) + implicit val BindTag: ClassTag[Bind] = ClassTag[Bind](classOf[Bind]) + implicit val NewTag: ClassTag[New] = ClassTag[New](classOf[New]) + implicit val ApplyDynamicTag: ClassTag[ApplyDynamic] = ClassTag[ApplyDynamic](classOf[ApplyDynamic]) + implicit val SuperTag: ClassTag[Super] = ClassTag[Super](classOf[Super]) + implicit val ConstantClassTag: ClassTag[Constant] = ClassTag[Constant](classOf[Constant]) + implicit val ClosureTag: ClassTag[Closure] = ClassTag[Closure](classOf[Closure]) + + /* dont emit any annotations for now*/ + def isRuntimeVisible(annot: Annotation): Boolean = { + annot.atp.typeSymbol.getAnnotation(AnnotationRetentionAttr) match { + case Some(retentionAnnot) => + retentionAnnot.tree.find(_.symbol == AnnotationRetentionRuntimeAttr).isDefined + case _ => + // SI-8926: if the annotation class symbol doesn't have a @RetentionPolicy annotation, the + // annotation is emitted with visibility `RUNTIME` + // dotty bug: #389 + true + } + } + + def shouldEmitAnnotation(annot: Annotation): Boolean = { + annot.symbol.isJavaDefined && + retentionPolicyOf(annot) != AnnotationRetentionSourceAttr && + annot.args.isEmpty + } + + private def retentionPolicyOf(annot: Annotation): Symbol = + annot.atp.typeSymbol.getAnnotation(AnnotationRetentionAttr). + flatMap(_.argument(0).map(_.symbol)).getOrElse(AnnotationRetentionClassAttr) + + private def emitArgument(av: AnnotationVisitor, + name: String, + arg: Tree, bcodeStore: BCodeHelpers)(innerClasesStore: bcodeStore.BCInnerClassGen): Unit = { + (arg: @unchecked) match { + + case Literal(const @ Constant(_)) => + const.tag match { + case BooleanTag | ByteTag | ShortTag | CharTag | IntTag | LongTag | FloatTag | DoubleTag => av.visit(name, const.value) + case StringTag => + assert(const.value != null, const) // TODO this invariant isn't documented in `case class Constant` + av.visit(name, const.stringValue) // `stringValue` special-cases null, but that execution path isn't exercised for a const with StringTag + case ClazzTag => av.visit(name, const.typeValue.toTypeKind(bcodeStore)(innerClasesStore).toASMType) + case EnumTag => + val edesc = innerClasesStore.typeDescriptor(const.tpe.asInstanceOf[bcodeStore.int.Type]) // the class descriptor of the enumeration class. + val evalue = const.symbolValue.name.toString // value the actual enumeration value. + av.visitEnum(name, edesc, evalue) + } + case t: TypeApply if (t.fun.symbol == Predef_classOf) => + av.visit(name, t.args.head.tpe.classSymbol.denot.info.toTypeKind(bcodeStore)(innerClasesStore).toASMType) + case t: tpd.Select => + if (t.symbol.denot.is(Flags.Enum)) { + val edesc = innerClasesStore.typeDescriptor(t.tpe.asInstanceOf[bcodeStore.int.Type]) // the class descriptor of the enumeration class. + val evalue = t.symbol.name.toString // value the actual enumeration value. + av.visitEnum(name, edesc, evalue) + } else { + assert(toDenot(t.symbol).name.toTermName.defaultGetterIndex >= 0) // this should be default getter. do not emmit. + } + case t: SeqLiteral => + val arrAnnotV: AnnotationVisitor = av.visitArray(name) + for(arg <- t.elems) { emitArgument(arrAnnotV, null, arg, bcodeStore)(innerClasesStore) } + arrAnnotV.visitEnd() + + case Apply(fun, args) if (fun.symbol == defn.ArrayClass.primaryConstructor || + (toDenot(fun.symbol).owner == defn.ArrayClass.linkedClass && fun.symbol.name == nme_apply)) => + val arrAnnotV: AnnotationVisitor = av.visitArray(name) + + var actualArgs = if (fun.tpe.isInstanceOf[ImplicitMethodType]) { + // generic array method, need to get implicit argument out of the way + fun.asInstanceOf[Apply].args + } else args + + val flatArgs = actualArgs.flatMap { + case t: tpd.SeqLiteral => t.elems + case e => List(e) + } + for(arg <- flatArgs) { emitArgument(arrAnnotV, null, arg, bcodeStore)(innerClasesStore) } + arrAnnotV.visitEnd() +/* + case sb @ ScalaSigBytes(bytes) => + // see http://www.scala-lang.org/sid/10 (Storage of pickled Scala signatures in class files) + // also JVMS Sec. 4.7.16.1 The element_value structure and JVMS Sec. 4.4.7 The CONSTANT_Utf8_info Structure. + if (sb.fitsInOneString) { + av.visit(name, BCodeAsmCommon.strEncode(sb)) + } else { + val arrAnnotV: asm.AnnotationVisitor = av.visitArray(name) + for(arg <- BCodeAsmCommon.arrEncode(sb)) { arrAnnotV.visit(name, arg) } + arrAnnotV.visitEnd() + } // for the lazy val in ScalaSigBytes to be GC'ed, the invoker of emitAnnotations() should hold the ScalaSigBytes in a method-local var that doesn't escape. +*/ + case t @ Apply(constr, args) if t.tpe.derivesFrom(JavaAnnotationClass) => + val typ = t.tpe.classSymbol.denot.info + val assocs = assocsFromApply(t) + val desc = innerClasesStore.typeDescriptor(typ.asInstanceOf[bcodeStore.int.Type]) // the class descriptor of the nested annotation class + val nestedVisitor = av.visitAnnotation(name, desc) + emitAssocs(nestedVisitor, assocs, bcodeStore)(innerClasesStore) + } + } + + override def emitAnnotations(cw: asm.ClassVisitor, annotations: List[Annotation], bcodeStore: BCodeHelpers) + (innerClasesStore: bcodeStore.BCInnerClassGen) = { + for(annot <- annotations; if shouldEmitAnnotation(annot)) { + val typ = annot.atp + val assocs = annot.assocs + val av = cw.visitAnnotation(innerClasesStore.typeDescriptor(typ.asInstanceOf[bcodeStore.int.Type]), isRuntimeVisible(annot)) + emitAssocs(av, assocs, bcodeStore)(innerClasesStore) + } + } + + private def emitAssocs(av: asm.AnnotationVisitor, assocs: List[(Name, Object)], bcodeStore: BCodeHelpers) + (innerClasesStore: bcodeStore.BCInnerClassGen) = { + for ((name, value) <- assocs) + emitArgument(av, name.toString, value.asInstanceOf[Tree], bcodeStore)(innerClasesStore) + av.visitEnd() + } + + override def emitAnnotations(mw: asm.MethodVisitor, annotations: List[Annotation], bcodeStore: BCodeHelpers) + (innerClasesStore: bcodeStore.BCInnerClassGen) = { + for(annot <- annotations; if shouldEmitAnnotation(annot)) { + val typ = annot.atp + val assocs = annot.assocs + val av = mw.visitAnnotation(innerClasesStore.typeDescriptor(typ.asInstanceOf[bcodeStore.int.Type]), isRuntimeVisible(annot)) + emitAssocs(av, assocs, bcodeStore)(innerClasesStore) + } + } + + override def emitAnnotations(fw: asm.FieldVisitor, annotations: List[Annotation], bcodeStore: BCodeHelpers) + (innerClasesStore: bcodeStore.BCInnerClassGen) = { + for(annot <- annotations; if shouldEmitAnnotation(annot)) { + val typ = annot.atp + val assocs = annot.assocs + val av = fw.visitAnnotation(innerClasesStore.typeDescriptor(typ.asInstanceOf[bcodeStore.int.Type]), isRuntimeVisible(annot)) + emitAssocs(av, assocs, bcodeStore)(innerClasesStore) + } + } + + override def emitParamAnnotations(jmethod: asm.MethodVisitor, pannotss: List[List[Annotation]], bcodeStore: BCodeHelpers) + (innerClasesStore: bcodeStore.BCInnerClassGen): Unit = { + val annotationss = pannotss map (_ filter shouldEmitAnnotation) + if (annotationss forall (_.isEmpty)) return + for ((annots, idx) <- annotationss.zipWithIndex; + annot <- annots) { + val typ = annot.atp + val assocs = annot.assocs + val pannVisitor: asm.AnnotationVisitor = jmethod.visitParameterAnnotation(idx, innerClasesStore.typeDescriptor(typ.asInstanceOf[bcodeStore.int.Type]), isRuntimeVisible(annot)) + emitAssocs(pannVisitor, assocs, bcodeStore)(innerClasesStore) + } + } + + def getAnnotPickle(jclassName: String, sym: Symbol): Option[Annotation] = None + + + def getRequiredClass(fullname: String): Symbol = ctx.requiredClass(fullname.toTermName) + + def getClassIfDefined(fullname: String): Symbol = NoSymbol // used only for android. todo: implement + + private def erasureString(clazz: Class[_]): String = { + if (clazz.isArray) "Array[" + erasureString(clazz.getComponentType) + "]" + else clazz.getName + } + + def requiredClass[T](implicit evidence: ClassTag[T]): Symbol = { + ctx.requiredClass(erasureString(evidence.runtimeClass).toTermName) + } + + def requiredModule[T](implicit evidence: ClassTag[T]): Symbol = { + val moduleName = erasureString(evidence.runtimeClass) + val className = if (moduleName.endsWith("$")) moduleName.dropRight(1) else moduleName + ctx.requiredModule(className.toTermName) + } + + + def debuglog(msg: => String): Unit = ctx.debuglog(msg) + def informProgress(msg: String): Unit = ctx.informProgress(msg) + def log(msg: => String): Unit = ctx.log(msg) + def error(pos: Position, msg: String): Unit = ctx.error(msg, pos) + def warning(pos: Position, msg: String): Unit = ctx.warning(msg, pos) + def abort(msg: String): Nothing = { + ctx.error(msg) + throw new RuntimeException(msg) + } + + def emitAsmp: Option[String] = None + + def shouldEmitJumpAfterLabels = true + + def dumpClasses: Option[String] = + if (ctx.settings.Ydumpclasses.isDefault) None + else Some(ctx.settings.Ydumpclasses.value) + + def mainClass: Option[String] = + if (ctx.settings.mainClass.isDefault) None + else Some(ctx.settings.mainClass.value) + def setMainClass(name: String): Unit = ctx.settings.mainClass.update(name) + + + def noForwarders: Boolean = ctx.settings.noForwarders.value + def debuglevel: Int = 3 // 0 -> no debug info; 1-> filename; 2-> lines; 3-> varnames + def settings_debug: Boolean = ctx.settings.debug.value + def targetPlatform: String = ctx.settings.target.value + + val perRunCaches: Caches = new Caches { + def newAnyRefMap[K <: AnyRef, V](): mutable.AnyRefMap[K, V] = new mutable.AnyRefMap[K, V]() + def newWeakMap[K, V](): mutable.WeakHashMap[K, V] = new mutable.WeakHashMap[K, V]() + def recordCache[T <: Clearable](cache: T): T = cache + def newWeakSet[K <: AnyRef](): WeakHashSet[K] = new WeakHashSet[K]() + def newMap[K, V](): mutable.HashMap[K, V] = new mutable.HashMap[K, V]() + def newSet[K](): mutable.Set[K] = new mutable.HashSet[K] + } + + + + val MODULE_INSTANCE_FIELD: String = nme.MODULE_INSTANCE_FIELD.toString + + def internalNameString(offset: Int, length: Int): String = new String(Names.chrs, offset, length) + + def newTermName(prefix: String): Name = prefix.toTermName + + val Flag_SYNTHETIC: Flags = Flags.Synthetic.bits + val Flag_METHOD: Flags = Flags.Method.bits + val ExcludedForwarderFlags: Flags = { + Flags.Specialized | Flags.Lifted | Flags.Protected | Flags.JavaStatic | + Flags.ExpandedName | Flags.Bridge | Flags.VBridge | Flags.Private | Flags.Macro + }.bits + + + def isQualifierSafeToElide(qual: Tree): Boolean = tpd.isIdempotentExpr(qual) + def desugarIdent(i: Ident): Option[tpd.Select] = { + i.tpe match { + case TermRef(prefix: TermRef, name) => + Some(tpd.ref(prefix).select(i.symbol)) + case TermRef(prefix: ThisType, name) => + Some(tpd.This(prefix.cls).select(i.symbol)) + case TermRef(NoPrefix, name) => + if (i.symbol is Flags.Method) Some(This(i.symbol.topLevelClass).select(i.symbol)) // workaround #342 todo: remove after fixed + else None + case _ => None + } + } + def getLabelDefOwners(tree: Tree): Map[Tree, List[LabelDef]] = { + // for each rhs of a defdef returns LabelDefs inside this DefDef + val res = new collection.mutable.HashMap[Tree, List[LabelDef]]() + + val t = new TreeTraverser { + var outerRhs: Tree = tree + + def traverse(tree: tpd.Tree)(implicit ctx: Context): Unit = tree match { + case t: DefDef => + if (t.symbol is Flags.Label) + res.put(outerRhs, t :: res.getOrElse(outerRhs, Nil)) + else outerRhs = t + traverseChildren(t) + case _ => traverseChildren(tree) + } + } + + t.traverse(tree) + res.toMap + } + + // todo: remove + def isMaybeBoxed(sym: Symbol) = { + (sym == ObjectClass) || + (sym == JavaSerializableClass) || + (sym == defn.ComparableClass) || + (sym derivesFrom BoxedNumberClass) || + (sym derivesFrom BoxedCharacterClass) || + (sym derivesFrom BoxedBooleanClass) + } + + def getSingleOutput: Option[AbstractFile] = None // todo: implement + + + def getGenericSignature(sym: Symbol, owner: Symbol): String = null // todo: implement + + def getStaticForwarderGenericSignature(sym: Symbol, moduleClass: Symbol): String = null // todo: implement + + + def sourceFileFor(cu: CompilationUnit): String = cu.source.file.name + + + + implicit def positionHelper(a: Position): PositionHelper = new PositionHelper { + def isDefined: Boolean = a.exists + def line: Int = sourcePos(a).line + 1 + def finalPosition: Position = a + } + + implicit def constantHelper(a: Constant): ConstantHelper = new ConstantHelper { + def booleanValue: Boolean = a.booleanValue + def longValue: Long = a.longValue + def byteValue: Byte = a.byteValue + def stringValue: String = a.stringValue + def symbolValue: Symbol = a.symbolValue + def floatValue: Float = a.floatValue + def value: Any = a.value + def tag: ConstantTag = a.tag + def typeValue: Type = a.typeValue + def shortValue: Short = a.shortValue + def intValue: Int = a.intValue + def doubleValue: Double = a.doubleValue + def charValue: Char = a.charValue + } + + + implicit def treeHelper(a: Tree): TreeHelper = new TreeHelper { + def symbol: Symbol = a.symbol + + def pos: Position = a.pos + + def isEmpty: Boolean = a.isEmpty + + def tpe: Type = a.tpe + + def exists(pred: (Tree) => Boolean): Boolean = a.find(pred).isDefined + } + + + implicit def annotHelper(a: Annotation): AnnotationHelper = new AnnotationHelper { + def atp: Type = a.tree.tpe + + def assocs: List[(Name, Tree)] = assocsFromApply(a.tree) + + def symbol: Symbol = a.tree.symbol + + def args: List[Tree] = List.empty // those arguments to scala-defined annotations. they are never emmited + } + + def assocsFromApply(tree: Tree) = { + tree match { + case Apply(fun, args) => + fun.tpe.widen match { + case MethodType(names, _) => + names zip args + } + } + } + + + implicit def nameHelper(n: Name): NameHelper = new NameHelper { + def toTypeName: Name = n.toTypeName + def isTypeName: Boolean = n.isTypeName + def toTermName: Name = n.toTermName + def dropModule: Name = n.stripModuleClassSuffix + + def len: Int = n.length + def offset: Int = n.start + def isTermName: Boolean = n.isTermName + def startsWith(s: String): Boolean = n.startsWith(s) + } + + + implicit def symHelper(sym: Symbol): SymbolHelper = new SymbolHelper { + // names + def fullName(sep: Char): String = sym.showFullName + def fullName: String = sym.showFullName + def simpleName: Name = sym.name + def javaSimpleName: Name = toDenot(sym).name // addModuleSuffix(simpleName.dropLocal) + def javaBinaryName: Name = toDenot(sym).fullNameSeparated("/") // addModuleSuffix(fullNameInternal('/')) + def javaClassName: String = toDenot(sym).fullName.toString// addModuleSuffix(fullNameInternal('.')).toString + def name: Name = sym.name + def rawname: Name = sym.name // todo ???? + + // types + def info: Type = toDenot(sym).info + def tpe: Type = toDenot(sym).info // todo whats the differentce between tpe and info? + def thisType: Type = toDenot(sym).thisType + + // tests + def isClass: Boolean = { + sym.isPackageObject || (sym.isClass) + } + def isType: Boolean = sym.isType + def isAnonymousClass: Boolean = toDenot(sym).isAnonymousClass + def isConstructor: Boolean = toDenot(sym).isConstructor + def isAnonymousFunction: Boolean = toDenot(sym).isAnonymousFunction + def isMethod: Boolean = sym is Flags.Method + def isPublic: Boolean = sym.flags.is(Flags.EmptyFlags, Flags.Private | Flags.Protected) + def isSynthetic: Boolean = sym is Flags.Synthetic + def isPackageClass: Boolean = sym is Flags.PackageClass + def isModuleClass: Boolean = sym is Flags.ModuleClass + def isModule: Boolean = sym is Flags.Module + def isStrictFP: Boolean = false // todo: implement + def isLabel: Boolean = sym is Flags.Label + def hasPackageFlag: Boolean = sym is Flags.Package + def isImplClass: Boolean = sym is Flags.ImplClass + def isInterface: Boolean = (sym is Flags.PureInterface) || (sym is Flags.Trait) + def hasGetter: Boolean = false // used only for generaration of beaninfo todo: implement + def isGetter: Boolean = toDenot(sym).isGetter + def isSetter: Boolean = toDenot(sym).isSetter + def isGetClass: Boolean = sym eq defn.Any_getClass + def isJavaDefined: Boolean = sym is Flags.JavaDefined + def isJavaDefaultMethod: Boolean = !((sym is Flags.Deferred) || toDenot(sym).isClassConstructor) + def isDeferred: Boolean = sym is Flags.Deferred + def isPrivate: Boolean = sym is Flags.Private + def getsJavaFinalFlag: Boolean = + isFinal && !toDenot(sym).isClassConstructor && !(sym is Flags.Mutable) && !(sym.enclosingClass is Flags.Trait) + + def getsJavaPrivateFlag: Boolean = + isPrivate //|| (sym.isPrimaryConstructor && sym.owner.isTopLevelModuleClass) + + def isFinal: Boolean = sym is Flags.Final + def isStaticMember: Boolean = (sym ne NoSymbol) && + ((sym is Flags.JavaStatic) || (owner is Flags.ImplClass) || toDenot(sym).hasAnnotation(ctx.definitions.ScalaStaticAnnot)) + // guard against no sumbol cause this code is executed to select which call type(static\dynamic) to use to call array.clone + + def isBottomClass: Boolean = (sym ne defn.NullClass) && (sym ne defn.NothingClass) + def isBridge: Boolean = sym is Flags.Bridge + def isArtifact: Boolean = sym is Flags.Artifact + def hasEnumFlag: Boolean = sym is Flags.Enum + def hasAccessBoundary: Boolean = sym.accessBoundary(defn.RootClass) ne defn.RootClass + def isVarargsMethod: Boolean = sym is Flags.JavaVarargs + def isDeprecated: Boolean = false + def isMutable: Boolean = sym is Flags.Mutable + def hasAbstractFlag: Boolean = + (sym is Flags.Abstract) || (sym is Flags.JavaInterface) || (sym is Flags.Trait) + def hasModuleFlag: Boolean = sym is Flags.Module + def isSynchronized: Boolean = sym is Flags.Synchronized + def isNonBottomSubClass(other: Symbol): Boolean = sym.derivesFrom(other) + def hasAnnotation(ann: Symbol): Boolean = toDenot(sym).hasAnnotation(ann) + def shouldEmitForwarders: Boolean = + (sym is Flags.Module) && !(sym is Flags.ImplClass) && sym.isStatic + def isJavaEntryPoint: Boolean = CollectEntryPoints.isJavaEntryPoint(sym) + + def isClassConstructor: Boolean = toDenot(sym).isClassConstructor + + /** + * True for module classes of modules that are top-level or owned only by objects. Module classes + * for such objects will get a MODULE$ flag and a corresponding static initializer. + */ + def isStaticModuleClass: Boolean = + (sym is Flags.Module) && { + // scalac uses atPickling here + // this would not work if modules are created after pickling + // for example by specialization + val original = toDenot(sym).initial + val validity = original.validFor + val shiftedContext = ctx.withPhase(validity.phaseId) + toDenot(sym)(shiftedContext).isStatic(shiftedContext) + } + + def isStaticConstructor: Boolean = (isStaticMember && isClassConstructor) || (sym.name eq core.Names.STATIC_CONSTRUCTOR) + + + // navigation + def owner: Symbol = toDenot(sym).owner + def rawowner: Symbol = { + originalOwner + } + def originalOwner: Symbol = + // used to populate the EnclosingMethod attribute. + // it is very tricky in presence of classes(and annonymous classes) defined inside supper calls. + if (sym.exists) { + val original = toDenot(sym).initial + val validity = original.validFor + val shiftedContext = ctx.withPhase(validity.phaseId) + val r = toDenot(sym)(shiftedContext).maybeOwner.lexicallyEnclosingClass(shiftedContext) + r + } else NoSymbol + def parentSymbols: List[Symbol] = toDenot(sym).info.parents.map(_.typeSymbol) + def superClass: Symbol = { + val t = toDenot(sym).asClass.superClass + if (t.exists) t + else if (sym is Flags.ModuleClass) { + // workaround #371 + + println(s"Warning: mocking up superclass for $sym") + ObjectClass + } + else t + } + def enclClass: Symbol = toDenot(sym).enclosingClass + def linkedClassOfClass: Symbol = linkedClass + def linkedClass: Symbol = { + toDenot(sym)(ctx).linkedClass(ctx) + } //exitingPickler(sym.linkedClassOfClass) + def companionClass: Symbol = toDenot(sym).companionClass + def companionModule: Symbol = toDenot(sym).companionModule + def companionSymbol: Symbol = if (sym is Flags.Module) companionClass else companionModule + def moduleClass: Symbol = toDenot(sym).moduleClass + def enclosingClassSym: Symbol = { + if (this.isClass) { + val ct = ctx.withPhase(ctx.flattenPhase.prev) + toDenot(sym)(ct).owner.enclosingClass(ct) + } + else sym.enclosingClass(ctx.withPhase(ctx.flattenPhase.prev)) + } //todo is handled specially for JavaDefined symbols in scalac + + + + // members + def primaryConstructor: Symbol = toDenot(sym).primaryConstructor + + /** For currently compiled classes: All locally defined classes including local classes. + * The empty list for classes that are not currently compiled. + */ + def nestedClasses: List[Symbol] = definedClasses(ctx.flattenPhase) + + /** For currently compiled classes: All classes that are declared as members of this class + * (but not inherited ones). The empty list for classes that are not currently compiled. + */ + def memberClasses: List[Symbol] = definedClasses(ctx.lambdaLiftPhase) + + private def definedClasses(phase: Phase) = + if (sym.isDefinedInCurrentRun) + ctx.atPhase(phase) { implicit ctx => + toDenot(sym).info.decls.filter(_.isClass).toList + } + else Nil + + def annotations: List[Annotation] = Nil + def companionModuleMembers: List[Symbol] = { + // phase travel to exitingPickler: this makes sure that memberClassesOf only sees member classes, + // not local classes of the companion module (E in the exmaple) that were lifted by lambdalift. + if (linkedClass.isTopLevelModuleClass) /*exitingPickler*/ linkedClass.memberClasses + else Nil + } + def fieldSymbols: List[Symbol] = { + toDenot(sym).info.decls.filter(p => p.isTerm && !p.is(Flags.Method)).toList + } + def methodSymbols: List[Symbol] = + for (f <- toDenot(sym).info.decls.toList if f.isMethod && f.isTerm && !f.isModule) yield f + def serialVUID: Option[Long] = None + + + def freshLocal(cunit: CompilationUnit, name: String, tpe: Type, pos: Position, flags: Flags): Symbol = { + ctx.newSymbol(sym, name.toTermName, FlagSet(flags), tpe, NoSymbol, pos) + } + + def getter(clz: Symbol): Symbol = decorateSymbol(sym).getter + def setter(clz: Symbol): Symbol = decorateSymbol(sym).setter + + def moduleSuffix: String = "" // todo: validate that names already have $ suffix + def outputDirectory: AbstractFile = DottyBackendInterface.this.outputDirectory + def pos: Position = sym.pos + + def throwsAnnotations: List[Symbol] = Nil + + /** + * All interfaces implemented by a class, except for those inherited through the superclass. + * Redundant interfaces are removed unless there is a super call to them. + */ + def superInterfaces: List[Symbol] = { + val directlyInheritedTraits = decorateSymbol(sym).directlyInheritedTraits + val directlyInheritedTraitsSet = directlyInheritedTraits.toSet + val allBaseClasses = directlyInheritedTraits.iterator.flatMap(_.symbol.asClass.baseClasses.drop(1)).toSet + val superCalls = superCallsMap.getOrElse(sym, Set.empty) + val additional = (superCalls -- directlyInheritedTraitsSet).filter(_.is(Flags.Trait)) +// if (additional.nonEmpty) +// println(s"$fullName: adding supertraits $additional") + directlyInheritedTraits.filter(t => !allBaseClasses(t) || superCalls(t)) ++ additional + } + + /** + * True for module classes of package level objects. The backend will generate a mirror class for + * such objects. + */ + def isTopLevelModuleClass: Boolean = sym.isModuleClass && sym.isStatic + + /** + * This is basically a re-implementation of sym.isStaticOwner, but using the originalOwner chain. + * + * The problem is that we are interested in a source-level property. Various phases changed the + * symbol's properties in the meantime, mostly lambdalift modified (destructively) the owner. + * Therefore, `sym.isStatic` is not what we want. For example, in + * object T { def f { object U } } + * the owner of U is T, so UModuleClass.isStatic is true. Phase travel does not help here. + */ + def isOriginallyStaticOwner: Boolean = sym.isStatic + + + def addRemoteRemoteExceptionAnnotation: Unit = () + + def samMethod(): Symbol = + toDenot(sym).info.abstractTermMembers.headOption.getOrElse(toDenot(sym).info.member(nme.apply)).symbol + } + + + implicit def typeHelper(tp: Type): TypeHelper = new TypeHelper { + def member(string: Name): Symbol = tp.member(string.toTermName).symbol + + def isFinalType: Boolean = tp.typeSymbol is Flags.Final //in scalac checks for type parameters. Why? Aren't they gone by backend? + + def underlying: Type = tp match { + case t: TypeProxy => t.underlying + case _ => tp + } + + def paramTypes: List[Type] = tp.firstParamTypes + + def <:<(other: Type): Boolean = tp <:< other + + def memberInfo(s: Symbol): Type = tp.memberInfo(s) + + def decls: List[Symbol] = tp.decls.map(_.symbol).toList + + def members: List[Symbol] = + tp.memberDenots(takeAllFilter, (name, buf) => buf ++= tp.member(name).alternatives).map(_.symbol).toList + + def typeSymbol: Symbol = tp.widenDealias.typeSymbol + + def =:=(other: Type): Boolean = tp =:= other + + def membersBasedOnFlags(excludedFlags: Flags, requiredFlags: Flags): List[Symbol] = + tp.membersBasedOnFlags(FlagSet(requiredFlags), FlagSet(excludedFlags)).map(_.symbol).toList + + def resultType: Type = tp.resultType + + def toTypeKind(ct: BCodeHelpers)(storage: ct.BCInnerClassGen): ct.bTypes.BType = { + import ct.bTypes._ + val defn = ctx.definitions + import coreBTypes._ + import Types._ + /** + * Primitive types are represented as TypeRefs to the class symbol of, for example, scala.Int. + * The `primitiveTypeMap` maps those class symbols to the corresponding PrimitiveBType. + */ + def primitiveOrClassToBType(sym: Symbol): BType = { + assert(sym.isClass, sym) + assert(sym != ArrayClass || isCompilingArray, sym) + primitiveTypeMap.getOrElse(sym.asInstanceOf[ct.bTypes.coreBTypes.bTypes.int.Symbol], + storage.getClassBTypeAndRegisterInnerClass(sym.asInstanceOf[ct.int.Symbol])).asInstanceOf[BType] + } + + /** + * When compiling Array.scala, the type parameter T is not erased and shows up in method + * signatures, e.g. `def apply(i: Int): T`. A TyperRef to T is replaced by ObjectReference. + */ + def nonClassTypeRefToBType(sym: Symbol): ClassBType = { + assert(sym.isType && isCompilingArray, sym) + ObjectReference.asInstanceOf[ct.bTypes.ClassBType] + } + + tp.widenDealias match { + case JavaArrayType(el) =>ArrayBType(el.toTypeKind(ct)(storage)) // Array type such as Array[Int] (kept by erasure) + case t: TypeRef => + t.info match { + + case _ => + if (!t.symbol.isClass) nonClassTypeRefToBType(t.symbol) // See comment on nonClassTypeRefToBType + else primitiveOrClassToBType(t.symbol) // Common reference to a type such as scala.Int or java.lang.String + } + case Types.ClassInfo(_, sym, _, _, _) => primitiveOrClassToBType(sym) // We get here, for example, for genLoadModule, which invokes toTypeKind(moduleClassSymbol.info) + + case t: MethodType => // triggers for LabelDefs + t.resultType.toTypeKind(ct)(storage) + + /* AnnotatedType should (probably) be eliminated by erasure. However we know it happens for + * meta-annotated annotations (@(ann @getter) val x = 0), so we don't emit a warning. + * The type in the AnnotationInfo is an AnnotatedTpe. Tested in jvm/annotations.scala. + */ + case a @ AnnotatedType(t, _) => + debuglog(s"typeKind of annotated type $a") + t.toTypeKind(ct)(storage) + + /* ExistentialType should (probably) be eliminated by erasure. We know they get here for + * classOf constants: + * class C[T] + * class T { final val k = classOf[C[_]] } + */ + /* case e @ ExistentialType(_, t) => + debuglog(s"typeKind of existential type $e") + t.toTypeKind(ctx)(storage)*/ + + /* The cases below should probably never occur. They are kept for now to avoid introducing + * new compiler crashes, but we added a warning. The compiler / library bootstrap and the + * test suite don't produce any warning. + */ + + case tp => + ctx.warning( + s"an unexpected type representation reached the compiler backend while compiling $currentUnit: $tp. " + + "If possible, please file a bug on issues.scala-lang.org.") + + tp match { + case tp: ThisType if tp.cls == ArrayClass => ObjectReference.asInstanceOf[ct.bTypes.ClassBType] // was introduced in 9b17332f11 to fix SI-999, but this code is not reached in its test, or any other test + case tp: ThisType => storage.getClassBTypeAndRegisterInnerClass(tp.cls.asInstanceOf[ct.int.Symbol]) + // case t: SingletonType => primitiveOrClassToBType(t.classSymbol) + case t: SingletonType => t.underlying.toTypeKind(ct)(storage) + case t: RefinedType => t.parent.toTypeKind(ct)(storage) //parents.map(_.toTypeKind(ct)(storage).asClassBType).reduceLeft((a, b) => a.jvmWiseLUB(b)) + } + } + } + + def summaryString: String = tp.showSummary + + def params: List[Symbol] = + Nil // backend uses this to emmit annotations on parameter lists of forwarders + // to static methods of companion class + // in Dotty this link does not exists: there is no way to get from method type + // to inner symbols of DefDef + // todo: somehow handle. + + def parents: List[Type] = tp.parents + } + + + + object Assign extends AssignDeconstructor { + def _1: Tree = field.lhs + def _2: Tree = field.rhs + } + + object Select extends SelectDeconstructor { + + var desugared: tpd.Select = null + + override def isEmpty: Boolean = + desugared eq null + + def _1: Tree = desugared.qualifier + + def _2: Name = desugared.name + + override def unapply(s: Select): this.type = { + s match { + case t: tpd.Select => desugared = t + case t: Ident => + desugarIdent(t) match { + case Some(t) => desugared = t + case None => desugared = null + } + case _ => desugared = null + } + + this + } + } + + object Apply extends ApplyDeconstructor { + def _1: Tree = field.fun + def _2: List[Tree] = field.args + } + + object If extends IfDeconstructor { + def _1: Tree = field.cond + def _2: Tree = field.thenp + def _3: Tree = field.elsep + } + + object ValDef extends ValDefDeconstructor { + def _1: Modifiers = null + def _2: Name = field.name + def _3: Tree = field.tpt + def _4: Tree = field.rhs + } + + object ApplyDynamic extends ApplyDynamicDeconstructor { + def _1: Tree = ??? + def _2: List[Tree] = ??? + } + + // todo: this product1s should also eventually become name-based pattn matching + object Literal extends LiteralDeconstructor { + def get = field.const + } + + object Throw extends ThrowDeconstructor { + def get = field.args.head + + override def unapply(s: Throw): DottyBackendInterface.this.Throw.type = { + if (s.fun.symbol eq defn.throwMethod) { + field = s + } else { + field = null + } + this + } + } + + object New extends NewDeconstructor { + def get = field.tpt.tpe + } + + object This extends ThisDeconstructor { + def get = field.qual.name + def apply(s: Symbol): This = tpd.This(s.asClass) + } + + object Return extends ReturnDeconstructor { + def get = field.expr + } + + object Ident extends IdentDeconstructor { + def get = field.name + } + + object Alternative extends AlternativeDeconstructor { + def get = field.trees + } + + object Constant extends ConstantDeconstructor { + def get = field.value + } + object ThrownException extends ThrownException { + def unapply(a: Annotation): Option[Symbol] = None // todo + } + + object Try extends TryDeconstructor { + def _1: Tree = field.expr + def _2: List[Tree] = field.cases + def _3: Tree = field.finalizer + } + + object LabelDef extends LabelDeconstructor { + def _1: Name = field.name + def _2: List[Symbol] = field.vparamss.flatMap(_.map(_.symbol)) + def _3: Tree = field.rhs + + override def unapply(s: LabelDef): DottyBackendInterface.this.LabelDef.type = { + if (s.symbol is Flags.Label) this.field = s + else this.field = null + this + } + } + + object Typed extends TypedDeconstrutor { + def _1: Tree = field.expr + def _2: Tree = field.tpt + } + object Super extends SuperDeconstructor { + def _1: Tree = field.qual + def _2: Name = field.mix.name + } + object ArrayValue extends ArrayValueDeconstructor { + def _1: Type = field.tpe match { + case JavaArrayType(elem) => elem + case _ => + ctx.error(s"JavaSeqArray with type ${field.tpe} reached backend: $field", field.pos) + ErrorType + } + def _2: List[Tree] = field.elems + } + object Match extends MatchDeconstructor { + def _1: Tree = field.selector + def _2: List[Tree] = field.cases + } + object Block extends BlockDeconstructor { + def _1: List[Tree] = field.stats + def _2: Tree = field.expr + } + object TypeApply extends TypeApplyDeconstructor { + def _1: Tree = field.fun + def _2: List[Tree] = field.args + } + object CaseDef extends CaseDeconstructor { + def _1: Tree = field.pat + def _2: Tree = field.guard + def _3: Tree = field.body + } + + object DefDef extends DefDefDeconstructor { + def _1: Modifiers = null + def _2: Name = field.name + def _3: List[TypeDef] = field.tparams + def _4: List[List[ValDef]] = field.vparamss + def _5: Tree = field.tpt + def _6: Tree = field.rhs + } + + object ModuleDef extends ModuleDefDeconstructor { + def _1: Modifiers = ??? + def _2: Name = ??? + def _3: Tree = ??? + } + + object Template extends TemplateDeconstructor { + def _1: List[Tree] = field.parents + def _2: ValDef = field.self + def _3: List[Tree] = field.constr :: field.body + } + + object Bind extends BindDeconstructor { + def _1: Name = field.name + def _2: Tree = field.body + } + + object ClassDef extends ClassDefDeconstructor { + def _1: Modifiers = null + def _2: Name = field.name + def _4: Template = field.rhs.asInstanceOf[Template] + def _3: List[TypeDef] = Nil + } + + object Closure extends ClosureDeconstructor { + def _1 = field.env + def _2 = field.meth + def _3 = { + val t = field.tpt.tpe.typeSymbol + if (t.exists) t + else { + val arity = field.meth.tpe.widenDealias.paramTypes.size - _1.size + val returnsUnit = field.meth.tpe.widenDealias.resultType.classSymbol == UnitClass + if (returnsUnit) + ctx.requiredClass(("scala.compat.java8.JProcedure" + arity).toTermName) + else ctx.requiredClass(("scala.compat.java8.JFunction" + arity).toTermName) + } + } + } + + def currentUnit = ctx.compilationUnit +} |