diff options
56 files changed, 924 insertions, 287 deletions
diff --git a/project/Build.scala b/project/Build.scala index ea0e84f0cc..d3be8cd810 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -156,6 +156,8 @@ object ScalaBuild extends Build with Layers { def settingOverrides: Seq[Setting[_]] = publishSettings ++ Seq( crossPaths := false, autoScalaLibrary := false, + // Work around a bug where scala-library (and forkjoin) is put on classpath for analysis. + classpathOptions := ClasspathOptions.manual, publishArtifact in packageDoc := false, publishArtifact in packageSrc := false, target <<= (baseDirectory, name) apply (_ / "target" / _), @@ -168,8 +170,8 @@ object ScalaBuild extends Build with Layers { // Most libs in the compiler use this order to build. compileOrder in Compile := CompileOrder.JavaThenScala, lockFile <<= target(_ / "compile.lock"), - skip in Compile <<= lockFile.map(_ exists), - lock <<= lockFile map { f => IO.touch(f) }, + skip in Compile <<= lockFile map (_.exists), + lock <<= lockFile map (f => IO.touch(f)), unlock <<= lockFile map IO.delete ) diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Index.scala b/src/compiler/scala/tools/nsc/doc/html/page/Index.scala index 346780147e..f8fffdc726 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Index.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Index.scala @@ -44,7 +44,7 @@ class Index(universe: doc.Universe, index: doc.Index) extends HtmlPage { </div> { browser } <div id="content" class="ui-layout-center"> - <iframe name="template" src={ relativeLinkTo{List("package.html")} }/> + <iframe id="template" src={ relativeLinkTo{List("package.html")} }/> </div> </body> diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala index 220321d225..49cd17c176 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala @@ -87,7 +87,7 @@ class Template(universe: doc.Universe, tpl: DocTemplateEntity) extends HtmlPage { memberToCommentHtml(tpl, true) } <div id="mbrsel"> - <div id='textfilter'><span class='pre'/><span class='input'><input type='text' accesskey='/'/></span><span class='post'/></div> + <div id='textfilter'><span class='pre'/><span class='input'><input id='mbrsel-input' type='text' accesskey='/'/></span><span class='post'/></div> { if (tpl.linearizationTemplates.isEmpty && tpl.conversions.isEmpty) NodeSeq.Empty else <div id="order"> <span class="filtertype">Ordering</span> diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.css b/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.css index c6136c508e..2a8f9b570a 100644 --- a/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.css +++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.css @@ -1,23 +1,32 @@ * { - color: inherit; - font-size: 10pt; - text-decoration: none; + color: inherit; + font-size: 10pt; + text-decoration: none; font-family: Arial, sans-serif; - border-width: 0px; - padding: 0px; - margin: 0px; + border-width: 0px; + padding: 0px; + margin: 0px; } a { - cursor: pointer; + cursor: pointer; } a:hover { - text-decoration: underline; + text-decoration: underline; } h1 { - display: none; + display: none; +} + +.selected { + -moz-box-shadow: inset 0px 5px 10px rgba(58, 88, 97, .36); + -webkit-box-shadow: inset 0px 5px 10px rgba(58, 88, 97, .36); + border-top: solid 1px rgba(119, 138, 153, 0.8); + border-bottom: solid 1px rgba(151, 173, 191, 0.4); + background-color: #ced2d9; + margin: -1px 0px; } /*.letters { @@ -33,81 +42,81 @@ h1 { } #browser { - top: 0px; - left: 0px; - bottom: 0px; - width: 100%; - display: block; - position: fixed; + top: 0px; + left: 0px; + bottom: 0px; + width: 100%; + display: block; + position: fixed; } #filter { - position: absolute; - display: block; -/* padding: 5px;*/ - right: 0; - left: 0; - top: 0; - background-image:url('filterbg.gif'); - background-repeat:repeat-x; - background-color: #ededee; /* light gray */ - /*background-color: #DADADA;*/ - border:1px solid #bbbbbb; - border-top:0; - border-left:0; - border-right:0; + position: absolute; + display: block; +/* padding: 5px;*/ + right: 0; + left: 0; + top: 0; + background-image:url('filterbg.gif'); + background-repeat:repeat-x; + background-color: #ededee; /* light gray */ + /*background-color: #DADADA;*/ + border:1px solid #bbbbbb; + border-top:0; + border-left:0; + border-right:0; } #textfilter { - position: relative; - display: block; - height: 20px; - margin-top: 5px; - margin-bottom: 5px; + position: relative; + display: block; + height: 20px; + margin-top: 5px; + margin-bottom: 5px; } #textfilter > .pre { - display: block; - position: absolute; - top: 0; - left: 0; - height: 23px; - width: 21px; - background: url("filter_box_left.png"); + display: block; + position: absolute; + top: 0; + left: 0; + height: 23px; + width: 21px; + background: url("filter_box_left.png"); } #textfilter > .input { - display: block; - position: absolute; - top: 0; - right: 20px; - left: 20px; + display: block; + position: absolute; + top: 0; + right: 20px; + left: 20px; } #textfilter > .input > input { - height: 20px; - padding: 1px; - font-weight: bold; - color: #000000; - background: #ffffff url("filterboxbarbg.png") repeat-x bottom left; - width: 100%; + height: 20px; + padding: 1px; + font-weight: bold; + color: #000000; + background: #ffffff url("filterboxbarbg.png") repeat-x bottom left; + width: 100%; } #textfilter > .post { - display: block; - position: absolute; - top: 0; - right: 0; - height: 23px; - width: 21px; - background: url("filter_box_right.png"); + display: block; + position: absolute; + top: 0; + right: 0; + height: 23px; + width: 21px; + background: url("filter_box_right.png"); } /*#textfilter { - position: relative; - display: block; + position: relative; + display: block; height: 20px; - margin-bottom: 5px; + margin-bottom: 5px; } #textfilter > .pre { @@ -121,7 +130,7 @@ h1 { } #textfilter > .input { - display: block; + display: block; position: absolute; top: 0; right: 20px; @@ -129,11 +138,11 @@ h1 { } #textfilter > .input > input { - height: 16px; - padding: 2px; - font-weight: bold; - color: darkblue; - background-color: white; + height: 16px; + padding: 2px; + font-weight: bold; + color: darkblue; + background-color: white; width: 100%; } @@ -148,22 +157,22 @@ h1 { }*/ #focusfilter { - position: relative; - text-align: center; - display: block; - padding: 5px; - background-color: #fffebd; /* light yellow*/ - text-shadow: #ffffff 0 1px 0; + position: relative; + text-align: center; + display: block; + padding: 5px; + background-color: #fffebd; /* light yellow*/ + text-shadow: #ffffff 0 1px 0; } #focusfilter .focuscoll { - font-weight: bold; - text-shadow: #ffffff 0 1px 0; + font-weight: bold; + text-shadow: #ffffff 0 1px 0; } #focusfilter img { - bottom: -2px; - position: relative; + bottom: -2px; + position: relative; } #kindfilter { @@ -182,10 +191,9 @@ h1 { } #kindfilter > a:hover { - color: #4C4C4C; - text-decoration: none; - text-shadow: #ffffff 0 1px 0; - + color: #4C4C4C; + text-decoration: none; + text-shadow: #ffffff 0 1px 0; } #letters { @@ -208,117 +216,117 @@ h1 { } #tpl { - display: block; - position: fixed; - overflow: auto; - right: 0; - left: 0; - bottom: 0; - top: 5px; - position: absolute; - display: block; + display: block; + position: fixed; + overflow: auto; + right: 0; + left: 0; + bottom: 0; + top: 5px; + position: absolute; + display: block; } #tpl .packhide { - display: block; - float: right; - font-weight: normal; - color: white; + display: block; + float: right; + font-weight: normal; + color: white; } #tpl .packfocus { - display: block; - float: right; - font-weight: normal; - color: white; + display: block; + float: right; + font-weight: normal; + color: white; } #tpl .packages > ol { - background-color: #dadfe6; - /*margin-bottom: 5px;*/ + background-color: #dadfe6; + /*margin-bottom: 5px;*/ } /*#tpl .packages > ol > li { - margin-bottom: 1px; + margin-bottom: 1px; }*/ #tpl .packages > li > a { - padding: 0px 5px; + padding: 0px 5px; } #tpl .packages > li > a.tplshow { - display: block; - color: white; - font-weight: bold; - display: block; - text-shadow: #000000 0 1px 0; + display: block; + color: white; + font-weight: bold; + display: block; + text-shadow: #000000 0 1px 0; } #tpl ol > li.pack { - padding: 3px 5px; - background: url("packagesbg.gif"); - background-repeat:repeat-x; - min-height: 14px; - background-color: #6e808e; + padding: 3px 5px; + background: url("packagesbg.gif"); + background-repeat:repeat-x; + min-height: 14px; + background-color: #6e808e; } #tpl ol > li { - display: block; + display: block; } #tpl .templates > li { - padding-left: 5px; - min-height: 18px; + padding-left: 5px; + min-height: 18px; } #tpl ol > li .icon { - padding-right: 5px; - bottom: -2px; - position: relative; + padding-right: 5px; + bottom: -2px; + position: relative; } #tpl .templates div.placeholder { - padding-right: 5px; - width: 13px; - display: inline-block; + padding-right: 5px; + width: 13px; + display: inline-block; } #tpl .templates span.tplLink { - padding-left: 5px; + padding-left: 5px; } #content { - border-left-width: 1px; - border-left-color: black; - border-left-style: white; - right: 0px; - left: 0px; - bottom: 0px; - top: 0px; - position: fixed; - margin-left: 300px; - display: block; + border-left-width: 1px; + border-left-color: black; + border-left-style: white; + right: 0px; + left: 0px; + bottom: 0px; + top: 0px; + position: fixed; + margin-left: 300px; + display: block; } #content > iframe { - display: block; - height: 100%; - width: 100%; + display: block; + height: 100%; + width: 100%; } .ui-layout-pane { - background: #FFF; - overflow: auto; + background: #FFF; + overflow: auto; } .ui-layout-resizer { - background-image:url('filterbg.gif'); - background-repeat:repeat-x; - background-color: #ededee; /* light gray */ - border:1px solid #bbbbbb; - border-top:0; - border-bottom:0; - border-left: 0; + background-image:url('filterbg.gif'); + background-repeat:repeat-x; + background-color: #ededee; /* light gray */ + border:1px solid #bbbbbb; + border-top:0; + border-bottom:0; + border-left: 0; } .ui-layout-toggler { diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.js b/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.js index b767722b8c..eb7f752440 100644 --- a/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.js +++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.js @@ -15,10 +15,10 @@ var lastHash = ""; $(document).ready(function() { $('body').layout({ west__size: '20%' }); - $('#browser').layout({ - center__paneSelector: ".ui-west-center" + $('#browser').layout({ + center__paneSelector: ".ui-west-center" //,center__initClosed:true - ,north__paneSelector: ".ui-west-north" + ,north__paneSelector: ".ui-west-north" }); $('iframe').bind("load", function(){ var subtitle = $(this).contents().find('title').text(); @@ -260,18 +260,95 @@ function prepareEntityList() { .prepend("<a class='packfocus'>focus</a>"); } +/* Handles all key presses while scrolling around with keyboard shortcuts in left panel */ +function keyboardScrolldownLeftPane() { + scheduler.add("init", function() { + $("#textfilter input").blur(); + var $items = $("#tpl li"); + $items.first().addClass('selected'); + + $(window).bind("keydown", function(e) { + var $old = $items.filter('.selected'), + $new; + + switch ( e.keyCode ) { + + case 9: // tab + $old.removeClass('selected'); + break; + + case 13: // enter + $old.removeClass('selected'); + var $url = $old.children().filter('a:last').attr('href'); + $("#template").attr("src",$url); + break; + + case 27: // escape + $old.removeClass('selected'); + $(window).unbind(e); + $("#textfilter input").focus(); + + break; + + case 38: // up + $new = $old.prev(); + + if (!$new.length) { + $new = $old.parent().prev(); + } + + if ($new.is('ol') && $new.children(':last').is('ol')) { + $new = $new.children().children(':last'); + } else if ($new.is('ol')) { + $new = $new.children(':last'); + } + + break; + + case 40: // down + $new = $old.next(); + if (!$new.length) { + $new = $old.parent().parent().next(); + } + if ($new.is('ol')) { + $new = $new.children(':first'); + } + break; + } + + if ($new.is('li')) { + $old.removeClass('selected'); + $new.addClass('selected'); + } else if (e.keyCode == 38) { + $(window).unbind(e); + $("#textfilter input").focus(); + } + }); + }); +} + /* Configures the text filter */ function configureTextFilter() { scheduler.add("init", function() { - $("#filter").append("<div id='textfilter'><span class='pre'/><span class='input'><input type='text' accesskey='/'/></span><span class='post'/></div>"); + $("#filter").append("<div id='textfilter'><span class='pre'/><span class='input'><input id='index-input' type='text' accesskey='/'/></span><span class='post'/></div>"); printAlphabet(); var input = $("#textfilter input"); resizeFilterBlock(); - input.bind("keyup", function(event) { + input.bind("keydown", function(event) { if (event.keyCode == 27) { // escape input.attr("value", ""); } - textFilter(); + if (event.keyCode == 9) { // tab + $("#template").contents().find("#mbrsel-input").focus(); + input.attr("value", ""); + return false; + } + if (event.keyCode == 40) { // down arrow + $(window).unbind("keydown"); + keyboardScrolldownLeftPane(); + return false; + } + textFilter(); }); input.focus(function(event) { input.select(); }); }); diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.js b/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.js index fd5a981cb0..33fbd83bee 100644 --- a/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.js +++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/template.js @@ -25,9 +25,37 @@ $(document).ready(function(){ // Member filter box var input = $("#textfilter input"); input.bind("keyup", function(event) { - if (event.keyCode == 27) - input.val(""); // escape key - filter(true); + + switch ( event.keyCode ) { + + case 27: // escape key + input.val(""); + filter(true); + break; + + case 38: // up + input.val(""); + filter(false); + window.scrollTo(0, $("body").offset().top); + input.focus(); + break; + + case 33: //page up + input.val(""); + filter(false); + break; + + case 34: //page down + input.val(""); + filter(false); + break; + + default: + window.scrollTo(0, $("#mbrsel").offset().top); + filter(true); + break; + + } }); input.focus(function(event) { input.select(); @@ -37,13 +65,13 @@ $(document).ready(function(){ filter(); }); $(document).keydown(function(event) { - if(!event.altKey && !event.ctrlKey && - (event.keyCode == 27 || (event.keyCode >= 48 && event.keyCode <= 90)) && - document.activeElement != $("#textfilter input")[0]) { - $("#textfilter input").focus(); + + if (event.keyCode == 9) { // tab + $("#index-input", window.parent.document).focus(); + input.attr("value", ""); + return false; } }); - $("#textfilter input").focus(); $("#linearization li").click(function(){ if ($(this).hasClass("in")) { @@ -251,7 +279,8 @@ function initInherit() { }); }; -function filter(scrollToMember) { +/* filter used to take boolean scrollToMember */ +function filter() { var query = $.trim($("#textfilter input").val()).toLowerCase(); query = query.replace(/[-[\]{}()*+?.,\\^$|#]/g, "\\$&").replace(/\s+/g, "|"); var queryRegExp = new RegExp(query, "i"); @@ -327,10 +356,6 @@ function filter(scrollToMember) { members.hide(); }; - if (scrollToMember) { - window.scrollTo(0, $("#mbrsel").offset().top); - } - return false; }; diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 7f220992a3..8af12f3f10 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -77,9 +77,17 @@ abstract class UnCurry extends InfoTransform private var inConstructorFlag = 0L private val byNameArgs = mutable.HashSet[Tree]() private val noApply = mutable.HashSet[Tree]() - private val newMembers = mutable.ArrayBuffer[Tree]() + private val newMembers = mutable.Map[Symbol, mutable.Buffer[Tree]]() private val repeatedParams = mutable.Map[Symbol, List[ValDef]]() + /** Add a new synthetic member for `currentOwner` */ + private def addNewMember(t: Tree): Unit = + newMembers.getOrElseUpdate(currentOwner, mutable.Buffer()) += t + + /** Process synthetic members for `owner`. They are removed form the `newMembers` as a side-effect. */ + @inline private def useNewMembers[T](owner: Symbol)(f: List[Tree] => T): T = + f(newMembers.remove(owner).getOrElse(Nil).toList) + @inline private def withInPattern[T](value: Boolean)(body: => T): T = { inPattern = value try body @@ -568,7 +576,12 @@ abstract class UnCurry extends InfoTransform if ((sym ne null) && (sym.elisionLevel.exists (_ < settings.elidebelow.value || settings.noassertions.value))) replaceElidableTree(tree) else translateSynchronized(tree) match { - case dd @ DefDef(mods, name, tparams, vparamss, tpt, rhs) => + case dd @ DefDef(mods, name, tparams, _, tpt, rhs) => + // Remove default argument trees from parameter ValDefs, SI-4812 + val vparamssNoRhs = dd.vparamss mapConserve (_ mapConserve {p => + treeCopy.ValDef(p, p.mods, p.name, p.tpt, EmptyTree) + }) + if (dd.symbol hasAnnotation VarargsClass) saveRepeatedParams(dd) withNeedLift(false) { @@ -586,10 +599,10 @@ abstract class UnCurry extends InfoTransform } treeCopy.DefDef( dd, mods, name, transformTypeDefs(tparams), - transformValDefss(vparamss), transform(tpt), rhs1) + transformValDefss(vparamssNoRhs), transform(tpt), rhs1) } } else { - super.transform(dd) + super.transform(treeCopy.DefDef(dd, mods, name, tparams, vparamssNoRhs, tpt, rhs)) } } case ValDef(_, _, _, rhs) => @@ -675,9 +688,8 @@ abstract class UnCurry extends InfoTransform tree match { /* Some uncurry post transformations add members to templates. - * When inside a template, the following sequence is available: - * - newMembers - * Any entry in this sequence will be added into the template + * + * Members registered by `addMembers` for the current template are added * once the template transformation has finished. * * In particular, this case will add: @@ -685,8 +697,10 @@ abstract class UnCurry extends InfoTransform */ case Template(_, _, _) => localTyper = typer.atOwner(tree, currentClass) - try deriveTemplate(tree)(transformTrees(newMembers.toList) ::: _) - finally newMembers.clear() + useNewMembers(currentClass) { + newMembers => + deriveTemplate(tree)(transformTrees(newMembers) ::: _) + } case dd @ DefDef(_, _, _, vparamss0, _, rhs0) => val flatdd = copyDefDef(dd)( @@ -758,7 +772,7 @@ abstract class UnCurry extends InfoTransform /* Called during post transform, after the method argument lists have been flattened. * It looks for the method in the `repeatedParams` map, and generates a Java-style - * varargs forwarder. It then adds the forwarder to the `newMembers` sequence. + * varargs forwarder. */ private def addJavaVarargsForwarders(dd: DefDef, flatdd: DefDef): DefDef = { if (!dd.symbol.hasAnnotation(VarargsClass) || !repeatedParams.contains(dd.symbol)) @@ -835,8 +849,7 @@ abstract class UnCurry extends InfoTransform case None => // enter symbol into scope currentClass.info.decls enter forwsym - // add the method to `newMembers` - newMembers += forwtree + addNewMember(forwtree) } flatdd diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index df0258832c..eb3a1ffb5b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -874,8 +874,12 @@ trait ContextErrors { val s1 = if (prevSym.isModule) "case class companion " else "" val s2 = if (prevSym.isSynthetic) "(compiler-generated) " + s1 else "" val s3 = if (prevSym.isCase) "case class " + prevSym.name else "" + prevSym + val where = if (currentSym.owner.isPackageClass != prevSym.owner.isPackageClass) { + val inOrOut = if (prevSym.owner.isPackageClass) "outside of" else "in" + " %s package object %s".format(inOrOut, ""+prevSym.effectiveOwner.name) + } else "" - issueSymbolTypeError(currentSym, prevSym.name + " is already defined as " + s2 + s3) + issueSymbolTypeError(currentSym, prevSym.name + " is already defined as " + s2 + s3 + where) } def MaxParametersCaseClassError(tree: Tree) = @@ -1034,6 +1038,12 @@ trait ContextErrors { setError(arg) } else arg } + + def WarnAfterNonSilentRecursiveInference(param: Symbol, arg: Tree)(implicit context: Context) = { + val note = "type-checking the invocation of "+ param.owner +" checks if the named argument expression '"+ param.name + " = ...' is a valid assignment\n"+ + "in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for "+ param.name +"." + context.warning(arg.pos, note) + } def UnknownParameterNameNamesDefaultError(arg: Tree, name: Name)(implicit context: Context) = { issueNormalTypeError(arg, "unknown parameter name: " + name) diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala index 2574a1d241..b7a6ea677e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala @@ -143,8 +143,8 @@ abstract class Duplicators extends Analyzer { else sym - private def invalidate(tree: Tree) { - debuglog("attempting to invalidate " + tree.symbol + ", owner - " + (if (tree.symbol ne null) tree.symbol.owner else "<NULL>")) + private def invalidate(tree: Tree, owner: Symbol = NoSymbol) { + debuglog("attempting to invalidate " + tree.symbol) if (tree.isDef && tree.symbol != NoSymbol) { debuglog("invalid " + tree.symbol) invalidSyms(tree.symbol) = tree @@ -158,18 +158,20 @@ abstract class Duplicators extends Analyzer { newsym.setInfo(fixType(ldef.symbol.info)) ldef.symbol = newsym debuglog("newsym: " + newsym + " info: " + newsym.info) - + case vdef @ ValDef(mods, name, _, rhs) if mods.hasFlag(Flags.LAZY) => debuglog("ValDef " + name + " sym.info: " + vdef.symbol.info) invalidSyms(vdef.symbol) = vdef - val newsym = vdef.symbol.cloneSymbol(context.owner) + val newowner = if (owner != NoSymbol) owner else context.owner + val newsym = vdef.symbol.cloneSymbol(newowner) newsym.setInfo(fixType(vdef.symbol.info)) vdef.symbol = newsym - debuglog("newsym: " + newsym + " info: " + newsym.info) - + debuglog("newsym: " + newsym + " info: " + newsym.info + ", owner: " + newsym.owner + ", " + newsym.owner.isClass) + if (newsym.owner.isClass) newsym.owner.info.decls enter newsym + case DefDef(_, name, tparams, vparamss, _, rhs) => // invalidate parameters - invalidate(tparams ::: vparamss.flatten) + invalidateAll(tparams ::: vparamss.flatten) tree.symbol = NoSymbol case _ => @@ -178,14 +180,14 @@ abstract class Duplicators extends Analyzer { } } - private def invalidate(stats: List[Tree]) { - stats foreach invalidate + private def invalidateAll(stats: List[Tree], owner: Symbol = NoSymbol) { + stats.foreach(invalidate(_, owner)) } def retypedMethod(ddef: DefDef, oldThis: Symbol, newThis: Symbol): Tree = { oldClassOwner = oldThis newClassOwner = newThis - invalidate(ddef.tparams) + invalidateAll(ddef.tparams) mforeach(ddef.vparamss) { vdef => invalidate(vdef) vdef.tpe = null @@ -239,15 +241,15 @@ abstract class Duplicators extends Analyzer { case Block(stats, res) => debuglog("invalidating block") - invalidate(stats) + invalidateAll(stats) invalidate(res) tree.tpe = null super.typed(tree, mode, pt) case ClassDef(_, _, _, tmpl @ Template(parents, _, stats)) => - // log("invalidating classdef " + tree.tpe) + // log("invalidating classdef " + tree) tmpl.symbol = tree.symbol.newLocalDummy(tree.pos) - invalidate(stats) + invalidateAll(stats, tree.symbol) tree.tpe = null super.typed(tree, mode, pt) diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 5534cd179c..1c1adee343 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -617,7 +617,8 @@ trait Infer { } else if (argPos.contains(pos)) { // parameter specified twice namesOK = false } else { - positionalAllowed = false + if (index != pos) + positionalAllowed = false argPos(index) = pos } index += 1 diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 9e6b9617a5..88e464a1f4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -478,7 +478,14 @@ trait NamesDefaults { self: Analyzer => // instead of arg, but can't do that because eventually setType(ErrorType) // is called, and EmptyTree can only be typed NoType. Thus we need to // disable conforms as a view... - try typer.silent(_.typed(arg, subst(paramtpe))) match { + val errsBefore = reporter.ERROR.count + try typer.silent { tpr => + val res = tpr.typed(arg, subst(paramtpe)) + // better warning for SI-5044: if `silent` was not actually silent give a hint to the user + if (errsBefore < reporter.ERROR.count) + WarnAfterNonSilentRecursiveInference(param, arg)(context) + res + } match { case SilentResultValue(t) => !t.isErroneous // #4041 case _ => false } @@ -487,7 +494,7 @@ trait NamesDefaults { self: Analyzer => // CyclicReferences. Fix for #3685 case cr @ CyclicReference(sym, _) => (sym.name == param.name) && sym.accessedOrSelf.isVariable && { - NameClashError(sym, arg)(typer.context) + NameClashError(sym, arg)(context) true } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index b5e58efaff..e40a567f1d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -114,6 +114,8 @@ trait Typers extends Modes with Adaptations with Taggings { case MethodType(params, _) => val argResultsBuff = new ListBuffer[SearchResult]() val argBuff = new ListBuffer[Tree]() + // paramFailed cannot be initialized with params.exists(_.tpe.isError) because that would + // hide some valid errors for params preceding the erroneous one. var paramFailed = false def mkPositionalArg(argTree: Tree, paramName: Name) = argTree @@ -129,7 +131,7 @@ trait Typers extends Modes with Adaptations with Taggings { for(ar <- argResultsBuff) paramTp = paramTp.subst(ar.subst.from, ar.subst.to) - val res = if (paramFailed) SearchFailure else inferImplicit(fun, paramTp, context.reportErrors, false, context) + val res = if (paramFailed || (paramTp.isError && {paramFailed = true; true})) SearchFailure else inferImplicit(fun, paramTp, context.reportErrors, false, context) argResultsBuff += res if (res != SearchFailure) { @@ -3246,7 +3248,9 @@ trait Typers extends Modes with Adaptations with Taggings { reportAnnotationError(NestedAnnotationError(ann, annType)) } else { val typedAnn = if (selfsym == NoSymbol) { - typed(ann, mode, annClass.tpe) + // local dummy fixes SI-5544 + val localTyper = newTyper(context.make(ann, context.owner.newLocalDummy(ann.pos))) + localTyper.typed(ann, mode, annClass.tpe) } else { // Since a selfsym is supplied, the annotation should have // an extra "self" identifier in scope for type checking. diff --git a/src/library/scala/collection/mutable/ObservableBuffer.scala b/src/library/scala/collection/mutable/ObservableBuffer.scala index a619edf281..6b5079e402 100644 --- a/src/library/scala/collection/mutable/ObservableBuffer.scala +++ b/src/library/scala/collection/mutable/ObservableBuffer.scala @@ -70,4 +70,18 @@ trait ObservableBuffer[A] extends Buffer[A] with Publisher[Message[A] with Undoa def undo() { throw new UnsupportedOperationException("cannot undo") } }) } + + abstract override def insertAll(n: Int, elems: collection.Traversable[A]) { + super.insertAll(n, elems) + var curr = n - 1 + val msg = elems.foldLeft(new Script[A]() with Undoable { + def undo() { throw new UnsupportedOperationException("cannot undo") } + }) { + case (msg, elem) => + curr += 1 + msg += Include(Index(curr), elem) + } + publish(msg) + } + } diff --git a/src/library/scala/collection/parallel/Tasks.scala b/src/library/scala/collection/parallel/Tasks.scala index 4a581f219e..7a0116b3b3 100644 --- a/src/library/scala/collection/parallel/Tasks.scala +++ b/src/library/scala/collection/parallel/Tasks.scala @@ -541,7 +541,7 @@ trait ExecutionContextTasks extends Tasks { // this part is a hack which allows switching val driver: Tasks = executionContext match { - case eci: scala.concurrent.impl.ExecutionContextImpl => eci.executorService match { + case eci: scala.concurrent.impl.ExecutionContextImpl => eci.executor match { case fjp: ForkJoinPool => new ForkJoinTaskSupport(fjp) case tpe: ThreadPoolExecutor => new ThreadPoolTaskSupport(tpe) case _ => ??? diff --git a/src/library/scala/concurrent/ConcurrentPackageObject.scala b/src/library/scala/concurrent/ConcurrentPackageObject.scala index c3c329121c..330a2f0e25 100644 --- a/src/library/scala/concurrent/ConcurrentPackageObject.scala +++ b/src/library/scala/concurrent/ConcurrentPackageObject.scala @@ -8,7 +8,7 @@ package scala.concurrent -import java.util.concurrent.{ Executors, ExecutorService, ThreadFactory } +import java.util.concurrent.{ Executors, Executor, ThreadFactory } import scala.concurrent.forkjoin.{ ForkJoinPool, ForkJoinWorkerThread } import scala.concurrent.util.Duration import language.implicitConversions @@ -19,7 +19,7 @@ import language.implicitConversions abstract class ConcurrentPackageObject { /** A global execution environment for executing lightweight tasks. */ - lazy val defaultExecutionContext = new impl.ExecutionContextImpl(null) + lazy val defaultExecutionContext: ExecutionContext with Executor = impl.ExecutionContextImpl.fromExecutor(null: Executor) val currentExecutionContext = new ThreadLocal[ExecutionContext] diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala index d2a2d5e8a8..436a17a33b 100644 --- a/src/library/scala/concurrent/ExecutionContext.scala +++ b/src/library/scala/concurrent/ExecutionContext.scala @@ -47,11 +47,13 @@ object ExecutionContext { /** Creates an `ExecutionContext` from the given `ExecutorService`. */ - def fromExecutorService(e: ExecutorService, reporter: Throwable => Unit = defaultReporter): ExecutionContext with Executor = new impl.ExecutionContextImpl(e, reporter) + def fromExecutorService(e: ExecutorService, reporter: Throwable => Unit = defaultReporter): ExecutionContext with ExecutorService = + impl.ExecutionContextImpl.fromExecutorService(e, reporter) /** Creates an `ExecutionContext` from the given `Executor`. */ - def fromExecutor(e: Executor, reporter: Throwable => Unit = defaultReporter): ExecutionContext with Executor = new impl.ExecutionContextImpl(e, reporter) + def fromExecutor(e: Executor, reporter: Throwable => Unit = defaultReporter): ExecutionContext with Executor = + impl.ExecutionContextImpl.fromExecutor(e, reporter) def defaultReporter: Throwable => Unit = { // re-throwing `Error`s here causes an exception handling test to fail. diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala index 2f90afe056..4df2bb63af 100644 --- a/src/library/scala/concurrent/Future.scala +++ b/src/library/scala/concurrent/Future.scala @@ -96,9 +96,9 @@ trait Future[+T] extends Awaitable[T] { * * $multipleCallbacks */ - def onSuccess[U](pf: PartialFunction[T, U]): this.type = onComplete { - case Left(t) => // do nothing - case Right(v) => if (pf isDefinedAt v) pf(v) else { /*do nothing*/ } + def onSuccess[U](pf: PartialFunction[T, U]): Unit = onComplete { + case Right(v) if pf isDefinedAt v => pf(v) + case _ => } /** When this future is completed with a failure (i.e. with a throwable), @@ -113,9 +113,9 @@ trait Future[+T] extends Awaitable[T] { * * $multipleCallbacks */ - def onFailure[U](callback: PartialFunction[Throwable, U]): this.type = onComplete { - case Left(t) => if (isFutureThrowable(t) && callback.isDefinedAt(t)) callback(t) else { /*do nothing*/ } - case Right(v) => // do nothing + def onFailure[U](callback: PartialFunction[Throwable, U]): Unit = onComplete { + case Left(t) if (isFutureThrowable(t) && callback.isDefinedAt(t)) => callback(t) + case _ => } /** When this future is completed, either through an exception, or a value, @@ -126,7 +126,7 @@ trait Future[+T] extends Awaitable[T] { * * $multipleCallbacks */ - def onComplete[U](func: Either[Throwable, T] => U): this.type + def onComplete[U](func: Either[Throwable, T] => U): Unit /* Miscellaneous */ @@ -169,7 +169,7 @@ trait Future[+T] extends Awaitable[T] { onComplete { case Left(t) => p success t - case Right(v) => p failure (new NoSuchElementException("Future.failed not completed with a throwable. Instead completed with: " + v)) + case Right(v) => p failure (new NoSuchElementException("Future.failed not completed with a throwable.")) } p.future @@ -184,7 +184,36 @@ trait Future[+T] extends Awaitable[T] { */ def foreach[U](f: T => U): Unit = onComplete { case Right(r) => f(r) - case Left(_) => // do nothing + case _ => // do nothing + } + + /** Creates a new future by applying the 's' function to the successful result of + * this future, or the 'f' function to the failed result. If there is any non-fatal + * exception thrown when 's' or 'f' is applied, that exception will be propagated + * to the resulting future. + * + * @param s function that transforms a successful result of the receiver into a + * successful result of the returned future + * @param f function that transforms a failure of the receiver into a failure of + * the returned future + * @return a future that will be completed with the transformed value + */ + def transform[S](s: T => S, f: Throwable => Throwable): Future[S] = { + val p = Promise[S]() + + onComplete { + case result => + try { + result match { + case Left(t) => p failure f(t) + case Right(r) => p success s(r) + } + } catch { + case NonFatal(t) => p failure t + } + } + + p.future } /** Creates a new future by applying a function to the successful result of @@ -193,14 +222,17 @@ trait Future[+T] extends Awaitable[T] { * * $forComprehensionExamples */ - def map[S](f: T => S): Future[S] = { + def map[S](f: T => S): Future[S] = { // transform(f, identity) val p = Promise[S]() onComplete { - case Left(t) => p failure t - case Right(v) => - try p success f(v) - catch { + case result => + try { + result match { + case Right(r) => p success f(r) + case l: Left[_, _] => p complete l.asInstanceOf[Left[Throwable, S]] + } + } catch { case NonFatal(t) => p failure t } } @@ -219,11 +251,11 @@ trait Future[+T] extends Awaitable[T] { val p = Promise[S]() onComplete { - case Left(t) => p failure t + case l: Left[_, _] => p complete l.asInstanceOf[Left[Throwable, S]] case Right(v) => try { f(v) onComplete { - case Left(t) => p failure t + case l: Left[_, _] => p complete l.asInstanceOf[Left[Throwable, S]] case Right(v) => p success v } } catch { @@ -254,7 +286,7 @@ trait Future[+T] extends Awaitable[T] { val p = Promise[T]() onComplete { - case Left(t) => p failure t + case l: Left[_, _] => p complete l.asInstanceOf[Left[Throwable, T]] case Right(v) => try { if (pred(v)) p success v @@ -303,7 +335,7 @@ trait Future[+T] extends Awaitable[T] { val p = Promise[S]() onComplete { - case Left(t) => p failure t + case l: Left[_, _] => p complete l.asInstanceOf[Left[Throwable, S]] case Right(v) => try { if (pf.isDefinedAt(v)) p success pf(v) @@ -384,7 +416,7 @@ trait Future[+T] extends Awaitable[T] { val p = Promise[(T, U)]() this onComplete { - case Left(t) => p failure t + case l: Left[_, _] => p complete l.asInstanceOf[Left[Throwable, (T, U)]] case Right(r) => that onSuccess { case r2 => p success ((r, r2)) @@ -431,7 +463,7 @@ trait Future[+T] extends Awaitable[T] { val p = Promise[S]() onComplete { - case l: Left[Throwable, _] => p complete l.asInstanceOf[Either[Throwable, S]] + case l: Left[_, _] => p complete l.asInstanceOf[Left[Throwable, S]] case Right(t) => p complete (try { Right(boxedType(tag.erasure).cast(t).asInstanceOf[S]) @@ -470,9 +502,7 @@ trait Future[+T] extends Awaitable[T] { val p = Promise[T]() onComplete { - case r => - try if (pf isDefinedAt r) pf(r) - finally p complete r + case r => try if (pf isDefinedAt r) pf(r) finally p complete r } p.future @@ -493,11 +523,7 @@ trait Future[+T] extends Awaitable[T] { */ def either[U >: T](that: Future[U]): Future[U] = { val p = Promise[U]() - - val completePromise: PartialFunction[Either[Throwable, U], _] = { - case Left(t) => p tryFailure t - case Right(v) => p trySuccess v - } + val completePromise: PartialFunction[Either[Throwable, U], _] = { case result => p tryComplete result } this onComplete completePromise that onComplete completePromise diff --git a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala index 3ed960c7ab..1083a93439 100644 --- a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala +++ b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala @@ -10,18 +10,20 @@ package scala.concurrent.impl -import java.util.concurrent.{ Callable, Executor, ExecutorService, Executors, ThreadFactory } +import java.util.concurrent.{ Callable, Executor, ExecutorService, Executors, ThreadFactory, TimeUnit } +import java.util.Collection import scala.concurrent.forkjoin._ import scala.concurrent.{ ExecutionContext, Awaitable } import scala.concurrent.util.Duration -private[scala] class ExecutionContextImpl(es: AnyRef, reporter: Throwable => Unit = ExecutionContext.defaultReporter) -extends ExecutionContext with Executor { - import ExecutionContextImpl._ - - val executorService: AnyRef = if (es eq null) getExecutorService else es +private[scala] class ExecutionContextImpl private[impl] (es: Executor, reporter: Throwable => Unit) extends ExecutionContext with Executor { + + val executor: Executor = es match { + case null => createExecutorService + case some => some + } // to ensure that the current execution context thread local is properly set def executorsThreadFactory = new ThreadFactory { @@ -42,51 +44,46 @@ extends ExecutionContext with Executor { } } - def getExecutorService: AnyRef = - if (scala.util.Properties.isJavaAtLeast("1.6")) { - val vendor = scala.util.Properties.javaVmVendor - if ((vendor contains "Oracle") || (vendor contains "Sun") || (vendor contains "Apple")) - new ForkJoinPool( - Runtime.getRuntime.availableProcessors(), + def createExecutorService: ExecutorService = try { new ForkJoinPool( + Runtime.getRuntime.availableProcessors(), //FIXME from config forkJoinPoolThreadFactory, - null, - false) - else - Executors.newCachedThreadPool(executorsThreadFactory) - } else Executors.newCachedThreadPool(executorsThreadFactory) + null, //FIXME we should have an UncaughtExceptionHandler, see what Akka does + true) //FIXME I really think this should be async... + } catch { + case NonFatal(t) => + System.err.println("Failed to create ForkJoinPool for the default ExecutionContext, falling back to Executors.newCachedThreadPool") + t.printStackTrace(System.err) + Executors.newCachedThreadPool(executorsThreadFactory) + } - def execute(runnable: Runnable): Unit = executorService match { + def execute(runnable: Runnable): Unit = executor match { case fj: ForkJoinPool => Thread.currentThread match { case fjw: ForkJoinWorkerThread if fjw.getPool eq fj => - val fjtask = runnable match { + (runnable match { case fjt: ForkJoinTask[_] => fjt case _ => ForkJoinTask.adapt(runnable) - } - fjtask.fork - case _ => - fj.execute(runnable) + }).fork + case _ => fj.execute(runnable) } - case executor: Executor => - executor execute runnable + case generic => generic execute runnable } def internalBlockingCall[T](awaitable: Awaitable[T], atMost: Duration): T = { Future.releaseStack(this) - executorService match { + executor match { case fj: ForkJoinPool => var result: T = null.asInstanceOf[T] - val managedBlocker = new ForkJoinPool.ManagedBlocker { + ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker { @volatile var isdone = false - def block() = { - result = awaitable.result(atMost)(scala.concurrent.Await.canAwaitEvidence) + def block(): Boolean = { + result = awaitable.result(atMost)(scala.concurrent.Await.canAwaitEvidence) // FIXME what happens if there's an exception thrown here? isdone = true true } def isReleasable = isdone - } - ForkJoinPool.managedBlock(managedBlocker) + }) result case _ => awaitable.result(atMost)(scala.concurrent.Await.canAwaitEvidence) @@ -94,12 +91,29 @@ extends ExecutionContext with Executor { } def reportFailure(t: Throwable) = reporter(t) - } private[concurrent] object ExecutionContextImpl { - + + def fromExecutor(e: Executor, reporter: Throwable => Unit = ExecutionContext.defaultReporter): ExecutionContextImpl = new ExecutionContextImpl(e, reporter) + def fromExecutorService(es: ExecutorService, reporter: Throwable => Unit = ExecutionContext.defaultReporter): ExecutionContextImpl with ExecutorService = + new ExecutionContextImpl(es, reporter) with ExecutorService { + final def asExecutorService: ExecutorService = executor.asInstanceOf[ExecutorService] + override def execute(command: Runnable) = executor.execute(command) + override def shutdown() { asExecutorService.shutdown() } + override def shutdownNow() = asExecutorService.shutdownNow() + override def isShutdown = asExecutorService.isShutdown + override def isTerminated = asExecutorService.isTerminated + override def awaitTermination(l: Long, timeUnit: TimeUnit) = asExecutorService.awaitTermination(l, timeUnit) + override def submit[T](callable: Callable[T]) = asExecutorService.submit(callable) + override def submit[T](runnable: Runnable, t: T) = asExecutorService.submit(runnable, t) + override def submit(runnable: Runnable) = asExecutorService.submit(runnable) + override def invokeAll[T](callables: Collection[_ <: Callable[T]]) = asExecutorService.invokeAll(callables) + override def invokeAll[T](callables: Collection[_ <: Callable[T]], l: Long, timeUnit: TimeUnit) = asExecutorService.invokeAll(callables, l, timeUnit) + override def invokeAny[T](callables: Collection[_ <: Callable[T]]) = asExecutorService.invokeAny(callables) + override def invokeAny[T](callables: Collection[_ <: Callable[T]], l: Long, timeUnit: TimeUnit) = asExecutorService.invokeAny(callables, l, timeUnit) + } } diff --git a/src/library/scala/concurrent/impl/Future.scala b/src/library/scala/concurrent/impl/Future.scala index bf136b6195..a54e81bd05 100644 --- a/src/library/scala/concurrent/impl/Future.scala +++ b/src/library/scala/concurrent/impl/Future.scala @@ -65,6 +65,8 @@ private[concurrent] object Future { promise.future } + private[impl] val throwableId: Throwable => Throwable = identity _ + // an optimization for batching futures // TODO we should replace this with a public queue, // so that it can be stolen from diff --git a/src/library/scala/concurrent/impl/Promise.scala b/src/library/scala/concurrent/impl/Promise.scala index 5a5b893f16..78053f5117 100644 --- a/src/library/scala/concurrent/impl/Promise.scala +++ b/src/library/scala/concurrent/impl/Promise.scala @@ -112,7 +112,7 @@ object Promise { } } - def onComplete[U](func: Either[Throwable, T] => U): this.type = { + def onComplete[U](func: Either[Throwable, T] => U): Unit = { @tailrec //Tries to add the callback, if already completed, it dispatches the callback to be executed def dispatchOrAddCallback(): Unit = getState match { @@ -120,7 +120,6 @@ object Promise { case listeners: List[_] => if (updateState(listeners, func :: listeners)) () else dispatchOrAddCallback() } dispatchOrAddCallback() - this } private final def notifyCompleted(func: Either[Throwable, T] => Any, result: Either[Throwable, T]) { @@ -144,10 +143,9 @@ object Promise { def tryComplete(value: Either[Throwable, T]): Boolean = false - def onComplete[U](func: Either[Throwable, T] => U): this.type = { - val completedAs = value.get + def onComplete[U](func: Either[Throwable, T] => U): Unit = { + val completedAs = value.get // Avoid closing over "this" Future.dispatchFuture(executor, () => func(completedAs)) - this } def ready(atMost: Duration)(implicit permit: CanAwait): this.type = this diff --git a/src/library/scala/util/parsing/combinator/JavaTokenParsers.scala b/src/library/scala/util/parsing/combinator/JavaTokenParsers.scala index bc71391bdb..06567ea348 100644 --- a/src/library/scala/util/parsing/combinator/JavaTokenParsers.scala +++ b/src/library/scala/util/parsing/combinator/JavaTokenParsers.scala @@ -9,6 +9,8 @@ package scala.util.parsing.combinator +import annotation.migration + /** `JavaTokenParsers` differs from [[scala.util.parsing.combinator.RegexParsers]] * by adding the following definitions: * @@ -39,12 +41,13 @@ trait JavaTokenParsers extends RegexParsers { /** Double quotes (`"`) enclosing a sequence of: * * - Any character except double quotes, control characters or backslash (`\`) - * - A backslash followed by a slash, another backslash, or one of the letters - * `b`, `f`, `n`, `r` or `t`. + * - A backslash followed by another backslash, a single or double quote, or one + * of the letters `b`, `f`, `n`, `r` or `t` * - `\` followed by `u` followed by four hexadecimal digits */ + @migration("`stringLiteral` allows escaping single and double quotes, but not forward slashes any longer.", "2.10.0") def stringLiteral: Parser[String] = - ("\""+"""([^"\p{Cntrl}\\]|\\[\\/bfnrt]|\\u[a-fA-F0-9]{4})*"""+"\"").r + ("\""+"""([^"\p{Cntrl}\\]|\\[\\'"bfnrt]|\\u[a-fA-F0-9]{4})*"""+"\"").r /** A number following the rules of `decimalNumber`, with the following * optional additions: * diff --git a/test/files/jvm/future-spec/FutureTests.scala b/test/files/jvm/future-spec/FutureTests.scala index 9a9cf951bb..e5e01a5954 100644 --- a/test/files/jvm/future-spec/FutureTests.scala +++ b/test/files/jvm/future-spec/FutureTests.scala @@ -19,7 +19,7 @@ object FutureTests extends MinimalScalaTest { case "NoReply" => Promise[String]().future } - val defaultTimeout = Inf + val defaultTimeout = 5 seconds /* future specification */ diff --git a/test/files/jvm/future-spec/PromiseTests.scala b/test/files/jvm/future-spec/PromiseTests.scala index 6016746a23..bf9d9b39d7 100644 --- a/test/files/jvm/future-spec/PromiseTests.scala +++ b/test/files/jvm/future-spec/PromiseTests.scala @@ -133,7 +133,7 @@ object PromiseTests extends MinimalScalaTest { (future, result) => intercept[NoSuchElementException] { Await.result(future.failed, defaultTimeout) - }.getMessage mustBe ("Future.failed not completed with a throwable. Instead completed with: " + result) + }.getMessage mustBe ("Future.failed not completed with a throwable.") } } diff --git a/test/files/jvm/scala-concurrent-tck.scala b/test/files/jvm/scala-concurrent-tck.scala index fce1a25bb6..86655ad89c 100644 --- a/test/files/jvm/scala-concurrent-tck.scala +++ b/test/files/jvm/scala-concurrent-tck.scala @@ -182,6 +182,72 @@ trait FutureCombinators extends TestBase { } } + def testMapSuccessPF(): Unit = once { + done => + val f = future { 5 } + val g = f map { case r => "result: " + r } + g onSuccess { + case s => + done() + assert(s == "result: 5") + } + g onFailure { + case _ => + done() + assert(false) + } + } + + def testTransformSuccess(): Unit = once { + done => + val f = future { 5 } + val g = f.transform(r => "result: " + r, identity) + g onSuccess { + case s => + done() + assert(s == "result: 5") + } + g onFailure { + case _ => + done() + assert(false) + } + } + + def testTransformSuccessPF(): Unit = once { + done => + val f = future { 5 } + val g = f.transform( { case r => "result: " + r }, identity) + g onSuccess { + case s => + done() + assert(s == "result: 5") + } + g onFailure { + case _ => + done() + assert(false) + } + } + + def testFoldFailure(): Unit = once { + done => + val f = future { + throw new Exception("exception message") + } + val g = f.transform(r => "result: " + r, identity) + g onSuccess { + case _ => + done() + assert(false) + } + g onFailure { + case t => + done() + assert(t.getMessage() == "exception message") + } + } + def testFlatMapSuccess(): Unit = once { done => val f = future { 5 } @@ -340,14 +406,17 @@ trait FutureCombinators extends TestBase { } recover { case re: RuntimeException => "recovered" - } onSuccess { + } + f onSuccess { case x => done() assert(x == "recovered") - } onFailure { case any => + } + f onFailure { case any => done() assert(false) } + f } def testRecoverFailure(): Unit = once { @@ -357,11 +426,13 @@ trait FutureCombinators extends TestBase { throw cause } recover { case te: TimeoutException => "timeout" - } onSuccess { + } + f onSuccess { case x => done() assert(false) - } onFailure { case any => + } + f onFailure { case any => done() assert(any == cause) } @@ -375,11 +446,13 @@ trait FutureCombinators extends TestBase { } recoverWith { case re: RuntimeException => future { "recovered" } - } onSuccess { + } + f onSuccess { case x => done() assert(x == "recovered") - } onFailure { case any => + } + f onFailure { case any => done() assert(false) } @@ -393,11 +466,13 @@ trait FutureCombinators extends TestBase { } recoverWith { case te: TimeoutException => future { "timeout" } - } onSuccess { + } + f onSuccess { case x => done() assert(false) - } onFailure { case any => + } + f onFailure { case any => done() assert(any == cause) } @@ -635,11 +710,12 @@ trait Promises extends TestBase { val p = promise[Int]() val f = p.future - f.onSuccess { + f onSuccess { case x => done() assert(x == 5) - } onFailure { + } + f onFailure { case any => done() assert(false) diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check index b5f544c97e..2809350855 100644 --- a/test/files/neg/names-defaults-neg.check +++ b/test/files/neg/names-defaults-neg.check @@ -149,8 +149,12 @@ names-defaults-neg.scala:170: error: reference to x is ambiguous; it is both a m names-defaults-neg.scala:177: error: variable definition needs type because 'x' is used as a named argument in its body. class u15 { var x = u.f(x = 1) } ^ +names-defaults-neg.scala:177: warning: type-checking the invocation of method f checks if the named argument expression 'x = ...' is a valid assignment +in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for x. + class u15 { var x = u.f(x = 1) } + ^ names-defaults-neg.scala:180: error: reference to x is ambiguous; it is both a method parameter and a variable in scope. class u18 { var x: Int = u.f(x = 1) } ^ -one warning found +two warnings found 41 errors found diff --git a/test/files/neg/t2488.check b/test/files/neg/t2488.check new file mode 100644 index 0000000000..170dbf88ff --- /dev/null +++ b/test/files/neg/t2488.check @@ -0,0 +1,31 @@ +t2488.scala:7: error: overloaded method value f with alternatives: + ()Int <and> + (a: Int,b: Int)Int + cannot be applied to (b: Int, Int) + println(c.f(b = 2, 2)) + ^ +t2488.scala:8: error: overloaded method value f with alternatives: + ()Int <and> + (a: Int,b: Int)Int + cannot be applied to (a: Int, c: Int) + println(c.f(a = 2, c = 2)) + ^ +t2488.scala:9: error: overloaded method value f with alternatives: + ()Int <and> + (a: Int,b: Int)Int + cannot be applied to (Int, c: Int) + println(c.f(2, c = 2)) + ^ +t2488.scala:10: error: overloaded method value f with alternatives: + ()Int <and> + (a: Int,b: Int)Int + cannot be applied to (c: Int, Int) + println(c.f(c = 2, 2)) + ^ +t2488.scala:11: error: overloaded method value f with alternatives: + ()Int <and> + (a: Int,b: Int)Int + cannot be applied to (Int) + println(c.f(2)) + ^ +5 errors found diff --git a/test/files/neg/t2488.scala b/test/files/neg/t2488.scala new file mode 100644 index 0000000000..8db052eec1 --- /dev/null +++ b/test/files/neg/t2488.scala @@ -0,0 +1,12 @@ +class C { + def f(a:Int, b:Int) = 1 + def f() = 2 +} +object Test extends App { + val c = new C() + println(c.f(b = 2, 2)) + println(c.f(a = 2, c = 2)) + println(c.f(2, c = 2)) + println(c.f(c = 2, 2)) + println(c.f(2)) +} diff --git a/test/files/neg/t5044.check b/test/files/neg/t5044.check new file mode 100644 index 0000000000..197da2a4e8 --- /dev/null +++ b/test/files/neg/t5044.check @@ -0,0 +1,9 @@ +t5044.scala:7: error: recursive value a needs type + val id = m(a) + ^ +t5044.scala:6: warning: type-checking the invocation of method foo checks if the named argument expression 'id = ...' is a valid assignment +in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for id. + val a = foo(id = 1) + ^ +one warning found +one error found diff --git a/test/files/neg/t5044.scala b/test/files/neg/t5044.scala new file mode 100644 index 0000000000..2663ec1bbb --- /dev/null +++ b/test/files/neg/t5044.scala @@ -0,0 +1,9 @@ +class T { + def foo[T](id: T) = 0 + def m(a: Int) = 0 + + def f { + val a = foo(id = 1) + val id = m(a) + } +} diff --git a/test/files/neg/t5544.check b/test/files/neg/t5544.check new file mode 100644 index 0000000000..d4113935a3 --- /dev/null +++ b/test/files/neg/t5544.check @@ -0,0 +1,4 @@ +Test_2.scala:2: error: value baz is not a member of object Api + Api.baz + ^ +one error found diff --git a/test/files/neg/t5544/Api_1.scala b/test/files/neg/t5544/Api_1.scala new file mode 100644 index 0000000000..77637f440a --- /dev/null +++ b/test/files/neg/t5544/Api_1.scala @@ -0,0 +1,8 @@ +import scala.annotation.StaticAnnotation + +class ann(val bar: Any) extends StaticAnnotation + +object Api { + @ann({def baz = "baz!!"}) + def foo = println("foo") +} diff --git a/test/files/neg/t5544/Test_2.scala b/test/files/neg/t5544/Test_2.scala new file mode 100644 index 0000000000..4c8c99cbc7 --- /dev/null +++ b/test/files/neg/t5544/Test_2.scala @@ -0,0 +1,3 @@ +object Test extends App { + Api.baz +} diff --git a/test/files/neg/t5760-pkgobj-warn.check b/test/files/neg/t5760-pkgobj-warn.check new file mode 100644 index 0000000000..a89398c3f7 --- /dev/null +++ b/test/files/neg/t5760-pkgobj-warn.check @@ -0,0 +1,4 @@ +stalepkg_2.scala:6: error: Foo is already defined as class Foo in package object stalepkg + class Foo + ^ +one error found diff --git a/test/files/neg/t5760-pkgobj-warn/stalepkg_1.scala b/test/files/neg/t5760-pkgobj-warn/stalepkg_1.scala new file mode 100644 index 0000000000..ed4b731bb0 --- /dev/null +++ b/test/files/neg/t5760-pkgobj-warn/stalepkg_1.scala @@ -0,0 +1,11 @@ + +package object stalepkg { + class Foo +} + +package stalepkg { + object Test { + def main(args: Array[String]) { + } + } +} diff --git a/test/files/neg/t5760-pkgobj-warn/stalepkg_2.scala b/test/files/neg/t5760-pkgobj-warn/stalepkg_2.scala new file mode 100644 index 0000000000..9abcdbab17 --- /dev/null +++ b/test/files/neg/t5760-pkgobj-warn/stalepkg_2.scala @@ -0,0 +1,11 @@ + +package object stalepkg { +} + +package stalepkg { + class Foo + object Test { + def main(args: Array[String]) { + } + } +} diff --git a/test/files/neg/t5801.check b/test/files/neg/t5801.check new file mode 100644 index 0000000000..abf8e6e932 --- /dev/null +++ b/test/files/neg/t5801.check @@ -0,0 +1,22 @@ +t5801.scala:1: error: object sth is not a member of package scala +import scala.sth + ^ +t5801.scala:4: error: not found: value sth + def foo(a: Int)(implicit b: sth.Sth): Unit = {} + ^ +t5801.scala:7: error: not found: value sth + def bar(x: Int)(implicit y: Int): sth.Sth = null + ^ +t5801.scala:8: error: could not find implicit value for parameter y: Int + bar(1) + ^ +t5801.scala:10: error: not found: value sth + def meh(x: Int)(implicit a: sth.Sth, b: Int): Unit = {} + ^ +t5801.scala:13: error: not found: value sth + def meh2(x: Int)(implicit b: Int, a: sth.Sth): Unit = {} + ^ +t5801.scala:14: error: could not find implicit value for parameter b: Int + meh2(1) + ^ +7 errors found diff --git a/test/files/neg/t5801.scala b/test/files/neg/t5801.scala new file mode 100644 index 0000000000..d452222ac8 --- /dev/null +++ b/test/files/neg/t5801.scala @@ -0,0 +1,16 @@ +import scala.sth + +object Test extends App { + def foo(a: Int)(implicit b: sth.Sth): Unit = {} + foo(1) + + def bar(x: Int)(implicit y: Int): sth.Sth = null + bar(1) + + def meh(x: Int)(implicit a: sth.Sth, b: Int): Unit = {} + meh(1) + + def meh2(x: Int)(implicit b: Int, a: sth.Sth): Unit = {} + meh2(1) +} + diff --git a/test/files/pos/t3880.scala b/test/files/pos/t3880.scala new file mode 100644 index 0000000000..b6f06c43a3 --- /dev/null +++ b/test/files/pos/t3880.scala @@ -0,0 +1,16 @@ +abstract class Bar[+B] { +} +abstract class C1[+B] extends Bar[B] { + private[this] def g(x: C1[B]): Unit = () + + // this method is fine: notice that it allows the call to g, + // which requires C1[B], even though we matched on C1[_]. + // (That is good news.) + private[this] def f1(x: Bar[B]): Unit = x match { + case x: C1[_] => g(x) + } + // this one crashes. + private[this] def f2(x: Bar[B]): Unit = x match { + case x: C1[_] => f2(x) + } +}
\ No newline at end of file diff --git a/test/files/pos/t4717.scala b/test/files/pos/t4717.scala new file mode 100644 index 0000000000..4acfe489cc --- /dev/null +++ b/test/files/pos/t4717.scala @@ -0,0 +1,35 @@ + + + + + + + +trait Bug1[@specialized(Boolean) A] extends TraversableOnce[A] { + + def ++[B >: A](that: TraversableOnce[B]): Iterator[B] = new Iterator[B] { + lazy val it = that.toIterator + def hasNext = it.hasNext + def next = it.next + } + +} + + + +trait WorksFine[@specialized(Boolean) A] { + class SubBounds[B >: A] extends Bounds[B] { + lazy val it = ??? + } + def x[B >: A]: Unit = new SubBounds[B] +} + + +trait Bounds[@specialized(Boolean) A] { + // okay without `>: A` + def x[B >: A]: Unit = new Bounds[B] { + lazy val it = ??? // def or val okay + } +} + + diff --git a/test/files/pos/t4812.scala b/test/files/pos/t4812.scala new file mode 100644 index 0000000000..2a807ab05e --- /dev/null +++ b/test/files/pos/t4812.scala @@ -0,0 +1,4 @@ +trait Test1 { + def m1(sym: Symbol = 'TestSym) + def m2(s: String = "TestString") +} diff --git a/test/files/run/t2488.check b/test/files/run/t2488.check new file mode 100644 index 0000000000..1af4bf8965 --- /dev/null +++ b/test/files/run/t2488.check @@ -0,0 +1,4 @@ +1 +1 +1 +2 diff --git a/test/files/run/t2488.scala b/test/files/run/t2488.scala new file mode 100644 index 0000000000..22abdf8af2 --- /dev/null +++ b/test/files/run/t2488.scala @@ -0,0 +1,11 @@ +class C { + def f(a:Int, b:Int) = 1 + def f() = 2 +} +object Test extends App { + val c = new C() + println(c.f(a = 1,2)) + println(c.f(a = 1, b = 2)) + println(c.f(b = 2, a = 1)) + println(c.f()) +} diff --git a/test/files/run/t4138.check b/test/files/run/t4138.check new file mode 100644 index 0000000000..f561b5e6b0 --- /dev/null +++ b/test/files/run/t4138.check @@ -0,0 +1,2 @@ +[1.45] parsed: "lir 'de\' ' \\ \n / upa \"new\" \t parsing" +[1.5] parsed: "s " diff --git a/test/files/run/t4138.scala b/test/files/run/t4138.scala new file mode 100644 index 0000000000..131489e581 --- /dev/null +++ b/test/files/run/t4138.scala @@ -0,0 +1,6 @@ +object Test extends App { + object p extends scala.util.parsing.combinator.JavaTokenParsers + + println(p.parse(p.stringLiteral, """"lir 'de\' ' \\ \n / upa \"new\" \t parsing"""")) + println(p.parse(p.stringLiteral, """"s " lkjse"""")) +} diff --git a/test/files/run/t4461.check b/test/files/run/t4461.check index b05c7b5589..e9c01e769d 100644 --- a/test/files/run/t4461.check +++ b/test/files/run/t4461.check @@ -4,4 +4,8 @@ Include(End,3) Include(End,4) Include(End,5) Include(End,6) -Include(End,7)
\ No newline at end of file +Include(End,7) +Script([1] Include(Index(7),8), [2] Include(Index(8),9), [3] Include(Index(9),10)) +Include(Start,0) +Script([1] Include(Index(0),-2), [2] Include(Index(1),-1)) +Remove(Index(0),-2)
\ No newline at end of file diff --git a/test/files/run/t4461.scala b/test/files/run/t4461.scala index 99da122f6b..adc9201313 100644 --- a/test/files/run/t4461.scala +++ b/test/files/run/t4461.scala @@ -15,5 +15,9 @@ object Test { buf ++= ArrayBuffer(3, 4) // works buf ++= List(5) // works buf ++= collection.immutable.Vector(6, 7) // works + buf.insertAll(7, List(8, 9, 10)) + 0 +=: buf + List(-2, -1) ++=: buf + buf remove 0 } } diff --git a/test/files/run/t5125.check b/test/files/run/t5125.check new file mode 100644 index 0000000000..d8a0565005 --- /dev/null +++ b/test/files/run/t5125.check @@ -0,0 +1,4 @@ +public void O1$.f(java.lang.String[]) +public void O1$.f(scala.collection.Seq) +public void O2$.f(java.lang.String[]) +public void O2$.f(scala.collection.Seq) diff --git a/test/files/run/t5125.scala b/test/files/run/t5125.scala new file mode 100644 index 0000000000..7ec2b929d9 --- /dev/null +++ b/test/files/run/t5125.scala @@ -0,0 +1,24 @@ +object O1 { + def instance = this + @scala.annotation.varargs + def f(values:String*) = println("Calling O1.f(): " + values) +} + +object O2 { + def instance = this + @scala.annotation.varargs + def f(values:String*) = println("Calling O2.f(): " + values) + // uncommenting g() results in errors in A.java + def g(): String => Int = s => s.hashCode +} + +object Test extends App { + def check(c: Class[_]) { + val methodName = "f" + val methods = c.getDeclaredMethods.filter(_.getName == methodName) + println(methods.map(_.toString).sorted.mkString("\n")) + } + + check(O1.getClass) + check(O2.getClass) +}
\ No newline at end of file diff --git a/test/files/run/t5125b.check b/test/files/run/t5125b.check new file mode 100644 index 0000000000..ddbf908f04 --- /dev/null +++ b/test/files/run/t5125b.check @@ -0,0 +1,7 @@ +public void C1.f(java.lang.String[]) +public void C1.f(scala.collection.Seq) +public void C2.f(java.lang.String[]) +public void C2.f(scala.collection.Seq) +public void C2$C3.f(java.lang.String[]) +public void C2$C3.f(scala.collection.Seq) +public void C4.f(scala.collection.Seq) diff --git a/test/files/run/t5125b.scala b/test/files/run/t5125b.scala new file mode 100644 index 0000000000..29c08fee4c --- /dev/null +++ b/test/files/run/t5125b.scala @@ -0,0 +1,37 @@ +class C1 { + @scala.annotation.varargs + def f(values:String*) = println("Calling C1.f(): " + values) +} + +class C2 { + @scala.annotation.varargs + def f(values:String*) = println("Calling C2.f(): " + values) + def g(): String => Int = s => s.hashCode + + class C3 { + @scala.annotation.varargs + def f(values:String*) = println("Calling C3.f(): " + values) + } +} + +class C4 { + def f(values: String*) = println("Calling C4.f(): " + values) + + locally { + @scala.annotation.varargs + def f(values: String*) = println("Calling C4.<locally>.f(): " + values) + } +} + +object Test extends App { + def check(c: Class[_]) { + val methodName = "f" + val methods = c.getDeclaredMethods.filter(_.getName == methodName) + println(methods.map(_.toString).sorted.mkString("\n")) + } + + check(classOf[C1]) + check(classOf[C2]) + check(classOf[C2#C3]) + check(classOf[C4]) +} diff --git a/test/files/run/t5544.check b/test/files/run/t5544.check new file mode 100644 index 0000000000..257cc5642c --- /dev/null +++ b/test/files/run/t5544.check @@ -0,0 +1 @@ +foo diff --git a/test/files/run/t5544/Api_1.scala b/test/files/run/t5544/Api_1.scala new file mode 100644 index 0000000000..b4c92864de --- /dev/null +++ b/test/files/run/t5544/Api_1.scala @@ -0,0 +1,8 @@ +import scala.annotation.StaticAnnotation + +class ann(val bar: Any) extends StaticAnnotation + +object Api { + @ann({def foo = "foo!!"}) + def foo = println("foo") +} diff --git a/test/files/run/t5544/Test_2.scala b/test/files/run/t5544/Test_2.scala new file mode 100644 index 0000000000..285f8959e0 --- /dev/null +++ b/test/files/run/t5544/Test_2.scala @@ -0,0 +1,3 @@ +object Test extends App { + Api.foo +} diff --git a/test/pending/run/t3899.check b/test/pending/run/t3899.check new file mode 100644 index 0000000000..c317608eab --- /dev/null +++ b/test/pending/run/t3899.check @@ -0,0 +1,4 @@ +a,b +a,b +a,b +a,b diff --git a/test/pending/run/t3899/Base_1.java b/test/pending/run/t3899/Base_1.java new file mode 100644 index 0000000000..114cc0b7a6 --- /dev/null +++ b/test/pending/run/t3899/Base_1.java @@ -0,0 +1,5 @@ +public class Base_1 { + public String[] varargs1(String... as) { + return as; + } +} diff --git a/test/pending/run/t3899/Derived_2.scala b/test/pending/run/t3899/Derived_2.scala new file mode 100644 index 0000000000..bb4e53784d --- /dev/null +++ b/test/pending/run/t3899/Derived_2.scala @@ -0,0 +1,30 @@ +trait T extends Base_1 { + def t1(as: String*): Array[String] = { + varargs1(as: _*) + } + def t2(as: String*): Array[String] = { + // This is the bug reported in the ticket. + super.varargs1(as: _*) + } +} + +class C extends Base_1 { + def c1(as: String*): Array[String] = { + varargs1(as: _*) + } + def c2(as: String*): Array[String] = { + super.varargs1(as: _*) + } +} + + +object Test extends App { + val t = new T {} + println(t.t1("a", "b").mkString(",")) + println(t.t2("a", "b").mkString(",")) + + val c = new C {} + println(c.c1("a", "b").mkString(",")) + println(c.c2("a", "b").mkString(",")) + +} |