From 67cf4f5e32bc036788ff7a5426a5f5c0bb07fb70 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 7 Feb 2007 18:30:46 +0000 Subject: changed non-exhaustivity to attributes --- src/compiler/scala/tools/nsc/Global.scala | 3 +- .../scala/tools/nsc/ast/TreeBrowsers.scala | 11 +-- .../scala/tools/nsc/ast/TreePrinters.scala | 13 +++- src/compiler/scala/tools/nsc/ast/Trees.scala | 42 ++++++++---- .../scala/tools/nsc/ast/parser/Parsers.scala | 37 +++++----- .../scala/tools/nsc/ast/parser/TreeBuilder.scala | 13 +++- .../scala/tools/nsc/backend/icode/GenICode.scala | 2 +- .../scala/tools/nsc/backend/jvm/GenJVM.scala | 4 +- .../scala/tools/nsc/matching/PatternMatchers.scala | 6 +- src/compiler/scala/tools/nsc/models/Models.scala | 2 +- .../scala/tools/nsc/models/SemanticTokens.scala | 1 + .../scala/tools/nsc/symtab/Definitions.scala | 2 + src/compiler/scala/tools/nsc/symtab/Types.scala | 27 ++++---- .../scala/tools/nsc/transform/Erasure.scala | 4 +- .../scala/tools/nsc/transform/ExplicitOuter.scala | 58 ++++++++++------ .../scala/tools/nsc/transform/TailCalls.scala | 4 +- .../scala/tools/nsc/transform/UnCurry.scala | 7 +- .../scala/tools/nsc/typechecker/RefChecks.scala | 2 +- .../tools/nsc/typechecker/SyntheticMethods.scala | 2 +- .../scala/tools/nsc/typechecker/Typers.scala | 79 ++++++++++++++++++++-- src/library/scala/unsealed.scala | 18 +++++ 21 files changed, 240 insertions(+), 97 deletions(-) create mode 100755 src/library/scala/unsealed.scala diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 108d68d9b7..2d64666980 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -363,7 +363,6 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable uncurry, tailCalls, explicitOuter, - //transMatcher, // checkDefined, erasure, lambdaLift, @@ -513,7 +512,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable if (sym.isTerm) sym.moduleClass.reset(loaders.moduleClassLoader) } } else { - assert(symData.isEmpty || !settings.stop.value.isEmpty || !settings.skip.value.isEmpty) + assert(symData.isEmpty || !settings.stop.value.isEmpty || !settings.skip.value.isEmpty, symData) if (deprecationWarnings) { warning("there were deprecation warnings; re-run with -deprecation for details") } diff --git a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala index b0e3fa4838..830194c5c1 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala @@ -305,7 +305,7 @@ abstract class TreeBrowsers { case Bind(name, rhs) => Pair("Bind", name) - case Match(selector, cases, _) => + case Match(selector, cases) => Pair("Visitor", EMPTY) case Function(vparams, body) => @@ -353,6 +353,9 @@ abstract class TreeBrowsers { case TypeTree() => Pair("TypeTree", EMPTY) + case Attributed(constr, elements, arg) => + Pair("AttributedTypeTree", EMPTY) + case AttributedTypeTree(attribs, tpt) => Pair("AttributedTypeTree", EMPTY) @@ -449,7 +452,7 @@ abstract class TreeBrowsers { case Bind(name, rhs) => List(rhs) - case Match(selector, cases, _) => + case Match(selector, cases) => selector :: cases case Function(vparams, body) => @@ -497,8 +500,8 @@ abstract class TreeBrowsers { case TypeTree() => Nil - case AttributedTypeTree(attribs, tpt) => - attribs ::: List(tpt) + case Attributed(constr, elements, arg) => + constr :: elements ::: List(arg) case SingletonTypeTree(ref) => List(ref) diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala index 0ce8c00bf3..e0bce93ea8 100644 --- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala @@ -191,8 +191,8 @@ abstract class TreePrinters { case Block(stats, expr) => printColumn(stats ::: List(expr), "{", ";", "}") - case Match(selector, cases, check) => - print(selector); printColumn(cases, if (check) " match {" else "match! {", "", "}") + case Match(selector, cases) => + print(selector); printColumn(cases, " match {", "", "}") case CaseDef(pat, guard, body) => print("case "); print(pat); printOpt(" if ", guard) @@ -294,6 +294,15 @@ abstract class TreePrinters { print(" ") print(tree) + case Attributed(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), elements, tree) => + print("@"); print(tpt) + if (!args.isEmpty) + printRow(args, "(", ",", ")") + if (!elements.isEmpty) + print((for (val Assign(name, value) <- elements) yield "val " + name + " = " + value). + mkString("{", ",", "}")) + print(" "); print(tree) + case SingletonTypeTree(ref) => print(ref); print(".type") diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index b575e2e1f6..25cfaf6cf4 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -537,7 +537,7 @@ trait Trees requires Global { * Ident(nme.WILDCARD) * */ - case class Match(selector: Tree, cases: List[CaseDef], checkExhaustive: boolean) + case class Match(selector: Tree, cases: List[CaseDef]) extends TermTree /** Return expression */ @@ -658,6 +658,11 @@ trait Trees requires Global { def TypeTree(tp: Type): TypeTree = TypeTree() setType tp // def TypeTree(tp: Type, tree : Tree): TypeTree = TypeTree(tree) setType tp + /** A tree that has anP attribute attached to it */ + case class Attributed(constr: Tree, elements: List[Tree], arg: Tree) extends Tree { + override def isType = arg.isType + } + /** A type tree that has attributes attached to it */ case class AttributedTypeTree(attribs: List[Tree], tpt: Tree) extends TypTree { @@ -712,7 +717,7 @@ trait Trees requires Global { case Function(vparams, body) => (eliminated by lambdaLift) case Assign(lhs, rhs) => case If(cond, thenp, elsep) => - case Match(selector, cases, check) => + case Match(selector, cases) => case Return(expr) => case Try(block, catches, finalizer) => case Throw(expr) => @@ -726,6 +731,7 @@ trait Trees requires Global { case Ident(name) => case Literal(value) => case TypeTree() => (introduced by refcheck) + case Attributed(constr, elements, arg) => (eliminated by typer) case AttributedTypeTree(attribs, tpt) => (eliminated by uncurry) case SingletonTypeTree(ref) => (eliminated by uncurry) case SelectFromTypeTree(qualifier, selector) => (eliminated by uncurry) @@ -758,7 +764,7 @@ trait Trees requires Global { def Function(tree: Tree, vparams: List[ValDef], body: Tree): Function def Assign(tree: Tree, lhs: Tree, rhs: Tree): Assign def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree): If - def Match(tree: Tree, selector: Tree, cases: List[CaseDef], check: boolean): Match + def Match(tree: Tree, selector: Tree, cases: List[CaseDef]): Match def Return(tree: Tree, expr: Tree): Return def Try(tree: Tree, block: Tree, catches: List[CaseDef], finalizer: Tree): Try def Throw(tree: Tree, expr: Tree): Throw @@ -772,6 +778,7 @@ trait Trees requires Global { def Ident(tree: Tree, name: Name): Ident def Literal(tree: Tree, value: Constant): Literal def TypeTree(tree: Tree): TypeTree + def Attributed(tree: Tree, constr: Tree, elements: List[Tree], arg: Tree): Attributed def AttributedTypeTree(tree: Tree, attribs: List[Tree], tpt: Tree): AttributedTypeTree def SingletonTypeTree(tree: Tree, ref: Tree): SingletonTypeTree def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name): SelectFromTypeTree @@ -827,8 +834,8 @@ trait Trees requires Global { new Assign(lhs, rhs).copyAttrs(tree) def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree) = new If(cond, thenp, elsep).copyAttrs(tree) - def Match(tree: Tree, selector: Tree, cases: List[CaseDef], check: boolean) = - new Match(selector, cases, check).copyAttrs(tree) + def Match(tree: Tree, selector: Tree, cases: List[CaseDef]) = + new Match(selector, cases).copyAttrs(tree) def Return(tree: Tree, expr: Tree) = new Return(expr).copyAttrs(tree) def Try(tree: Tree, block: Tree, catches: List[CaseDef], finalizer: Tree) = @@ -855,6 +862,8 @@ trait Trees requires Global { new Literal(value).copyAttrs(tree) def TypeTree(tree: Tree) = new TypeTree().copyAttrs(tree) + def Attributed(tree: Tree, constr: Tree, elements: List[Tree], arg: Tree) = + new Attributed(constr, elements, arg) def AttributedTypeTree(tree: Tree, attribs: List[Tree], tpt: Tree) = new AttributedTypeTree(attribs, tpt) def SingletonTypeTree(tree: Tree, ref: Tree) = @@ -987,10 +996,10 @@ trait Trees requires Global { if (cond0 == cond) && (thenp0 == thenp) && (elsep0 == elsep) => t case _ => copy.If(tree, cond, thenp, elsep) } - def Match(tree: Tree, selector: Tree, cases: List[CaseDef], check: boolean) = tree match { - case t @ Match(selector0, cases0, check0) - if (selector0 == selector) && (cases0 == cases) && (check0 == check) => t - case _ => copy.Match(tree, selector, cases, check) + def Match(tree: Tree, selector: Tree, cases: List[CaseDef]) = tree match { + case t @ Match(selector0, cases0) + if (selector0 == selector) && (cases0 == cases) => t + case _ => copy.Match(tree, selector, cases) } def Return(tree: Tree, expr: Tree) = tree match { case t @ Return(expr0) @@ -1056,6 +1065,11 @@ trait Trees requires Global { case t @ TypeTree() => t case _ => copy.TypeTree(tree) } + def Attributed(tree: Tree, constr: Tree, elements: List[Tree], arg: Tree) = tree match { + case t @ Attributed(constr0, elements0, arg0) + if (constr0==constr) && (elements0==elements) && (arg0==arg) => t + case _ => copy.Attributed(tree, constr, elements, arg) + } def AttributedTypeTree(tree: Tree, attribs: List[Tree], tpt: Tree) = tree match { case t @ AttributedTypeTree(attribs0, tpt0) if (attribs0==attribs) && (tpt0==tpt) => t @@ -1161,8 +1175,8 @@ trait Trees requires Global { copy.Assign(tree, transform(lhs), transform(rhs)) case If(cond, thenp, elsep) => copy.If(tree, transform(cond), transform(thenp), transform(elsep)) - case Match(selector, cases, check) => - copy.Match(tree, transform(selector), transformCaseDefs(cases), check) + case Match(selector, cases) => + copy.Match(tree, transform(selector), transformCaseDefs(cases)) case Return(expr) => copy.Return(tree, transform(expr)) case Try(block, catches, finalizer) => @@ -1189,6 +1203,8 @@ trait Trees requires Global { copy.Literal(tree, value) case TypeTree() => copy.TypeTree(tree) + case Attributed(constr, elements, arg) => + copy.Attributed(tree, transform(constr), transformTrees(elements), transform(arg)) case AttributedTypeTree(attribs, tpt) => copy.AttributedTypeTree(tree, transformTrees(attribs), transform(tpt)) case SingletonTypeTree(ref) => @@ -1271,6 +1287,8 @@ trait Trees requires Global { traverse(expr) case Attribute(constr, elements) => traverse(constr); traverseTrees(elements) + case Attributed(constr: Tree, elements: List[Tree], arg: Tree) => + traverse(constr); traverseTrees(elements); traverse(arg) case DocDef(comment, definition) => traverse(definition) case Template(parents, body) => @@ -1299,7 +1317,7 @@ trait Trees requires Global { traverse(lhs); traverse(rhs) case If(cond, thenp, elsep) => traverse(cond); traverse(thenp); traverse(elsep) - case Match(selector, cases, _) => + case Match(selector, cases) => traverse(selector); traverseTrees(cases) case Return(expr) => traverse(expr) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 9a8810e330..aef8f96181 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -645,8 +645,9 @@ trait Parsers requires SyntaxAnalyzer { } } - /** SimpleType ::= SimpleType TypeArgs - * | SimpleType `#' Id + /** SimpleType ::= {`@' Attribute} SimpleType1 + * SimpleType1 ::= SimpleType1 TypeArgs + * | SimpleType1 `#' Id * | StableId * | Path `.' type * | `(' Type `)' @@ -659,11 +660,7 @@ trait Parsers requires SyntaxAnalyzer { * | `{' [ArgTypePattern `,' [ArgTypePatterns [`,']]] `}' */ def simpleType(isPattern: boolean): Tree = { - val attribs = - if(settings.Xplugtypes.value) - typeAttributes - else - Nil + val attribs = typeAttributes() val pos = in.currentPos var t: Tree = @@ -707,7 +704,10 @@ trait Parsers requires SyntaxAnalyzer { done=true } - t.withAttributes(attribs) + if (settings.Xplugtypes.value) t.withAttributes(attribs) + else (t /: attribs) ((t, attr) => attr match { + case Attribute(constr, elements) => Attributed(constr, elements, t) + }) } /** TypeArgs ::= `[' ArgTypes `]' @@ -954,12 +954,10 @@ trait Parsers requires SyntaxAnalyzer { } } else if (in.token == MATCH) { t = atPos(in.skipToken()) { - val nocheck = isIdent && in.name == BANG - if (nocheck) in.nextToken() accept(LBRACE) val cases = caseClauses() accept(RBRACE) - Match(t, cases, !nocheck) + Match(t, cases) } } if ((mode & ClosureOK) != 0 && in.token == ARROW) { @@ -2159,12 +2157,19 @@ trait Parsers requires SyntaxAnalyzer { * * Type attributes may be arbitrary expressions. */ - def typeAttributes: List[Tree] = { + def typeAttributes(): List[Tree] = { val exps = new ListBuffer[Tree] - while(in.token == LBRACKET) { - accept(LBRACKET) - exps ++= argExprs - accept(RBRACKET) + if (settings.Xplugtypes.value) { + while(in.token == LBRACKET) { + accept(LBRACKET) + exps ++= argExprs + accept(RBRACKET) + } + } else { + while (in.token == AT) { + val pos = in.skipToken() + exps += attribute() + } } exps.toList } diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index ca1eb1005c..f6cbead3ca 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -360,11 +360,18 @@ abstract class TreeBuilder { def makeVisitor(cases: List[CaseDef], checkExhaustive: boolean): Tree = makeVisitor(cases, checkExhaustive, "x$") + private def makeUnsealed(expr: Tree): Tree = + Attributed(New(scalaDot(definitions.UnsealedClass.name), List(List())), List(), expr) + + private def checkAttr(expr: Tree, check: boolean) = + if (check) expr else makeUnsealed(expr) + /** Create visitor x match cases> */ def makeVisitor(cases: List[CaseDef], checkExhaustive: boolean, prefix: String): Tree = { val x = freshName(prefix) + val sel = if (checkExhaustive) Ident(x) else makeUnsealed(Ident(x)) Function(List(ValDef(Modifiers(PARAM | SYNTHETIC), x, TypeTree(), EmptyTree)), - Match(Ident(x), cases, checkExhaustive)) + Match(sel, cases)) } /** Create tree for case definition <case pat if guard => rhs> */ @@ -395,7 +402,9 @@ abstract class TreeBuilder { val pat1 = patvarTransformer.transform(pat) val vars = getVariables(pat1) val matchExpr = atPos(pat1.pos){ - Match(rhs, List(CaseDef(pat1, EmptyTree, makeTupleTerm(vars map (._1) map Ident, true))), false) + Match( + makeUnsealed(rhs), + List(CaseDef(pat1, EmptyTree, makeTupleTerm(vars map (._1) map Ident, true)))) } vars match { case List() => diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 2da62c7806..3855438e6e 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -894,7 +894,7 @@ abstract class GenICode extends SubComponent { } ctx1 - case Match(selector, cases, _) => + case Match(selector, cases) => if (settings.debug.value) log("Generating SWITCH statement."); var ctx1 = genLoad(selector, ctx, INT) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 34e52699da..f1825e2b6e 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -122,9 +122,7 @@ abstract class GenJVM extends SubComponent { val outfile = getFile(jclass, ".class") jclass.writeTo(outfile) val file = scala.tools.nsc.io.AbstractFile.getFile(outfile) - informProgress("wrote " + outfile + " " + - (if (file ne null) "" + file.file + " " + file.file.exists() - else "no file")) + informProgress("wrote " + outfile) } var serialVUID: Option[Long] = None diff --git a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala index 3b4a88e63c..c66c3e1ff8 100644 --- a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala +++ b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala @@ -1001,7 +1001,7 @@ print() return Switch(selector, tags, bodies, defaultBody1, resultType); */ nCases = CaseDef(Ident(nme.WILDCARD), squeezedBlock(List(ValDef(root.symbol, selector)),defaultBody1)) :: nCases; - Match(selector, nCases, false) + Match(selector, nCases) } @@ -1057,7 +1057,6 @@ print() //Console.println("remain "+remainingCases+" carry covered "+ carryCovered + "real "+realRemainingCases) if(!realRemainingCases.isEmpty) { val word = if(realRemainingCases.size > 1) "cases " else "case " - //Console.println(_h.print("non-exhaustive ", new StringBuilder()).toString()) cunit.warning(node.pos, "does not cover "+word+realRemainingCases.elements.mkString("{",",","}")) //Console.println("full"); print() //Console.println(_h.print("", new StringBuilder()).toString()) @@ -1214,8 +1213,7 @@ print() nCases = CaseDef(Ident(nme.WILDCARD), defBody) :: nCases; return Match(Apply(Select(selector.duplicate, defs.ScalaObjectClass_tag), List()), - nCases, - false) + nCases) } /** why not use plain `if's? the reason is that a failing *guard* must still remain diff --git a/src/compiler/scala/tools/nsc/models/Models.scala b/src/compiler/scala/tools/nsc/models/Models.scala index d29dce02ab..1fe18a0ff5 100644 --- a/src/compiler/scala/tools/nsc/models/Models.scala +++ b/src/compiler/scala/tools/nsc/models/Models.scala @@ -404,7 +404,7 @@ abstract class Models { flatten(expr0,filter) case Try(block, catches, finalizer) => flatten(block, filter) ::: flatten(finalizer, filter) ::: flatten0(catches, filter) - case Match(selector, cases, _) => + case Match(selector, cases) => flatten(selector, filter) ::: flatten0(cases, filter) case Apply(fun, args) => flatten(fun, filter) ::: flatten0(args, filter) diff --git a/src/compiler/scala/tools/nsc/models/SemanticTokens.scala b/src/compiler/scala/tools/nsc/models/SemanticTokens.scala index efe79e2baf..9d2abb6aec 100644 --- a/src/compiler/scala/tools/nsc/models/SemanticTokens.scala +++ b/src/compiler/scala/tools/nsc/models/SemanticTokens.scala @@ -477,6 +477,7 @@ class SemanticTokens(val compiler: Global) { case tree : DocDef => build(tree.definition); case tree: Import => build(tree.expr) case tree: AppliedTypeTree => ; + case tree: Attributed => ; case tree: AttributedTypeTree => ; case tree: SingletonTypeTree => ; case tree: Super => ; diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index f2ed6bb6e1..c6fcbee6c7 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -106,6 +106,7 @@ trait Definitions requires SymbolTable { def checkDefinedMethod = getMember(ScalaRunTimeModule, "checkDefined") var RepeatedParamClass: Symbol = _ var ByNameParamClass: Symbol = _ + var UnsealedClass: Symbol = _ val MaxTupleArity = 22 val TupleClass: Array[Symbol] = new Array(MaxTupleArity + 1) @@ -782,6 +783,7 @@ trait Definitions requires SymbolTable { ByNameParamClass = newCovariantPolyClass( ScalaPackageClass, nme.BYNAME_PARAM_CLASS_NAME, tparam => AnyClass.typeConstructor) /* */ + UnsealedClass = getClass("scala.unsealed") OptionClass = getClass("scala.Option") for (val i <- 1 to MaxTupleArity) { diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index b68d487d79..0f860ee5f3 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -56,18 +56,6 @@ trait Types requires SymbolTable { /** The base class for all types */ abstract class Type { - /** Add an attribute to this type */ - def withAttribute(attrib: Any) = withAttributes(List(attrib)) - - /** Add a number of attributes to this type */ - def withAttributes(attribs: List[Any]): Type = - attribs match { - case Nil => this - case _ => AttributedType(attribs, this) - } - - /** Remove any attributes from this type */ - def withoutAttributes = this /** Types for which asSeenFrom always is the identity, no matter what * prefix or owner. @@ -495,6 +483,19 @@ trait Types requires SymbolTable { baseClasses.head.newOverloaded(this, members.toList) } } + + /** Add an attribute to this type */ + def withAttribute(attrib: Any) = withAttributes(List(attrib)) + + /** Add a number of attributes to this type */ + def withAttributes(attribs: List[Any]): Type = + attribs match { + case Nil => this + case _ => AttributedType(attribs, this) + } + + /** Remove any attributes from this type */ + def withoutAttributes = this } // Subclasses ------------------------------------------------------------ @@ -1120,7 +1121,7 @@ trait Types requires SymbolTable { override def symbol: Symbol = tp.symbol override def singleDeref: Type = maybeRewrap(tp.singleDeref) - override def widen: Type = maybeRewrap(tp.widen) + override def widen: Type = tp.widen override def deconst: Type = maybeRewrap(tp.deconst) override def bounds: TypeBounds = { val oftp = tp.bounds diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index e10fdaf406..8d70c8360c 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -487,8 +487,8 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { tree1 match { case If(cond, thenp, elsep) => copy.If(tree1, cond, adaptBranch(thenp), adaptBranch(elsep)) - case Match(selector, cases, check) => - copy.Match(tree1, selector, cases map adaptCase, check) + case Match(selector, cases) => + copy.Match(tree1, selector, cases map adaptCase) case Try(block, catches, finalizer) => copy.Try(tree1, adaptBranch(block), catches map adaptCase, finalizer) case _ => diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index 25f4695af7..de5e99c91e 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -468,7 +468,7 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter } super.transform(copy.Apply(tree, sel, outerVal :: args)) - case Match(selector, cases, checkExhaustive) => // <----- transmatch hook + case Match(selector, cases) => // <----- transmatch hook val tid = if (settings.debug.value) { val q = unit.fresh.newName("tidmark") Console.println("transforming patmat with tidmark "+q+" ncases = "+cases.length) @@ -488,35 +488,49 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter } */ - val nselector = transform(selector) + var nselector = transform(selector) assert(nselector.tpe =:= selector.tpe) val ncases = transformCaseDefs(cases) + var checkExhaustive = true + def isUnsealedAttribute(tpe: Type) = tpe match { + case AttributedType(List(AttrInfo(atp, _, _)), _) if atp.symbol == UnsealedClass => + true + case _ => + false + } + nselector match { + case Typed(nselector1, tpt) if isUnsealedAttribute(tpt.tpe) => + nselector = nselector1 + checkExhaustive = false + case _ => + } + ExplicitOuter.this.resultType = tree.tpe //Console.println("TransMatcher currentOwner ="+currentOwner+")") //Console.println("TransMatcher selector.tpe ="+selector.tpe+")") //Console.println("TransMatcher resultType ="+resultType+")") - val t_untyped = handlePattern(nselector, ncases, checkExhaustive, currentOwner, transform) - try { - //Console.println("t_untyped "+t_untyped.toString()) - val t = atPos(tree.pos) { localTyper.typed(t_untyped, resultType) } - - //t = transform(t) - //val t = atPos(tree.pos) { typed(t_untyped, resultType) } - //val t = atPos(tree.pos) { typed(t_untyped) } - //Console.println("t typed "+t.toString()) - if (settings.debug.value) - Console.println("finished translation of " + tid) - t - } catch { - case e => - e.printStackTrace() - //treeBrowser.browse(Seq.single(unit).elements) - Console.println("[died while typechecking the translated pattern match:]") - Console.println(t_untyped) - null - } + val t_untyped = handlePattern(nselector, ncases, checkExhaustive, currentOwner, transform) + try { + //Console.println("t_untyped "+t_untyped.toString()) + val t = atPos(tree.pos) { localTyper.typed(t_untyped, resultType) } + + //t = transform(t) + //val t = atPos(tree.pos) { typed(t_untyped, resultType) } + //val t = atPos(tree.pos) { typed(t_untyped) } + //Console.println("t typed "+t.toString()) + if (settings.debug.value) + Console.println("finished translation of " + tid) + t + } catch { + case e => + e.printStackTrace() + //treeBrowser.browse(Seq.single(unit).elements) + Console.println("[died while typechecking the translated pattern match:]") + Console.println(t_untyped) + null + } case _ => val x = super.transform(tree) diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index 6628751d30..c83430f265 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -213,8 +213,8 @@ abstract class TailCalls extends Transform case If(cond, thenp, elsep) => copy.If(tree, cond, transform(thenp), transform(elsep)); - case Match(selector, cases, check) => //super.transform(tree); - copy.Match(tree, transform(selector, mkContext(ctx, false)), transformTrees(cases).asInstanceOf[List[CaseDef]], check); + case Match(selector, cases) => //super.transform(tree); + copy.Match(tree, transform(selector, mkContext(ctx, false)), transformTrees(cases).asInstanceOf[List[CaseDef]]); case Return(expr) => super.transform(tree) case Try(block, catches, finalizer) => diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 02d2d69c85..3fb78e63b2 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -244,7 +244,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { .setFlag(FINAL).setInfo(MethodType(formals, BooleanClass.tpe)) anonClass.info.decls enter isDefinedAtMethod def idbody(idparam: Symbol) = fun.body match { - case Match(_, cases, check) => + case Match(_, cases) => val substParam = new TreeSymSubstituter(List(fun.vparams.head.symbol), List(idparam)); def transformCase(cdef: CaseDef): CaseDef = substParam( @@ -255,8 +255,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { Match( Ident(idparam), (cases map transformCase) ::: - List(CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(false))), - check) + List(CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(false)))) } members = DefDef(isDefinedAtMethod, vparamss => idbody(vparamss.head.head)) :: members; } @@ -471,7 +470,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { CaseDef( Bind(exname, Ident(nme.WILDCARD)), EmptyTree, - Match(Ident(exname), cases, false)) + Match(Ident(exname), cases)) } if (settings.debug.value) log("rewrote try: " + catches + " ==> " + catchall); val catches1 = localTyper.typedCases( diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 6dfba7ace7..0c1df47925 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -616,7 +616,7 @@ abstract class RefChecks extends InfoTransform { Select(qual, nme.filter), List(Function( List(ValDef(_, pname, tpt, _)), - Match(_, CaseDef(pat1, _, _) :: _, _)))) + Match(_, CaseDef(pat1, _, _) :: _)))) if ((pname startsWith nme.CHECK_IF_REFUTABLE_STRING) && isIrrefutable(pat1, tpt.tpe)) => result = qual diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 9bd64801d8..f5999b3582 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -87,7 +87,7 @@ trait SyntheticMethods requires Analyzer { Throw(New(TypeTree(IndexOutOfBoundsExceptionClass.tpe), List(List( Select(Ident(vparamss.head.head), nme.toString_) )))))) - }, false))) + }))) } def moduleToStringMethod: Tree = { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 42a3bd1831..9b905f6319 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -883,6 +883,9 @@ trait Typers requires Analyzer { case DocDef(comment, defn) => addGetterSetter(defn) map (stat => DocDef(comment, stat)) + case Attributed(constr, elements, defn) => + addGetterSetter(defn) map (stat => Attributed(constr, elements, stat)) + case _ => List(stat) } @@ -1512,6 +1515,54 @@ trait Typers requires Analyzer { } } + def typedAttribute(constr: Tree, elements: List[Tree]): AttrInfo = { + var attrError: Boolean = false; + def error(pos: PositionType, msg: String): Null = { + context.error(pos, msg) + attrError = true + null + } + def getConstant(tree: Tree): Constant = tree match { + case Literal(value) => value + case arg => error(arg.pos, "attribute argument needs to be a constant; found: "+arg) + } + val attrInfo = + typed(constr, EXPRmode | CONSTmode, AttributeClass.tpe) match { + case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) => + val constrArgs = args map getConstant + val attrScope = tpt.tpe.decls + .filter(sym => sym.isMethod && !sym.isConstructor && sym.hasFlag(JAVA)); + val names = new collection.mutable.HashSet[Symbol] + names ++= attrScope.elements.filter(.isMethod) + if (args.length == 1) { + names.retain(sym => sym.name != nme.value) + } + val nvPairs = elements map { + case Assign(ntree @ Ident(name), rhs) => { + val sym = attrScope.lookup(name); + if (sym == NoSymbol) { + error(ntree.pos, "unknown attribute element name: " + name) + } else if (!names.contains(sym)) { + error(ntree.pos, "duplicate value for element " + name) + } else { + names -= sym + {sym.name, getConstant(typed(rhs, EXPRmode | CONSTmode, sym.tpe.resultType))} + } + } + } + for (val name <- names) { + if (!name.attributes.contains{AnnotationDefaultAttr.tpe, List(), List()}) { + error(constr.pos, "attribute " + tpt.tpe.symbol.fullNameString + " is missing element " + name.name) + } + } + if (tpt.tpe.symbol.hasFlag(JAVA) && settings.target.value == "jvm-1.4") { + context.unit.warning (constr.pos, "Java annotation will not be emitted in classfile unless you use the '-target:jvm-1.5' option") + } + AttrInfo(tpt.tpe, constrArgs, nvPairs) + } + if (attrError) AttrInfo(ErrorType, List(), List()) else attrInfo + } + /** * @param tree ... * @param mode ... @@ -1870,11 +1921,29 @@ trait Typers requires Analyzer { } typer1.typedLabelDef(ldef) - case DocDef(comment, defn) => { + case DocDef(comment, defn) => val ret = typed(defn, mode, pt) - if (comments ne null) comments(defn . symbol) = comment; + if (comments ne null) comments(defn.symbol) = comment ret - } + + case Attributed(constr, elements, arg) => + val attrInfo = typedAttribute(constr, elements) + val arg1 = typed(arg, mode, pt) + def attrType = + TypeTree(arg1.tpe.withAttribute(attrInfo)) setOriginal tree + arg1 match { + case _: DefTree => + if (!attrInfo.atp.isError) { + val attributed = + if (arg1.symbol.isModule) arg1.symbol.moduleClass else arg1.symbol + attributed.attributes = attrInfo :: attributed.attributes + } + arg1 + case _ => + if (arg1.isType) attrType + else Typed(arg1, attrType) setPos tree.pos setType attrType.tpe + } + case tree @ Block(_, _) => newTyper(makeNewScope(context, tree, context.owner)) .typedBlock(tree, mode, pt) @@ -1979,10 +2048,10 @@ trait Typers requires Analyzer { copy.If(tree, cond1, thenp1, elsep1) setType ptOrLub(List(thenp1.tpe, elsep1.tpe)) } - case Match(selector, cases, check) => + case Match(selector, cases) => val selector1 = typed(selector) val cases1 = typedCases(tree, cases, selector1.tpe.widen, pt) - copy.Match(tree, selector1, cases1, check) setType ptOrLub(cases1 map (.tpe)) + copy.Match(tree, selector1, cases1) setType ptOrLub(cases1 map (.tpe)) case Return(expr) => val enclMethod = context.enclMethod diff --git a/src/library/scala/unsealed.scala b/src/library/scala/unsealed.scala new file mode 100755 index 0000000000..5ea51ae144 --- /dev/null +++ b/src/library/scala/unsealed.scala @@ -0,0 +1,18 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2007, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +// $Id: remote.scala 9400 2006-11-28 17:22:45 +0000 (Tue, 28 Nov 2006) michelou $ + + +package scala + +/** + * An attribute that gets applied to a selector in a match expression. + * If it is present, exhaustiveness warnings for that expression will be suppressed. + */ +class unsealed extends Attribute {} -- cgit v1.2.3