diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2016-12-20 13:32:02 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-12-20 13:32:02 +0100 |
commit | 246653f024c13ba0348fec3f83b147de11251fe3 (patch) | |
tree | 22f1a21ae2548f859817952421c0d25f98fa6ad8 /src/compiler/scala | |
parent | 0924e7318046ea27a69c5f9d1675c9981f7ebeae (diff) | |
parent | 079e8dc61704a768792c6b210a5b0cd25522ee55 (diff) | |
download | scala-246653f024c13ba0348fec3f83b147de11251fe3.tar.gz scala-246653f024c13ba0348fec3f83b147de11251fe3.tar.bz2 scala-246653f024c13ba0348fec3f83b147de11251fe3.zip |
Merge pull request #5608 from retronym/merge/2.11.x-to-2.12.x-20161220
Merge 2.11.x to 2.12.x [ci: last-only]
Diffstat (limited to 'src/compiler/scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/javac/JavaParsers.scala | 61 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/javac/JavaScanners.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 60 |
3 files changed, 104 insertions, 19 deletions
diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index e4bc055da4..947af55724 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -572,10 +572,48 @@ 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 == EQUALS && !mods.isParameter) skipTo(COMMA, SEMI) + + /** Tries to detect final static literals syntactically and returns a constant type replacement */ + def optConstantTpe(): Tree = { + def constantTpe(const: Constant): Tree = TypeTree(ConstantType(const)) + + def forConst(const: Constant): Tree = { + if (in.token != SEMI) tpt1 + else { + def isStringTyped = tpt1 match { + case Ident(TypeName("String")) => true + case _ => false + } + if (const.tag == StringTag && isStringTyped) constantTpe(const) + else if (tpt1.tpe != null && (const.tag == BooleanTag || const.isNumeric)) { + // for example, literal 'a' is ok for float. 127 is ok for byte, but 128 is not. + val converted = const.convertTo(tpt1.tpe) + if (converted == null) tpt1 + else constantTpe(converted) + } else tpt1 + } + } + + in.nextToken() // EQUALS + if (mods.hasFlag(Flags.STATIC) && mods.isFinal) { + val neg = in.token match { + case MINUS | BANG => in.nextToken(); true + case _ => false + } + tryLiteral(neg).map(forConst).getOrElse(tpt1) + } else tpt1 + } + + val tpt2: Tree = + if (in.token == EQUALS && !mods.isParameter) { + val res = optConstantTpe() + skipTo(COMMA, SEMI) + res + } else tpt1 + val mods1 = if (mods.isFinal) mods &~ Flags.FINAL else mods | Flags.MUTABLE atPos(pos) { - ValDef(mods1, name, tpt1, blankExpr) + ValDef(mods1, name, tpt2, blankExpr) } } @@ -831,6 +869,25 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { case _ => in.nextToken(); syntaxError("illegal start of type declaration", skipIt = true); List(errorTypeTree) } + def tryLiteral(negate: Boolean = false): Option[Constant] = { + val l = in.token match { + case TRUE => !negate + case FALSE => negate + case CHARLIT => in.name.charAt(0) + case INTLIT => in.intVal(negate).toInt + case LONGLIT => in.intVal(negate) + case FLOATLIT => in.floatVal(negate).toFloat + case DOUBLELIT => in.floatVal(negate) + case STRINGLIT => in.name.toString + case _ => null + } + if (l == null) None + else { + in.nextToken() + Some(Constant(l)) + } + } + /** CompilationUnit ::= [package QualId semi] TopStatSeq */ def compilationUnit(): Tree = { diff --git a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala index f77e53c54b..af9b63c8ae 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala @@ -89,6 +89,7 @@ trait JavaScanners extends ast.parser.ScannersCommon { javanme.ELSEkw -> ELSE, javanme.ENUMkw -> ENUM, javanme.EXTENDSkw -> EXTENDS, + javanme.FALSEkw -> FALSE, javanme.FINALkw -> FINAL, javanme.FINALLYkw -> FINALLY, javanme.FLOATkw -> FLOAT, @@ -118,6 +119,7 @@ trait JavaScanners extends ast.parser.ScannersCommon { javanme.THROWkw -> THROW, javanme.THROWSkw -> THROWS, javanme.TRANSIENTkw -> TRANSIENT, + javanme.TRUEkw -> TRUE, javanme.TRYkw -> TRY, javanme.VOIDkw -> VOID, javanme.VOLATILEkw -> VOLATILE, diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index e017c7d864..58a44d3ac0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -4624,22 +4624,55 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val appStart = if (Statistics.canEnable) Statistics.startTimer(failedApplyNanos) else null val opeqStart = if (Statistics.canEnable) Statistics.startTimer(failedOpEqNanos) else null - def onError(reportError: => Tree): Tree = fun match { - case Select(qual, name) - if !mode.inPatternMode && nme.isOpAssignmentName(newTermName(name.decode)) && !qual.exists(_.isErroneous) => + def isConversionCandidate(qual: Tree, name: Name): Boolean = + !mode.inPatternMode && nme.isOpAssignmentName(TermName(name.decode)) && !qual.exists(_.isErroneous) + def reportError(error: SilentTypeError): Tree = { + error.reportableErrors foreach context.issue + error.warnings foreach { case (p, m) => context.warning(p, m) } + args foreach (arg => typed(arg, mode, ErrorType)) + setError(tree) + } + def advice1(convo: Tree, errors: List[AbsTypeError], err: SilentTypeError): List[AbsTypeError] = + errors.map { e => + if (e.errPos == tree.pos) { + val header = f"${e.errMsg}%n Expression does not convert to assignment because:%n " + val expansion = f"%n expansion: ${show(convo)}" + NormalTypeError(tree, err.errors.flatMap(_.errMsg.lines.toList).mkString(header, f"%n ", expansion)) + } else e + } + def advice2(errors: List[AbsTypeError]): List[AbsTypeError] = + errors.map { e => + if (e.errPos == tree.pos) { + val msg = f"${e.errMsg}%n Expression does not convert to assignment because receiver is not assignable." + NormalTypeError(tree, msg) + } else e + } + def onError(error: SilentTypeError): Tree = fun match { + case Select(qual, name) if isConversionCandidate(qual, name) => val qual1 = typedQualifier(qual) if (treeInfo.isVariableOrGetter(qual1)) { if (Statistics.canEnable) Statistics.stopTimer(failedOpEqNanos, opeqStart) - convertToAssignment(fun, qual1, name, args) + val erred = qual1.isErroneous || args.exists(_.isErroneous) + if (erred) reportError(error) else { + val convo = convertToAssignment(fun, qual1, name, args) + silent(op = _.typed1(convo, mode, pt)) match { + case SilentResultValue(t) => t + case err: SilentTypeError => reportError(SilentTypeError(advice1(convo, error.errors, err), error.warnings)) + } + } } else { if (Statistics.canEnable) Statistics.stopTimer(failedApplyNanos, appStart) - reportError + val Apply(Select(qual2, _), args2) = tree + val erred = qual2.isErroneous || args2.exists(_.isErroneous) + reportError { + if (erred) error else SilentTypeError(advice2(error.errors), error.warnings) + } } case _ => if (Statistics.canEnable) Statistics.stopTimer(failedApplyNanos, appStart) - reportError + reportError(error) } val silentResult = silent( op = _.typed(fun, mode.forFunMode, funpt), @@ -4664,13 +4697,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper tryTypedApply(fun2, args) else doTypedApply(tree, fun2, args, mode, pt) - case err: SilentTypeError => - onError({ - err.reportableErrors foreach context.issue - err.warnings foreach { case (p, m) => context.warning(p, m) } - args foreach (arg => typed(arg, mode, ErrorType)) - setError(tree) - }) + case err: SilentTypeError => onError(err) } } @@ -4713,7 +4740,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper Select(vble.duplicate, prefix) setPos fun.pos.focus, args) setPos tree.pos.makeTransparent ) setPos tree.pos - def mkUpdate(table: Tree, indices: List[Tree]) = { + def mkUpdate(table: Tree, indices: List[Tree]) = gen.evalOnceAll(table :: indices, context.owner, context.unit) { case tab :: is => def mkCall(name: Name, extraArgs: Tree*) = ( @@ -4728,9 +4755,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper ) case _ => EmptyTree } - } - val tree1 = qual match { + val assignment = qual match { case Ident(_) => mkAssign(qual) @@ -4746,7 +4772,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper case _ => UnexpectedTreeAssignmentConversionError(qual) } } - typed1(tree1, mode, pt) + assignment } def typedSuper(tree: Super) = { |