From d5c27ed09d695cd8ed465d14d832a397ddbcd52c Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Thu, 5 Apr 2012 14:41:34 +0200 Subject: parse patterns, not exprs in interpolatedString's holes --- .../scala/tools/nsc/ast/parser/Parsers.scala | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index daabfae6b3..1280ef6937 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -70,6 +70,9 @@ trait ParsersCommon extends ScannersCommon { @inline final def inBracesOrNil[T](body: => List[T]): List[T] = inBracesOrError(body, Nil) @inline final def inBracesOrUnit[T](body: => Tree): Tree = inBracesOrError(body, Literal(Constant())) + @inline final def dropAnyBraces[T](body: => T): T = + if (in.token == LBRACE) inBraces(body) + else body @inline final def inBrackets[T](body: => T): T = { accept(LBRACKET) @@ -1106,7 +1109,7 @@ self => * }}} * @note The returned tree does not yet have a position */ - def literal(isNegated: Boolean = false): Tree = { + def literal(isNegated: Boolean = false, inPattern: Boolean = false): Tree = { def finish(value: Any): Tree = { val t = Literal(Constant(value)) in.nextToken() @@ -1115,7 +1118,7 @@ self => if (in.token == SYMBOLLIT) Apply(scalaDot(nme.Symbol), List(finish(in.strVal))) else if (in.token == INTERPOLATIONID) - interpolatedString() + interpolatedString(inPattern) else finish(in.token match { case CHARLIT => in.charVal case INTLIT => in.intVal(isNegated).toInt @@ -1141,7 +1144,7 @@ self => } } - private def interpolatedString(): Tree = atPos(in.offset) { + private def interpolatedString(inPattern: Boolean = false): Tree = atPos(in.offset) { val start = in.offset val interpolator = in.name @@ -1151,8 +1154,11 @@ self => while (in.token == STRINGPART) { partsBuf += literal() exprBuf += { - if (in.token == IDENTIFIER) atPos(in.offset)(Ident(ident())) - else expr() + if (inPattern) dropAnyBraces(pattern()) + else { + if (in.token == IDENTIFIER) atPos(in.offset)(Ident(ident())) + else expr() + } } } if (in.token == STRINGLIT) partsBuf += literal() @@ -1850,7 +1856,7 @@ self => case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => t match { case Ident(nme.MINUS) => - return atPos(start) { literal(isNegated = true) } + return atPos(start) { literal(isNegated = true, inPattern = true) } case _ => } case _ => @@ -1868,7 +1874,7 @@ self => atPos(start, start) { Ident(nme.WILDCARD) } case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | INTERPOLATIONID | SYMBOLLIT | TRUE | FALSE | NULL => - atPos(start) { literal() } + atPos(start) { literal(inPattern = true) } case LPAREN => atPos(start)(makeParens(noSeq.patterns())) case XMLSTART => -- cgit v1.2.3 From b92eb70113a03fe989a57482f6308fefadf74137 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Thu, 5 Apr 2012 15:27:55 +0200 Subject: enable implicit enrichment when typing patterns --- .../scala/tools/nsc/typechecker/Contexts.scala | 25 ++++++++++++++++++-- .../scala/tools/nsc/typechecker/Typers.scala | 27 +++++++++++++++++++--- test/files/run/virtpatmat_stringinterp.check | 1 + test/files/run/virtpatmat_stringinterp.flags | 1 + test/files/run/virtpatmat_stringinterp.scala | 13 +++++++++++ 5 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 test/files/run/virtpatmat_stringinterp.check create mode 100644 test/files/run/virtpatmat_stringinterp.flags create mode 100644 test/files/run/virtpatmat_stringinterp.scala (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index fe1c90fe67..e2d4efab83 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -67,6 +67,7 @@ trait Contexts { self: Analyzer => val c = sc.make(unit, tree, sc.owner, sc.scope, sc.imports) if (erasedTypes) c.setThrowErrors() else c.setReportErrors() c.implicitsEnabled = !erasedTypes + c.enrichmentEnabled = c.implicitsEnabled c } @@ -106,7 +107,7 @@ trait Contexts { self: Analyzer => var depth: Int = 0 var imports: List[ImportInfo] = List() // currently visible imports var openImplicits: List[(Type,Tree)] = List() // types for which implicit arguments - // are currently searched + // are currently searched // for a named application block (Tree) the corresponding NamedApplyInfo var namedApplyBlockInfo: Option[(Tree, NamedApplyInfo)] = None var prefix: Type = NoPrefix @@ -120,6 +121,7 @@ trait Contexts { self: Analyzer => var diagnostic: List[String] = Nil // these messages are printed when issuing an error var implicitsEnabled = false var macrosEnabled = true + var enrichmentEnabled = false // to selectively allow enrichment in patterns, where other kinds of implicit conversions are not allowed var checking = false var retyping = false @@ -192,8 +194,25 @@ trait Contexts { self: Analyzer => def withImplicitsDisabled[T](op: => T): T = { val saved = implicitsEnabled implicitsEnabled = false + val savedP = enrichmentEnabled + enrichmentEnabled = false try op - finally implicitsEnabled = saved + finally { + implicitsEnabled = saved + enrichmentEnabled = savedP + } + } + + def withImplicitsDisabledAllowEnrichment[T](op: => T): T = { + val saved = implicitsEnabled + implicitsEnabled = false + val savedP = enrichmentEnabled + enrichmentEnabled = true + try op + finally { + implicitsEnabled = saved + enrichmentEnabled = savedP + } } def withMacrosEnabled[T](op: => T): T = { @@ -246,6 +265,7 @@ trait Contexts { self: Analyzer => c.typingIndentLevel = typingIndentLevel c.implicitsEnabled = this.implicitsEnabled c.macrosEnabled = this.macrosEnabled + c.enrichmentEnabled = this.enrichmentEnabled c.checking = this.checking c.retyping = this.retyping c.openImplicits = this.openImplicits @@ -298,6 +318,7 @@ trait Contexts { self: Analyzer => def makeImplicit(reportAmbiguousErrors: Boolean) = { val c = makeSilent(reportAmbiguousErrors) c.implicitsEnabled = false + c.enrichmentEnabled = false c } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 2b7c8e8304..a6a670f163 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1171,7 +1171,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { && !qtpe.typeSymbol.isBottomClass && qtpe != WildcardType && !qual.isInstanceOf[ApplyImplicitView] // don't chain views - && context.implicitsEnabled + && (context.implicitsEnabled || context.enrichmentEnabled) // Elaborating `context.implicitsEnabled`: // don't try to adapt a top-level type that's the subject of an implicit search // this happens because, if isView, typedImplicit tries to apply the "current" implicit value to @@ -4063,7 +4063,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } else { member(qual, name) } - if (sym == NoSymbol && name != nme.CONSTRUCTOR && (mode & EXPRmode) != 0) { + + // symbol not found? --> try to convert implicitly to a type that does have the required member + // added `| PATTERNmode` to allow enrichment in patterns (so we can add e.g., an xml member to StringContext, which in turn has an unapply[Seq] method) + if (sym == NoSymbol && name != nme.CONSTRUCTOR && (mode & (EXPRmode | PATTERNmode)) != 0) { val qual1 = if (member(qual, name) != NoSymbol) qual else adaptToMemberWithArgs(tree, qual, name, mode, true, true) @@ -4071,6 +4074,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (qual1 ne qual) return typed(treeCopy.Select(tree, qual1, name), mode, pt) } + if (!reallyExists(sym)) { if (context.owner.enclosingTopLevelClass.isJavaDefined && name.isTypeName) { val tree1 = atPos(tree.pos) { gen.convertToSelectFromType(qual, name) } @@ -4806,6 +4810,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { ptLine("typing %s: pt = %s".format(ptTree(tree), pt), "undetparams" -> context.undetparams, "implicitsEnabled" -> context.implicitsEnabled, + "enrichmentEnabled" -> context.enrichmentEnabled, + "mode" -> modeString(mode), "silent" -> context.bufferErrors, "context.owner" -> context.owner ) @@ -4909,7 +4915,22 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // We disable implicits because otherwise some constructs will // type check which should not. The pattern matcher does not // perform implicit conversions in an attempt to consummate a match. - context.withImplicitsDisabled(typed(tree, PATTERNmode, pt)) + + // on the one hand, + // "abc" match { case Seq('a', 'b', 'c') => true } + // should be ruled out statically, otherwise this is a runtime + // error both because there is an implicit from String to Seq + // (even though such implicits are not used by the matcher) and + // because the typer is fine with concluding that "abc" might + // be of type "String with Seq[T]" and thus eligible for a call + // to unapplySeq. + + // on the other hand, we want to be able to use implicits to add members retro-actively (e.g., add xml to StringContext) + + // as a compromise, context.enrichmentEnabled tells adaptToMember to go ahead and enrich, + // but arbitrary conversions (in adapt) are disabled + // TODO: can we achieve the pattern matching bit of the string interpolation SIP without this? + context.withImplicitsDisabledAllowEnrichment(typed(tree, PATTERNmode, pt)) } /** Types a (fully parameterized) type tree */ diff --git a/test/files/run/virtpatmat_stringinterp.check b/test/files/run/virtpatmat_stringinterp.check new file mode 100644 index 0000000000..7927f4f2d9 --- /dev/null +++ b/test/files/run/virtpatmat_stringinterp.check @@ -0,0 +1 @@ +Node(1) diff --git a/test/files/run/virtpatmat_stringinterp.flags b/test/files/run/virtpatmat_stringinterp.flags new file mode 100644 index 0000000000..0612c4f8ff --- /dev/null +++ b/test/files/run/virtpatmat_stringinterp.flags @@ -0,0 +1 @@ +-Xexperimental -Yvirtpatmat \ No newline at end of file diff --git a/test/files/run/virtpatmat_stringinterp.scala b/test/files/run/virtpatmat_stringinterp.scala new file mode 100644 index 0000000000..213712f17a --- /dev/null +++ b/test/files/run/virtpatmat_stringinterp.scala @@ -0,0 +1,13 @@ +object Test extends App { + case class Node(x: Int) + + implicit def sc2xml(sc: StringContext): XMLContext = new XMLContext(sc) + class XMLContext(sc: StringContext) { + object xml { + def unapplySeq(xml: Node): Option[Seq[Node]] = Some(List(Node(1))) + } + } + + val x: Node = Node(0) + x match { case xml"""""" => println(a) } +} \ No newline at end of file -- cgit v1.2.3 From f5857462ccb770f3433637efa3c342ec98622137 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Thu, 29 Mar 2012 16:50:29 +0200 Subject: print labeldef's parameter types --- src/compiler/scala/reflect/internal/TreePrinters.scala | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/compiler/scala/reflect/internal/TreePrinters.scala b/src/compiler/scala/reflect/internal/TreePrinters.scala index 9b4c18ce86..486a3d3567 100644 --- a/src/compiler/scala/reflect/internal/TreePrinters.scala +++ b/src/compiler/scala/reflect/internal/TreePrinters.scala @@ -103,6 +103,16 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable => } } + def printLabelParams(ps: List[Ident]) { + print("(") + printSeq(ps){printLabelParam}{print(", ")} + print(")") + } + + def printLabelParam(p: Ident) { + print(symName(p, p.name)); printOpt(": ", TypeTree() setType p.tpe) + } + def printValueParams(ts: List[ValDef]) { print("(") if (!ts.isEmpty) printFlags(ts.head.mods.flags & IMPLICIT, "") @@ -219,7 +229,7 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable => } case LabelDef(name, params, rhs) => - print(symName(tree, name)); printRow(params, "(", ",", ")"); printBlock(rhs) + print(symName(tree, name)); printLabelParams(params); printBlock(rhs) case Import(expr, selectors) => // Is this selector remapping a name (i.e, {name1 => name2}) -- cgit v1.2.3 From 98a85ccae54195ee17f4b4aa12c22d018fd43bee Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Fri, 13 Apr 2012 13:58:48 +0200 Subject: cleanup in refchecks --- src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index af75c75156..2d656e02b4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1655,9 +1655,10 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R inPattern = false treeCopy.CaseDef(tree, pat1, transform(guard), transform(body)) case LabelDef(_, _, _) if gen.hasSynthCaseSymbol(result) => + val old = inPattern inPattern = true val res = deriveLabelDef(result)(transform) - inPattern = false + inPattern = old res case _ => super.transform(result) -- cgit v1.2.3 From d383f458aa5c53629727c5b6abb5134218471543 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Wed, 11 Apr 2012 15:05:27 +0200 Subject: synth PartialFunction in uncurry due to interaction with the CPS plugin, can't synth PartialFun during typer (the types don't work out: in PartialFun[T, U @cps[V]], U @cps[V] does not conform to Any, and we can't move the annot from the type arg directly to applyOrElse's result, since then it won't override anything) thus, we face the pain of mangling labeldefs again resetLocalAttrsKeepLabels can't use leaveAlone don't cast matcherror throw, uncurry gets confused uncurry: cast selector valdef's rhs to avoid skolem mismatch NOTE: I'm not happy about this code, but I don't know how to make the clean way (typedMatchAnonFun) compatible with the CPS plugin one avenue to explor would be to introduce PartialFunCPS, which is transformed into a regular PartialFun when T @cps[U] is turned into ControlContext[T, U] --- src/compiler/scala/tools/nsc/ast/TreeGen.scala | 55 ++------ src/compiler/scala/tools/nsc/ast/Trees.scala | 9 +- .../scala/tools/nsc/transform/UnCurry.scala | 146 +++++++++++++++++++-- .../tools/nsc/typechecker/PatMatVirtualiser.scala | 6 +- .../scala/tools/nsc/typechecker/Typers.scala | 71 +++++----- test/files/pos/virtpatmat_exist_uncurry.scala | 6 + 6 files changed, 194 insertions(+), 99 deletions(-) create mode 100644 test/files/pos/virtpatmat_exist_uncurry.scala (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index e566384713..d3e64811d3 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -72,14 +72,6 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL { Annotated(Ident(nme.synthSwitch), expr) } - // must be kept in synch with the codegen in PatMatVirtualiser - object VirtualCaseDef { - def unapply(b: Block): Option[(Assign, Tree, Tree)] = b match { - case Block(List(assign@Assign(keepGoingLhs, falseLit), matchRes), zero) => Some((assign, matchRes, zero)) // TODO: check tree annotation - case _ => None - } - } - def hasSynthCaseSymbol(t: Tree) = (t.symbol ne null) && (t.symbol hasFlag (CASE | SYNTHETIC)) // TODO: would be so much nicer if we would know during match-translation (i.e., type checking) @@ -87,9 +79,11 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL { class MatchMatcher { def caseMatch(orig: Tree, selector: Tree, cases: List[CaseDef], wrap: Tree => Tree): Tree = unknownTree(orig) def caseVirtualizedMatch(orig: Tree, _match: Tree, targs: List[Tree], scrut: Tree, matcher: Tree): Tree = unknownTree(orig) - def caseVirtualizedMatchOpt(orig: Tree, zero: ValDef, x: ValDef, matchRes: ValDef, keepGoing: ValDef, stats: List[Tree], epilogue: Tree, wrap: Tree => Tree): Tree = unknownTree(orig) + def caseVirtualizedMatchOpt(orig: Tree, prologue: List[Tree], cases: List[Tree], matchEndDef: Tree, wrap: Tree => Tree): Tree = unknownTree(orig) - def apply(matchExpr: Tree): Tree = (matchExpr: @unchecked) match { + def genVirtualizedMatch(prologue: List[Tree], cases: List[Tree], matchEndDef: Tree): Tree = Block(prologue ++ cases, matchEndDef) + + def apply(matchExpr: Tree): Tree = matchExpr match { // old-style match or virtpatmat switch case Match(selector, cases) => // println("simple match: "+ (selector, cases) + "for:\n"+ matchExpr ) caseMatch(matchExpr, selector, cases, identity) @@ -100,11 +94,15 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL { case Apply(Apply(TypeApply(Select(tgt, nme.runOrElse), targs), List(scrut)), List(matcher)) if opt.virtPatmat => // println("virt match: "+ (tgt, targs, scrut, matcher) + "for:\n"+ matchExpr ) caseVirtualizedMatch(matchExpr, tgt, targs, scrut, matcher) // optimized version of virtpatmat - case Block((zero: ValDef) :: (x: ValDef) :: (matchRes: ValDef) :: (keepGoing: ValDef) :: stats, epilogue) if opt.virtPatmat => // TODO: check tree annotation // println("virtopt match: "+ (zero, x, matchRes, keepGoing, stats) + "for:\n"+ matchExpr ) - caseVirtualizedMatchOpt(matchExpr, zero, x, matchRes, keepGoing, stats, epilogue, identity) + case Block(stats, matchEndDef) if opt.virtPatmat && (stats forall hasSynthCaseSymbol) => + // the assumption is once we encounter a case, the remainder of the block will consist of cases + // the prologue may be empty, usually it is the valdef that stores the scrut + val (prologue, cases) = stats span (s => !s.isInstanceOf[LabelDef]) + caseVirtualizedMatchOpt(matchExpr, prologue, cases, matchEndDef, identity) // optimized version of virtpatmat - case Block(outerStats, orig@Block((zero: ValDef) :: (x: ValDef) :: (matchRes: ValDef) :: (keepGoing: ValDef) :: stats, epilogue)) if opt.virtPatmat => // TODO: check tree annotation // println("virt opt block match: "+ (zero, x, matchRes, keepGoing, stats, outerStats) + "for:\n"+ matchExpr ) - caseVirtualizedMatchOpt(matchExpr, zero, x, matchRes, keepGoing, stats, epilogue, m => copyBlock(matchExpr, outerStats, m)) + case Block(outerStats, orig@Block(stats, matchEndDef)) if opt.virtPatmat && (stats forall hasSynthCaseSymbol) => + val (prologue, cases) = stats span (s => !s.isInstanceOf[LabelDef]) + caseVirtualizedMatchOpt(matchExpr, prologue, cases, matchEndDef, m => copyBlock(matchExpr, outerStats, m)) case other => unknownTree(other) } @@ -120,35 +118,6 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL { } } - def withDefaultCase(matchExpr: Tree, defaultAction: Tree/*scrutinee*/ => Tree): Tree = { - object withDefaultTransformer extends MatchMatcher { - override def caseMatch(orig: Tree, selector: Tree, cases: List[CaseDef], wrap: Tree => Tree): Tree = { - val casesNoSynthCatchAll = dropSyntheticCatchAll(cases) - if (casesNoSynthCatchAll exists treeInfo.isDefaultCase) orig - else { - val defaultCase = CaseDef(Ident(nme.WILDCARD), EmptyTree, defaultAction(selector.duplicate)) - wrap(Match(selector, casesNoSynthCatchAll :+ defaultCase)) - } - } - override def caseVirtualizedMatch(orig: Tree, _match: Tree, targs: List[Tree], scrut: Tree, matcher: Tree): Tree = { import CODE._ - ((matcher APPLY (scrut)) DOT nme.getOrElse) APPLY (defaultAction(scrut.duplicate)) // TODO: pass targs - } - override def caseVirtualizedMatchOpt(orig: Tree, zero: ValDef, x: ValDef, matchRes: ValDef, keepGoing: ValDef, stats: List[Tree], epilogue: Tree, wrap: Tree => Tree): Tree = { import CODE._ - wrap(Block( - zero :: - x :: - matchRes :: - keepGoing :: - stats, - // replace `if (keepGoing) throw new MatchError(...) else matchRes` by `if (keepGoing) ${defaultAction(`x`)} else matchRes` - (IF (REF(keepGoing.symbol)) THEN defaultAction(x.rhs.duplicate) ELSE REF(matchRes.symbol)) - )) - } - } - withDefaultTransformer(matchExpr) - } - - def mkCached(cvar: Symbol, expr: Tree): Tree = { val cvarRef = mkUnattributedRef(cvar) Block( diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 59e36e86f6..04452c68e5 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -255,6 +255,7 @@ trait Trees extends reflect.internal.Trees { self: Global => def resetAllAttrs[A <: Tree](x: A, leaveAlone: Tree => Boolean = null): A = new ResetAttrs(false, leaveAlone).transform(x) def resetLocalAttrs[A <: Tree](x: A, leaveAlone: Tree => Boolean = null): A = new ResetAttrs(true, leaveAlone).transform(x) + def resetLocalAttrsKeepLabels[A<:Tree](x: A, leaveAlone: Tree => Boolean = null): A = new ResetAttrs(true, leaveAlone, true).transform(x) /** A transformer which resets symbol and tpe fields of all nodes in a given tree, * with special treatment of: @@ -265,7 +266,7 @@ trait Trees extends reflect.internal.Trees { self: Global => * * (bq:) This transformer has mutable state and should be discarded after use */ - private class ResetAttrs(localOnly: Boolean, leaveAlone: Tree => Boolean = null) { + private class ResetAttrs(localOnly: Boolean, leaveAlone: Tree => Boolean = null, keepLabels: Boolean = false) { val debug = settings.debug.value val trace = scala.tools.nsc.util.trace when debug @@ -328,18 +329,18 @@ trait Trees extends reflect.internal.Trees { self: Global => case EmptyTree => tree case _ => - if (tree.hasSymbol && (!localOnly || (locals contains tree.symbol))) + if (tree.hasSymbol && (!localOnly || (locals contains tree.symbol)) && !(keepLabels && tree.symbol.isLabel)) tree.symbol = NoSymbol tree.tpe = null tree } } - } + } } def transform[T <: Tree](x: T): T = { if (localOnly) - new MarkLocals().traverse(x) + new MarkLocals().traverse(x) if (localOnly && debug) { assert(locals.size == orderedLocals.size) diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 1d2206bc3d..57cd51ad35 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -241,7 +241,6 @@ abstract class UnCurry extends InfoTransform def owner = fun.symbol.owner def targs = fun.tpe.typeArgs def isPartial = fun.tpe.typeSymbol == PartialFunctionClass - assert(!(opt.virtPatmat && isPartial)) // empty-selector matches have already been translated into instantiations of anonymous (partial) functions def parents = if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe), SerializableClass.tpe) @@ -282,7 +281,44 @@ abstract class UnCurry extends InfoTransform val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), List(x)) val body = localTyper.typedPos(fun.pos) { import CODE._ - gen.mkUncheckedMatch(gen.withDefaultCase(substParam(fun.body), scrut => REF(default) APPLY (REF(x)))) + def defaultAction(scrut: Tree) = REF(default) APPLY (REF(x)) + + object withDefaultTransformer extends gen.MatchMatcher { + override def caseMatch(orig: Tree, selector: Tree, cases: List[CaseDef], wrap: Tree => Tree): Tree = { + val casesNoSynthCatchAll = dropSyntheticCatchAll(cases) + if (casesNoSynthCatchAll exists treeInfo.isDefaultCase) orig + else { + val defaultCase = CaseDef(Ident(nme.WILDCARD), EmptyTree, defaultAction(selector.duplicate)) + wrap(Match(/*gen.mkUnchecked*/(selector), casesNoSynthCatchAll :+ defaultCase)) + } + } + override def caseVirtualizedMatch(orig: Tree, _match: Tree, targs: List[Tree], scrut: Tree, matcher: Tree): Tree = { import CODE._ + ((matcher APPLY (scrut)) DOT nme.getOrElse) APPLY (defaultAction(scrut.duplicate)) // TODO: pass targs + } + override def caseVirtualizedMatchOpt(orig: Tree, prologue: List[Tree], cases: List[Tree], matchEndDef: Tree, wrap: Tree => Tree): Tree = { import CODE._ + val scrutRef = REF(prologue.head.symbol) // scrut valdef is always emitted (except for nested matchers that handle alternatives) + + val casesNewSynthCatchAll = cases.init :+ (deriveLabelDef(cases.last){ + case Apply(matchEnd, List(Throw(Apply(Select(New(exTpt), nme.CONSTRUCTOR), _)))) if exTpt.tpe.typeSymbol eq MatchErrorClass => + assert(matchEnd.symbol == matchEndDef.symbol, "matchEnd discrepancy "+(matchEnd, matchEndDef)) + matchEnd APPLY (defaultAction(scrutRef)) + case x => x + } setSymbol cases.last.symbol setType null) + + val LabelDef(_, List(matchRes), rhs) = matchEndDef + val matchEnd = matchEndDef.symbol + matchRes setType B1.tpe + rhs setType B1.tpe + matchEndDef setType B1.tpe + matchRes.symbol setInfo B1.tpe + matchEnd setInfo MethodType(List(matchRes.symbol), B1.tpe) + cases foreach (c => c.symbol setInfo MethodType(List(), B1.tpe)) + + wrap(Block(prologue ++ casesNewSynthCatchAll, matchEndDef)) + } + } + + withDefaultTransformer(substParam(fun.body)) } body.changeOwner(fun.symbol -> methSym) @@ -294,30 +330,115 @@ abstract class UnCurry extends InfoTransform methDef } - // duplicate before applyOrElseMethodDef is run so we start with the same symbols as applyOrElseMethodDef + // duplicate before applyOrElseMethodDef is run so that it does not mess up our trees and label symbols (we have a fresh set) // otherwise `TreeSymSubstituter(fun.vparams map (_.symbol), params)` won't work as the subst has been run already - val bodyForIDA = fun.body.duplicate + val bodyForIDA = { + val duped = fun.body.duplicate + val oldParams = new mutable.ListBuffer[Symbol]() + val newParams = new mutable.ListBuffer[Symbol]() + + val oldSyms0 = + duped filter { + case l@LabelDef(_, params, _) => + params foreach {p => + val oldSym = p.symbol + p.symbol = oldSym.cloneSymbol + oldParams += oldSym + newParams += p.symbol + } + true + case _ => false + } map (_.symbol) + val oldSyms = oldParams.toList ++ oldSyms0 + val newSyms = newParams.toList ++ (oldSyms0 map (_.cloneSymbol)) + // println("duping "+ oldSyms +" --> "+ (newSyms map (_.ownerChain))) + + val substLabels = new TreeSymSubstituter(oldSyms, newSyms) + + substLabels(duped) + } + def isDefinedAtMethodDef = { val methSym = anonClass.newMethod(nme.isDefinedAt, fun.pos, FINAL) val params = methSym newSyntheticValueParams formals methSym setInfoAndEnter MethodType(params, BooleanClass.tpe) val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), params) - def doSubst(x: Tree) = substParam(resetLocalAttrs(x)) // see pos/t1761 for why `resetLocalAttrs` + def doSubst(x: Tree) = substParam(resetLocalAttrsKeepLabels(x)) // see pos/t1761 for why `resetLocalAttrs`, but must keep label symbols around + object isDefinedAtTransformer extends gen.MatchMatcher { // TODO: optimize duplication, but make sure ValDef's introduced by wrap are treated correctly override def caseMatch(orig: Tree, selector: Tree, cases: List[CaseDef], wrap: Tree => Tree): Tree = { import CODE._ - gen.mkUncheckedMatch( - if (cases exists treeInfo.isDefaultCase) TRUE_typed + val casesNoSynthCatchAll = dropSyntheticCatchAll(cases) + if (casesNoSynthCatchAll exists treeInfo.isDefaultCase) TRUE_typed else doSubst(wrap( - Match(selector, - (cases map (c => deriveCaseDef(c)(x => TRUE_typed))) :+ ( + Match(/*gen.mkUnchecked*/(selector), + (casesNoSynthCatchAll map (c => deriveCaseDef(c)(x => TRUE_typed))) :+ ( DEFAULT ==> FALSE_typed) ))) - ) + } + override def caseVirtualizedMatch(orig: Tree, _match: Tree, targs: List[Tree], scrut: Tree, matcher: Tree): Tree = { + object noOne extends Transformer { + override val treeCopy = newStrictTreeCopier // must duplicate everything + val one = _match.tpe member newTermName("one") + override def transform(tree: Tree): Tree = tree match { + case Apply(fun, List(a)) if fun.symbol == one => + // blow one's argument away since all we want to know is whether the match succeeds or not + // (the alternative, making `one` CBN, would entail moving away from Option) + Apply(fun.duplicate, List(gen.mkZeroContravariantAfterTyper(a.tpe))) + case _ => + super.transform(tree) + } + } + doSubst(Apply(Apply(TypeApply(Select(_match.duplicate, _match.tpe.member(newTermName("isSuccess"))), targs map (_.duplicate)), List(scrut.duplicate)), List(noOne.transform(matcher)))) + } + + override def caseVirtualizedMatchOpt(orig: Tree, prologue: List[Tree], cases: List[Tree], matchEndDef: Tree, wrap: Tree => Tree) = { + val matchEnd = matchEndDef.symbol + val LabelDef(_, List(matchRes), rhs) = matchEndDef + matchRes setType BooleanClass.tpe + rhs setType BooleanClass.tpe + matchEndDef setType BooleanClass.tpe + matchRes.symbol setInfo BooleanClass.tpe + matchEnd setInfo MethodType(List(matchRes.symbol), BooleanClass.tpe) + cases foreach (c => c.symbol setInfo MethodType(List(), BooleanClass.tpe)) + // println("matchEnd: "+ matchEnd) + + // when the type of the selector contains a skolem owned by the applyOrElseMethod, should reskolemize everything, + // for now, just cast the RHS (since we're just trying to keep the typer happy, the cast is meaningless) + // ARGH -- this is why I would prefer the typedMatchAnonFun approach (but alas, CPS blocks that) + val newPrologue = prologue match { + case List(vd@ValDef(mods, name, tpt, rhs)) => List(treeCopy.ValDef(vd, mods, name, tpt, gen.mkAsInstanceOf(rhs, tpt.tpe, true, false))) + case _ => prologue + } + object casesReturnTrue extends Transformer { + // override val treeCopy = newStrictTreeCopier // will duplicate below + override def transform(tree: Tree): Tree = tree match { + // don't compute the result of the match, return true instead + case Apply(fun, List(res)) if fun.symbol eq matchEnd => + // println("matchend call "+ fun.symbol) + Apply(fun, List(TRUE_typed)) setType BooleanClass.tpe + case _ => super.transform(tree) + } + } + val newCatchAll = cases.last match { + case LabelDef(n, ps, Apply(matchEnd1, List(Throw(Apply(Select(New(exTpt), nme.CONSTRUCTOR), _))))) if exTpt.tpe.typeSymbol eq MatchErrorClass => + assert(matchEnd1.symbol == matchEnd, "matchEnd discrepancy "+(matchEnd, matchEndDef)) + List(treeCopy.LabelDef(cases.last, n, ps, matchEnd APPLY (FALSE_typed)) setSymbol cases.last.symbol) + case x => Nil + } + val casesWithoutCatchAll = if(newCatchAll.isEmpty) cases else cases.init + doSubst(wrap(Block(newPrologue ++ casesReturnTrue.transformTrees(casesWithoutCatchAll) ++ newCatchAll, matchEndDef))) + + // val duped = idaBlock //.duplicate // TODO: duplication of labeldefs is BROKEN + // duped foreach { + // case l@LabelDef(name, params, rhs) if gen.hasSynthCaseSymbol(l) => println("newInfo"+ l.symbol.info) + // case _ => + // } } } + val body = isDefinedAtTransformer(bodyForIDA) body.changeOwner(fun.symbol -> methSym) @@ -328,11 +449,14 @@ abstract class UnCurry extends InfoTransform if (isPartial) List(applyOrElseMethodDef, isDefinedAtMethodDef) else List(applyMethodDef) - localTyper.typedPos(fun.pos) { + // println("MEMBERS "+ members) + val res = localTyper.typedPos(fun.pos) { Block( List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, fun.pos)), Typed(New(anonClass.tpe), TypeTree(fun.tpe))) } + // println("MEMBERS TYPED "+ members) + res } def transformArgs(pos: Position, fun: Symbol, args: List[Tree], formals: List[Type]) = { diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala index e8e65071af..313818a9d4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala @@ -1650,7 +1650,11 @@ class Foo(x: Other) { x._1 } // no error in this order def catchAll = matchFailGen map { matchFailGen => val scrutRef = if(scrutSym ne NoSymbol) REF(scrutSym) else EmptyTree // for alternatives - LabelDef(nextCase, Nil, matchEnd APPLY (_asInstanceOf(matchFailGen(scrutRef), restpe))) // need to jump to matchEnd with result generated by matchFailGen (could be `FALSE` for isDefinedAt) + // must jump to matchEnd, use result generated by matchFailGen (could be `FALSE` for isDefinedAt) + LabelDef(nextCase, Nil, matchEnd APPLY (matchFailGen(scrutRef))) + // don't cast the arg to matchEnd when using PartialFun synth in uncurry, since it won't detect the throw (see gen.withDefaultCase) + // the cast is necessary when using typedMatchAnonFun-style PartialFun synth: + // (_asInstanceOf(matchFailGen(scrutRef), restpe)) } toList // catchAll.isEmpty iff no synthetic default case needed (the (last) user-defined case is a default) // if the last user-defined case is a default, it will never jump to the next case; it will go immediately to matchEnd diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index a6893ff4b2..c4eb43c427 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2193,7 +2193,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def adaptCase(cdef: CaseDef, mode: Int, tpe: Type): CaseDef = deriveCaseDef(cdef)(adapt(_, mode, tpe)) - def prepareTranslateMatch(selector0: Tree, cases: List[CaseDef], mode: Int, resTp: Type) = { + def typedMatch(selector0: Tree, cases: List[CaseDef], mode: Int, resTp: Type) = { val (selector, doTranslation) = selector0 match { case Annotated(Ident(nme.synthSwitch), selector) => (selector, false) case s => (s, true) @@ -2210,7 +2210,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { (selector1, selectorTp, casesAdapted, ownType, doTranslation) } - def translateMatch(selector1: Tree, selectorTp: Type, casesAdapted: List[CaseDef], ownType: Type, doTranslation: Boolean, matchFailGen: Option[Tree => Tree] = None) = { + def translatedMatch(selector1: Tree, selectorTp: Type, casesAdapted: List[CaseDef], ownType: Type, doTranslation: Boolean, matchFailGen: Option[Tree => Tree] = None) = { def repeatedToSeq(tp: Type): Type = (tp baseType RepeatedParamClass) match { case TypeRef(_, RepeatedParamClass, arg :: Nil) => seqType(arg) case _ => tp @@ -2220,7 +2220,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { Match(selector1, casesAdapted) setType ownType // setType of the Match to avoid recursing endlessly } else { val scrutType = repeatedToSeq(elimAnonymousClass(selectorTp)) - // we've packed the type for each case in prepareTranslateMatch so that if all cases have the same existential case, we get a clean lub + // we've packed the type for each case in typedMatch so that if all cases have the same existential case, we get a clean lub // here, we should open up the existential again // relevant test cases: pos/existentials-harmful.scala, pos/gadt-gilles.scala, pos/t2683.scala, pos/virtpatmat_exist4.scala MatchTranslator(this).translateMatch(selector1, casesAdapted, repeatedToSeq(ownType.skolemizeExistential(context.owner, context.tree)), scrutType, matchFailGen) @@ -2283,7 +2283,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) paramSyms foreach (methodBodyTyper.context.scope enter _) - val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, cases, mode, ptRes) + val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.typedMatch(selector, cases, mode, ptRes) val methFormals = paramSyms map (_.tpe) val parents = List(abstractFunctionType(methFormals, resTp), SerializableClass.tpe) @@ -2291,7 +2291,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { anonClass setInfo ClassInfoType(parents, newScope, anonClass) methodSym setInfoAndEnter MethodType(paramSyms, resTp) - DefDef(methodSym, methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation)) + DefDef(methodSym, methodBodyTyper.translatedMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation)) } } @@ -2321,7 +2321,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) paramSyms foreach (methodBodyTyper.context.scope enter _) - val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, cases, mode, ptRes) + val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.typedMatch(selector, cases, mode, ptRes) anonClass setInfo ClassInfoType(parents(List(argTp, resTp)), newScope, anonClass) B1 setInfo TypeBounds.lower(resTp) @@ -2330,7 +2330,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // use applyOrElse's first parameter since the scrut's type has been widened def doDefault(scrut_ignored: Tree) = REF(default) APPLY (REF(x)) - val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, B1.tpe, doTranslation, Some(doDefault)) + val body = methodBodyTyper.translatedMatch(selector1, selectorTp, casesAdapted, B1.tpe, doTranslation, Some(doDefault)) DefDef(methodSym, body) } @@ -2345,8 +2345,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { paramSyms foreach (methodBodyTyper.context.scope enter _) methodSym setInfoAndEnter MethodType(paramSyms, BooleanClass.tpe) - val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, casesTrue, mode, BooleanClass.tpe) - val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation, Some(scrutinee => FALSE_typed)) + val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.typedMatch(selector, casesTrue, mode, BooleanClass.tpe) + val body = methodBodyTyper.translatedMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation, Some(scrutinee => FALSE_typed)) DefDef(methodSym, body) } @@ -2407,29 +2407,21 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } } - fun.body match { - case Match(sel, cases) if opt.virtPatmat => - // go to outer context -- must discard the context that was created for the Function since we're discarding the function - // thus, its symbol, which serves as the current context.owner, is not the right owner - // you won't know you're using the wrong owner until lambda lift crashes (unless you know better than to use the wrong owner) - newTyper(context.outer).typedMatchAnonFun(fun, cases, mode, pt, Some((fun.vparams, sel))) - case _ => - val vparamSyms = fun.vparams map { vparam => - enterSym(context, vparam) - if (context.retyping) context.scope enter vparam.symbol - vparam.symbol - } - val vparams = fun.vparams mapConserve (typedValDef) - // for (vparam <- vparams) { - // checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); () - // } - val formals = vparamSyms map (_.tpe) - val body1 = typed(fun.body, respt) - val restpe = packedType(body1, fun.symbol).deconst.resultType - val funtpe = typeRef(clazz.tpe.prefix, clazz, formals :+ restpe) - // body = checkNoEscaping.locals(context.scope, restpe, body) - treeCopy.Function(fun, vparams, body1).setType(funtpe) + val vparamSyms = fun.vparams map { vparam => + enterSym(context, vparam) + if (context.retyping) context.scope enter vparam.symbol + vparam.symbol } + val vparams = fun.vparams mapConserve (typedValDef) +// for (vparam <- vparams) { +// checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); () +// } + val formals = vparamSyms map (_.tpe) + val body1 = typed(fun.body, respt) + val restpe = packedType(body1, fun.symbol).deconst.resultType + val funtpe = typeRef(clazz.tpe.prefix, clazz, formals :+ restpe) +// body = checkNoEscaping.locals(context.scope, restpe, body) + treeCopy.Function(fun, vparams, body1).setType(funtpe) } } @@ -3797,13 +3789,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } } - def typedMatch(tree: Tree, selector: Tree, cases: List[CaseDef]): Tree = { - if (opt.virtPatmat && !isPastTyper) { - if (selector ne EmptyTree) { - val (selector1, selectorTp, casesAdapted, ownType, doTranslation) = prepareTranslateMatch(selector, cases, mode, pt) - typed(translateMatch(selector1, selectorTp, casesAdapted, ownType, doTranslation), mode, pt) - } else typedMatchAnonFun(tree, cases, mode, pt) - } else if (selector == EmptyTree) { + // translation only happens when (selector != EmptyTree) && !isPastTyper && opt.virtPatmat + def typedTranslatedMatch(tree: Tree, selector: Tree, cases: List[CaseDef]): Tree = { + if (selector == EmptyTree) { val arity = if (isFunctionType(pt)) pt.normalize.typeArgs.length - 1 else 1 val params = for (i <- List.range(0, arity)) yield atPos(tree.pos.focusStart) { @@ -3814,7 +3802,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { val selector1 = atPos(tree.pos.focusStart) { if (arity == 1) ids.head else gen.mkTuple(ids) } val body = treeCopy.Match(tree, selector1, cases) typed1(atPos(tree.pos) { Function(params, body) }, mode, pt) - } else { + } else if (!opt.virtPatmat || isPastTyper) { val selector1 = checkDead(typed(selector, EXPRmode | BYVALmode, WildcardType)) var cases1 = typedCases(cases, packCaptured(selector1.tpe.widen), pt) val (owntype, needAdapt) = ptOrLub(cases1 map (_.tpe)) @@ -3822,6 +3810,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { cases1 = cases1 map (adaptCase(_, mode, owntype)) } treeCopy.Match(tree, selector1, cases1) setType owntype + } else { + val (selector1, selectorTp, casesAdapted, ownType, doTranslation) = typedMatch(selector, cases, mode, pt) + typed(translatedMatch(selector1, selectorTp, casesAdapted, ownType, doTranslation), mode, pt) } } @@ -4681,7 +4672,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { typedIf(cond, thenp, elsep) case tree @ Match(selector, cases) => - typedMatch(tree, selector, cases) + typedTranslatedMatch(tree, selector, cases) case Return(expr) => typedReturn(expr) diff --git a/test/files/pos/virtpatmat_exist_uncurry.scala b/test/files/pos/virtpatmat_exist_uncurry.scala new file mode 100644 index 0000000000..e017da6343 --- /dev/null +++ b/test/files/pos/virtpatmat_exist_uncurry.scala @@ -0,0 +1,6 @@ +object Test { + trait Leaf[T] { + def collect[U](f: PartialFunction[Leaf[_], U]): List[U] + def leaves: List[Leaf[T]] = collect { case l: Leaf[T] => l } + } +} \ No newline at end of file -- cgit v1.2.3 From 3515ac4449c72992be411e1e0579d76189dc7bf1 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Fri, 13 Apr 2012 18:52:12 +0200 Subject: more prudent bridging to unapply[Seq] since we can't statically know whether the unapply we'll be bridging to is synthetic, drop this condition, and do pessimistic bridging for all unapply[Seq] (i.e., if we can't statically guarantee the type that would be assumed to be safe to cast to by a synthetic extractor, do the type test and return None if it fails) --- .../scala/tools/nsc/transform/Erasure.scala | 9 ++-- test/files/run/patmat_unapp_abstype.check | 2 + test/files/run/patmat_unapp_abstype.scala | 49 +++++++++++++++++++--- 3 files changed, 50 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index bdf2f2883f..5e61359a25 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -480,11 +480,10 @@ abstract class Erasure extends AddInterfaces // TODO: should we do this for user-defined unapplies as well? // does the first argument list have exactly one argument -- for user-defined unapplies we can't be sure def maybeWrap(bridgingCall: Tree): Tree = { - val canReturnNone = afterErasure( - member.isSynthetic - && (member.name == nme.unapply || member.name == nme.unapplySeq) - && !(member.tpe <:< other.tpe) // no static guarantees (TODO: is the subtype test ever true?) - ) + val canReturnNone = ( // can't statically know which member is going to be selected, so don't let this depend on member.isSynthetic + (member.name == nme.unapply || member.name == nme.unapplySeq) + && !afterErasure((member.tpe <:< other.tpe))) // no static guarantees (TODO: is the subtype test ever true?) + if (canReturnNone) { import CODE._ val typeTest = gen.mkIsInstanceOf(REF(bridge.firstParam), member.tpe.params.head.tpe) diff --git a/test/files/run/patmat_unapp_abstype.check b/test/files/run/patmat_unapp_abstype.check index ac28ccdb95..72239d16cd 100644 --- a/test/files/run/patmat_unapp_abstype.check +++ b/test/files/run/patmat_unapp_abstype.check @@ -1,2 +1,4 @@ TypeRef none of the above +Bar +Foo diff --git a/test/files/run/patmat_unapp_abstype.scala b/test/files/run/patmat_unapp_abstype.scala index e5adec5c16..fb0b491d39 100644 --- a/test/files/run/patmat_unapp_abstype.scala +++ b/test/files/run/patmat_unapp_abstype.scala @@ -32,8 +32,47 @@ trait TypesImpl extends TypesAPI { //lazy val typeRefMani = manifest[TypeRef] } -object Test extends TypesImpl with TypesUser with App { - shouldNotCrash(TypeRef(10)) // should and does print "TypeRef" - // once #1697/#2337 are fixed, this should generate the correct output - shouldNotCrash(MethodType(10)) // should print "MethodType" but prints "none of the above" -- good one, pattern matcher! -} \ No newline at end of file +trait Foos { + trait Bar + type Foo <: Bar + trait FooExtractor { + def unapply(foo: Foo): Option[Int] + } + val Foo: FooExtractor +} + +trait RealFoos extends Foos { + class Foo(val x: Int) extends Bar + object Foo extends FooExtractor { + def unapply(foo: Foo): Option[Int] = Some(foo.x) + } +} + +trait Intermed extends Foos { + def crash(bar: Bar): Unit = + bar match { + case Foo(x) => println("Foo") + case _ => println("Bar") + } +} + +object TestUnappStaticallyKnownSynthetic extends TypesImpl with TypesUser { + def test() = { + shouldNotCrash(TypeRef(10)) // should and does print "TypeRef" + // once #1697/#2337 are fixed, this should generate the correct output + shouldNotCrash(MethodType(10)) // should print "MethodType" but prints "none of the above" -- good one, pattern matcher! + } +} + +object TestUnappDynamicSynth extends RealFoos with Intermed { + case class FooToo(n: Int) extends Bar + def test() = { + crash(FooToo(10)) + crash(new Foo(5)) + } +} + +object Test extends App { + TestUnappStaticallyKnownSynthetic.test() + TestUnappDynamicSynth.test() +} -- cgit v1.2.3 From e1c8e2da26831c9a2d123bed5cb0f53230a3f939 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Fri, 13 Apr 2012 17:32:38 +0200 Subject: wip: put skeleton for typetag-based typetests in place --- .../scala/tools/nsc/typechecker/Infer.scala | 44 ++++++++++++++++++++++ .../tools/nsc/typechecker/PatMatVirtualiser.scala | 36 ++++++++++++++---- test/files/run/patmat_unapp_abstype.scala | 5 +++ 3 files changed, 78 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index d78fd35d25..fb0616c890 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -1189,6 +1189,50 @@ trait Infer { } } + /** Does `tp` contain any types that cannot be checked at run-time (i.e., after erasure, will isInstanceOf[erased(tp)] imply conceptualIsInstanceOf[tp]?) + * we should find a way to ask erasure: hey, is `tp` going to make it through you with all of its isInstanceOf resolving powers intact? + * TODO: at the very least, reduce duplication wrt checkCheckable + */ + def containsUnchecked(tp: Type): Boolean = { + def check(tp: Type, bound: List[Symbol]): Boolean = { + def isSurroundingTypeParam(sym: Symbol) = { + val e = context.scope.lookupEntry(sym.name) + ( (e ne null) + && (e.sym == sym ) + && !e.sym.isTypeParameterOrSkolem + && (e.owner == context.scope) + ) + } + def isLocalBinding(sym: Symbol) = ( + sym.isAbstractType && ( + (bound contains sym) + || (sym.name == tpnme.WILDCARD) + || isSurroundingTypeParam(sym) + ) + ) + tp.normalize match { + case SingleType(pre, _) => + check(pre, bound) + case TypeRef(_, ArrayClass, arg :: _) => + check(arg, bound) + case tp @ TypeRef(pre, sym, args) => + ( (sym.isAbstractType && !isLocalBinding(sym)) + || (args exists (x => !isLocalBinding(x.typeSymbol))) + || check(pre, bound) + ) + // case RefinedType(_, decls) if decls.nonEmpty => + // patternWarning(tp, "refinement ") + case RefinedType(parents, _) => + parents exists (p => check(p, bound)) + case ExistentialType(quantified, tp1) => + check(tp1, bound ::: quantified) + case _ => + false + } + } + check(tp, Nil) + } + def checkCheckable(tree: Tree, tp: Type, kind: String) { def patternWarning(tp0: Type, prefix: String) = { context.unit.uncheckedWarning(tree.pos, prefix+tp0+" in type "+kind+tp+" is unchecked since it is eliminated by erasure") diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala index 313818a9d4..9b50853c51 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala @@ -22,7 +22,7 @@ import language.postfixOps * - Array patterns * - implement spec more closely (see TODO's) * - DCE - * - use manifests for type testing + * - use TypeTags for type testing * * (longer-term) TODO: * - user-defined unapplyProd @@ -119,6 +119,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => trait MatchTranslation extends MatchMonadInterface { self: TreeMakers with CodegenCore => import typer.{typed, context, silent, reallyExists} + // import typer.infer.containsUnchecked /** Implement a pattern match by turning its cases (including the implicit failure case) * into the corresponding (monadic) extractors, and combining them with the `orElse` combinator. @@ -820,13 +821,34 @@ class Foo(x: Other) { x._1 } // no error in this order cond } - // TODO: also need to test when erasing pt loses crucial information (and if we can recover it using a manifest) - def needsTypeTest(tp: Type, pt: Type) = !(tp <:< pt) - private def typeTest(binder: Symbol, pt: Type) = maybeWithOuterCheck(binder, pt)(codegen._isInstanceOf(binder, pt)) + // containsUnchecked: also need to test when erasing pt loses crucial information (maybe we can recover it using a TypeTag) + def needsTypeTest(tp: Type, pt: Type): Boolean = !(tp <:< pt) // || containsUnchecked(pt) + // TODO: try to find the TypeTag for the binder's type and the expected type, and if they exists, + // check that the TypeTag of the binder's type conforms to the TypeTag of the expected type + private def typeTest(binderToTest: Symbol, expectedTp: Type, disableOuterCheck: Boolean = false, dynamic: Boolean = false): Tree = { import CODE._ + // def coreTest = + if (disableOuterCheck) codegen._isInstanceOf(binderToTest, expectedTp) else maybeWithOuterCheck(binderToTest, expectedTp)(codegen._isInstanceOf(binderToTest, expectedTp)) + // if (opt.experimental && containsUnchecked(expectedTp)) { + // if (dynamic) { + // val expectedTpTagTree = findManifest(expectedTp, true) + // if (!expectedTpTagTree.isEmpty) + // ((expectedTpTagTree DOT "erasure".toTermName) DOT "isAssignableFrom".toTermName)(REF(binderToTest) DOT nme.getClass_) + // else + // coreTest + // } else { + // val expectedTpTagTree = findManifest(expectedTp, true) + // val binderTpTagTree = findManifest(binderToTest.info, true) + // if(!(expectedTpTagTree.isEmpty || binderTpTagTree.isEmpty)) + // coreTest AND (binderTpTagTree DOT nme.CONFORMS)(expectedTpTagTree) + // else + // coreTest + // } + // } else coreTest + } // need to substitute since binder may be used outside of the next extractor call (say, in the body of the case) case class TypeTestTreeMaker(prevBinder: Symbol, nextBinderTp: Type, pos: Position) extends CondTreeMaker { - val cond = typeTest(prevBinder, nextBinderTp) + val cond = typeTest(prevBinder, nextBinderTp, dynamic = true) val res = codegen._asInstanceOf(prevBinder, nextBinderTp) override def toString = "TT"+(prevBinder, nextBinderTp) } @@ -866,7 +888,7 @@ class Foo(x: Other) { x._1 } // no error in this order // TODO: `null match { x : T }` will yield a check that (indirectly) tests whether `null ne null` // don't bother (so that we don't end up with the warning "comparing values of types Null and Null using `ne' will always yield false") def genEqualsAndInstanceOf(sym: Symbol): Tree - = codegen._equals(REF(sym), patBinder) AND codegen._isInstanceOf(patBinder, pt.widen) + = codegen._equals(REF(sym), patBinder) AND typeTest(patBinder, pt.widen, disableOuterCheck = true) def isRefTp(tp: Type) = tp <:< AnyRefClass.tpe @@ -874,7 +896,7 @@ class Foo(x: Other) { x._1 } // no error in this order def isMatchUnlessNull = isRefTp(pt) && !needsTypeTest(patBinderTp, pt) // TODO: [SPEC] type test for Array - // TODO: use manifests to improve tests (for erased types we can do better when we have a manifest) + // TODO: use TypeTags to improve tests (for erased types we can do better when we have a TypeTag) pt match { case SingleType(_, sym) /*this implies sym.isStable*/ => genEqualsAndInstanceOf(sym) // TODO: [SPEC] the spec requires `eq` instead of `==` here case ThisType(sym) if sym.isModule => genEqualsAndInstanceOf(sym) // must use == to support e.g. List() == Nil diff --git a/test/files/run/patmat_unapp_abstype.scala b/test/files/run/patmat_unapp_abstype.scala index fb0b491d39..45496f08a2 100644 --- a/test/files/run/patmat_unapp_abstype.scala +++ b/test/files/run/patmat_unapp_abstype.scala @@ -19,6 +19,11 @@ trait TypesUser extends TypesAPI { def shouldNotCrash(tp: Type): Unit = { tp match { case TypeRef(x) => println("TypeRef") + // the above checks tp.isInstanceOf[TypeRef], which is erased to tp.isInstanceOf[Type] + // before calling TypeRef.unapply(tp), which will then crash unless tp.isInstanceOf[TypesImpl#TypeRef] (which is not implied by tp.isInstanceOf[Type]) + // tp.isInstanceOf[TypesImpl#TypeRef] is equivalent to classOf[TypesImpl#TypeRef].isAssignableFrom(tp.getClass) + // this is equivalent to manifest + // it is NOT equivalent to manifest[Type] <:< typeRefMani case MethodType(x) => println("MethodType") case _ => println("none of the above") } -- cgit v1.2.3 From 391f92f4005700799ac2e775980f5c5a77fea203 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Fri, 13 Apr 2012 19:15:35 +0200 Subject: virtpatmat: initial CPS support typers&patmatvirtualizer have ad-hoc support for dropping annotations in a way that makes the CPS plugins happy... this is not ideal, but unless virtpatmat runs after the plugin phases, I don't see how to solve it running virtpatmat after the CPS plugin would mean the pattern matching evaluation cannot be captured by CPS, so it's not even desirable to move it to a later phase - typedIf must lub annotated types - drop selector.tpe's annotations - drop annots in matchEnd's argument type - deal with annots in casts synth by in virtpatmat (drop them from type arg to asInstanceof, recover them using type ascription) - workaround skolemize existential dropping annots CPS is the main reason why typedMatchAnonFun is not used anymore, and PartialFunction synthesis is moved back to uncurry (which is quite painful due to labeldefs being so broken) we can't synth partialfunction during typer since T @cps[U] does not conform to Any, so we can't pass it as a type arg to PartialFunction, so we can't type a cps-transformed PF after the CPS plugin, T @cps[U] becomes ControlContext[...], which is a type we can pass to PartialFunction virtpatmat is now also run until right before uncurry (so, can't use isPastTyper, although it means more or less the same thing -- we don't run after uncurry) the main functional improvements are in the selective ANF transform its treatment of labeldefs was broken: for example, LabelDef L1; LabelDef L2 --> DefDef L1; L1(); DefDef L2; L2() but this does not take into account L1 may jump over L2 to another label since methods always return (or fail), and the ANF transform generates ValDefs to store the result of those method calls, both L1 and L2 would always be executed (so you would run a match with N cases N times, with each partial run starting at a later case) also fixed a couple of weird bugs in selective anf that caused matches to be duplicated (with the duplicate being nested in the original) since label defs are turned into method defs, and later defs will be nested in the flatMap calls on the controlcontext yielded by earlier statements, we reverse the list of method definitions, so that earlier (in the control flow sense) methods are visible in later ones selective CPS now generates a catch that's directly digestible by backend --- .../tools/nsc/typechecker/PatMatVirtualiser.scala | 28 ++-- .../scala/tools/nsc/typechecker/Typers.scala | 16 +- .../tools/selectivecps/SelectiveANFTransform.scala | 168 +++++++++++++-------- .../tools/selectivecps/SelectiveCPSTransform.scala | 16 +- test/files/continuations-run/match2.scala | 2 +- 5 files changed, 137 insertions(+), 93 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala index 9b50853c51..1fd9f6fc13 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala @@ -132,10 +132,10 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer => * this could probably optimized... (but note that the matchStrategy must be solved for each nested patternmatch) */ def translateMatch(scrut: Tree, cases: List[CaseDef], pt: Type, scrutType: Type, matchFailGenOverride: Option[Tree => Tree] = None): Tree = { - // we don't transform after typers - // (that would require much more sophistication when generating trees, + // we don't transform after uncurry + // (that would require more sophistication when generating trees, // and the only place that emits Matches after typers is for exception handling anyway) - assert(phase.id <= currentRun.typerPhase.id, phase) + assert(phase.id < currentRun.uncurryPhase.id, phase) val scrutSym = freshSym(scrut.pos, pureType(scrutType)) setFlag SYNTH_CASE // pt = Any* occurs when compiling test/files/pos/annotDepMethType.scala with -Xexperimental @@ -1105,22 +1105,14 @@ class Foo(x: Other) { x._1 } // no error in this order def _equals(checker: Tree, binder: Symbol): Tree = checker MEMBER_== REF(binder) // NOTE: checker must be the target of the ==, that's the patmat semantics for ya def and(a: Tree, b: Tree): Tree = a AND b + // drop annotations generated by CPS plugin etc, since its annotationchecker rejects T @cps[U] <: Any + // let's assume for now annotations don't affect casts, drop them there, and bring them back using the outer Typed tree + private def mkCast(t: Tree, tp: Type) = Typed(gen.mkAsInstanceOf(t, tp.withoutAnnotations, true, false), TypeTree() setType tp) // the force is needed mainly to deal with the GADT typing hack (we can't detect it otherwise as tp nor pt need contain an abstract type, we're just casting wildly) - def _asInstanceOf(t: Tree, tp: Type, force: Boolean = false): Tree = { val tpX = /*repackExistential*/(tp) - if (!force && (t.tpe ne NoType) && t.isTyped && typesConform(t.tpe, tpX)) t //{ println("warning: emitted redundant asInstanceOf: "+(t, t.tpe, tp)); t } //.setType(tpX) - else gen.mkAsInstanceOf(t, tpX, true, false) - } - - def _isInstanceOf(b: Symbol, tp: Type): Tree = gen.mkIsInstanceOf(REF(b), /*repackExistential*/(tp), true, false) - // { val tpX = /*repackExistential*/(tp) + def _asInstanceOf(t: Tree, tp: Type, force: Boolean = false): Tree = if (!force && (t.tpe ne NoType) && t.isTyped && typesConform(t.tpe, tp)) t else mkCast(t, tp) + def _asInstanceOf(b: Symbol, tp: Type): Tree = if (typesConform(b.info, tp)) REF(b) else mkCast(REF(b), tp) + def _isInstanceOf(b: Symbol, tp: Type): Tree = gen.mkIsInstanceOf(REF(b), tp.withoutAnnotations, true, false) // if (typesConform(b.info, tpX)) { println("warning: emitted spurious isInstanceOf: "+(b, tp)); TRUE } - // else gen.mkIsInstanceOf(REF(b), tpX, true, false) - // } - - def _asInstanceOf(b: Symbol, tp: Type): Tree = { val tpX = /*repackExistential*/(tp) - if (typesConform(b.info, tpX)) REF(b) //{ println("warning: emitted redundant asInstanceOf: "+(b, b.info, tp)); REF(b) } //.setType(tpX) - else gen.mkAsInstanceOf(REF(b), tpX, true, false) - } // duplicated out of frustration with cast generation def mkZero(tp: Type): Tree = { @@ -1658,7 +1650,7 @@ class Foo(x: Other) { x._1 } // no error in this order */ def matcher(scrut: Tree, scrutSym: Symbol, restpe: Type)(cases: List[Casegen => Tree], matchFailGen: Option[Tree => Tree]): Tree = { val matchEnd = NoSymbol.newLabel(freshName("matchEnd"), NoPosition) setFlag SYNTH_CASE - val matchRes = NoSymbol.newValueParameter(newTermName("x"), NoPosition, SYNTHETIC) setInfo restpe + val matchRes = NoSymbol.newValueParameter(newTermName("x"), NoPosition, SYNTHETIC) setInfo restpe.withoutAnnotations // matchEnd setInfo MethodType(List(matchRes), restpe) def newCaseSym = NoSymbol.newLabel(freshName("case"), NoPosition) setInfo MethodType(Nil, restpe) setFlag SYNTH_CASE diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index c4eb43c427..dd8631ba21 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2199,7 +2199,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case s => (s, true) } val selector1 = checkDead(typed(selector, EXPRmode | BYVALmode, WildcardType)) - val selectorTp = packCaptured(selector1.tpe.widen) + val selectorTp = packCaptured(selector1.tpe.widen.withoutAnnotations) val casesTyped = typedCases(cases, selectorTp, resTp) val caseTypes = casesTyped map (c => packedType(c, context.owner).deconst) @@ -2223,7 +2223,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // we've packed the type for each case in typedMatch so that if all cases have the same existential case, we get a clean lub // here, we should open up the existential again // relevant test cases: pos/existentials-harmful.scala, pos/gadt-gilles.scala, pos/t2683.scala, pos/virtpatmat_exist4.scala - MatchTranslator(this).translateMatch(selector1, casesAdapted, repeatedToSeq(ownType.skolemizeExistential(context.owner, context.tree)), scrutType, matchFailGen) + // TODO: fix skolemizeExistential (it should preserve annotations, right?) + val ownTypeSkolemized = ownType.skolemizeExistential(context.owner, context.tree) withAnnotations ownType.annotations + MatchTranslator(this).translateMatch(selector1, casesAdapted, repeatedToSeq(ownTypeSkolemized), scrutType, matchFailGen) } } @@ -3772,12 +3774,16 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { lazy val thenTp = packedType(thenp1, context.owner) lazy val elseTp = packedType(elsep1, context.owner) + // println("typedIf: "+(thenp1.tpe, elsep1.tpe, ptOrLub(List(thenp1.tpe, elsep1.tpe)),"\n", thenTp, elseTp, thenTp =:= elseTp)) val (owntype, needAdapt) = // in principle we should pack the types of each branch before lubbing, but lub doesn't really work for existentials anyway // in the special (though common) case where the types are equal, it pays to pack before comparing // especially virtpatmat needs more aggressive unification of skolemized types // this breaks src/library/scala/collection/immutable/TrieIterator.scala - if (opt.virtPatmat && !isPastTyper && thenTp =:= elseTp) (thenp1.tpe, false) // use unpacked type + if ( opt.virtPatmat && !isPastTyper + && thenp1.tpe.annotations.isEmpty && elsep1.tpe.annotations.isEmpty // annotated types need to be lubbed regardless (at least, continations break if you by pass them like this) + && thenTp =:= elseTp + ) (thenp1.tpe, false) // use unpacked type // TODO: skolemize (lub of packed types) when that no longer crashes on files/pos/t4070b.scala else ptOrLub(List(thenp1.tpe, elsep1.tpe)) @@ -3802,7 +3808,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { val selector1 = atPos(tree.pos.focusStart) { if (arity == 1) ids.head else gen.mkTuple(ids) } val body = treeCopy.Match(tree, selector1, cases) typed1(atPos(tree.pos) { Function(params, body) }, mode, pt) - } else if (!opt.virtPatmat || isPastTyper) { + } else if (!((phase.id < currentRun.uncurryPhase.id) && opt.virtPatmat)) { val selector1 = checkDead(typed(selector, EXPRmode | BYVALmode, WildcardType)) var cases1 = typedCases(cases, packCaptured(selector1.tpe.widen), pt) val (owntype, needAdapt) = ptOrLub(cases1 map (_.tpe)) @@ -4688,7 +4694,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { catches1 = catches1 map (adaptCase(_, mode, owntype)) } - if(!isPastTyper && opt.virtPatmat) { + if((phase.id < currentRun.uncurryPhase.id) && opt.virtPatmat) { catches1 = (MatchTranslator(this)).translateTry(catches1, owntype, tree.pos) } diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala index a6737573ea..0975f16c6e 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala @@ -71,24 +71,46 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with // { x => x match { case A => ... }} to // { x => shiftUnit(x match { case A => ... })} // which Uncurry cannot handle (see function6.scala) + // thus, we push down the shiftUnit to each of the case bodies val ext = getExternalAnswerTypeAnn(body.tpe) + val pureBody = getAnswerTypeAnn(body.tpe).isEmpty + + def transformPureMatch(tree: Tree, selector: Tree, cases: List[CaseDef]) = { + val caseVals = cases map { case cd @ CaseDef(pat, guard, body) => + // if (!hasPlusMarker(body.tpe)) body.tpe = body.tpe withAnnotation newPlusMarker() // TODO: to avoid warning + val bodyVal = transExpr(body, None, ext) // ??? triggers "cps-transformed unexpectedly" warning in transTailValue + treeCopy.CaseDef(cd, transform(pat), transform(guard), bodyVal) + } + treeCopy.Match(tree, transform(selector), caseVals) + } + + def transformPureVirtMatch(body: Block, selDef: ValDef, cases: List[Tree], matchEnd: Tree) = { + val stats = transform(selDef) :: (cases map (transExpr(_, None, ext))) + treeCopy.Block(body, stats, transExpr(matchEnd, None, ext)) + } val body1 = body match { - case Match(selector, cases) if (ext.isDefined && getAnswerTypeAnn(body.tpe).isEmpty) => - val cases1 = for { - cd @ CaseDef(pat, guard, caseBody) <- cases - caseBody1 = transExpr(body, None, ext) - } yield { - treeCopy.CaseDef(cd, transform(pat), transform(guard), caseBody1) - } - treeCopy.Match(tree, transform(selector), cases1) + case Match(selector, cases) if ext.isDefined && pureBody => + transformPureMatch(body, selector, cases) + + // virtpatmat switch + case Block(List(selDef: ValDef), mat@Match(selector, cases)) if ext.isDefined && pureBody => + treeCopy.Block(body, List(transform(selDef)), transformPureMatch(mat, selector, cases)) + + // virtpatmat + case b@Block(matchStats@((selDef: ValDef) :: cases), matchEnd) if ext.isDefined && pureBody && (matchStats forall gen.hasSynthCaseSymbol) => + transformPureVirtMatch(b, selDef, cases, matchEnd) + + // virtpatmat that stores the scrut separately -- TODO: can we eliminate this case?? + case Block(List(selDef0: ValDef), mat@Block(matchStats@((selDef: ValDef) :: cases), matchEnd)) if ext.isDefined && pureBody && (matchStats forall gen.hasSynthCaseSymbol)=> + treeCopy.Block(body, List(transform(selDef0)), transformPureVirtMatch(mat, selDef, cases, matchEnd)) case _ => transExpr(body, None, ext) } - debuglog("result "+body1) + debuglog("anf result "+body1) debuglog("result is of type "+body1.tpe) treeCopy.Function(ff, transformValDefs(vparams), body1) @@ -170,63 +192,72 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with tree match { case Block(stms, expr) => val (cpsA2, cpsR2) = (cpsA, linearize(cpsA, getAnswerTypeAnn(tree.tpe))) // tbd -// val (cpsA2, cpsR2) = (None, getAnswerTypeAnn(tree.tpe)) - val (a, b) = transBlock(stms, expr, cpsA2, cpsR2) + // val (cpsA2, cpsR2) = (None, getAnswerTypeAnn(tree.tpe)) - val tree1 = (treeCopy.Block(tree, a, b)) // no updateSynthFlag here!!! + val (a, b) = transBlock(stms, expr, cpsA2, cpsR2) + val tree1 = (treeCopy.Block(tree, a, b)) // no updateSynthFlag here!!! (Nil, tree1, cpsA) - case If(cond, thenp, elsep) => - /* possible situations: - cps before (cpsA) - cps in condition (spc) <-- synth flag set if *only* here! - cps in (one or both) branches */ - val (condStats, condVal, spc) = transInlineValue(cond, cpsA) - val (cpsA2, cpsR2) = if (hasSynthMarker(tree.tpe)) - (spc, linearize(spc, getAnswerTypeAnn(tree.tpe))) else - (None, getAnswerTypeAnn(tree.tpe)) // if no cps in condition, branches must conform to tree.tpe directly - val thenVal = transExpr(thenp, cpsA2, cpsR2) - val elseVal = transExpr(elsep, cpsA2, cpsR2) - - // check that then and else parts agree (not necessary any more, but left as sanity check) - if (cpsR.isDefined) { - if (elsep == EmptyTree) - unit.error(tree.pos, "always need else part in cps code") - } - if (hasAnswerTypeAnn(thenVal.tpe) != hasAnswerTypeAnn(elseVal.tpe)) { - unit.error(tree.pos, "then and else parts must both be cps code or neither of them") - } - - (condStats, updateSynthFlag(treeCopy.If(tree, condVal, thenVal, elseVal)), spc) + case If(cond, thenp, elsep) => + /* possible situations: + cps before (cpsA) + cps in condition (spc) <-- synth flag set if *only* here! + cps in (one or both) branches */ + val (condStats, condVal, spc) = transInlineValue(cond, cpsA) + val (cpsA2, cpsR2) = if (hasSynthMarker(tree.tpe)) + (spc, linearize(spc, getAnswerTypeAnn(tree.tpe))) else + (None, getAnswerTypeAnn(tree.tpe)) // if no cps in condition, branches must conform to tree.tpe directly + val thenVal = transExpr(thenp, cpsA2, cpsR2) + val elseVal = transExpr(elsep, cpsA2, cpsR2) + + // check that then and else parts agree (not necessary any more, but left as sanity check) + if (cpsR.isDefined) { + if (elsep == EmptyTree) + unit.error(tree.pos, "always need else part in cps code") + } + if (hasAnswerTypeAnn(thenVal.tpe) != hasAnswerTypeAnn(elseVal.tpe)) { + unit.error(tree.pos, "then and else parts must both be cps code or neither of them") + } - case Match(selector, cases) => + (condStats, updateSynthFlag(treeCopy.If(tree, condVal, thenVal, elseVal)), spc) - val (selStats, selVal, spc) = transInlineValue(selector, cpsA) - val (cpsA2, cpsR2) = if (hasSynthMarker(tree.tpe)) - (spc, linearize(spc, getAnswerTypeAnn(tree.tpe))) else - (None, getAnswerTypeAnn(tree.tpe)) + case Match(selector, cases) => + val (selStats, selVal, spc) = transInlineValue(selector, cpsA) + val (cpsA2, cpsR2) = + if (hasSynthMarker(tree.tpe)) (spc, linearize(spc, getAnswerTypeAnn(tree.tpe))) + else (None, getAnswerTypeAnn(tree.tpe)) - val caseVals = for { - cd @ CaseDef(pat, guard, body) <- cases - bodyVal = transExpr(body, cpsA2, cpsR2) - } yield { - treeCopy.CaseDef(cd, transform(pat), transform(guard), bodyVal) - } + val caseVals = cases map { case cd @ CaseDef(pat, guard, body) => + val bodyVal = transExpr(body, cpsA2, cpsR2) + treeCopy.CaseDef(cd, transform(pat), transform(guard), bodyVal) + } - (selStats, updateSynthFlag(treeCopy.Match(tree, selVal, caseVals)), spc) + (selStats, updateSynthFlag(treeCopy.Match(tree, selVal, caseVals)), spc) + // this is utterly broken: LabelDefs need to be considered together when transforming them to DefDefs: + // suppose a Block {L1; ... ; LN} + // this should become {D1def ; ... ; DNdef ; D1()} + // where D$idef = def L$i(..) = {L$i.body; L${i+1}(..)} case ldef @ LabelDef(name, params, rhs) => if (hasAnswerTypeAnn(tree.tpe)) { - val sym = currentOwner.newMethod(name, tree.pos, Flags.SYNTHETIC) setInfo ldef.symbol.info - val rhs1 = new TreeSymSubstituter(List(ldef.symbol), List(sym)).transform(rhs) + // currentOwner.newMethod(name, tree.pos, Flags.SYNTHETIC) setInfo ldef.symbol.info + val sym = ldef.symbol resetFlag Flags.LABEL + val rhs1 = rhs //new TreeSymSubstituter(List(ldef.symbol), List(sym)).transform(rhs) val rhsVal = transExpr(rhs1, None, getAnswerTypeAnn(tree.tpe)) changeOwner (currentOwner -> sym) val stm1 = localTyper.typed(DefDef(sym, rhsVal)) - val expr = localTyper.typed(Apply(Ident(sym), List())) - - (List(stm1), expr, cpsA) + // since virtpatmat does not rely on fall-through, don't call the labels it emits + // transBlock will take care of calling the first label + // calling each labeldef is wrong, since some labels may be jumped over + // we can get away with this for now since the only other labels we emit are for tailcalls/while loops, + // which do not have consecutive labeldefs (and thus fall-through is irrelevant) + if (gen.hasSynthCaseSymbol(ldef)) (List(stm1), localTyper.typed{Literal(Constant(()))}, cpsA) + else { + assert(params.isEmpty, "problem in ANF transforming label with non-empty params "+ ldef) + (List(stm1), localTyper.typed{Apply(Ident(sym), List())}, cpsA) + } } else { val rhsVal = transExpr(rhs, None, None) (Nil, updateSynthFlag(treeCopy.LabelDef(tree, name, params, rhsVal)), cpsA) @@ -412,18 +443,29 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with } def transBlock(stms: List[Tree], expr: Tree, cpsA: CPSInfo, cpsR: CPSInfo): (List[Tree], Tree) = { - stms match { - case Nil => - transTailValue(expr, cpsA, cpsR) - - case stm::rest => - var (rest2, expr2) = (rest, expr) - val (headStms, headSpc) = transInlineStm(stm, cpsA) - val (restStms, restExpr) = transBlock(rest2, expr2, headSpc, cpsR) - (headStms:::restStms, restExpr) - } + def rec(currStats: List[Tree], currAns: CPSInfo, accum: List[Tree]): (List[Tree], Tree) = + currStats match { + case Nil => + val (anfStats, anfExpr) = transTailValue(expr, currAns, cpsR) + (accum ++ anfStats, anfExpr) + + case stat :: rest => + val (stats, nextAns) = transInlineStm(stat, currAns) + rec(rest, nextAns, accum ++ stats) + } + + val (anfStats, anfExpr) = rec(stms, cpsA, List()) + // println("\nanf-block:\n"+ ((stms :+ expr) mkString ("{", "\n", "}")) +"\nBECAME\n"+ ((anfStats :+ anfExpr) mkString ("{", "\n", "}"))) + + if (anfStats.nonEmpty && (anfStats forall gen.hasSynthCaseSymbol)) { + val (prologue, rest) = (anfStats :+ anfExpr) span (s => !s.isInstanceOf[DefDef]) // find first case + // val (defs, calls) = rest partition (_.isInstanceOf[DefDef]) + if (rest nonEmpty){ + val stats = prologue ++ rest.reverse // ++ calls + // println("REVERSED "+ (stats mkString ("{", "\n", "}"))) + (stats, localTyper.typed{Apply(Ident(rest.head.symbol), List())}) // call first label to kick-start the match + } else (anfStats, anfExpr) + } else (anfStats, anfExpr) } - - } } diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala index 6453671eac..2db4054ef5 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveCPSTransform.scala @@ -15,7 +15,7 @@ import scala.tools.nsc.ast._ * In methods marked @cps, CPS-transform assignments introduced by ANF-transform phase. */ abstract class SelectiveCPSTransform extends PluginComponent with - InfoTransform with TypingTransformers with CPSUtils { + InfoTransform with TypingTransformers with CPSUtils with TreeDSL { // inherits abstract value `global` and class `Phase` from Transform import global._ // the global environment @@ -203,12 +203,16 @@ abstract class SelectiveCPSTransform extends PluginComponent with rhs.changeOwner(currentOwner -> fun.symbol) val exSym = currentOwner.newValueParameter(cpsNames.ex, pos).setInfo(ThrowableClass.tpe) - val catch2 = { localTyper.typedCases(List( - CaseDef(Bind(exSym, Typed(Ident("_"), TypeTree(ThrowableClass.tpe))), - Apply(Select(Ident(funSym), nme.isDefinedAt), List(Ident(exSym))), - Apply(Ident(funSym), List(Ident(exSym)))) - ), ThrowableClass.tpe, targettp) } + import CODE._ + // generate a case that is supported directly by the back-end + val catchIfDefined = CaseDef( + Bind(exSym, Ident(nme.WILDCARD)), + EmptyTree, + IF ((REF(funSym) DOT nme.isDefinedAt)(REF(exSym))) THEN (REF(funSym) APPLY (REF(exSym))) ELSE Throw(REF(exSym)) + ) + + val catch2 = localTyper.typedCases(List(catchIfDefined), ThrowableClass.tpe, targettp) //typedCases(tree, catches, ThrowableClass.tpe, pt) localTyper.typed(Block(List(funDef), treeCopy.Try(tree, treeCopy.Block(block1, stms, expr2), catch2, finalizer1))) diff --git a/test/files/continuations-run/match2.scala b/test/files/continuations-run/match2.scala index 8b0fb946df..5092ce3abe 100644 --- a/test/files/continuations-run/match2.scala +++ b/test/files/continuations-run/match2.scala @@ -18,7 +18,7 @@ object Test { } - def main(args: Array[String]): Any = { + def main(args: Array[String]): Unit = { println(reset(test1())) println(reset(test2())) } -- cgit v1.2.3 From 4804efef205adbe359dd353d51ab16e1e0337dc5 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Fri, 13 Apr 2012 20:15:10 +0200 Subject: virtpatmat on by default; chicken out: -Xoldpatmat some tests (unreachability, exhaustivity, @switch annotation checking) are still run under -Xoldpatmat, but that will change before we go into RC mode (then the test/ partest of this commit will be reverted) removed irrelevant dependency on patmat --- src/compiler/scala/reflect/internal/Types.scala | 2 +- .../internal/settings/MutableSettings.scala | 2 +- src/compiler/scala/reflect/runtime/Settings.scala | 2 +- src/compiler/scala/tools/nsc/Global.scala | 2 +- .../nsc/interactive/tests/core/CoreTestDefs.scala | 2 +- .../tools/nsc/settings/AestheticSettings.scala | 2 +- .../scala/tools/nsc/settings/ScalaSettings.scala | 3 +- test/files/buildmanager/t2559/D.scala | 6 +- test/files/buildmanager/t2559/t2559.check | 5 - test/files/jvm/interpreter.scala | 2 +- test/files/neg/array-not-seq.check | 12 +- test/files/neg/exhausting.flags | 2 +- test/files/neg/gadts1.check | 5 +- test/files/neg/pat_unreachable.flags | 1 + test/files/neg/patmat-type-check.check | 14 +- test/files/neg/patmatexhaust.flags | 2 +- test/files/neg/sealed-java-enums.flags | 2 +- test/files/neg/switch.flags | 1 + test/files/neg/t0418.check | 5 +- test/files/neg/t112706A.check | 5 +- test/files/neg/t1878.check | 5 +- test/files/neg/t3098.flags | 2 +- test/files/neg/t3392.check | 5 +- test/files/neg/t3683a.flags | 2 +- test/files/neg/t3692.flags | 1 + test/files/neg/t418.check | 5 +- test/files/neg/t4425.check | 2 +- test/files/neg/t5589neg.check | 5 +- test/files/neg/tailrec.check | 6 +- test/files/neg/unreachablechar.flags | 1 + test/files/pos/t1439.flags | 2 +- test/files/pos/virtpatmat_alts_subst.flags | 2 +- test/files/pos/virtpatmat_anonfun_for.flags | 1 - test/files/pos/virtpatmat_binding_opt.flags | 2 +- test/files/pos/virtpatmat_castbinder.flags | 2 +- test/files/pos/virtpatmat_exist1.flags | 2 +- test/files/pos/virtpatmat_exist2.flags | 2 +- test/files/pos/virtpatmat_exist3.flags | 2 +- test/files/pos/virtpatmat_gadt_array.flags | 2 +- test/files/pos/virtpatmat_infer_single_1.flags | 2 +- test/files/pos/virtpatmat_instof_valuetype.flags | 2 +- test/files/pos/virtpatmat_obj_in_case.flags | 2 +- .../presentation/callcc-interpreter/Runner.scala | 4 +- test/files/presentation/random.check | 3 +- test/files/run/inline-ex-handlers.check | 261 +++++++++++---------- test/files/run/patmat_unapp_abstype.flags | 1 + test/files/run/reify_fors.flags | 1 + test/files/run/reify_maps.flags | 1 + test/files/run/repl-suppressed-warnings.scala | 1 + test/files/run/t5273_1.flags | 1 + test/files/run/t5273_2a.flags | 1 + test/files/run/t5273_2b.flags | 1 + test/files/run/virtpatmat_alts.flags | 2 +- test/files/run/virtpatmat_apply.flags | 2 +- test/files/run/virtpatmat_casting.flags | 2 +- test/files/run/virtpatmat_extends_product.flags | 2 +- test/files/run/virtpatmat_literal.flags | 2 +- test/files/run/virtpatmat_nested_lists.flags | 2 +- test/files/run/virtpatmat_npe.flags | 2 +- test/files/run/virtpatmat_opt_sharing.flags | 2 +- test/files/run/virtpatmat_partial.flags | 2 +- test/files/run/virtpatmat_staging.flags | 2 +- test/files/run/virtpatmat_switch.flags | 2 +- .../run/virtpatmat_tailcalls_verifyerror.flags | 2 +- test/files/run/virtpatmat_try.flags | 2 +- test/files/run/virtpatmat_typed.flags | 2 +- test/files/run/virtpatmat_unapply.flags | 2 +- test/files/run/virtpatmat_unapplyprod.flags | 2 +- test/files/run/virtpatmat_unapplyseq.flags | 2 +- test/files/specialized/spec-patmatch.check | 2 +- 70 files changed, 248 insertions(+), 197 deletions(-) create mode 100644 test/files/neg/pat_unreachable.flags create mode 100644 test/files/neg/switch.flags create mode 100644 test/files/neg/t3692.flags create mode 100644 test/files/neg/unreachablechar.flags create mode 100644 test/files/run/patmat_unapp_abstype.flags create mode 100644 test/files/run/reify_fors.flags create mode 100644 test/files/run/reify_maps.flags create mode 100644 test/files/run/t5273_1.flags create mode 100644 test/files/run/t5273_2a.flags create mode 100644 test/files/run/t5273_2b.flags (limited to 'src') diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 3efbe4b4df..17c9b955ca 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -97,7 +97,7 @@ trait Types extends api.Types { self: SymbolTable => */ private final val propagateParameterBoundsToTypeVars = sys.props contains "scalac.debug.prop-constraints" - protected val enableTypeVarExperimentals = settings.Xexperimental.value || settings.YvirtPatmat.value + protected val enableTypeVarExperimentals = settings.Xexperimental.value || !settings.XoldPatmat.value /** Empty immutable maps to avoid allocations. */ private val emptySymMap = immutable.Map[Symbol, Symbol]() diff --git a/src/compiler/scala/reflect/internal/settings/MutableSettings.scala b/src/compiler/scala/reflect/internal/settings/MutableSettings.scala index b556c33aba..45ba4ed3e6 100644 --- a/src/compiler/scala/reflect/internal/settings/MutableSettings.scala +++ b/src/compiler/scala/reflect/internal/settings/MutableSettings.scala @@ -43,5 +43,5 @@ abstract class MutableSettings extends AbsSettings { def Yrecursion: IntSetting def maxClassfileName: IntSetting def Xexperimental: BooleanSetting - def YvirtPatmat: BooleanSetting + def XoldPatmat: BooleanSetting } \ No newline at end of file diff --git a/src/compiler/scala/reflect/runtime/Settings.scala b/src/compiler/scala/reflect/runtime/Settings.scala index 27e90c94bd..bbe4d60e9c 100644 --- a/src/compiler/scala/reflect/runtime/Settings.scala +++ b/src/compiler/scala/reflect/runtime/Settings.scala @@ -34,5 +34,5 @@ class Settings extends internal.settings.MutableSettings { val maxClassfileName = new IntSetting(255) val Xexperimental = new BooleanSetting(false) val deepCloning = new BooleanSetting (false) - val YvirtPatmat = new BooleanSetting(false) + val XoldPatmat = new BooleanSetting(false) } diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 0f9f7df548..403b5717b0 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -347,7 +347,7 @@ class Global(var currentSettings: Settings, var reporter: NscReporter) extends S override protected val etaExpandKeepsStar = settings.etaExpandKeepsStar.value // Here comes another one... override protected val enableTypeVarExperimentals = ( - settings.Xexperimental.value || settings.YvirtPatmat.value + settings.Xexperimental.value || !settings.XoldPatmat.value ) // True if -Xscript has been set, indicating a script run. diff --git a/src/compiler/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala b/src/compiler/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala index 40bbd3fa8e..99541ff4b4 100644 --- a/src/compiler/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala +++ b/src/compiler/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala @@ -81,7 +81,7 @@ private[tests] trait CoreTestDefs else { reporter.println("\naskHyperlinkPos for `" + tree.symbol.name + "` at " + format(pos) + " " + pos.source.file.name) val r = new Response[Position] - // `tree.symbol.sourceFile` was discovered to be null when testing -Yvirtpatmat on the akka presentation test, where a position had shifted to point to `Int` + // `tree.symbol.sourceFile` was discovered to be null when testing using virtpatmat on the akka presentation test, where a position had shifted to point to `Int` // askHyperlinkPos for `Int` at (73,19) pi.scala --> class Int in package scala has null sourceFile! val treePath = if (tree.symbol.sourceFile ne null) tree.symbol.sourceFile.path else null val treeName = if (tree.symbol.sourceFile ne null) tree.symbol.sourceFile.name else null diff --git a/src/compiler/scala/tools/nsc/settings/AestheticSettings.scala b/src/compiler/scala/tools/nsc/settings/AestheticSettings.scala index 2fdc3004d6..63775ff1c5 100644 --- a/src/compiler/scala/tools/nsc/settings/AestheticSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/AestheticSettings.scala @@ -31,7 +31,7 @@ trait AestheticSettings { def target = settings.target.value def unchecked = settings.unchecked.value def verbose = settings.verbose.value - def virtPatmat = settings.YvirtPatmat.value + def virtPatmat = !settings.XoldPatmat.value /** Derived values */ def jvm = target startsWith "jvm" diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index f7878cae71..d4c2ffa832 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -108,6 +108,8 @@ trait ScalaSettings extends AbsScalaSettings val showPhases = BooleanSetting ("-Xshow-phases", "Print a synopsis of compiler phases.") val sourceReader = StringSetting ("-Xsource-reader", "classname", "Specify a custom method for reading source files.", "") + val XoldPatmat = BooleanSetting ("-Xoldpatmat", "Use the pre-2.10 pattern matcher. Otherwise, the 'virtualizing' pattern matcher is used in 2.10.") + /** Compatibility stubs for options whose value name did * not previously match the option name. */ @@ -175,7 +177,6 @@ trait ScalaSettings extends AbsScalaSettings val YmethodInfer = BooleanSetting ("-Yinfer-argument-types", "Infer types for arguments of overriden methods.") val etaExpandKeepsStar = BooleanSetting ("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.") val noSelfCheck = BooleanSetting ("-Yno-self-type-checks", "Suppress check for self-type conformance among inherited members.") - val YvirtPatmat = BooleanSetting ("-Yvirtpatmat", "Translate pattern matches into flatMap/orElse calls. See scala.MatchingStrategy.") val YvirtClasses = false // too embryonic to even expose as a -Y //BooleanSetting ("-Yvirtual-classes", "Support virtual classes") val exposeEmptyPackage = BooleanSetting("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly() diff --git a/test/files/buildmanager/t2559/D.scala b/test/files/buildmanager/t2559/D.scala index 906b69a3e7..62dc5427f9 100644 --- a/test/files/buildmanager/t2559/D.scala +++ b/test/files/buildmanager/t2559/D.scala @@ -1,8 +1,4 @@ object D { - def x(a: A) = - a match { - case _: B => () - case _: C => () - } + def x(a: A) = if (a.isInstanceOf[B] || a.isInstanceOf[C]) () } diff --git a/test/files/buildmanager/t2559/t2559.check b/test/files/buildmanager/t2559/t2559.check index 752278fbe8..4d43838cf5 100644 --- a/test/files/buildmanager/t2559/t2559.check +++ b/test/files/buildmanager/t2559/t2559.check @@ -6,9 +6,4 @@ compiling Set(A.scala) Changes: Map(class B -> List(), class C -> List(), class E -> List(Changed(Class(A))[class E extends a sealed trait A]), trait A -> List()) invalidate D.scala because it references changed class [Changed(Class(A))[class E extends a sealed trait A]] compiling Set(D.scala) -D.scala:3: warning: match is not exhaustive! -missing combination E - - a match { - ^ Changes: Map(object D -> List()) diff --git a/test/files/jvm/interpreter.scala b/test/files/jvm/interpreter.scala index 1f289d9335..755b2ac9ae 100644 --- a/test/files/jvm/interpreter.scala +++ b/test/files/jvm/interpreter.scala @@ -2,7 +2,7 @@ import scala.tools.nsc._ import scala.tools.partest.ReplTest object Test extends ReplTest { - override def extraSettings = "-deprecation" + override def extraSettings = "-deprecation -Xoldpatmat" def code = // basics 3+4 diff --git a/test/files/neg/array-not-seq.check b/test/files/neg/array-not-seq.check index c16ecdad72..a3a639e772 100644 --- a/test/files/neg/array-not-seq.check +++ b/test/files/neg/array-not-seq.check @@ -1,7 +1,13 @@ array-not-seq.scala:2: error: An Array will no longer match as Seq[_]. def f1(x: Any) = x.isInstanceOf[Seq[_]] ^ -error: An Array will no longer match as Seq[_]. -error: An Array will no longer match as Seq[_]. -error: An Array will no longer match as Seq[_]. +array-not-seq.scala:4: error: An Array will no longer match as Seq[_]. + case _: Seq[_] => true + ^ +array-not-seq.scala:16: error: An Array will no longer match as Seq[_]. + case (Some(_: Seq[_]), Nil, _) => 1 + ^ +array-not-seq.scala:17: error: An Array will no longer match as Seq[_]. + case (None, List(_: List[_], _), _) => 2 + ^ four errors found diff --git a/test/files/neg/exhausting.flags b/test/files/neg/exhausting.flags index e8fb65d50c..b7eb21d5f5 100644 --- a/test/files/neg/exhausting.flags +++ b/test/files/neg/exhausting.flags @@ -1 +1 @@ --Xfatal-warnings \ No newline at end of file +-Xfatal-warnings -Xoldpatmat diff --git a/test/files/neg/gadts1.check b/test/files/neg/gadts1.check index 44d2b114d6..0441f604c9 100644 --- a/test/files/neg/gadts1.check +++ b/test/files/neg/gadts1.check @@ -11,4 +11,7 @@ gadts1.scala:20: error: type mismatch; required: a case Cell[a](x: Int) => c.x = 5 ^ -three errors found +gadts1.scala:20: error: Could not typecheck extractor call: case class with arguments List((x @ (_: Int))) + case Cell[a](x: Int) => c.x = 5 + ^ +four errors found diff --git a/test/files/neg/pat_unreachable.flags b/test/files/neg/pat_unreachable.flags new file mode 100644 index 0000000000..ba80cad69b --- /dev/null +++ b/test/files/neg/pat_unreachable.flags @@ -0,0 +1 @@ +-Xoldpatmat diff --git a/test/files/neg/patmat-type-check.check b/test/files/neg/patmat-type-check.check index e045841ce1..ab4451f089 100644 --- a/test/files/neg/patmat-type-check.check +++ b/test/files/neg/patmat-type-check.check @@ -3,19 +3,31 @@ patmat-type-check.scala:22: error: scrutinee is incompatible with pattern type; required: String def f1 = "bob".reverse match { case Seq('b', 'o', 'b') => true } // fail ^ +patmat-type-check.scala:22: error: value _1 is not a member of object Seq + def f1 = "bob".reverse match { case Seq('b', 'o', 'b') => true } // fail + ^ patmat-type-check.scala:23: error: scrutinee is incompatible with pattern type; found : Seq[A] required: Array[Char] def f2 = "bob".toArray match { case Seq('b', 'o', 'b') => true } // fail ^ +patmat-type-check.scala:23: error: value _1 is not a member of object Seq + def f2 = "bob".toArray match { case Seq('b', 'o', 'b') => true } // fail + ^ patmat-type-check.scala:27: error: scrutinee is incompatible with pattern type; found : Seq[A] required: Test.Bop2 def f3(x: Bop2) = x match { case Seq('b', 'o', 'b') => true } // fail ^ +patmat-type-check.scala:27: error: value _1 is not a member of object Seq + def f3(x: Bop2) = x match { case Seq('b', 'o', 'b') => true } // fail + ^ patmat-type-check.scala:30: error: scrutinee is incompatible with pattern type; found : Seq[A] required: Test.Bop3[Char] def f4[T](x: Bop3[Char]) = x match { case Seq('b', 'o', 'b') => true } // fail ^ -four errors found +patmat-type-check.scala:30: error: value _1 is not a member of object Seq + def f4[T](x: Bop3[Char]) = x match { case Seq('b', 'o', 'b') => true } // fail + ^ +8 errors found diff --git a/test/files/neg/patmatexhaust.flags b/test/files/neg/patmatexhaust.flags index e8fb65d50c..b7eb21d5f5 100644 --- a/test/files/neg/patmatexhaust.flags +++ b/test/files/neg/patmatexhaust.flags @@ -1 +1 @@ --Xfatal-warnings \ No newline at end of file +-Xfatal-warnings -Xoldpatmat diff --git a/test/files/neg/sealed-java-enums.flags b/test/files/neg/sealed-java-enums.flags index e709c65918..312f3a87ec 100644 --- a/test/files/neg/sealed-java-enums.flags +++ b/test/files/neg/sealed-java-enums.flags @@ -1 +1 @@ --Xexperimental -Xfatal-warnings +-Xexperimental -Xfatal-warnings -Xoldpatmat diff --git a/test/files/neg/switch.flags b/test/files/neg/switch.flags new file mode 100644 index 0000000000..809e9ff2f2 --- /dev/null +++ b/test/files/neg/switch.flags @@ -0,0 +1 @@ + -Xoldpatmat diff --git a/test/files/neg/t0418.check b/test/files/neg/t0418.check index 4e9ad2f9ae..50931a1bca 100644 --- a/test/files/neg/t0418.check +++ b/test/files/neg/t0418.check @@ -4,4 +4,7 @@ t0418.scala:2: error: not found: value Foo12340771 t0418.scala:2: error: not found: value x null match { case Foo12340771.Bar(x) => x } ^ -two errors found +t0418.scala:2: error: Could not typecheck extractor call: case class with arguments List((x @ _)) + null match { case Foo12340771.Bar(x) => x } + ^ +three errors found diff --git a/test/files/neg/t112706A.check b/test/files/neg/t112706A.check index 30d0c3ec91..fb18b31be1 100644 --- a/test/files/neg/t112706A.check +++ b/test/files/neg/t112706A.check @@ -3,4 +3,7 @@ t112706A.scala:5: error: constructor cannot be instantiated to expected type; required: String case Tuple2(node,_) => ^ -one error found +t112706A.scala:5: error: Could not typecheck extractor call: case class Tuple2 with arguments List((node @ _), _) + case Tuple2(node,_) => + ^ +two errors found diff --git a/test/files/neg/t1878.check b/test/files/neg/t1878.check index 128741a022..b47367e12c 100644 --- a/test/files/neg/t1878.check +++ b/test/files/neg/t1878.check @@ -9,10 +9,13 @@ t1878.scala:3: error: scrutinee is incompatible with pattern type; t1878.scala:3: error: not found: value f val err1 = "" match { case Seq(f @ _*, ',') => f } ^ +t1878.scala:3: error: value _2 is not a member of object Seq + val err1 = "" match { case Seq(f @ _*, ',') => f } + ^ t1878.scala:9: error: _* may only come last val List(List(_*, arg2), _) = List(List(1,2,3), List(4,5,6)) ^ t1878.scala:13: error: _* may only come last case

{ _* }

=> ^ -5 errors found +6 errors found diff --git a/test/files/neg/t3098.flags b/test/files/neg/t3098.flags index e8fb65d50c..b7eb21d5f5 100644 --- a/test/files/neg/t3098.flags +++ b/test/files/neg/t3098.flags @@ -1 +1 @@ --Xfatal-warnings \ No newline at end of file +-Xfatal-warnings -Xoldpatmat diff --git a/test/files/neg/t3392.check b/test/files/neg/t3392.check index 842d63eec9..3a39098c4e 100644 --- a/test/files/neg/t3392.check +++ b/test/files/neg/t3392.check @@ -1,4 +1,7 @@ t3392.scala:9: error: not found: value x case x@A(x/*<-- refers to the pattern that includes this comment*/.Ex(42)) => ^ -one error found +t3392.scala:9: error: Could not typecheck extractor call: case class with arguments List(42) + case x@A(x/*<-- refers to the pattern that includes this comment*/.Ex(42)) => + ^ +two errors found diff --git a/test/files/neg/t3683a.flags b/test/files/neg/t3683a.flags index 85d8eb2ba2..b7eb21d5f5 100644 --- a/test/files/neg/t3683a.flags +++ b/test/files/neg/t3683a.flags @@ -1 +1 @@ --Xfatal-warnings +-Xfatal-warnings -Xoldpatmat diff --git a/test/files/neg/t3692.flags b/test/files/neg/t3692.flags new file mode 100644 index 0000000000..82becdfbfd --- /dev/null +++ b/test/files/neg/t3692.flags @@ -0,0 +1 @@ + -Xoldpatmat \ No newline at end of file diff --git a/test/files/neg/t418.check b/test/files/neg/t418.check index 1489547823..c06088ba9d 100644 --- a/test/files/neg/t418.check +++ b/test/files/neg/t418.check @@ -4,4 +4,7 @@ t418.scala:2: error: not found: value Foo12340771 t418.scala:2: error: not found: value x null match { case Foo12340771.Bar(x) => x } ^ -two errors found +t418.scala:2: error: Could not typecheck extractor call: case class with arguments List((x @ _)) + null match { case Foo12340771.Bar(x) => x } + ^ +three errors found diff --git a/test/files/neg/t4425.check b/test/files/neg/t4425.check index 4ff4b1eec0..0f2fe6f2d1 100644 --- a/test/files/neg/t4425.check +++ b/test/files/neg/t4425.check @@ -1,4 +1,4 @@ -t4425.scala:3: error: erroneous or inaccessible type +t4425.scala:3: error: isInstanceOf cannot test if value types are references. 42 match { case _ X _ => () } ^ one error found diff --git a/test/files/neg/t5589neg.check b/test/files/neg/t5589neg.check index b3ff16d7e4..fb6858a397 100644 --- a/test/files/neg/t5589neg.check +++ b/test/files/neg/t5589neg.check @@ -22,6 +22,9 @@ t5589neg.scala:4: error: constructor cannot be instantiated to expected type; t5589neg.scala:4: error: not found: value y2 def f7(x: Either[Int, (String, Int)]) = for (y1 @ Tuple1(y2) <- x.right) yield ((y1, y2)) ^ +t5589neg.scala:4: error: Could not typecheck extractor call: case class Tuple1 with arguments List((y2 @ _)) + def f7(x: Either[Int, (String, Int)]) = for (y1 @ Tuple1(y2) <- x.right) yield ((y1, y2)) + ^ t5589neg.scala:5: error: constructor cannot be instantiated to expected type; found : (T1, T2, T3) required: (String, Int) @@ -34,4 +37,4 @@ t5589neg.scala:5: error: not found: value y2 def f8(x: Either[Int, (String, Int)]) = for ((y1, y2, y3) <- x.right) yield ((y1, y2)) ^ two warnings found -7 errors found +8 errors found diff --git a/test/files/neg/tailrec.check b/test/files/neg/tailrec.check index ad92731b2c..946d3421e6 100644 --- a/test/files/neg/tailrec.check +++ b/test/files/neg/tailrec.check @@ -4,9 +4,9 @@ tailrec.scala:45: error: could not optimize @tailrec annotated method facfail: i tailrec.scala:50: error: could not optimize @tailrec annotated method fail1: it is neither private nor final so can be overridden @tailrec def fail1(x: Int): Int = fail1(x) ^ -tailrec.scala:55: error: could not optimize @tailrec annotated method fail2: it contains a recursive call not in tail position - case x :: xs => x :: fail2[T](xs) - ^ +tailrec.scala:53: error: could not optimize @tailrec annotated method fail2: it contains a recursive call not in tail position + @tailrec final def fail2[T](xs: List[T]): List[T] = xs match { + ^ tailrec.scala:59: error: could not optimize @tailrec annotated method fail3: it is called recursively with different type arguments @tailrec final def fail3[T](x: Int): Int = fail3(x - 1) ^ diff --git a/test/files/neg/unreachablechar.flags b/test/files/neg/unreachablechar.flags new file mode 100644 index 0000000000..809e9ff2f2 --- /dev/null +++ b/test/files/neg/unreachablechar.flags @@ -0,0 +1 @@ + -Xoldpatmat diff --git a/test/files/pos/t1439.flags b/test/files/pos/t1439.flags index d86a0144e8..1e70f5c5c7 100644 --- a/test/files/pos/t1439.flags +++ b/test/files/pos/t1439.flags @@ -1 +1 @@ --unchecked -Xfatal-warnings -language:higherKinds \ No newline at end of file +-unchecked -Xfatal-warnings -Xoldpatmat -language:higherKinds diff --git a/test/files/pos/virtpatmat_alts_subst.flags b/test/files/pos/virtpatmat_alts_subst.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/pos/virtpatmat_alts_subst.flags +++ b/test/files/pos/virtpatmat_alts_subst.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/pos/virtpatmat_anonfun_for.flags b/test/files/pos/virtpatmat_anonfun_for.flags index 23e3dc7d26..e69de29bb2 100644 --- a/test/files/pos/virtpatmat_anonfun_for.flags +++ b/test/files/pos/virtpatmat_anonfun_for.flags @@ -1 +0,0 @@ --Yvirtpatmat \ No newline at end of file diff --git a/test/files/pos/virtpatmat_binding_opt.flags b/test/files/pos/virtpatmat_binding_opt.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/pos/virtpatmat_binding_opt.flags +++ b/test/files/pos/virtpatmat_binding_opt.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/pos/virtpatmat_castbinder.flags b/test/files/pos/virtpatmat_castbinder.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/pos/virtpatmat_castbinder.flags +++ b/test/files/pos/virtpatmat_castbinder.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/pos/virtpatmat_exist1.flags b/test/files/pos/virtpatmat_exist1.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/pos/virtpatmat_exist1.flags +++ b/test/files/pos/virtpatmat_exist1.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/pos/virtpatmat_exist2.flags b/test/files/pos/virtpatmat_exist2.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/pos/virtpatmat_exist2.flags +++ b/test/files/pos/virtpatmat_exist2.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/pos/virtpatmat_exist3.flags b/test/files/pos/virtpatmat_exist3.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/pos/virtpatmat_exist3.flags +++ b/test/files/pos/virtpatmat_exist3.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/pos/virtpatmat_gadt_array.flags b/test/files/pos/virtpatmat_gadt_array.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/pos/virtpatmat_gadt_array.flags +++ b/test/files/pos/virtpatmat_gadt_array.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/pos/virtpatmat_infer_single_1.flags b/test/files/pos/virtpatmat_infer_single_1.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/pos/virtpatmat_infer_single_1.flags +++ b/test/files/pos/virtpatmat_infer_single_1.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/pos/virtpatmat_instof_valuetype.flags b/test/files/pos/virtpatmat_instof_valuetype.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/pos/virtpatmat_instof_valuetype.flags +++ b/test/files/pos/virtpatmat_instof_valuetype.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/pos/virtpatmat_obj_in_case.flags b/test/files/pos/virtpatmat_obj_in_case.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/pos/virtpatmat_obj_in_case.flags +++ b/test/files/pos/virtpatmat_obj_in_case.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/presentation/callcc-interpreter/Runner.scala b/test/files/presentation/callcc-interpreter/Runner.scala index 1ef3cf9025..61b6efd50d 100644 --- a/test/files/presentation/callcc-interpreter/Runner.scala +++ b/test/files/presentation/callcc-interpreter/Runner.scala @@ -1,3 +1,5 @@ import scala.tools.nsc.interactive.tests._ -object Test extends InteractiveTest \ No newline at end of file +object Test extends InteractiveTest { + settings.XoldPatmat.value = true // TODO: could this be running into some kind of race condition? sometimes the match has been translated, sometimes it hasn't +} \ No newline at end of file diff --git a/test/files/presentation/random.check b/test/files/presentation/random.check index fce4b69fb3..1b73720312 100644 --- a/test/files/presentation/random.check +++ b/test/files/presentation/random.check @@ -4,7 +4,8 @@ askType at Random.scala(18,14) ================================================================================ [response] askTypeAt at (18,14) val filter: Int => Boolean = try { - java.this.lang.Integer.parseInt(args.apply(0)) match { + case val x1: Int = java.this.lang.Integer.parseInt(args.apply(0)); + x1 match { case 1 => ((x: Int) => x.%(2).!=(0)) case 2 => ((x: Int) => x.%(2).==(0)) case _ => ((x: Int) => x.!=(0)) diff --git a/test/files/run/inline-ex-handlers.check b/test/files/run/inline-ex-handlers.check index 7a8a744bfa..708fcc6985 100644 --- a/test/files/run/inline-ex-handlers.check +++ b/test/files/run/inline-ex-handlers.check @@ -1,40 +1,44 @@ 172c172 -< locals: value x$1, value temp1 +< locals: value x$1, value x1 --- -> locals: value x$1, value temp1, variable boxed1 +> locals: value x$1, value x1, variable boxed1 174c174 < blocks: [1,2,3,4] --- -> blocks: [1,2,3] -187,189d186 -< 92 JUMP 4 -< -< 4: -195a193,194 +> blocks: [1,3,4] +186a187,188 > 92 STORE_LOCAL(variable boxed1) > 92 LOAD_LOCAL(variable boxed1) -386c385 -< blocks: [1,2,3,4,5,7,8,10] +195,197d196 +< 92 JUMP 2 +< +< 2: +385c384 +< blocks: [1,2,3,4,5,8,11,13,14,16] --- -> blocks: [1,2,3,4,5,7,8,10,11] -410c409,418 +> blocks: [1,2,3,5,8,11,13,14,16,17] +409c408,417 < 103 THROW(MyException) --- -> ? STORE_LOCAL(value ex$1) -> ? JUMP 11 +> ? STORE_LOCAL(value ex5) +> ? JUMP 17 > -> 11: -> 101 LOAD_LOCAL(value ex$1) -> 101 STORE_LOCAL(value temp2) -> 101 SCOPE_ENTER value temp2 -> 101 LOAD_LOCAL(value temp2) -> 101 IS_INSTANCE REF(class MyException) -> 101 CZJUMP (BOOL)NE ? 4 : 5 -501c509 +> 17: +> 101 LOAD_LOCAL(value ex5) +> 101 STORE_LOCAL(value x3) +> 101 SCOPE_ENTER value x3 +> 106 LOAD_LOCAL(value x3) +> 106 IS_INSTANCE REF(class MyException) +> 106 CZJUMP (BOOL)NE ? 5 : 11 +422,424d429 +< 101 JUMP 4 +< +< 4: +512c517 < blocks: [1,2,3,4,6,7,8,9,10] --- > blocks: [1,2,3,4,6,7,8,9,10,11,12,13] -530c538,543 +541c546,551 < 306 THROW(MyException) --- > ? JUMP 11 @@ -43,7 +47,7 @@ > ? LOAD_LOCAL(variable monitor4) > 305 MONITOR_EXIT > ? JUMP 12 -536c549,555 +547c557,563 < ? THROW(Throwable) --- > ? JUMP 12 @@ -53,7 +57,7 @@ > 304 MONITOR_EXIT > ? STORE_LOCAL(value t) > ? JUMP 13 -542c561,574 +553c569,582 < ? THROW(Throwable) --- > ? STORE_LOCAL(value t) @@ -70,19 +74,19 @@ > 310 CALL_PRIMITIVE(EndConcat) > 310 CALL_METHOD scala.Predef.println (dynamic) > 310 JUMP 2 -566c598 +577c606 < catch (Throwable) in ArrayBuffer(7, 8, 9, 10) starting at: 6 --- > catch (Throwable) in ArrayBuffer(7, 8, 9, 10, 11) starting at: 6 -569c601 +580c609 < catch (Throwable) in ArrayBuffer(4, 6, 7, 8, 9, 10) starting at: 3 --- > catch (Throwable) in ArrayBuffer(4, 6, 7, 8, 9, 10, 11, 12) starting at: 3 -601c633 +612c641 < blocks: [1,2,3,4,5,6,7,9,10] --- > blocks: [1,2,3,4,5,6,7,9,10,11,12] -625c657,663 +636c665,671 < 78 THROW(IllegalArgumentException) --- > ? STORE_LOCAL(value e) @@ -92,7 +96,7 @@ > 81 LOAD_LOCAL(value e) > ? STORE_LOCAL(variable exc1) > ? JUMP 12 -654c692,706 +665c700,714 < 81 THROW(Exception) --- > ? STORE_LOCAL(variable exc1) @@ -110,57 +114,53 @@ > 84 STORE_LOCAL(variable result) > 84 LOAD_LOCAL(variable exc1) > 84 THROW(Throwable) -676c728 +687c736 < catch () in ArrayBuffer(4, 6, 7, 9) starting at: 3 --- > catch () in ArrayBuffer(4, 6, 7, 9, 11) starting at: 3 -702c754 -< blocks: [1,2,3,4,5,6,7,8,11,12,13,14,15,16,18,19] +713c762 +< blocks: [1,2,3,4,5,6,9,12,14,17,18,19,22,25,27,28,30,31] --- -> blocks: [1,2,3,4,5,6,7,8,11,12,13,14,15,16,18,19,20,21,22] -726c778,787 +> blocks: [1,2,3,4,5,6,9,12,14,17,18,19,22,25,27,28,30,31,32,33,34] +737c786,793 < 172 THROW(MyException) --- -> ? STORE_LOCAL(value ex$4) -> ? JUMP 20 +> ? STORE_LOCAL(value ex5) +> ? JUMP 32 > -> 20: -> 170 LOAD_LOCAL(value ex$4) -> 170 STORE_LOCAL(value temp11) -> 170 SCOPE_ENTER value temp11 -> 170 LOAD_LOCAL(value temp11) -> 170 IS_INSTANCE REF(class MyException) -> 170 CZJUMP (BOOL)NE ? 12 : 13 -780c841,842 +> 32: +> 170 LOAD_LOCAL(value ex5) +> 170 STORE_LOCAL(value x3) +> 170 SCOPE_ENTER value x3 +> 170 JUMP 18 +793c849,850 < 177 THROW(MyException) --- -> ? STORE_LOCAL(value ex$5) -> ? JUMP 21 -784c846,855 +> ? STORE_LOCAL(value ex5) +> ? JUMP 33 +797c854,861 < 170 THROW(Throwable) --- -> ? STORE_LOCAL(value ex$5) -> ? JUMP 21 +> ? STORE_LOCAL(value ex5) +> ? JUMP 33 > -> 21: -> 169 LOAD_LOCAL(value ex$5) -> 169 STORE_LOCAL(value temp14) -> 169 SCOPE_ENTER value temp14 -> 169 LOAD_LOCAL(value temp14) -> 169 IS_INSTANCE REF(class MyException) -> 169 CZJUMP (BOOL)NE ? 5 : 6 -815c886,887 +> 33: +> 169 LOAD_LOCAL(value ex5) +> 169 STORE_LOCAL(value x3) +> 169 SCOPE_ENTER value x3 +> 169 JUMP 5 +830c894,895 < 182 THROW(MyException) --- > ? STORE_LOCAL(variable exc2) -> ? JUMP 22 -819c891,905 +> ? JUMP 34 +834c899,900 < 169 THROW(Throwable) --- > ? STORE_LOCAL(variable exc2) -> ? JUMP 22 -> -> 22: +> ? JUMP 34 +835a902,914 +> 34: > 184 LOAD_MODULE object Predef > 184 CONSTANT("finally") > 184 CALL_METHOD scala.Predef.println (dynamic) @@ -172,57 +172,60 @@ > 185 STORE_LOCAL(variable result) > 185 LOAD_LOCAL(variable exc2) > 185 THROW(Throwable) -841c927 -< catch (Throwable) in ArrayBuffer(11, 12, 13, 14, 15, 16, 18) starting at: 4 +> +856c935 +< catch (Throwable) in ArrayBuffer(17, 18, 19, 22, 25, 27, 28, 30) starting at: 4 --- -> catch (Throwable) in ArrayBuffer(11, 12, 13, 14, 15, 16, 18, 20) starting at: 4 -844c930 -< catch () in ArrayBuffer(4, 5, 6, 7, 11, 12, 13, 14, 15, 16, 18) starting at: 3 +> catch (Throwable) in ArrayBuffer(17, 18, 19, 22, 25, 27, 28, 30, 32) starting at: 4 +859c938 +< catch () in ArrayBuffer(4, 5, 6, 9, 12, 17, 18, 19, 22, 25, 27, 28, 30) starting at: 3 --- -> catch () in ArrayBuffer(4, 5, 6, 7, 11, 12, 13, 14, 15, 16, 18, 20, 21) starting at: 3 -870c956 -< blocks: [1,2,3,6,7,8,10,11,13] +> catch () in ArrayBuffer(4, 5, 6, 9, 12, 17, 18, 19, 22, 25, 27, 28, 30, 32, 33) starting at: 3 +885c964 +< blocks: [1,2,3,6,7,8,11,14,16,17,19] --- -> blocks: [1,2,3,6,7,8,10,11,13,14] -894c980,989 +> blocks: [1,2,3,6,7,8,11,14,16,17,19,20] +909c988,995 < 124 THROW(MyException) --- -> ? STORE_LOCAL(value ex$2) -> ? JUMP 14 +> ? STORE_LOCAL(value ex5) +> ? JUMP 20 > -> 14: -> 122 LOAD_LOCAL(value ex$2) -> 122 STORE_LOCAL(value temp5) -> 122 SCOPE_ENTER value temp5 -> 122 LOAD_LOCAL(value temp5) -> 122 IS_INSTANCE REF(class MyException) -> 122 CZJUMP (BOOL)NE ? 7 : 8 -942c1037 -< catch (IllegalArgumentException) in ArrayBuffer(6, 7, 8, 10, 11, 13) starting at: 3 ---- -> catch (IllegalArgumentException) in ArrayBuffer(6, 7, 8, 10, 11, 13, 14) starting at: 3 -968c1063 -< blocks: [1,2,3,4,5,9,10,11,13] ---- -> blocks: [1,2,3,4,5,9,10,11,13,14] -992c1087,1096 +> 20: +> 122 LOAD_LOCAL(value ex5) +> 122 STORE_LOCAL(value x3) +> 122 SCOPE_ENTER value x3 +> 122 JUMP 7 +969c1055 +< catch (IllegalArgumentException) in ArrayBuffer(6, 7, 8, 11, 14, 16, 17, 19) starting at: 3 +--- +> catch (IllegalArgumentException) in ArrayBuffer(6, 7, 8, 11, 14, 16, 17, 19, 20) starting at: 3 +995c1081 +< blocks: [1,2,3,4,5,8,11,15,16,17,19] +--- +> blocks: [1,2,3,5,8,11,15,16,17,19,20] +1019c1105,1114 < 148 THROW(MyException) --- -> ? STORE_LOCAL(value ex$3) -> ? JUMP 14 +> ? STORE_LOCAL(value ex5) +> ? JUMP 20 > -> 14: -> 145 LOAD_LOCAL(value ex$3) -> 145 STORE_LOCAL(value temp8) -> 145 SCOPE_ENTER value temp8 -> 145 LOAD_LOCAL(value temp8) -> 145 IS_INSTANCE REF(class MyException) -> 145 CZJUMP (BOOL)NE ? 4 : 5 -1236c1340 +> 20: +> 145 LOAD_LOCAL(value ex5) +> 145 STORE_LOCAL(value x3) +> 145 SCOPE_ENTER value x3 +> 154 LOAD_LOCAL(value x3) +> 154 IS_INSTANCE REF(class MyException) +> 154 CZJUMP (BOOL)NE ? 5 : 11 +1040,1042d1134 +< 145 JUMP 4 +< +< 4: +1275c1367 < blocks: [1,2,3,4,5,7] --- > blocks: [1,2,3,4,5,7,8] -1260c1364,1371 +1299c1391,1398 < 38 THROW(IllegalArgumentException) --- > ? STORE_LOCAL(value e) @@ -233,33 +236,37 @@ > 42 CONSTANT("IllegalArgumentException") > 42 CALL_METHOD scala.Predef.println (dynamic) > 42 JUMP 2 -1309c1420 -< blocks: [1,2,3,4,5,7,8,10,11,13] +1348c1447 +< blocks: [1,2,3,4,5,8,11,13,14,16,17,19] --- -> blocks: [1,2,3,4,5,7,8,10,11,13,14] -1333c1444,1445 +> blocks: [1,2,3,5,8,11,13,14,16,17,19,20] +1372c1471,1472 < 203 THROW(MyException) --- -> ? STORE_LOCAL(value ex$6) -> ? JUMP 14 -1353c1465,1474 +> ? STORE_LOCAL(value ex5) +> ? JUMP 20 +1392c1492,1501 < 209 THROW(MyException) --- -> ? STORE_LOCAL(value ex$6) -> ? JUMP 14 +> ? STORE_LOCAL(value ex5) +> ? JUMP 20 > -> 14: -> 200 LOAD_LOCAL(value ex$6) -> 200 STORE_LOCAL(value temp17) -> 200 SCOPE_ENTER value temp17 -> 200 LOAD_LOCAL(value temp17) -> 200 IS_INSTANCE REF(class MyException) -> 200 CZJUMP (BOOL)NE ? 4 : 5 -1416c1537 +> 20: +> 200 LOAD_LOCAL(value ex5) +> 200 STORE_LOCAL(value x3) +> 200 SCOPE_ENTER value x3 +> 212 LOAD_LOCAL(value x3) +> 212 IS_INSTANCE REF(class MyException) +> 212 CZJUMP (BOOL)NE ? 5 : 11 +1405,1407d1513 +< 200 JUMP 4 +< +< 4: +1467c1573 < blocks: [1,2,3,4,5,7] --- > blocks: [1,2,3,4,5,7,8] -1440c1561,1568 +1491c1597,1604 < 58 THROW(IllegalArgumentException) --- > ? STORE_LOCAL(value e) @@ -270,11 +277,11 @@ > 62 CONSTANT("RuntimeException") > 62 CALL_METHOD scala.Predef.println (dynamic) > 62 JUMP 2 -1489c1617 +1540c1653 < blocks: [1,2,3,4] --- > blocks: [1,2,3,4,5] -1509c1637,1642 +1560c1673,1678 < 229 THROW(MyException) --- > ? JUMP 5 @@ -283,19 +290,19 @@ > ? LOAD_LOCAL(variable monitor1) > 228 MONITOR_EXIT > 228 THROW(Throwable) -1515c1648 +1566c1684 < ? THROW(Throwable) --- > 228 THROW(Throwable) -1543c1676 +1594c1712 < locals: value args, variable result, variable monitor2, variable monitorResult1 --- > locals: value exception$1, value args, variable result, variable monitor2, variable monitorResult1 -1545c1678 +1596c1714 < blocks: [1,2,3,4] --- > blocks: [1,2,3,4,5] -1568c1701,1709 +1619c1737,1745 < 245 THROW(MyException) --- > ? STORE_LOCAL(value exception$1) @@ -307,7 +314,7 @@ > ? LOAD_LOCAL(variable monitor2) > 244 MONITOR_EXIT > 244 THROW(Throwable) -1574c1715 +1625c1751 < ? THROW(Throwable) --- > 244 THROW(Throwable) diff --git a/test/files/run/patmat_unapp_abstype.flags b/test/files/run/patmat_unapp_abstype.flags new file mode 100644 index 0000000000..ba80cad69b --- /dev/null +++ b/test/files/run/patmat_unapp_abstype.flags @@ -0,0 +1 @@ +-Xoldpatmat diff --git a/test/files/run/reify_fors.flags b/test/files/run/reify_fors.flags new file mode 100644 index 0000000000..ba80cad69b --- /dev/null +++ b/test/files/run/reify_fors.flags @@ -0,0 +1 @@ +-Xoldpatmat diff --git a/test/files/run/reify_maps.flags b/test/files/run/reify_maps.flags new file mode 100644 index 0000000000..ba80cad69b --- /dev/null +++ b/test/files/run/reify_maps.flags @@ -0,0 +1 @@ +-Xoldpatmat diff --git a/test/files/run/repl-suppressed-warnings.scala b/test/files/run/repl-suppressed-warnings.scala index a78b00f36e..9afbbaf1a5 100644 --- a/test/files/run/repl-suppressed-warnings.scala +++ b/test/files/run/repl-suppressed-warnings.scala @@ -1,6 +1,7 @@ import scala.tools.partest.ReplTest object Test extends ReplTest { + override def extraSettings = "-Xoldpatmat" def code = """ // "Is this thing on?" Not working on first couple diff --git a/test/files/run/t5273_1.flags b/test/files/run/t5273_1.flags new file mode 100644 index 0000000000..ba80cad69b --- /dev/null +++ b/test/files/run/t5273_1.flags @@ -0,0 +1 @@ +-Xoldpatmat diff --git a/test/files/run/t5273_2a.flags b/test/files/run/t5273_2a.flags new file mode 100644 index 0000000000..ba80cad69b --- /dev/null +++ b/test/files/run/t5273_2a.flags @@ -0,0 +1 @@ +-Xoldpatmat diff --git a/test/files/run/t5273_2b.flags b/test/files/run/t5273_2b.flags new file mode 100644 index 0000000000..ba80cad69b --- /dev/null +++ b/test/files/run/t5273_2b.flags @@ -0,0 +1 @@ +-Xoldpatmat diff --git a/test/files/run/virtpatmat_alts.flags b/test/files/run/virtpatmat_alts.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/run/virtpatmat_alts.flags +++ b/test/files/run/virtpatmat_alts.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/run/virtpatmat_apply.flags b/test/files/run/virtpatmat_apply.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/run/virtpatmat_apply.flags +++ b/test/files/run/virtpatmat_apply.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/run/virtpatmat_casting.flags b/test/files/run/virtpatmat_casting.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/run/virtpatmat_casting.flags +++ b/test/files/run/virtpatmat_casting.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/run/virtpatmat_extends_product.flags b/test/files/run/virtpatmat_extends_product.flags index ac6b805bd0..8b13789179 100644 --- a/test/files/run/virtpatmat_extends_product.flags +++ b/test/files/run/virtpatmat_extends_product.flags @@ -1 +1 @@ --Yvirtpatmat + diff --git a/test/files/run/virtpatmat_literal.flags b/test/files/run/virtpatmat_literal.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/run/virtpatmat_literal.flags +++ b/test/files/run/virtpatmat_literal.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/run/virtpatmat_nested_lists.flags b/test/files/run/virtpatmat_nested_lists.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/run/virtpatmat_nested_lists.flags +++ b/test/files/run/virtpatmat_nested_lists.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/run/virtpatmat_npe.flags b/test/files/run/virtpatmat_npe.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/run/virtpatmat_npe.flags +++ b/test/files/run/virtpatmat_npe.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/run/virtpatmat_opt_sharing.flags b/test/files/run/virtpatmat_opt_sharing.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/run/virtpatmat_opt_sharing.flags +++ b/test/files/run/virtpatmat_opt_sharing.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/run/virtpatmat_partial.flags b/test/files/run/virtpatmat_partial.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/run/virtpatmat_partial.flags +++ b/test/files/run/virtpatmat_partial.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/run/virtpatmat_staging.flags b/test/files/run/virtpatmat_staging.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/run/virtpatmat_staging.flags +++ b/test/files/run/virtpatmat_staging.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/run/virtpatmat_switch.flags b/test/files/run/virtpatmat_switch.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/run/virtpatmat_switch.flags +++ b/test/files/run/virtpatmat_switch.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/run/virtpatmat_tailcalls_verifyerror.flags b/test/files/run/virtpatmat_tailcalls_verifyerror.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/run/virtpatmat_tailcalls_verifyerror.flags +++ b/test/files/run/virtpatmat_tailcalls_verifyerror.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/run/virtpatmat_try.flags b/test/files/run/virtpatmat_try.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/run/virtpatmat_try.flags +++ b/test/files/run/virtpatmat_try.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/run/virtpatmat_typed.flags b/test/files/run/virtpatmat_typed.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/run/virtpatmat_typed.flags +++ b/test/files/run/virtpatmat_typed.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/run/virtpatmat_unapply.flags b/test/files/run/virtpatmat_unapply.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/run/virtpatmat_unapply.flags +++ b/test/files/run/virtpatmat_unapply.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/run/virtpatmat_unapplyprod.flags b/test/files/run/virtpatmat_unapplyprod.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/run/virtpatmat_unapplyprod.flags +++ b/test/files/run/virtpatmat_unapplyprod.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/run/virtpatmat_unapplyseq.flags b/test/files/run/virtpatmat_unapplyseq.flags index 9769db9257..3f5a3100e4 100644 --- a/test/files/run/virtpatmat_unapplyseq.flags +++ b/test/files/run/virtpatmat_unapplyseq.flags @@ -1 +1 @@ - -Yvirtpatmat -Xexperimental + -Xexperimental diff --git a/test/files/specialized/spec-patmatch.check b/test/files/specialized/spec-patmatch.check index 33306ab5d9..a2746c0f48 100644 --- a/test/files/specialized/spec-patmatch.check +++ b/test/files/specialized/spec-patmatch.check @@ -17,4 +17,4 @@ long double float default -2 \ No newline at end of file +10 -- cgit v1.2.3