diff options
Diffstat (limited to 'src/compiler')
21 files changed, 368 insertions, 276 deletions
diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index df5952a4cf..c2caed70a0 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -98,6 +98,11 @@ trait CompilationUnits { global: Global => override def toString = map.toString } + // namer calls typer.computeType(rhs) on DefDef / ValDef when tpt is empty. the result + // is cached here and re-used in typedDefDef / typedValDef + // Also used to cache imports type-checked by namer. + val transformed = new mutable.AnyRefMap[Tree, Tree] + /** things to check at end of compilation unit */ val toCheck = new ListBuffer[() => Unit] diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 5492e563dd..1617db7517 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -81,6 +81,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def picklerPhase: Phase = if (currentRun.isDefined) currentRun.picklerPhase else NoPhase + def erasurePhase: Phase = if (currentRun.isDefined) currentRun.erasurePhase else NoPhase + // platform specific elements protected class GlobalPlatform extends { @@ -527,7 +529,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } with Erasure // phaseName = "posterasure" - object postErasure extends { + override object postErasure extends { val global: Global.this.type = Global.this val runsAfter = List("erasure") val runsRightAfter = Some("erasure") diff --git a/src/compiler/scala/tools/nsc/ast/parser/CommonTokens.scala b/src/compiler/scala/tools/nsc/ast/parser/CommonTokens.scala new file mode 100644 index 0000000000..5fcb02814b --- /dev/null +++ b/src/compiler/scala/tools/nsc/ast/parser/CommonTokens.scala @@ -0,0 +1,112 @@ +package scala.tools.nsc +package ast.parser + +/** Common code between Scala's Tokens and JavaTokens. */ +abstract class CommonTokens { + + def isIdentifier(code: Int): Boolean + def isLiteral(code: Int): Boolean + + /** special tokens */ + final val EMPTY = -3 + final val UNDEF = -2 + final val ERROR = -1 + final val EOF = 0 + + /** literals */ + final val CHARLIT = 1 + final val INTLIT = 2 + final val LONGLIT = 3 + final val FLOATLIT = 4 + final val DOUBLELIT = 5 + final val STRINGLIT = 6 + + /** keywords */ + final val NEW = 20 + final val THIS = 21 + final val SUPER = 23 + + final val NULL = 24 + final val TRUE = 25 + final val FALSE = 26 + + // J: INSTANCEOF = 27 + // J: CONST = 28 + + /** modifiers */ + // S: IMPLICIT = 40 + // S: OVERRIDE = 41 + // J: PUBLIC = 42 + final val PROTECTED = 43 + final val PRIVATE = 44 + // S: SEALED = 45 + final val ABSTRACT = 46 + // J: DEFAULT = 47 + // J: STATIC = 48 + final val FINAL = 49 + // J: TRANSIENT = 50 + // J: VOLATILE = 51 + // J: SYNCHRONIZED = 52 + // J: NATIVE = 53 + // J: STRICTFP = 54 + // S: LAZY = 55 + // J: THROWS = 56 + // S: MACRO = 57 + + /** templates */ + final val PACKAGE = 60 + final val IMPORT = 61 + final val CLASS = 62 + // S: CASECLASS = 63 + // S: OBJECT = 64 + // S: CASEOBJECT = 65 + // S: TRAIT, J: INTERFACE = 66 + // J: ENUM = 67 + final val EXTENDS = 68 + // S: WITH, J: IMPLEMENTS = 69 + // S: TYPE = 70 + // S: FORSOME = 71 + // S: DEF = 72 + // S: VAL = 73 + // S: VAR = 74 + + /** control structures */ + final val IF = 80 + // S: THEN = 81 + final val ELSE = 82 + final val WHILE = 83 + final val DO = 84 + final val FOR = 85 + // S: YIELD = 86 + // J: BREAK = 87 + // J: CONTINUE = 88 + // J: GOTO = 89 + final val THROW = 90 + final val TRY = 91 + final val CATCH = 92 + final val FINALLY = 93 + // J: SWITCH = 94 + // S: MATCH = 95 + final val CASE = 96 + final val RETURN = 97 + // J: ASSERT = 98 + + /** parenthesis */ + final val LPAREN = 100 + final val RPAREN = 101 + final val LBRACKET = 102 + final val RBRACKET = 103 + final val LBRACE = 104 + final val RBRACE = 105 + + /** special symbols */ + final val COMMA = 120 + final val SEMI = 121 + final val DOT = 122 + final val COLON = 123 + final val EQUALS = 124 + final val AT = 125 + // S: <special symbols> = 130 - 139 + // J: <special symbols> = 140 - 179 + // J: <primitive types> = 180 - 189 +} diff --git a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala index 5a7dc4950d..e624aec88c 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala @@ -6,123 +6,57 @@ package scala.tools.nsc package ast.parser -/** Common code between JavaTokens and Tokens. Not as much (and not as concrete) - * as one might like because JavaTokens for no clear reason chose new numbers for - * identical token sets. - */ -abstract class Tokens { - /** special tokens */ - final val EMPTY = -3 - final val UNDEF = -2 - final val ERROR = -1 - final val EOF = 0 - - /** literals */ - final val CHARLIT = 1 - final val INTLIT = 2 - final val LONGLIT = 3 - final val FLOATLIT = 4 - final val DOUBLELIT = 5 - final val STRINGLIT = 6 - - def LPAREN: Int - def RBRACE: Int - - def isIdentifier(code: Int): Boolean - def isLiteral(code: Int): Boolean -} - -object Tokens extends Tokens { - final val STRINGPART = 7 // a part of an interpolated string +object Tokens extends CommonTokens { + final val STRINGPART = 7 // a part of an interpolated string final val SYMBOLLIT = 8 final val INTERPOLATIONID = 9 // the lead identifier of an interpolated string - def isLiteral(code: Int) = - code >= CHARLIT && code <= INTERPOLATIONID + def isLiteral(code: Int) = code >= CHARLIT && code <= INTERPOLATIONID /** identifiers */ final val IDENTIFIER = 10 final val BACKQUOTED_IDENT = 11 - def isIdentifier(code: Int) = code >= IDENTIFIER && code <= BACKQUOTED_IDENT // used by ide - - /** keywords */ - final val IF = 20 - final val FOR = 21 - final val ELSE = 22 - final val THIS = 23 - final val NULL = 24 - final val NEW = 25 - final val WITH = 26 - final val SUPER = 27 - final val CASE = 28 - final val CASECLASS = 29 - final val CASEOBJECT = 30 - final val VAL = 31 - final val ABSTRACT = 32 - final val FINAL = 33 - final val PRIVATE = 34 - final val PROTECTED = 35 - final val OVERRIDE = 36 - final val IMPLICIT = 37 - final val VAR = 38 - final val DEF = 39 - final val TYPE = 40 - final val EXTENDS = 41 - final val TRUE = 42 - final val FALSE = 43 - final val OBJECT = 44 - final val CLASS = 45 - - final val IMPORT = 46 - final val PACKAGE = 47 - final val YIELD = 48 - final val DO = 49 - final val TRAIT = 50 - final val SEALED = 51 - final val THROW = 52 - final val TRY = 53 - final val CATCH = 54 - final val FINALLY = 55 - final val WHILE = 56 - final val RETURN = 57 - final val MATCH = 58 - final val FORSOME = 59 - final val LAZY = 61 - final val MACRO = 62 // not yet used in 2.10 - final val THEN = 63 // not yet used in 2.10 + def isIdentifier(code: Int) = code == IDENTIFIER || code == BACKQUOTED_IDENT // used by ide + + /** modifiers */ + final val IMPLICIT = 40 + final val OVERRIDE = 41 + final val SEALED = 45 + final val LAZY = 55 + final val MACRO = 57 + + /** templates */ + final val CASECLASS = 63 + final val OBJECT = 64 + final val CASEOBJECT = 65 + final val TRAIT = 66 + final val WITH = 69 + final val TYPE = 70 + final val FORSOME = 71 + final val DEF = 72 + final val VAL = 73 + final val VAR = 74 + + /** control structures */ + final val THEN = 81 + final val YIELD = 86 + final val MATCH = 95 /** special symbols */ - final val COMMA = 70 - final val SEMI = 71 - final val DOT = 72 - final val USCORE = 73 - final val COLON = 74 - final val EQUALS = 75 - final val LARROW = 76 - final val ARROW = 77 - final val NEWLINE = 78 - final val NEWLINES = 79 - final val SUBTYPE = 80 - final val SUPERTYPE = 81 - final val HASH = 82 - final val AT = 83 - final val VIEWBOUND = 84 - - /** parenthesis */ - final val LPAREN = 90 - final val RPAREN = 91 - final val LBRACKET = 92 - final val RBRACKET = 93 - final val LBRACE = 94 - final val RBRACE = 95 - - /** XML mode */ - final val XMLSTART = 96 + final val HASH = 130 + final val USCORE = 131 + final val ARROW = 132 + final val LARROW = 133 + final val SUBTYPE = 134 + final val SUPERTYPE = 135 + final val VIEWBOUND = 136 + final val NEWLINE = 137 + final val NEWLINES = 138 + final val XMLSTART = 139 /** for IDE only */ - final val COMMENT = 97 - - final val WHITESPACE = 105 - final val IGNORE = 106 - final val ESCAPE = 109 + final val COMMENT = 200 + final val WHITESPACE = 201 + final val IGNORE = 202 + final val ESCAPE = 203 } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index eb40e1dbde..b03519ce7d 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -171,10 +171,10 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { var pickledBytes = 0 // statistics - val javaNameCache = perRunCaches.newMap[Symbol, Name]() + val javaNameCache = perRunCaches.newAnyRefMap[Symbol, Name]() // unlike javaNameCache, reverseJavaName contains entries only for class symbols and their internal names. - val reverseJavaName = perRunCaches.newMap[String, Symbol]() + val reverseJavaName = perRunCaches.newAnyRefMap[String, Symbol]() private def mkFlags(args: Int*) = args.foldLeft(0)(_ | _) private def hasPublicBitSet(flags: Int) = (flags & asm.Opcodes.ACC_PUBLIC) != 0 diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 9875d27047..a61ad392ee 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -190,7 +190,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { case GTGTGT => GTGT case GTGTEQ => GTEQ case GTGT => GT - case GTEQ => ASSIGN + case GTEQ => EQUALS } if (closers isDefinedAt in.token) in.token = closers(in.token) else accept(GT) @@ -538,7 +538,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { in.nextToken() if (in.token == IDENTIFIER) { // if there's an ident after the comma ... val name = ident() - if (in.token == ASSIGN || in.token == SEMI) { // ... followed by a `=` or `;`, we know it's a real variable definition + if (in.token == EQUALS || in.token == SEMI) { // ... followed by a `=` or `;`, we know it's a real variable definition buf ++= maybe buf += varDecl(in.currentPos, mods, tpt.duplicate, name.toTermName) maybe.clear() @@ -563,7 +563,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { def varDecl(pos: Position, mods: Modifiers, tpt: Tree, name: TermName): ValDef = { val tpt1 = optArrayBrackets(tpt) - if (in.token == ASSIGN && !mods.isParameter) skipTo(COMMA, SEMI) + if (in.token == EQUALS && !mods.isParameter) skipTo(COMMA, SEMI) val mods1 = if (mods.isFinal) mods &~ Flags.FINAL else mods | Flags.MUTABLE atPos(pos) { ValDef(mods1, name, tpt1, blankExpr) diff --git a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala index b7ea70e2c7..c5401219dd 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala @@ -155,7 +155,6 @@ trait JavaScanners extends ast.parser.ScannersCommon { case AMP => "`&'" case AMPAMP => "`&&'" case AMPEQ => "`&='" - case ASSIGN => "`='" case ASTERISK => "`*'" case ASTERISKEQ => "`*='" case AT => "`@'" @@ -169,6 +168,7 @@ trait JavaScanners extends ast.parser.ScannersCommon { case DOT => "`.'" case DOTDOTDOT => "`...'" case EQEQ => "`=='" + case EQUALS => "`='" case GT => "`>'" case GTEQ => "`>='" case GTGT => "`>>'" @@ -337,7 +337,7 @@ trait JavaScanners extends ast.parser.ScannersCommon { return case '=' => - token = ASSIGN + token = EQUALS in.next() if (in.ch == '=') { token = EQEQ diff --git a/src/compiler/scala/tools/nsc/javac/JavaTokens.scala b/src/compiler/scala/tools/nsc/javac/JavaTokens.scala index 953a3c6d82..9b31e6e8a2 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaTokens.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaTokens.scala @@ -6,117 +6,89 @@ package scala.tools.nsc package javac -object JavaTokens extends ast.parser.Tokens { +object JavaTokens extends ast.parser.CommonTokens { - def isLiteral(code : Int) = + def isLiteral(code: Int) = code >= CHARLIT && code <= STRINGLIT /** identifiers */ final val IDENTIFIER = 10 - def isIdentifier(code : Int) = + def isIdentifier(code: Int) = code == IDENTIFIER /** keywords */ - final val ABSTRACT = 20 - final val ASSERT = 21 - final val BOOLEAN = 22 - final val BREAK = 23 - final val BYTE = 24 - final val CASE = 25 - final val CATCH = 26 - final val CHAR = 27 - final val CLASS = 28 - final val CONST = 29 - final val CONTINUE = 30 - final val DEFAULT = 31 - final val DO = 32 - final val DOUBLE = 33 - final val ELSE = 34 - final val ENUM = 35 - final val EXTENDS = 36 - final val FINAL = 37 - final val FINALLY = 38 - final val FLOAT = 39 - final val FOR = 40 - final val IF = 41 - final val GOTO = 42 - final val IMPLEMENTS = 43 - final val IMPORT = 44 - final val INSTANCEOF = 45 - final val INT = 46 - final val INTERFACE = 47 - final val LONG = 48 - final val NATIVE = 49 - final val NEW = 50 - final val PACKAGE = 51 - final val PRIVATE = 52 - final val PROTECTED = 53 - final val PUBLIC = 54 - final val RETURN = 55 - final val SHORT = 56 - final val STATIC = 57 - final val STRICTFP = 58 - final val SUPER = 59 - final val SWITCH = 60 - final val SYNCHRONIZED = 61 - final val THIS = 62 - final val THROW = 63 - final val THROWS = 64 - final val TRANSIENT = 65 - final val TRY = 66 - final val VOID = 67 - final val VOLATILE = 68 - final val WHILE = 69 + final val INSTANCEOF = 27 + final val CONST = 28 + + /** modifiers */ + final val PUBLIC = 42 + final val DEFAULT = 47 + final val STATIC = 48 + final val TRANSIENT = 50 + final val VOLATILE = 51 + final val SYNCHRONIZED = 52 + final val NATIVE = 53 + final val STRICTFP = 54 + final val THROWS = 56 + + /** templates */ + final val INTERFACE = 66 + final val ENUM = 67 + final val IMPLEMENTS = 69 + + /** control structures */ + final val BREAK = 87 + final val CONTINUE = 88 + final val GOTO = 89 + final val SWITCH = 94 + final val ASSERT = 98 /** special symbols */ - final val COMMA = 70 - final val SEMI = 71 - final val DOT = 72 - final val AT = 73 - final val COLON = 74 - final val ASSIGN = 75 - final val EQEQ = 76 - final val BANGEQ = 77 - final val LT = 78 - final val GT = 79 - final val LTEQ = 80 - final val GTEQ = 81 - final val BANG = 82 - final val QMARK = 83 - final val AMP = 84 - final val BAR = 85 - final val PLUS = 86 - final val MINUS = 87 - final val ASTERISK = 88 - final val SLASH = 89 - final val PERCENT = 90 - final val HAT = 91 - final val LTLT = 92 - final val GTGT = 93 - final val GTGTGT = 94 - final val AMPAMP = 95 - final val BARBAR = 96 - final val PLUSPLUS = 97 - final val MINUSMINUS = 98 - final val TILDE = 99 - final val DOTDOTDOT = 100 - final val AMPEQ = 104 - final val BAREQ = 105 - final val PLUSEQ = 106 - final val MINUSEQ = 107 - final val ASTERISKEQ = 1010 - final val SLASHEQ = 109 - final val PERCENTEQ = 110 - final val HATEQ = 111 - final val LTLTEQ = 112 - final val GTGTEQ = 113 - final val GTGTGTEQ = 114 + final val EQEQ = 140 + final val BANGEQ = 141 + final val LT = 142 + final val GT = 143 + final val LTEQ = 144 + final val GTEQ = 145 + final val BANG = 146 + final val QMARK = 147 + final val AMP = 148 + final val BAR = 149 + final val PLUS = 150 + final val MINUS = 151 + final val ASTERISK = 152 + final val SLASH = 153 + final val PERCENT = 154 + final val HAT = 155 + final val LTLT = 156 + final val GTGT = 157 + final val GTGTGT = 158 + final val AMPAMP = 159 + final val BARBAR = 160 + final val PLUSPLUS = 161 + final val MINUSMINUS = 162 + final val TILDE = 163 + final val DOTDOTDOT = 164 + final val AMPEQ = 165 + final val BAREQ = 166 + final val PLUSEQ = 167 + final val MINUSEQ = 168 + final val ASTERISKEQ = 169 + final val SLASHEQ = 170 + final val PERCENTEQ = 171 + final val HATEQ = 172 + final val LTLTEQ = 173 + final val GTGTEQ = 174 + final val GTGTGTEQ = 175 - /** parenthesis */ - final val LPAREN = 115 - final val RPAREN = 116 - final val LBRACKET = 117 - final val RBRACKET = 118 - final val LBRACE = 119 - final val RBRACE = 120 + /** primitive types */ + final val VOID = 180 + final val BOOLEAN = 181 + final val BYTE = 182 + final val SHORT = 183 + final val CHAR = 184 + final val INT = 185 + final val LONG = 186 + final val FLOAT = 187 + final val DOUBLE = 188 } diff --git a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala index 933a2f70a1..d81a5d5755 100644 --- a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala +++ b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala @@ -232,6 +232,10 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre val parents = addSerializable(abstractFunctionErasedType) val funOwner = originalFunction.symbol.owner + // TODO harmonize the naming of delamdafy anon-fun classes with those spun up by Uncurry + // - make `anonClass.isAnonymousClass` true. + // - use `newAnonymousClassSymbol` or push the required variations into a similar factory method + // - reinstate the assertion in `Erasure.resolveAnonymousBridgeClash` val suffix = "$lambda$" + ( if (funOwner.isPrimaryConstructor) "" else "$" + funOwner.name @@ -282,18 +286,11 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre if (sym == NoSymbol) sym.toString else s"$sym: ${sym.tpe} in ${sym.owner}" - def clashError(bm: Symbol) = { - unit.error( - applyMethodDef.symbol.pos, - sm"""bridge generated for member ${fulldef(applyMethodDef.symbol)} - |which overrides ${fulldef(getMember(abstractFunctionErasedType.typeSymbol, nme.apply))} - |clashes with definition of the member itself; - |both have erased type ${exitingPostErasure(bm.tpe)}""") - } - bridgeMethod foreach (bm => + // TODO SI-6260 maybe just create the apply method with the signature (Object => Object) in all cases + // rather than the method+bridge pair. if (bm.symbol.tpe =:= applyMethodDef.symbol.tpe) - clashError(bm.symbol) + erasure.resolveAnonymousBridgeClash(applyMethodDef.symbol, bm.symbol) ) val body = members ++ List(constr, applyMethodDef) ++ bridgeMethod diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index ccfddab94a..60c1553ef3 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -403,19 +403,19 @@ abstract class Erasure extends AddInterfaces * @param other The overidden symbol for which the bridge was generated * @param bridge The bridge */ - def checkBridgeOverrides(member: Symbol, other: Symbol, bridge: Symbol): Boolean = { + def checkBridgeOverrides(member: Symbol, other: Symbol, bridge: Symbol): Seq[(Position, String)] = { def fulldef(sym: Symbol) = if (sym == NoSymbol) sym.toString else s"$sym: ${sym.tpe} in ${sym.owner}" var noclash = true + val clashErrors = mutable.Buffer[(Position, String)]() def clashError(what: String) = { - noclash = false - unit.error( - if (member.owner == root) member.pos else root.pos, - sm"""bridge generated for member ${fulldef(member)} - |which overrides ${fulldef(other)} - |clashes with definition of $what; - |both have erased type ${exitingPostErasure(bridge.tpe)}""") + val pos = if (member.owner == root) member.pos else root.pos + val msg = sm"""bridge generated for member ${fulldef(member)} + |which overrides ${fulldef(other)} + |clashes with definition of $what; + |both have erased type ${exitingPostErasure(bridge.tpe)}""" + clashErrors += Tuple2(pos, msg) } for (bc <- root.baseClasses) { if (settings.debug) @@ -440,7 +440,7 @@ abstract class Erasure extends AddInterfaces } } } - noclash + clashErrors } /** TODO - work through this logic with a fine-toothed comb, incorporating @@ -478,8 +478,18 @@ abstract class Erasure extends AddInterfaces bridge setInfo (otpe cloneInfo bridge) bridgeTarget(bridge) = member - if (!(member.tpe exists (_.typeSymbol.isDerivedValueClass)) || - checkBridgeOverrides(member, other, bridge)) { + def sigContainsValueClass = (member.tpe exists (_.typeSymbol.isDerivedValueClass)) + + val shouldAdd = ( + !sigContainsValueClass + || (checkBridgeOverrides(member, other, bridge) match { + case Nil => true + case es if member.owner.isAnonymousClass => resolveAnonymousBridgeClash(member, bridge); true + case es => for ((pos, msg) <- es) unit.error(pos, msg); false + }) + ) + + if (shouldAdd) { exitingErasure(root.info.decls enter bridge) if (other.owner == root) { exitingErasure(root.info.decls.unlink(other)) @@ -1127,5 +1137,13 @@ abstract class Erasure extends AddInterfaces } } + final def resolveAnonymousBridgeClash(sym: Symbol, bridge: Symbol) { + // TODO reinstate this after Delambdafy generates anonymous classes that meet this requirement. + // require(sym.owner.isAnonymousClass, sym.owner) + log(s"Expanding name of ${sym.debugLocationString} as it clashes with bridge. Renaming deemed safe because the owner is anonymous.") + sym.expandName(sym.owner) + bridge.resetFlag(BRIDGE) + } + private class TypeRefAttachment(val tpe: TypeRef) } diff --git a/src/compiler/scala/tools/nsc/transform/PostErasure.scala b/src/compiler/scala/tools/nsc/transform/PostErasure.scala index cc78e27282..32987fed8c 100644 --- a/src/compiler/scala/tools/nsc/transform/PostErasure.scala +++ b/src/compiler/scala/tools/nsc/transform/PostErasure.scala @@ -8,7 +8,7 @@ package transform /** This phase maps ErasedValueTypes to the underlying unboxed representation and * performs peephole optimizations. */ -trait PostErasure extends InfoTransform with TypingTransformers { +trait PostErasure extends InfoTransform with TypingTransformers with scala.reflect.internal.transform.PostErasure { val global: Global import global._ @@ -19,16 +19,6 @@ trait PostErasure extends InfoTransform with TypingTransformers { def newTransformer(unit: CompilationUnit): Transformer = new PostErasureTransformer(unit) override def changesBaseClasses = false - object elimErasedValueType extends TypeMap { - def apply(tp: Type) = tp match { - case ConstantType(Constant(tp: Type)) => ConstantType(Constant(apply(tp))) - case ErasedValueType(_, underlying) => underlying - case _ => mapOver(tp) - } - } - - def transformInfo(sym: Symbol, tp: Type) = elimErasedValueType(tp) - class PostErasureTransformer(unit: CompilationUnit) extends TypingTransformer(unit) { override def transform(tree: Tree) = { def finish(res: Tree) = logResult(s"Posterasure reduction\n Old: $tree\n New")(res) diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index e5907e1a0f..c065fb54b7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -89,6 +89,8 @@ trait Contexts { self: Analyzer => if (settings.noimports) Nil else if (unit.isJava) RootImports.javaList else if (settings.nopredef || treeInfo.noPredefImportForUnit(unit.body)) { + // SI-8258 Needed for the presentation compiler using -sourcepath, otherwise cycles can occur. See the commit + // message for this ticket for an example. debuglog("Omitted import of Predef._ for " + unit) RootImports.javaAndScalaList } @@ -457,7 +459,9 @@ trait Contexts { self: Analyzer => c.prefix = prefixInChild c.enclClass = if (isTemplateOrPackage) c else enclClass c(ConstructorSuffix) = !isTemplateOrPackage && c(ConstructorSuffix) - c.enclMethod = if (isDefDef) c else enclMethod + + // SI-8245 `isLazy` need to skip lazy getters to ensure `return` binds to the right place + c.enclMethod = if (isDefDef && !owner.isLazy) c else enclMethod registerContext(c.asInstanceOf[analyzer.Context]) debuglog("[context] ++ " + c.unit + " / " + tree.summaryString) diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 997fd6fc65..2d6c94349b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -174,7 +174,8 @@ trait Infer extends Checkable { private lazy val stdErrorValue = stdErrorClass.newErrorValue(nme.ERROR) /** The context-dependent inferencer part */ - class Inferencer(context: Context) extends InferencerContextErrors with InferCheckable { + abstract class Inferencer extends InferencerContextErrors with InferCheckable { + def context: Context import InferErrorGen._ /* -- Error Messages --------------------------------------------------- */ diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala index ec2b7d49f5..ba183fe3e6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala +++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala @@ -427,7 +427,7 @@ trait MethodSynthesis { override def derivedSym = basisSym.lazyAccessor override def derivedTree: DefDef = { val ValDef(_, _, tpt0, rhs0) = tree - val rhs1 = transformed.getOrElse(rhs0, rhs0) + val rhs1 = context.unit.transformed.getOrElse(rhs0, rhs0) val body = ( if (tree.symbol.owner.isTrait || hasUnitType(basisSym)) rhs1 else gen.mkAssignAndReturn(basisSym, rhs1) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 632e25aa2e..60cae0c880 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1408,12 +1408,18 @@ trait Namers extends MethodSynthesis { if (expr1.isErrorTyped) ErrorType else { - if (!treeInfo.isStableIdentifierPattern(expr1)) - typer.TyperErrorGen.UnstableTreeError(expr1) + expr1 match { + case This(_) => + // SI-8207 okay, typedIdent expands Ident(self) to C.this which doesn't satisfy the next case + // TODO should we change `typedIdent` not to expand to the `Ident` to a `This`? + case _ if treeInfo.isStableIdentifierPattern(expr1) => + case _ => + typer.TyperErrorGen.UnstableTreeError(expr1) + } val newImport = treeCopy.Import(imp, expr1, selectors).asInstanceOf[Import] checkSelectors(newImport) - transformed(imp) = newImport + context.unit.transformed(imp) = newImport // copy symbol and type attributes back into old expression // so that the structure builder will find it. expr setSymbol expr1.symbol setType expr1.tpe diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 10fe530445..088aa5216a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -13,7 +13,7 @@ package scala package tools.nsc package typechecker -import scala.collection.{ mutable, immutable } +import scala.collection.{mutable, immutable} import scala.reflect.internal.util.{ BatchSourceFile, Statistics, shortClassOfInstance } import mutable.ListBuffer import symtab.Flags._ @@ -39,7 +39,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // namer calls typer.computeType(rhs) on DefDef / ValDef when tpt is empty. the result // is cached here and re-used in typedDefDef / typedValDef // Also used to cache imports type-checked by namer. - val transformed = new mutable.HashMap[Tree, Tree] + val transformed = new mutable.AnyRefMap[Tree, Tree] final val shortenImports = false @@ -52,7 +52,6 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper //println("resetTyper called") resetContexts() resetImplicits() - transformed.clear() resetDocComments() } @@ -108,7 +107,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val runDefinitions = currentRun.runDefinitions import runDefinitions._ - val infer = new Inferencer(context0) { + private val transformed: mutable.Map[Tree, Tree] = unit.transformed + + val infer = new Inferencer { + def context = Typer.this.context // See SI-3281 re undoLog override def isCoercible(tp: Type, pt: Type) = undoLog undo viewExists(tp, pt) } @@ -4901,6 +4903,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper ) arg match { case Bind(_, _) => enhanceBounds() + // TODO: consolidate fixes for SI-6169 and SI-1786 by dropping the Ident case, + // in favor of doing sharpenQuantifierBounds for all ExistentialTypes, not just java-defined ones + // (need to figure out how to sharpen the bounds on creation without running into cycles) case Ident(name) if canEnhanceIdent => enhanceBounds() case _ => } diff --git a/src/compiler/scala/tools/nsc/util/package.scala b/src/compiler/scala/tools/nsc/util/package.scala index 4237f36ade..bd95fdbb50 100644 --- a/src/compiler/scala/tools/nsc/util/package.scala +++ b/src/compiler/scala/tools/nsc/util/package.scala @@ -7,7 +7,7 @@ package scala package tools package nsc -import java.io.{ OutputStream, PrintStream, ByteArrayOutputStream, PrintWriter, StringWriter } +import java.io.{ OutputStream, PrintStream, ByteArrayOutputStream, PrintWriter, StringWriter, Reader } package object util { // forwarder for old code that builds against 2.9 and 2.10 @@ -46,6 +46,17 @@ package object util { (result, ts2 filterNot (ts1 contains _)) } + def stringFromReader(reader: Reader) = { + val writer = new StringWriter() + var c = reader.read() + while(c != -1) { + writer.write(c) + c = reader.read() + } + reader.close() + writer.toString() + } + /** Generate a string using a routine that wants to write on a stream. */ def stringFromWriter(writer: PrintWriter => Unit): String = { val stringWriter = new StringWriter() diff --git a/src/compiler/scala/tools/reflect/ReflectGlobal.scala b/src/compiler/scala/tools/reflect/ReflectGlobal.scala index f8ded56ec6..6f369212ad 100644 --- a/src/compiler/scala/tools/reflect/ReflectGlobal.scala +++ b/src/compiler/scala/tools/reflect/ReflectGlobal.scala @@ -12,9 +12,10 @@ class ReflectGlobal(currentSettings: Settings, reporter: Reporter, override val extends Global(currentSettings, reporter) with scala.tools.reflect.ReflectSetup with scala.reflect.runtime.SymbolTable { override def transformedType(sym: Symbol) = - erasure.transformInfo(sym, - uncurry.transformInfo(sym, - refChecks.transformInfo(sym, sym.info))) + postErasure.transformInfo(sym, + erasure.transformInfo(sym, + uncurry.transformInfo(sym, + refChecks.transformInfo(sym, sym.info)))) override def isCompilerUniverse = true diff --git a/src/compiler/scala/tools/reflect/ToolBox.scala b/src/compiler/scala/tools/reflect/ToolBox.scala index 02a458214f..4a3db09909 100644 --- a/src/compiler/scala/tools/reflect/ToolBox.scala +++ b/src/compiler/scala/tools/reflect/ToolBox.scala @@ -96,6 +96,15 @@ trait ToolBox[U <: scala.reflect.api.Universe] { */ def compile(tree: u.Tree): () => Any + /** Defines a top-level class, trait or module in this ToolBox, + * putting it into a uniquely-named package and returning a symbol that references the defined entity. + * For a ClassDef, a ClassSymbol is returned, and for a ModuleDef, a ModuleSymbol is returned (not a module class, but a module itself). + * + * This method can be used to generate definitions that will later be re-used by subsequent calls to + * `compile`, `define` or `eval`. To refer to the generated definition in a tree, use q"$sym". + */ + def define(tree: u.ImplDef): u.Symbol + /** Compiles and runs a tree using this ToolBox. * Is equivalent to `compile(tree)()`. */ diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index 541a915adb..7bae3203c2 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -193,6 +193,19 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => analyzer.inferImplicit(tree, pt, isView, currentTyper.context, silent, withMacrosDisabled, pos, (pos, msg) => throw ToolBoxError(msg)) }) + private def wrapInPackageAndCompile(packageName: TermName, tree: ImplDef): Symbol = { + val pdef = PackageDef(Ident(packageName), List(tree)) + val unit = new CompilationUnit(NoSourceFile) + unit.body = pdef + + val run = new Run + reporter.reset() + run.compileUnits(List(unit), run.namerPhase) + throwIfErrors() + + tree.symbol + } + def compile(expr0: Tree): () => Any = { val expr = wrapIntoTerm(expr0) @@ -200,7 +213,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => val thunks = freeTerms map (fte => () => fte.value) // need to be lazy in order not to distort evaluation order verify(expr) - def wrap(expr0: Tree): ModuleDef = { + def wrapInModule(expr0: Tree): ModuleDef = { val (expr, freeTerms) = extractFreeTerms(expr0, wrapFreeTermRefs = true) val (obj, _) = rootMirror.EmptyPackageClass.newModuleAndClassSymbol( @@ -241,17 +254,10 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => cleanedUp.asInstanceOf[ModuleDef] } - val mdef = wrap(expr) - val pdef = PackageDef(Ident(mdef.name), List(mdef)) - val unit = new CompilationUnit(NoSourceFile) - unit.body = pdef + val mdef = wrapInModule(expr) + val msym = wrapInPackageAndCompile(mdef.name, mdef) - val run = new Run - reporter.reset() - run.compileUnits(List(unit), run.namerPhase) - throwIfErrors() - - val className = mdef.symbol.fullName + val className = msym.fullName if (settings.debug) println("generated: "+className) def moduleFileName(className: String) = className + "$" val jclazz = jClass.forName(moduleFileName(className), true, classLoader) @@ -278,6 +284,13 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => } } + def define(tree: ImplDef): Symbol = { + val freeTerms = tree.freeTerms + if (freeTerms.nonEmpty) throw ToolBoxError(s"reflective toolbox has failed: cannot have free terms in a top-level definition") + verify(tree) + wrapInPackageAndCompile(nextWrapperModuleName(), tree) + } + def parse(code: String): Tree = { reporter.reset() val tree = gen.mkTreeOrBlock(newUnitParser(code, "<toolbox>").parseStatsOrPackages()) @@ -413,6 +426,18 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => compiler.compile(ctree) } + def define(tree: u.ImplDef): u.Symbol = withCompilerApi { compilerApi => + import compilerApi._ + + if (compiler.settings.verbose) println("importing "+tree) + val ctree: compiler.ImplDef = importer.importTree(tree).asInstanceOf[compiler.ImplDef] + + if (compiler.settings.verbose) println("defining "+ctree) + val csym: compiler.Symbol = compiler.define(ctree) + val usym = exporter.importSymbol(csym) + usym + } + def eval(tree: u.Tree): Any = compile(tree)() } } diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala index fcb8734644..9f6807fe17 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala @@ -200,7 +200,7 @@ trait Parsers { self: Quasiquotes => object PatternParser extends Parser { def entryPoint = { parser => - val pat = parser.noSeq.pattern1() + val pat = parser.noSeq.pattern() gen.patvarTransformer.transform(pat) } } |