diff options
37 files changed, 386 insertions, 130 deletions
diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf index 82f094bed7..88eabd4f8c 100644 --- a/bincompat-forward.whitelist.conf +++ b/bincompat-forward.whitelist.conf @@ -426,6 +426,10 @@ filter { { matchName="scala.reflect.internal.TreeInfo.effectivePatternArity" problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.internal.ModifierFlags.DEFAULTMETHOD" + problemName=MissingMethodProblem } ] } diff --git a/src/actors/scala/actors/remote/TcpService.scala b/src/actors/scala/actors/remote/TcpService.scala index bde05fd816..028dd3a083 100644 --- a/src/actors/scala/actors/remote/TcpService.scala +++ b/src/actors/scala/actors/remote/TcpService.scala @@ -14,7 +14,7 @@ package remote import java.io.{DataInputStream, DataOutputStream, IOException} import java.lang.{Thread, SecurityException} -import java.net.{InetAddress, ServerSocket, Socket, UnknownHostException} +import java.net.{InetAddress, InetSocketAddress, ServerSocket, Socket, SocketTimeoutException, UnknownHostException} import scala.collection.mutable import scala.util.Random @@ -59,6 +59,23 @@ object TcpService { portnum } + private val connectTimeoutMillis = { + val propName = "scala.actors.tcpSocket.connectTimeoutMillis" + val defaultTimeoutMillis = 0 + sys.props get propName flatMap { + timeout => + try { + val to = timeout.toInt + Debug.info("Using socket timeout $to") + Some(to) + } catch { + case e: NumberFormatException => + Debug.warning(s"""Could not parse $propName = "$timeout" as an Int""") + None + } + } getOrElse defaultTimeoutMillis + } + var BufSize: Int = 65536 } @@ -176,7 +193,15 @@ class TcpService(port: Int, cl: ClassLoader) extends Thread with Service { } def connect(n: Node): TcpServiceWorker = synchronized { - val socket = new Socket(n.address, n.port) + val socket = new Socket() + val start = System.nanoTime + try { + socket.connect(new InetSocketAddress(n.address, n.port), TcpService.connectTimeoutMillis) + } catch { + case e: SocketTimeoutException => + Debug.warning(f"Timed out connecting to $n after ${(System.nanoTime - start) / math.pow(10, 9)}%.3f seconds") + throw e + } val worker = new TcpServiceWorker(this, socket) worker.sendNode(n) worker.start() diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index b05902a6ef..b8791c15dc 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1107,32 +1107,33 @@ self => * | symbol * | null * }}} - * @note The returned tree does not yet have a position */ - def literal(isNegated: Boolean = false, inPattern: Boolean = false): Tree = { - def finish(value: Any): Tree = { - val t = Literal(Constant(value)) - in.nextToken() - t - } - if (in.token == SYMBOLLIT) - Apply(scalaDot(nme.Symbol), List(finish(in.strVal))) - else if (in.token == INTERPOLATIONID) - interpolatedString(inPattern = inPattern) - else finish(in.token match { - case CHARLIT => in.charVal - case INTLIT => in.intVal(isNegated).toInt - case LONGLIT => in.intVal(isNegated) - case FLOATLIT => in.floatVal(isNegated).toFloat - case DOUBLELIT => in.floatVal(isNegated) - case STRINGLIT | STRINGPART => in.strVal.intern() - case TRUE => true - case FALSE => false - case NULL => null - case _ => - syntaxErrorOrIncomplete("illegal literal", true) - null - }) + def literal(isNegated: Boolean = false, inPattern: Boolean = false, start: Int = in.offset): Tree = { + atPos(start) { + def finish(value: Any): Tree = { + val t = Literal(Constant(value)) + in.nextToken() + t + } + if (in.token == SYMBOLLIT) + Apply(scalaDot(nme.Symbol), List(finish(in.strVal))) + else if (in.token == INTERPOLATIONID) + interpolatedString(inPattern = inPattern) + else finish(in.token match { + case CHARLIT => in.charVal + case INTLIT => in.intVal(isNegated).toInt + case LONGLIT => in.intVal(isNegated) + case FLOATLIT => in.floatVal(isNegated).toFloat + case DOUBLELIT => in.floatVal(isNegated) + case STRINGLIT | STRINGPART => in.strVal.intern() + case TRUE => true + case FALSE => false + case NULL => null + case _ => + syntaxErrorOrIncomplete("illegal literal", true) + null + }) + } } private def stringOp(t: Tree, op: TermName) = { @@ -1509,7 +1510,7 @@ self => atPos(in.offset) { val name = nme.toUnaryName(rawIdent()) if (name == nme.UNARY_- && isNumericLit) - simpleExprRest(atPos(in.offset)(literal(isNegated = true)), canApply = true) + simpleExprRest(literal(isNegated = true), canApply = true) else Select(stripParens(simpleExpr()), name) } @@ -1534,7 +1535,7 @@ self => def simpleExpr(): Tree = { var canApply = true val t = - if (isLiteral) atPos(in.offset)(literal()) + if (isLiteral) literal() else in.token match { case XMLSTART => xmlLiteral() @@ -1923,7 +1924,7 @@ self => case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => t match { case Ident(nme.MINUS) => - return atPos(start) { literal(isNegated = true, inPattern = true) } + return literal(isNegated = true, inPattern = true, start = start) case _ => } case _ => @@ -1941,7 +1942,7 @@ self => atPos(start, start) { Ident(nme.WILDCARD) } case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | INTERPOLATIONID | SYMBOLLIT | TRUE | FALSE | NULL => - atPos(start) { literal(inPattern = true) } + literal(inPattern = true) case LPAREN => atPos(start)(makeParens(noSeq.patterns())) case XMLSTART => diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index c05906c740..1aa50be83a 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -425,6 +425,7 @@ trait Scanners extends ScannersCommon { if (ch == '\"') { nextRawChar() if (ch == '\"') { + offset += 3 nextRawChar() getStringPart(multiLine = true) sepRegions = STRINGPART :: sepRegions // indicate string part @@ -434,6 +435,7 @@ trait Scanners extends ScannersCommon { strVal = "" } } else { + offset += 1 getStringPart(multiLine = false) sepRegions = STRINGLIT :: sepRegions // indicate single line string part } diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 8aa9b81a72..0779e648cd 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -420,6 +420,9 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { case FINAL => flags |= Flags.FINAL in.nextToken + case DEFAULT => + flags |= Flags.DEFAULTMETHOD + in.nextToken() case NATIVE => addAnnot(NativeAttr) in.nextToken @@ -544,8 +547,9 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { val vparams = formalParams() if (!isVoid) rtpt = optArrayBrackets(rtpt) optThrows() + val bodyOk = !inInterface || (mods hasFlag Flags.DEFAULTMETHOD) val body = - if (!inInterface && in.token == LBRACE) { + if (bodyOk && in.token == LBRACE) { methodBody() } else { if (parentToken == AT && in.token == DEFAULT) { diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index fb2301de65..da117540b4 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -52,18 +52,14 @@ abstract class ClassfileParser { private def handleMissing(e: MissingRequirementError) = { if (settings.debug.value) e.printStackTrace - throw new IOException("Missing dependency '" + e.req + "', required by " + in.file) + throw new IOException(s"Missing dependency '${e.req}', required by ${in.file}") } private def handleError(e: Exception) = { if (settings.debug.value) e.printStackTrace() - throw new IOException("class file '%s' is broken\n(%s/%s)".format( - in.file, - e.getClass, - if (e.getMessage eq null) "" else e.getMessage) - ) + throw new IOException(s"class file '${in.file}' is broken\n(${e.getClass}/${e.getMessage})") } private def mismatchError(c: Symbol) = { - throw new IOException("class file '%s' has location not matching its contents: contains ".format(in.file) + c) + throw new IOException(s"class file '${in.file}' has location not matching its contents: contains $c") } private def parseErrorHandler[T]: PartialFunction[Throwable, T] = { @@ -72,8 +68,8 @@ abstract class ClassfileParser { } @inline private def pushBusy[T](sym: Symbol)(body: => T): T = { busy match { - case Some(`sym`) => throw new IOException("unsatisfiable cyclic dependency in '%s'".format(sym)) - case Some(sym1) => throw new IOException("illegal class file dependency between '%s' and '%s'".format(sym, sym1)) + case Some(`sym`) => throw new IOException(s"unsatisfiable cyclic dependency in '$sym'") + case Some(sym1) => throw new IOException(s"illegal class file dependency between '$sym' and '$sym1'") case _ => () } @@ -232,8 +228,6 @@ abstract class ClassfileParser { forceMangledName(tpe0.typeSymbol.name, false) val (name, tpe) = getNameAndType(in.getChar(start + 3), ownerTpe) -// println("new tpe: " + tpe + " at phase: " + phase) - if (name == nme.MODULE_INSTANCE_FIELD) { val index = in.getChar(start + 1) val name = getExternalName(in.getChar(starts(index) + 1)) @@ -244,14 +238,12 @@ abstract class ClassfileParser { } else { val origName = nme.originalName(name) val owner = if (static) ownerTpe.typeSymbol.linkedClassOfClass else ownerTpe.typeSymbol -// println("\t" + owner.info.member(name).tpe.widen + " =:= " + tpe) f = owner.info.findMember(origName, 0, 0, false).suchThat(_.tpe.widen =:= tpe) if (f == NoSymbol) f = owner.info.findMember(newTermName(origName + nme.LOCAL_SUFFIX_STRING), 0, 0, false).suchThat(_.tpe =:= tpe) if (f == NoSymbol) { // if it's an impl class, try to find it's static member inside the class if (ownerTpe.typeSymbol.isImplClass) { -// println("impl class, member: " + owner.tpe.member(origName) + ": " + owner.tpe.member(origName).tpe) f = ownerTpe.findMember(origName, 0, 0, false).suchThat(_.tpe =:= tpe) } else { log("Couldn't find " + name + ": " + tpe + " inside: \n" + ownerTpe) @@ -262,11 +254,13 @@ abstract class ClassfileParser { f setInfo tpe log("created fake member " + f.fullName) } -// println("\townerTpe.decls: " + ownerTpe.decls) -// println("Looking for: " + name + ": " + tpe + " inside: " + ownerTpe.typeSymbol + "\n\tand found: " + ownerTpe.members) } } - assert(f != NoSymbol, "could not find\n " + name + ": " + tpe + "\ninside:\n " + ownerTpe.members.mkString(", ")) + assert(f != NoSymbol, + s"could not find $name: $tpe in $ownerTpe" + ( + if (settings.debug.value) ownerTpe.members.mkString(", members are:\n ", "\n ", "") else "" + ) + ) values(index) = f } f @@ -586,11 +580,9 @@ abstract class ClassfileParser { def addEnclosingTParams(clazz: Symbol) { var sym = clazz.owner while (sym.isClass && !sym.isModuleClass) { -// println("adding tparams of " + sym) - for (t <- sym.tpe.typeArgs) { -// println("\tadding " + (t.typeSymbol.name + "->" + t.typeSymbol)) + for (t <- sym.tpe.typeArgs) classTParams = classTParams + (t.typeSymbol.name -> t.typeSymbol) - } + sym = sym.owner } } @@ -740,10 +732,7 @@ abstract class ClassfileParser { // raw type - existentially quantify all type parameters val eparams = typeParamsToExistentials(classSym, classSym.unsafeTypeParams) val t = typeRef(pre, classSym, eparams.map(_.tpeHK)) - val res = newExistentialType(eparams, t) - if (settings.debug.value && settings.verbose.value) - println("raw type " + classSym + " -> " + res) - res + newExistentialType(eparams, t) } case tp => assert(sig.charAt(index) != '<', s"sig=$sig, index=$index, tp=$tp") @@ -865,8 +854,6 @@ abstract class ClassfileParser { val sig = pool.getExternalName(in.nextChar) val newType = sigToType(sym, sig) sym.setInfo(newType) - if (settings.debug.value && settings.verbose.value) - println("" + sym + "; signature = " + sig + " type = " + newType) } else in.skip(attrLen) case tpnme.SyntheticATTR => @@ -883,10 +870,10 @@ abstract class ClassfileParser { val c = pool.getConstant(in.nextChar) val c1 = convertTo(c, symtype) if (c1 ne null) sym.setInfo(ConstantType(c1)) - else println("failure to convert " + c + " to " + symtype); //debug + else debugwarn(s"failure to convert $c to $symtype") case tpnme.ScalaSignatureATTR => if (!isScalaAnnot) { - debuglog("warning: symbol " + sym.fullName + " has pickled signature in attribute") + debugwarn(s"symbol ${sym.fullName} has pickled signature in attribute") unpickler.unpickle(in.buf, in.bp, clazz, staticModule, in.file.name) } in.skip(attrLen) @@ -931,6 +918,12 @@ abstract class ClassfileParser { case pkg => pkg.fullName(File.separatorChar)+File.separator+srcfileLeaf } srcfile0 = settings.outputDirs.srcFilesFor(in.file, srcpath).find(_.exists) + case tpnme.CodeATTR => + if (sym.owner.isInterface) { + sym setFlag DEFAULTMETHOD + log(s"$sym in ${sym.owner} is a java8+ default method.") + } + in.skip(attrLen) case _ => in.skip(attrLen) } @@ -1018,16 +1011,18 @@ abstract class ClassfileParser { } if (hasError) None else Some(AnnotationInfo(attrType, List(), nvpairs.toList)) - } catch { - case f: FatalError => throw f // don't eat fatal errors, they mean a class was not found - case ex: Throwable => + } + catch { + case f: FatalError => throw f // don't eat fatal errors, they mean a class was not found + case ex: java.lang.Error => throw ex + case ex: Throwable => // We want to be robust when annotations are unavailable, so the very least // we can do is warn the user about the exception // There was a reference to ticket 1135, but that is outdated: a reference to a class not on // the classpath would *not* end up here. A class not found is signaled // with a `FatalError` exception, handled above. Here you'd end up after a NPE (for example), // and that should never be swallowed silently. - warning("Caught: " + ex + " while parsing annotations in " + in.file) + warning(s"Caught: $ex while parsing annotations in ${in.file}") if (settings.debug.value) ex.printStackTrace() None // ignore malformed annotations diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index e8b0cd2696..c3aded2b2d 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -293,7 +293,6 @@ abstract class Pickler extends SubComponent { putTree(definition) */ case Template(parents, self, body) => - writeNat(parents.length) putTrees(parents) putTree(self) putTrees(body) diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 01ae0a7a94..04e0b9d653 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -149,7 +149,7 @@ trait Implicits { class SearchResult(val tree: Tree, val subst: TreeTypeSubstituter) { override def toString = "SearchResult(%s, %s)".format(tree, if (subst.isEmpty) "" else subst) - + def isFailure = false def isAmbiguousFailure = false final def isSuccess = !isFailure @@ -158,7 +158,7 @@ trait Implicits { lazy val SearchFailure = new SearchResult(EmptyTree, EmptyTreeTypeSubstituter) { override def isFailure = true } - + lazy val AmbiguousSearchFailure = new SearchResult(EmptyTree, EmptyTreeTypeSubstituter) { override def isFailure = true override def isAmbiguousFailure = true @@ -892,11 +892,20 @@ trait Implicits { */ if (divergence) throw DivergentImplicit - - if (invalidImplicits.nonEmpty) + else invalidImplicits take 1 foreach { sym => + def isSensibleAddendum = pt match { + case Function1(_, out) => out <:< sym.tpe.finalResultType + case tp => tp <:< sym.tpe.finalResultType + case _ => false + } + // Don't pitch in with this theory unless it looks plausible that the + // implicit would have helped setAddendum(pos, () => - "\n Note: implicit "+invalidImplicits.head+" is not applicable here"+ - " because it comes after the application point and it lacks an explicit result type") + if (isSensibleAddendum) + s"\n Note: implicit $sym is not applicable here because it comes after the application point and it lacks an explicit result type" + else "" + ) + } } best diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 94d92af228..03ce710700 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -383,7 +383,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans overrideError("cannot be used here - classes can only override abstract types"); } else if (other.isEffectivelyFinal) { // (1.2) overrideError("cannot override final member"); - } else if (!other.isDeferred && !member.isAnyOverride && !member.isSynthetic) { // (*) + } else if (!other.isDeferred && !other.hasFlag(DEFAULTMETHOD) && !member.isAnyOverride && !member.isSynthetic) { // (*) // (*) Synthetic exclusion for (at least) default getters, fixes SI-5178. We cannot assign the OVERRIDE flag to // the default getter: one default getter might sometimes override, sometimes not. Example in comment on ticket. if (isNeitherInClass && !(other.owner isSubClass member.owner)) diff --git a/src/compiler/scala/tools/reflect/MacroImplementations.scala b/src/compiler/scala/tools/reflect/MacroImplementations.scala index ae13cc561f..f4f385f8b3 100644 --- a/src/compiler/scala/tools/reflect/MacroImplementations.scala +++ b/src/compiler/scala/tools/reflect/MacroImplementations.scala @@ -4,6 +4,7 @@ import scala.reflect.macros.{ReificationException, UnexpectedReificationExceptio import scala.reflect.macros.runtime.Context import scala.collection.mutable.ListBuffer import scala.collection.mutable.Stack +import scala.reflect.internal.util.OffsetPosition abstract class MacroImplementations { val c: Context @@ -26,16 +27,12 @@ abstract class MacroImplementations { c.abort(args(parts.length-1).pos, "too many arguments for interpolated string") } - val stringParts = parts map { - case Literal(Constant(s: String)) => s; - case _ => throw new IllegalArgumentException("argument parts must be a list of string literals") - } - val pi = stringParts.iterator + val pi = parts.iterator val bldr = new java.lang.StringBuilder val evals = ListBuffer[ValDef]() val ids = ListBuffer[Ident]() - val argsStack = Stack(args : _*) + val argStack = Stack(args : _*) def defval(value: Tree, tpe: Type): Unit = { val freshName = newTermName(c.fresh("arg$")) @@ -82,50 +79,73 @@ abstract class MacroImplementations { } def copyString(first: Boolean): Unit = { - val str = StringContext.treatEscapes(pi.next()) + val strTree = pi.next() + val rawStr = strTree match { + case Literal(Constant(str: String)) => str + case _ => throw new IllegalArgumentException("internal error: argument parts must be a list of string literals") + } + val str = StringContext.treatEscapes(rawStr) val strLen = str.length val strIsEmpty = strLen == 0 - var start = 0 + def charAtIndexIs(idx: Int, ch: Char) = idx < strLen && str(idx) == ch + def isPercent(idx: Int) = charAtIndexIs(idx, '%') + def isConversion(idx: Int) = isPercent(idx) && !charAtIndexIs(idx + 1, 'n') && !charAtIndexIs(idx + 1, '%') var idx = 0 + def errorAtIndex(idx: Int, msg: String) = c.error(new OffsetPosition(strTree.pos.source, strTree.pos.point + idx), msg) + def wrongConversionString(idx: Int) = errorAtIndex(idx, "wrong conversion string") + def illegalConversionCharacter(idx: Int) = errorAtIndex(idx, "illegal conversion character") + def nonEscapedPercent(idx: Int) = errorAtIndex(idx, "percent signs not directly following splicees must be escaped") + + // STEP 1: handle argument conversion + // 1) "...${smth}" => okay, equivalent to "...${smth}%s" + // 2) "...${smth}blahblah" => okay, equivalent to "...${smth}%sblahblah" + // 3) "...${smth}%" => error + // 4) "...${smth}%n" => okay, equivalent to "...${smth}%s%n" + // 5) "...${smth}%%" => okay, equivalent to "...${smth}%s%%" + // 6) "...${smth}[%legalJavaConversion]" => okay, according to http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html + // 7) "...${smth}[%illegalJavaConversion]" => error if (!first) { - val arg = argsStack.pop - if (strIsEmpty || (str charAt 0) != '%') { - bldr append "%s" - defval(arg, AnyTpe) - } else { + val arg = argStack.pop + if (isConversion(0)) { // PRE str is not empty and str(0) == '%' // argument index parameter is not allowed, thus parse // [flags][width][.precision]conversion var pos = 1 - while(pos < strLen && isFlag(str charAt pos)) pos += 1 - while(pos < strLen && Character.isDigit(str charAt pos)) pos += 1 - if(pos < strLen && str.charAt(pos) == '.') { pos += 1 - while(pos < strLen && Character.isDigit(str charAt pos)) pos += 1 + while (pos < strLen && isFlag(str charAt pos)) pos += 1 + while (pos < strLen && Character.isDigit(str charAt pos)) pos += 1 + if (pos < strLen && str.charAt(pos) == '.') { + pos += 1 + while (pos < strLen && Character.isDigit(str charAt pos)) pos += 1 } - if(pos < strLen) { + if (pos < strLen) { conversionType(str charAt pos, arg) match { case Some(tpe) => defval(arg, tpe) - case None => c.error(arg.pos, "illegal conversion character") + case None => illegalConversionCharacter(pos) } } else { - // TODO: place error message on conversion string - c.error(arg.pos, "wrong conversion string") + wrongConversionString(pos - 1) } + idx = 1 + } else { + bldr append "%s" + defval(arg, AnyTpe) } - idx = 1 } + + // STEP 2: handle the rest of the text + // 1) %n tokens are left as is + // 2) %% tokens are left as is + // 3) other usages of percents are reported as errors if (!strIsEmpty) { - val len = str.length - while (idx < len) { - def notPercentN = str(idx) != '%' || (idx + 1 < len && str(idx + 1) != 'n') - if (str(idx) == '%' && notPercentN) { - bldr append (str substring (start, idx)) append "%%" - start = idx + 1 + while (idx < strLen) { + if (isPercent(idx)) { + if (isConversion(idx)) nonEscapedPercent(idx) + else idx += 1 // skip n and % in %n and %% } idx += 1 } - bldr append (str substring (start, idx)) + bldr append (str take idx) } } diff --git a/src/partest/scala/tools/partest/CompilerTest.scala b/src/partest/scala/tools/partest/CompilerTest.scala index d73d99bc89..848deef8c5 100644 --- a/src/partest/scala/tools/partest/CompilerTest.scala +++ b/src/partest/scala/tools/partest/CompilerTest.scala @@ -19,7 +19,7 @@ abstract class CompilerTest extends DirectTest { def check(source: String, unit: global.CompilationUnit): Unit lazy val global: Global = newCompiler() - lazy val units = compilationUnits(global)(sources: _ *) + lazy val units: List[global.CompilationUnit] = compilationUnits(global)(sources: _ *) import global._ import definitions._ diff --git a/src/partest/scala/tools/partest/DirectTest.scala b/src/partest/scala/tools/partest/DirectTest.scala index 483cb491a1..e2dac2fd55 100644 --- a/src/partest/scala/tools/partest/DirectTest.scala +++ b/src/partest/scala/tools/partest/DirectTest.scala @@ -7,7 +7,7 @@ package scala.tools.partest import scala.tools.nsc._ import io.Directory -import util.{BatchSourceFile, CommandLineParser} +import util.{ SourceFile, BatchSourceFile, CommandLineParser } import reporters.{Reporter, ConsoleReporter} /** A class for testing code which is embedded as a string. @@ -49,18 +49,32 @@ abstract class DirectTest extends App { def reporter(settings: Settings): Reporter = new ConsoleReporter(settings) - def newSources(sourceCodes: String*) = sourceCodes.toList.zipWithIndex map { - case (src, idx) => new BatchSourceFile("newSource" + (idx + 1), src) - } + private def newSourcesWithExtension(ext: String)(codes: String*): List[BatchSourceFile] = + codes.toList.zipWithIndex map { + case (src, idx) => new BatchSourceFile(s"newSource${idx + 1}.$ext", src) + } + + def newJavaSources(codes: String*) = newSourcesWithExtension("java")(codes: _*) + def newSources(codes: String*) = newSourcesWithExtension("scala")(codes: _*) + def compileString(global: Global)(sourceCode: String): Boolean = { withRun(global)(_ compileSources newSources(sourceCode)) !global.reporter.hasErrors } - def compilationUnits(global: Global)(sourceCodes: String*): List[global.CompilationUnit] = { - val units = withRun(global) { run => - run compileSources newSources(sourceCodes: _*) + + def javaCompilationUnits(global: Global)(sourceCodes: String*) = { + sourceFilesToCompiledUnits(global)(newJavaSources(sourceCodes: _*)) + } + + def sourceFilesToCompiledUnits(global: Global)(files: List[SourceFile]) = { + withRun(global) { run => + run compileSources files run.units.toList } + } + + def compilationUnits(global: Global)(sourceCodes: String*): List[global.CompilationUnit] = { + val units = sourceFilesToCompiledUnits(global)(newSources(sourceCodes: _*)) if (global.reporter.hasErrors) { global.reporter.flush() sys.error("Compilation failure.") diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala index 86cbba9c50..5ebe02d95d 100644 --- a/src/reflect/scala/reflect/internal/Flags.scala +++ b/src/reflect/scala/reflect/internal/Flags.scala @@ -59,9 +59,9 @@ import scala.collection.{ mutable, immutable } // 42: VBRIDGE // 43: VARARGS // 44: TRIEDCOOKING -// 45: -// 46: -// 47: +// 45: SYNCHRONIZED/M +// 46: ARTIFACT +// 47: DEFAULTMETHOD/M // 48: // 49: // 50: @@ -116,6 +116,8 @@ class ModifierFlags { final val LAZY = 1L << 31 // symbol is a lazy val. can't have MUTABLE unless transformed by typer final val PRESUPER = 1L << 37 // value is evaluated before super call final val DEFAULTINIT = 1L << 41 // symbol is initialized to the default value: used by -Xcheckinit + // ARTIFACT at #46 in 2.11+ + final val DEFAULTMETHOD = 1L << 47 // symbol is a java default method // Overridden. def flagToString(flag: Long): String = "" @@ -239,7 +241,7 @@ class Flags extends ModifierFlags { */ final val ExplicitFlags = PRIVATE | PROTECTED | ABSTRACT | FINAL | SEALED | - OVERRIDE | CASE | IMPLICIT | ABSOVERRIDE | LAZY + OVERRIDE | CASE | IMPLICIT | ABSOVERRIDE | LAZY | DEFAULTMETHOD /** The two bridge flags */ final val BridgeFlags = BRIDGE | VBRIDGE @@ -421,7 +423,7 @@ class Flags extends ModifierFlags { case TRIEDCOOKING => "<triedcooking>" // (1L << 44) case SYNCHRONIZED => "<synchronized>" // (1L << 45) case 0x400000000000L => "" // (1L << 46) - case 0x800000000000L => "" // (1L << 47) + case DEFAULTMETHOD => "<defaultmethod>" // (1L << 47) case 0x1000000000000L => "" // (1L << 48) case 0x2000000000000L => "" // (1L << 49) case 0x4000000000000L => "" // (1L << 50) diff --git a/src/reflect/scala/reflect/internal/util/Statistics.scala b/src/reflect/scala/reflect/internal/util/Statistics.scala index af4a0263ec..cbd27b0d65 100644 --- a/src/reflect/scala/reflect/internal/util/Statistics.scala +++ b/src/reflect/scala/reflect/internal/util/Statistics.scala @@ -103,7 +103,7 @@ quant) r <- q :: q.children.toList if r.prefix.nonEmpty) yield r private def showPercent(x: Double, base: Double) = - if (base == 0) "" else f" (${x / base * 100}%2.1f%)" + if (base == 0) "" else f" (${x / base * 100}%2.1f%%)" /** The base trait for quantities. * Quantities with non-empty prefix are printed in the statistics info. diff --git a/test/files/neg/stringinterpolation_macro-neg.check b/test/files/neg/stringinterpolation_macro-neg.check index 8986b899a3..457f497f2f 100644 --- a/test/files/neg/stringinterpolation_macro-neg.check +++ b/test/files/neg/stringinterpolation_macro-neg.check @@ -66,5 +66,5 @@ Note that implicit conversions are not applicable because they are ambiguous: ^ stringinterpolation_macro-neg.scala:30: error: illegal conversion character f"$s%i" - ^ + ^ 15 errors found diff --git a/test/files/neg/t5510.check b/test/files/neg/t5510.check index 04220e79bb..322a2f5e25 100644 --- a/test/files/neg/t5510.check +++ b/test/files/neg/t5510.check @@ -1,15 +1,15 @@ t5510.scala:2: error: unclosed string literal val s1 = s"xxx - ^ + ^ t5510.scala:3: error: unclosed string literal val s2 = s"xxx $x ^ t5510.scala:4: error: unclosed string literal val s3 = s"xxx $$ - ^ + ^ t5510.scala:5: error: unclosed string literal val s4 = ""s" - ^ + ^ t5510.scala:6: error: unclosed multi-line string literal val s5 = ""s""" $s1 $s2 s" ^ diff --git a/test/files/neg/t5856.check b/test/files/neg/t5856.check index ac49d4b9ac..08a61bdc07 100644 --- a/test/files/neg/t5856.check +++ b/test/files/neg/t5856.check @@ -1,6 +1,6 @@ t5856.scala:10: error: invalid string interpolation: `$$', `$'ident or `$'BlockExpr expected val s9 = s"$" - ^ + ^ t5856.scala:10: error: unclosed string literal val s9 = s"$" ^ diff --git a/test/files/neg/t7325.check b/test/files/neg/t7325.check new file mode 100644 index 0000000000..709ab6db3e --- /dev/null +++ b/test/files/neg/t7325.check @@ -0,0 +1,19 @@ +t7325.scala:2: error: percent signs not directly following splicees must be escaped + println(f"%") + ^ +t7325.scala:4: error: percent signs not directly following splicees must be escaped + println(f"%%%") + ^ +t7325.scala:6: error: percent signs not directly following splicees must be escaped + println(f"%%%%%") + ^ +t7325.scala:16: error: wrong conversion string + println(f"${0}%") + ^ +t7325.scala:19: error: percent signs not directly following splicees must be escaped + println(f"${0}%%%d") + ^ +t7325.scala:21: error: percent signs not directly following splicees must be escaped + println(f"${0}%%%%%d") + ^ +6 errors found diff --git a/test/files/neg/t7325.scala b/test/files/neg/t7325.scala new file mode 100644 index 0000000000..adfd8dd47a --- /dev/null +++ b/test/files/neg/t7325.scala @@ -0,0 +1,25 @@ +object Test extends App { + println(f"%") + println(f"%%") + println(f"%%%") + println(f"%%%%") + println(f"%%%%%") + println(f"%%%%%%") + + println(f"%%n") + println(f"%%%n") + println(f"%%%%n") + println(f"%%%%%n") + println(f"%%%%%%n") + println(f"%%%%%%%n") + + println(f"${0}%") + println(f"${0}%d") + println(f"${0}%%d") + println(f"${0}%%%d") + println(f"${0}%%%%d") + println(f"${0}%%%%%d") + + println(f"${0}%n") + println(f"${0}%d%n") +}
\ No newline at end of file diff --git a/test/files/neg/t7441.check b/test/files/neg/t7441.check new file mode 100644 index 0000000000..f259457197 --- /dev/null +++ b/test/files/neg/t7441.check @@ -0,0 +1,6 @@ +t7441.scala:4: error: type mismatch; + found : Int(1) + required: List[Any] + def test = apply(1) + ^ +one error found diff --git a/test/files/neg/t7441.scala b/test/files/neg/t7441.scala new file mode 100644 index 0000000000..dad7421e3f --- /dev/null +++ b/test/files/neg/t7441.scala @@ -0,0 +1,7 @@ +object Test { + object Bar { + def apply(xs: List[Any]): Int = 0 + def test = apply(1) + } + implicit def foo = 1 +} diff --git a/test/files/pos/t7426.scala b/test/files/pos/t7426.scala new file mode 100644 index 0000000000..8e42ad1812 --- /dev/null +++ b/test/files/pos/t7426.scala @@ -0,0 +1,3 @@ +class foo(x: Any) extends annotation.StaticAnnotation + +@foo(new AnyRef { }) trait A diff --git a/test/files/run/interpolation.scala b/test/files/run/interpolation.scala index f443bd5feb..14d9819348 100644 --- a/test/files/run/interpolation.scala +++ b/test/files/run/interpolation.scala @@ -13,7 +13,7 @@ object Test extends App { println(s"Best price: $f") println(f"Best price: $f%.2f") println(s"$f% discount included") - println(f"$f%3.2f% discount included") + println(f"$f%3.2f%% discount included") } test1(1) diff --git a/test/files/run/interpolationMultiline1.scala b/test/files/run/interpolationMultiline1.scala index 437aed44b0..db634e7775 100644 --- a/test/files/run/interpolationMultiline1.scala +++ b/test/files/run/interpolationMultiline1.scala @@ -13,7 +13,7 @@ object Test extends App { println(s"""Best price: $f""") println(f"""Best price: $f%.2f""") println(s"""$f% discount included""") - println(f"""$f%3.2f% discount included""") + println(f"""$f%3.2f%% discount included""") } test1(1) diff --git a/test/files/run/t5527.check b/test/files/run/t5527.check index 1518168c51..36bee9bb55 100644 --- a/test/files/run/t5527.check +++ b/test/files/run/t5527.check @@ -1,4 +1,4 @@ -[[syntax trees at end of parser]] // newSource1 +[[syntax trees at end of parser]] // newSource1.scala package <empty> { object UselessComments extends scala.AnyRef { def <init>() = { diff --git a/test/files/run/t5603.check b/test/files/run/t5603.check index 5127d3c1c7..3f19a0a4b1 100644 --- a/test/files/run/t5603.check +++ b/test/files/run/t5603.check @@ -1,4 +1,4 @@ -[[syntax trees at end of parser]] // newSource1 +[[syntax trees at end of parser]] // newSource1.scala [0:241]package [0:0]<empty> { [0:82]abstract trait Greeting extends [15:82][83]scala.AnyRef { [15]def $init$() = [15]{ diff --git a/test/files/run/t6028.check b/test/files/run/t6028.check index 94013efd36..613d25b075 100644 --- a/test/files/run/t6028.check +++ b/test/files/run/t6028.check @@ -1,4 +1,4 @@ -[[syntax trees at end of lambdalift]] // newSource1 +[[syntax trees at end of lambdalift]] // newSource1.scala package <empty> { class T extends Object { <paramaccessor> val T$$classParam: Int = _; diff --git a/test/files/run/t6288.check b/test/files/run/t6288.check index e6467edc95..e940975e44 100644 --- a/test/files/run/t6288.check +++ b/test/files/run/t6288.check @@ -1,4 +1,4 @@ -[[syntax trees at end of patmat]] // newSource1 +[[syntax trees at end of patmat]] // newSource1.scala [7]package [7]<empty> { [7]object Case3 extends [13][106]scala.AnyRef { [13]def <init>(): [13]Case3.type = [13]{ diff --git a/test/files/run/t6440.check b/test/files/run/t6440.check index 69c253eab4..806279fb74 100644 --- a/test/files/run/t6440.check +++ b/test/files/run/t6440.check @@ -1,4 +1,4 @@ -pos: source-newSource1,line-9,offset=109 bad symbolic reference. A signature in U.class refers to term pack1 +pos: source-newSource1.scala,line-9,offset=109 bad symbolic reference. A signature in U.class refers to term pack1 in package <root> which is not available. It may be completely missing from the current classpath, or the version on the classpath might be incompatible with the version used when compiling U.class. ERROR diff --git a/test/files/run/t6555.check b/test/files/run/t6555.check index 04117b7c2f..a18a8e8023 100644 --- a/test/files/run/t6555.check +++ b/test/files/run/t6555.check @@ -1,4 +1,4 @@ -[[syntax trees at end of specialize]] // newSource1 +[[syntax trees at end of specialize]] // newSource1.scala package <empty> { class Foo extends Object { def <init>(): Foo = { diff --git a/test/files/run/t7271.check b/test/files/run/t7271.check new file mode 100644 index 0000000000..dcd828a307 --- /dev/null +++ b/test/files/run/t7271.check @@ -0,0 +1,12 @@ +[[syntax trees at end of parser]] // newSource1.scala +[0:91]package [0:0]<empty> { + [0:91]class C extends [8:91][91]scala.AnyRef { + [8]def <init>() = [8]{ + [8][8][8]super.<init>(); + [8]() + }; + [16:44]def quote = [28:44]<28:44><28:44>[28]StringContext([30:34]"foo", [40:44]"baz").s([35:39]this); + [51:85]def tripleQuote = [69:85]<69:85><69:85>[69]StringContext([71:75]"foo", [81:85]"baz").s([76:80]this) + } +} + diff --git a/test/files/run/t7271.scala b/test/files/run/t7271.scala new file mode 100644 index 0000000000..6fccf14d20 --- /dev/null +++ b/test/files/run/t7271.scala @@ -0,0 +1,34 @@ +import scala.tools.partest._ +import java.io._ +import scala.tools.nsc._ +import scala.tools.nsc.util.CommandLineParser +import scala.tools.nsc.{Global, Settings, CompilerCommand} +import scala.tools.nsc.reporters.ConsoleReporter + +object Test extends DirectTest { + + override def extraSettings: String = "-usejavacp -Xprint:parser -Ystop-after:parser -d " + testOutput.path + + override def code = """ + class C { + def quote = s"foo${this}baz" + def tripleQuote = s"foo${this}baz" + } + """.trim + + override def show(): Unit = { + // redirect err to out, for logging + val prevErr = System.err + System.setErr(System.out) + compile() + System.setErr(prevErr) + } + + override def newCompiler(args: String*): Global = { + + val settings = new Settings() + settings.Xprintpos.value = true + val command = new CompilerCommand((CommandLineParser tokenize extraSettings) ++ args.toList, settings) + new Global(command.settings, new ConsoleReporter(settings)) with interactive.RangePositions + } +} diff --git a/test/files/run/t7325.check b/test/files/run/t7325.check new file mode 100644 index 0000000000..3c7652f42c --- /dev/null +++ b/test/files/run/t7325.check @@ -0,0 +1,19 @@ +% +%% +%%% +%n +% + +%%n +%% + +%%%n +%%% + +0 +0%d +0%%d +0 + +0 + diff --git a/test/files/run/t7325.scala b/test/files/run/t7325.scala new file mode 100644 index 0000000000..26f6bc6ef7 --- /dev/null +++ b/test/files/run/t7325.scala @@ -0,0 +1,25 @@ +object Test extends App { + // println(f"%") + println(f"%%") + // println(f"%%%") + println(f"%%%%") + // println(f"%%%%%") + println(f"%%%%%%") + + println(f"%%n") + println(f"%%%n") + println(f"%%%%n") + println(f"%%%%%n") + println(f"%%%%%%n") + println(f"%%%%%%%n") + + // println(f"${0}%") + println(f"${0}%d") + println(f"${0}%%d") + // println(f"${0}%%%d") + println(f"${0}%%%%d") + // println(f"${0}%%%%%d") + + println(f"${0}%n") + println(f"${0}%d%n") +}
\ No newline at end of file diff --git a/test/files/run/t7398.scala b/test/files/run/t7398.scala new file mode 100644 index 0000000000..e4090f7db3 --- /dev/null +++ b/test/files/run/t7398.scala @@ -0,0 +1,31 @@ +import scala.tools.partest._ + +object Test extends CompilerTest { + import global._ + + def javaVersion = scala.util.Properties.javaVersion + def isJavaEight = javaVersion startsWith "1.8" + // This way we auto-pass on non-java8 since there's nothing to check + override lazy val units = { + val res: List[CompilationUnit] = if (isJavaEight) javaCompilationUnits(global)(defaultMethodSource) else Nil + val word = if (isJavaEight) "Attempting" else "Skipping" + log(s"$word java8-specific test under java version $javaVersion") + res + } + + private def defaultMethodSource = """ +public interface Iterator<E> { + boolean hasNext(); + E next(); + default void remove() { + throw new UnsupportedOperationException("remove"); + } + default void forEachRemaining(Consumer<? super E> action) { + throw new UnsupportedOperationException("forEachRemaining"); + } +} + """ + + // We're only checking we can parse it. + def check(source: String, unit: global.CompilationUnit): Unit = () +} diff --git a/test/files/run/typetags_without_scala_reflect_typetag_lookup.check b/test/files/run/typetags_without_scala_reflect_typetag_lookup.check index 8c558ced60..84e5435afe 100644 --- a/test/files/run/typetags_without_scala_reflect_typetag_lookup.check +++ b/test/files/run/typetags_without_scala_reflect_typetag_lookup.check @@ -1,2 +1,2 @@ -pos: source-newSource1,line-9,offset=466 could not find implicit value for evidence parameter of type reflect.runtime.package.universe.TypeTag[Int] ERROR +pos: source-newSource1.scala,line-9,offset=466 could not find implicit value for evidence parameter of type reflect.runtime.package.universe.TypeTag[Int] ERROR diff --git a/test/files/run/typetags_without_scala_reflect_typetag_manifest_interop.check b/test/files/run/typetags_without_scala_reflect_typetag_manifest_interop.check index acfecce628..8c9d07d836 100644 --- a/test/files/run/typetags_without_scala_reflect_typetag_manifest_interop.check +++ b/test/files/run/typetags_without_scala_reflect_typetag_manifest_interop.check @@ -1,2 +1,2 @@ -pos: source-newSource1,line-9,offset=479 No Manifest available for App.this.T. ERROR +pos: source-newSource1.scala,line-9,offset=479 No Manifest available for App.this.T. ERROR |