From 7fd3db89c8850ea332ba99cf311b5b60cd86c550 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 3 Oct 2009 22:38:39 +0000 Subject: Reaping the spoils of patternization. or obsolete code now that I'm gaining some confidence about what exists for a reason and what exists only because it once existed. --- .../tools/nsc/matching/ParallelMatching.scala | 105 ++++++++----- .../scala/tools/nsc/matching/PatternBindings.scala | 12 ++ .../scala/tools/nsc/matching/PatternNodes.scala | 174 ++------------------- .../scala/tools/nsc/matching/Patterns.scala | 22 ++- 4 files changed, 109 insertions(+), 204 deletions(-) diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 6d7e4e56a9..adeaf452fa 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -141,10 +141,10 @@ trait ParallelMatching extends ast.TreeDSL lazy val headType = head.tree match { case p @ (_:Ident | _:Select) => head.mkSingleton // should be singleton object - case __UnApply(_,argtpe,_) => argtpe // ?? why argtpe? + case UnapplyParamType(x) => x case _ => head.tpe } - def isCaseHead = isCaseClass(headType) + def isCaseHead = head.isCaseClass def dummies = if (isCaseHead) getDummies(headType.typeSymbol.caseFieldAccessors.length) else Nil def dummyPatterns = dummies map (x => Pattern(x)) @@ -153,11 +153,7 @@ trait ParallelMatching extends ast.TreeDSL def zip[T](others: List[T]) = trees zip others def pzip[T](others: List[T]) = ps zip others - /** returns true if pattern tests an object */ - def isObjectTest(pat: Pattern) = - pat.isSymValid && pat.prefix.isStable && (headType =:= pat.mkSingleton) - - def extractSimpleSwitch(): Option[(List[Tree], Option[Tree])] = { + def extractSimpleSwitch(): Option[(List[Tree], Option[Pattern])] = { def isSwitchableTag(tag: Int) = cond(tag) { case ByteTag | ShortTag | IntTag | CharTag => true } def isSwitchableConst(t: Tree) = cond(unbind(t)) { case Literal(x: Constant) => isSwitchableTag(x.tag) } def isSwitchableDefault(x: Tree) = isSwitchableConst(x) || isDefaultPattern(x) @@ -166,7 +162,7 @@ trait ParallelMatching extends ast.TreeDSL others match { case Nil => Some((lits, None)) // TODO: This needs to also allow the case that the last is a compatible type pattern. - case List(x) if isSwitchableDefault(x) => Some((lits, Some(x))) + case List(x) if isSwitchableDefault(x) => Some((lits, Some(Pattern(x)))) case _ => None } } @@ -174,7 +170,7 @@ trait ParallelMatching extends ast.TreeDSL // Any unapply - returns Some(true) if a type test is needed before the unapply can // be called (e.g. def unapply(x: Foo) = { ... } but our scrutinee is type Any.) object AnyUnapply { - def unapply(x: Tree): Option[Boolean] = condOpt(x) { case __UnApply(_,tpe,_) => !(scrut.tpe <:< tpe) } + def unapply(x: Tree): Option[Boolean] = condOpt(x) { case UnapplyParamType(tpe) => !(scrut.tpe <:< tpe) } } object SimpleSwitch { @@ -276,7 +272,7 @@ trait ParallelMatching extends ast.TreeDSL val pats: Patterns, val rest: Rep, literals: List[Tree], - defaultPattern: Option[Tree]) + defaultPattern: Option[Pattern]) extends RuleApplication { private object NUM { @@ -284,8 +280,8 @@ trait ParallelMatching extends ast.TreeDSL } // bound vars and rows for default pattern (only one row, but a list is easier to use later) val (defaultVars, defaultRows) = defaultPattern match { - case None => (Nil, Nil) - case Some(Strip(vs, p)) => (vs, List((rest rows literals.size).rebind2(vs, scrut.sym))) + case None => (Nil, Nil) + case Some(Pattern(_, vs)) => (vs, List((rest rows literals.size).rebind2(vs, scrut.sym))) } // literalMap is a map from each literal to a list of row indices. // varMap is a list from each literal to a list of the defined vars. @@ -357,7 +353,10 @@ trait ParallelMatching extends ast.TreeDSL object sameUnapplyCall { private def sameFunction(fn1: Tree) = fxn.symbol == fn1.symbol && (fxn equalsStructure fn1) - def unapply(t: Tree) = condOpt(t) { case UnApply(Apply(fn1, _), args) if sameFunction(fn1) => args } + + def unapply(p: Pattern) = condOpt(p) { + case Pattern(UnApply(Apply(fn1, _), args), _) if sameFunction(fn1) => args + } } def newVarCapture(pos: Position, tpe: Type) = @@ -367,10 +366,10 @@ trait ParallelMatching extends ast.TreeDSL final def getTransition(): Branch[UnapplyCall] = { val unapplyRes = newVarCapture(ua.pos, app.tpe) val rhs = Apply(fxn, scrut.id :: trailingArgs) setType unapplyRes.tpe - val zipped = pats zip rest.rows + val zipped = pats pzip rest.rows val nrowsOther = zipped.tail flatMap { - case (Stripped(sameUnapplyCall(_)), _) => Nil - case (pat, r) => List(r insert Pattern(pat)) + case (sameUnapplyCall(_), _) => Nil + case (pat, r) => List(r insert pat) } def mkTransition(vdefs: List[Tree], ntemps: List[Symbol], nrows: List[Row]) = @@ -382,9 +381,9 @@ trait ParallelMatching extends ast.TreeDSL // Second argument is number of dummies to prepend in the default case def mkNewRows(sameFilter: (List[Tree]) => List[Tree], dum: Int) = - for ((pat @ Strip(vs, p), r) <- zipped) yield p match { - case sameUnapplyCall(args) => r.insert2(toPats(sameFilter(args)) ::: List(NoPattern), vs, scrut.sym) - case _ => r insert (emptyPatterns(dum) ::: List(Pattern(pat))) + for ((pat, r) <- zipped) yield pat match { + case sameUnapplyCall(args) => r.insert2(toPats(sameFilter(args)) ::: List(NoPattern), pat.boundVariables, scrut.sym) + case _ => r insert (emptyPatterns(dum) ::: List(pat)) } def mkGet(s: Symbol) = typedValDef(s, fn(ID(unapplyRes), nme.get)) def mkVar(tpe: Type) = newVarCapture(ua.pos, tpe) @@ -600,6 +599,7 @@ trait ParallelMatching extends ast.TreeDSL private def matches(arg1: Type, arg2: Type) = { val List(t1, t2) = List(arg1, arg2) map decodedEqualsType def eqSymbols = t1.typeSymbol eq t2.typeSymbol + // note: writing this as "t1.baseTypeSeq exists (_ =:= t2)" does not lead to 1434 passing. def isSubtype = t1.baseTypeSeq exists (_.typeSymbol eq t2.typeSymbol) (t1 <:< t2) || ((t1, t2) match { @@ -619,14 +619,14 @@ trait ParallelMatching extends ast.TreeDSL def eqHead(tpe: Type) = pats.headType =:= tpe def alts(yes: Tree, no: Tree) = if (eqHead(pat.tpe)) yes else no + def isObjectTest = pattern.isObject && eqHead(pattern.mkSingleton) - def isDef = pattern.isDefault lazy val dummy = (j, pats.dummies) - lazy val pass = (j, pat) - lazy val subs = (j, pattern.subpatterns(pats) map (_.boundTree)) + lazy val pass = (j, pattern.boundTree) + lazy val subs = (j, (pattern subpatterns pats) map (_.boundTree)) - // scrutinee, pattern - val (s, p) = (spat.tpe, pats.headType) + // scrutinee, head of pattern group + val (s, p) = (pattern.tpe, pats.headType) def sMatchesP = matches(s, p) def pMatchesS = matches(p, s) @@ -634,16 +634,24 @@ trait ParallelMatching extends ast.TreeDSL // each pattern will yield a triple of options corresponding to the three lists, // which will be flattened down to the values implicit def mkOpt[T](x: T): Option[T] = Some(x) // limits noise from Some(value) - (spat match { - case LIT(null) if !eqHead(spat.tpe) => (None, None, pass) // special case for constant null - case _ if pats.isObjectTest(pattern) => (EmptyTree, dummy, None) // matching an object - case Typed(pp @ Stripped(_: UnApply), _) if sMatchesP => (pp, dummy, None) // <:< is never - case q @ Typed(pp, _) if sMatchesP => (alts(pp, q), dummy, None) // never =:= for - case z: UnApply => (EmptyTree, dummy, pass) - case _ => - if (sMatchesP && !pattern.isDefault) (alts(EmptyTree, pat), subs, None) - else if (pMatchesS || pattern.isDefault) (EmptyTree, dummy, pass) - else (None, None, pass) + + // Note - at the moment these comments are mostly trivial or nonsensical, but + // they persist from a much earlier time and I still try to read the tea leaves + // + // (1) special case for constant null + // (2) matching an object + // (3) <:< is never + // (4) never =:= for + + (pattern match { + case Pattern(LIT(null), _) if !eqHead(pattern.tpe) => (None, None, pass) // (1) + case x if isObjectTest => (EmptyTree, dummy, None) // (2) + case Pattern(Typed(pp @ Pattern(_: UnApply, _), _), _) if sMatchesP => (pp, dummy, None) // (3) + case Pattern(Typed(pp, _), _) if sMatchesP => (alts(pp, pattern.tree), dummy, None) // (4) + case Pattern(_: UnApply, _) => (EmptyTree, dummy, pass) + case x if !x.isDefault && sMatchesP => (alts(EmptyTree, pat), subs, None) + case x if x.isDefault || pMatchesS => (EmptyTree, dummy, pass) + case _ => (None, None, pass) // The below (once fixed) bugs 425 and 816 with only the small downside // of causing 60 other tests to fail. @@ -726,7 +734,7 @@ trait ParallelMatching extends ast.TreeDSL case class Row(pat: List[Pattern], subst: Bindings, guard: Guard, bx: Int) { def insert(h: Pattern) = copy(pat = h :: pat) - def insert(hs: List[Pattern]) = copy(pat = hs ::: pat) // prepends supplied tree + def insert(hs: List[Pattern]) = copy(pat = hs ::: pat) // prepends supplied pattern def replace(hs: List[Pattern]) = copy(pat = hs) // substitutes for patterns def rebind(b: Bindings) = copy(subst = b) // substitutes for bindings @@ -816,9 +824,26 @@ trait ParallelMatching extends ast.TreeDSL case class Combo(index: Int, sym: Symbol) { // is this combination covered by the given pattern? - def isCovered(p: Pattern) = cond(p.tree) { - case _: UnApply | _: ArrayValue => true - case x => isDefaultPattern(x) || (p.tpe coversSym sym) + def isCovered(p: Pattern) = { + def cmpSymbols(t1: Type, t2: Type) = t1.typeSymbol eq t2.typeSymbol + def coversSym = { + val tpe = decodedEqualsType(p.tpe) + lazy val lmoc = sym.linkedModuleOfClass + val symtpe = + if ((sym hasFlag Flags.MODULE) && (lmoc ne NoSymbol)) + singleType(sym.tpe.prefix, lmoc) // e.g. None, Nil + else sym.tpe + + (tpe.typeSymbol == sym) || + (symtpe <:< tpe) || + (symtpe.parents exists (x => cmpSymbols(x, tpe))) || // e.g. Some[Int] <: Option[&b] + ((tpe.prefix memberType sym) <:< tpe) // outer, see combinator.lexical.Scanner + } + + cond(p.tree) { + case _: UnApply | _: ArrayValue => true + case x => isDefaultPattern(x) || coversSym + } } } case class SetCombo(index: Int, syms: Set[Symbol]) {} @@ -985,11 +1010,11 @@ trait ParallelMatching extends ast.TreeDSL typer typed (tpe match { case ct: ConstantType => ct.value match { - case v @ Constant(null) if isAnyRef(scrutTree.tpe) => scrutTree ANY_EQ NULL + case v @ Constant(null) if scrutTree.tpe.isAnyRef => scrutTree ANY_EQ NULL case v => scrutTree MEMBER_== Literal(v) } case _: SingletonType if useEqTest => REF(tpe.termSymbol) MEMBER_== scrutTree - case _ if scrutTree.tpe <:< tpe && isAnyRef(tpe) => scrutTree OBJ_!= NULL + case _ if scrutTree.tpe <:< tpe && tpe.isAnyRef => scrutTree OBJ_!= NULL case _ => scrutTree IS tpe }) } diff --git a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala index 575050821a..0fd3043281 100644 --- a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala +++ b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala @@ -27,6 +27,18 @@ trait PatternBindings extends ast.TreeDSL override def safeToString: String = "PseudoType("+o+")" } + final def definedVars(x: Tree): List[Symbol] = { + def vars(x: Tree): List[Symbol] = x match { + case Apply(_, args) => args flatMap vars + case b @ Bind(_, p) => b.symbol :: vars(p) + case Typed(p, _) => vars(p) // otherwise x @ (_:T) + case UnApply(_, args) => args flatMap vars + case ArrayValue(_, xs) => xs flatMap vars + case x => Nil + } + vars(x) reverse + } + // If the given pattern contains alternatives, return it as a list of patterns. // Makes typed copies of any bindings found so all alternatives point to final state. def extractBindings(p: Tree, prevBindings: Tree => Tree = identity[Tree] _): List[Tree] = { diff --git a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala index dd9022cd2d..59fe3ed0d7 100644 --- a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala +++ b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala @@ -7,7 +7,7 @@ package scala.tools.nsc package matching -import scala.tools.nsc.util.{Position, NoPosition} +import scala.tools.nsc.util.NoPosition /** * @author Burak Emir @@ -17,76 +17,16 @@ trait PatternNodes extends ast.TreeDSL self: transform.ExplicitOuter => import global.{ typer => _, _ } - import analyzer.Typer - import symtab.Flags - import Types._ import CODE._ - import definitions.{ ConsClass, ListClass, AnyRefClass, EqualsPatternClass, ListModule } - - type TypeComparison = (Type, Type) => Boolean - - // Tests on Types - def isAnyRef(t: Type) = t <:< AnyRefClass.tpe - def isCaseClass(t: Type) = t.typeSymbol hasFlag Flags.CASE - - // Comparisons on types - // def sameSymbols: TypeComparison = _.typeSymbol eq _.typeSymbol - // def samePrefix: TypeComparison = _.prefix =:= _.prefix - // def isSubErased: TypeComparison = (t1, t2) => cond((t1, t2)) { - // case (_: TypeRef, _: TypeRef) => !t1.isArray && samePrefix(t1,t2) && (sameSymbols(t1,t2) || isSubClass(t1, t2)) - // } - - // def isSubClass: TypeComparison = (t1, t2) => t1.baseClasses exists (_ eq t2.typeSymbol) - // def isSubType: TypeComparison = (t1, t2) => isSubClass(t1, t2) && (t1 <:< t2) - // def isPatMatch: TypeComparison = (t1, t2) => isSubType(t1, t2) - - - // If we write isSubtypeOf like: - // - // = t1.baseTypeSeq exists (_ =:= t2) - // - // ..then all tests pass except for test/files/run/bug1434.scala, which involves: - // class A[T], B extends A[Any], C extends B ; ... match { case _: A[_] => .. ; case _: C => .. ; case _: B => .. } - // and a match error is thrown, which is interesting because either of C or B should match. - def isSubtypeOf(t1: Type, t2: Type) = t1.baseTypeSeq exists (p => cmpSymbols(p, t2)) - def cmpSymbols(t1: Type, t2: Type) = t1.typeSymbol eq t2.typeSymbol - - case class TypeComp(x: Type, y: Type) { - def xIsaY = x <:< y - def yIsaX = y <:< x - def eqSymbol = cmpSymbols(x, y) - def eqPrefix = x.prefix =:= y.prefix - - object erased { - import Types._ - /** an approximation of _tp1 <:< tp2 that ignores _ types. this code is wrong, - * ideally there is a better way to do it, and ideally defined in Types.scala - */ - private def cmpErased(t1: Type, t2: Type) = (t1, t2) match { - case (_: TypeRef, _: TypeRef) => !t1.isArray && eqPrefix && (eqSymbol || isSubtypeOf(t1, t2)) - case _ => false - } - - def xIsaY = cmpErased(x, y) - def yIsaX = cmpErased(y, x) - } - } + import definitions.{ ListClass, ConsClass } object Types { import definitions._ - implicit def enrichType(_tpe: Type): RichType = new RichType(_tpe) + implicit def enrichType(x: Type): RichType = new RichType(x) - class RichType(_tpe: Type) { - /* equality checks for named constant patterns like "Foo()" are encoded as "_:[Foo().type]" - * and later compiled to "if(Foo() == scrutinee) ...". This method extracts type information from - * such an encoded type, which is used in optimization. If the argument is not an encoded equals - * test, it is returned as is. - */ - private def tpeWRTEquality(t: Type) = t match { - case TypeRef(_, EqualsPatternClass, List(arg)) => arg - case _ => t - } - lazy val tpe = tpeWRTEquality(_tpe) + class RichType(undecodedTpe: Type) { + def tpe = decodedEqualsType(undecodedTpe) + def isAnyRef = tpe <:< AnyRefClass.tpe // These tests for final classes can inspect the typeSymbol private def is(s: Symbol) = tpe.typeSymbol eq s @@ -97,23 +37,7 @@ trait PatternNodes extends ast.TreeDSL def isBoolean = is(BooleanClass) def isNothing = is(NothingClass) def isArray = is(ArrayClass) - - def cmp(other: Type): TypeComp = TypeComp(tpe, tpeWRTEquality(other)) - - def coversSym(sym: Symbol) = { - lazy val lmoc = sym.linkedModuleOfClass - val symtpe = - if ((sym hasFlag Flags.MODULE) && (lmoc ne NoSymbol)) - singleType(sym.tpe.prefix, lmoc) // e.g. None, Nil - else sym.tpe - - (tpe.typeSymbol == sym) || - (symtpe <:< tpe) || - (symtpe.parents exists (x => cmpSymbols(x, tpe))) || // e.g. Some[Int] <: Option[&b] - ((tpe.prefix memberType sym) <:< tpe) // outer, see combinator.lexical.Scanner - } } - } /** For folding a list into a well-typed x :: y :: etc :: tree. */ @@ -122,9 +46,9 @@ trait PatternNodes extends ast.TreeDSL val consRef = typeRef(pre, sym, List(tpe)) val listRef = typeRef(pre, ListClass, List(tpe)) - def fold(x: Tree, xs: Tree) = x match { - case sp @ Strip(_, _: Star) => makeBind(definedVars(sp), WILD(sp.tpe)) - case _ => + def fold(x: Tree, xs: Tree) = unbind(x) match { + case _: Star => makeBind(definedVars(x), WILD(x.tpe)) + case _ => val dummyMethod = new TermSymbol(NoSymbol, NoPosition, "matching$dummy") val consType = MethodType(dummyMethod newSyntheticValueParams List(tpe, listRef), consRef) @@ -137,83 +61,11 @@ trait PatternNodes extends ast.TreeDSL def normalizedListPattern(pats: List[Tree], tptArg: Type): Tree = pats.foldRight(gen.mkNil)(listFolder(tptArg)) - // An Apply that's a constructor pattern (case class) - // foo match { case C() => true } - object Apply_CaseClass { - def unapply(x: Any) = condOpt(x) { - case x @ Apply(fn, args) if fn.isType => (x.tpe, args) - } - } - - // No-args Apply where fn is not a type - looks like, case object with prefix? - // - // class Pip { - // object opcodes { case object EmptyInstr } - // def bop(x: Any) = x match { case opcodes.EmptyInstr => true } - // } - object Apply_Value { - def unapply(x: Any) = condOpt(x) { - case x @ Apply(fn, Nil) if !fn.isType => (x.tpe.prefix, x.symbol) - } - } - - // No-args Apply for all the other cases - // val Bop = Nil - // def foo(x: Any) = x match { case Bop => true } - object Apply_Function { - def isApplyFunction(t: Apply) = cond(t) { - case Apply_Value(_, _) => true - case x if !isCaseClass(x.tpe) => true - } - def unapply(x: Any) = condOpt(x) { - case x @ Apply(fn, Nil) if isApplyFunction(x) => fn - } - } - - // unapplySeq extractor - // val List(x,y) = List(1,2) - object UnapplySeq { - private object TypeApp { - def unapply(x: Any) = condOpt(x) { - case TypeApply(sel @ Select(stor, nme.unapplySeq), List(tpe)) if stor.symbol eq ListModule => tpe + object UnapplyParamType { + def unapply(x: Tree): Option[Type] = condOpt(unbind(x)) { + case UnApply(Apply(fn, _), _) => fn.tpe match { + case m: MethodType => m.paramTypes.head } } - def unapply(x: UnApply) = condOpt(x) { - case UnApply(Apply(TypeApp(tptArg), _), List(ArrayValue(_, xs))) => (tptArg, xs) - } - } - - // unapply extractor - // val Pair(_,x) = Pair(1,2) - object __UnApply { - private def paramType(fn: Tree) = fn.tpe match { case m: MethodType => m.paramTypes.head } - def unapply(x: Tree) = condOpt(x) { - case Strip(vs, UnApply(Apply(fn, _), args)) => (vs, paramType(fn), args) - } - } - - // break a pattern down into bound variables and underlying tree. - object Strip { - private def strip(t: Tree, syms: List[Symbol] = Nil): (Tree, List[Symbol]) = t match { - case b @ Bind(_, pat) => strip(pat, b.symbol :: syms) - case _ => (t, syms) - } - def unapply(x: Tree): Option[(List[Symbol], Tree)] = Some(strip(x).swap) - } - - object Stripped { - def unapply(x: Tree): Option[Tree] = Some(unbind(x)) - } - - final def definedVars(x: Tree): List[Symbol] = { - def vars(x: Tree): List[Symbol] = x match { - case Apply(_, args) => args flatMap vars - case b @ Bind(_, p) => b.symbol :: vars(p) - case Typed(p, _) => vars(p) // otherwise x @ (_:T) - case UnApply(_, args) => args flatMap vars - case ArrayValue(_, xs) => xs flatMap vars - case x => Nil - } - vars(x) reverse } } diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala index 078c0862e7..3c4ea68b1c 100644 --- a/src/compiler/scala/tools/nsc/matching/Patterns.scala +++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala @@ -83,7 +83,7 @@ trait Patterns extends ast.TreeDSL { // 8.1.5 case class ConstructorPattern(tree: Apply) extends ApplyPattern { - require(fn.isType && isCaseClass(tpe)) + require(fn.isType && this.isCaseClass) override def subpatterns(pats: MatchMatrix#Patterns) = if (pats.isCaseHead) args map Pattern.apply @@ -197,10 +197,25 @@ trait Patterns extends ast.TreeDSL { case x: Star => MiscPattern(x) // XXX case _ => abort("Unknown Tree reached pattern matcher: %s/%s".format(tree, tree.getClass)) } - def unapply(other: Pattern): Option[Tree] = Some(other.tree) + def unapply(other: Any): Option[(Tree, List[Symbol])] = other match { + case x: Tree => unapply(Pattern(x)) + case x: Pattern => Some((x.tree, x.boundVariables)) + case _ => None + } } object UnapplyPattern { + private object UnapplySeq { + private object TypeApp { + def unapply(x: Any) = condOpt(x) { + case TypeApply(sel @ Select(stor, nme.unapplySeq), List(tpe)) if stor.symbol eq ListModule => tpe + } + } + def unapply(x: UnApply) = condOpt(x) { + case UnApply(Apply(TypeApp(tptArg), _), List(ArrayValue(_, xs))) => (tptArg, xs) + } + } + def apply(x: UnApply): Pattern = { x match { case UnapplySeq(_, _) => SequenceExtractorPattern(x) @@ -238,7 +253,6 @@ trait Patterns extends ast.TreeDSL { sealed abstract class ApplyPattern extends Pattern { protected lazy val Apply(fn, args) = tree - private def isCaseClass = tree.tpe.typeSymbol hasFlag Flags.CASE def isConstructorPattern = fn.isType } // trait SimplePattern extends Pattern { @@ -302,6 +316,8 @@ trait Patterns extends ast.TreeDSL { def isSymValid = (sym != null) && (sym != NoSymbol) def isModule = sym.isModule || tpe.termSymbol.isModule + def isCaseClass = tpe.typeSymbol hasFlag Flags.CASE + def isObject = isSymValid && prefix.isStable def setType(tpe: Type): this.type = { tree setType tpe -- cgit v1.2.3