summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan@lightbend.com>2017-01-04 12:00:52 -0800
committerGitHub <noreply@github.com>2017-01-04 12:00:52 -0800
commit18269eabe19a33e627b07a83b43521efafb95ba1 (patch)
tree6eb773359b9323cf0cf56e69e69d64a7244f4f72 /src
parent8367bf68c16d1693796ea4e0584e811cbde60a7f (diff)
parentda986839d17dbbd41877df809e3efed8d63deb4e (diff)
downloadscala-18269eabe19a33e627b07a83b43521efafb95ba1.tar.gz
scala-18269eabe19a33e627b07a83b43521efafb95ba1.tar.bz2
scala-18269eabe19a33e627b07a83b43521efafb95ba1.zip
Merge pull request #5612 from adriaanm/patmat_cleanup
Cleanup in aisle patmat
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/Logic.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala16
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala30
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala18
5 files changed, 38 insertions, 32 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala
index 91777b34d5..40fcceb0bf 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala
@@ -691,7 +691,7 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis {
// if X is mutable.
freshExistentialSubtype(t.tpe)
}
- else trees find (a => a.correspondsStructure(t)(sameValue)) match {
+ else trees find (a => equivalentTree(a, t)) match {
case Some(orig) =>
debug.patmat("unique tp for tree: " + ((orig, orig.tpe)))
orig.tpe
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
index 1331eb6993..c71299b893 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
@@ -85,11 +85,15 @@ trait TreeAndTypeAnalysis extends Debugging {
tp <:< tpImpliedNormalizedToAny
}
- // TODO: improve, e.g., for constants
- def sameValue(a: Tree, b: Tree): Boolean = (a eq b) || ((a, b) match {
- case (_ : Ident, _ : Ident) => a.symbol eq b.symbol
- case _ => false
- })
+ def equivalentTree(a: Tree, b: Tree): Boolean = (a, b) match {
+ case (Select(qual1, _), Select(qual2, _)) => equivalentTree(qual1, qual2) && a.symbol == b.symbol
+ case (Ident(_), Ident(_)) => a.symbol == b.symbol
+ case (Literal(c1), Literal(c2)) => c1 == c2
+ case (This(_), This(_)) => a.symbol == b.symbol
+ case (Apply(fun1, args1), Apply(fun2, args2)) => equivalentTree(fun1, fun2) && args1.corresponds(args2)(equivalentTree)
+ // Those are the only cases we need to handle in the pattern matcher
+ case _ => false
+ }
trait CheckableTreeAndTypeAnalysis {
val typer: Typer
@@ -277,7 +281,7 @@ trait MatchApproximation extends TreeAndTypeAnalysis with ScalaLogic with MatchT
// hashconsing trees (modulo value-equality)
def unique(t: Tree, tpOverride: Type = NoType): Tree =
- trees find (a => a.correspondsStructure(t)(sameValue)) match {
+ trees find (a => equivalentTree(a, t)) match {
case Some(orig) =>
// debug.patmat("unique: "+ (t eq orig, orig))
orig
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala
index cca8d2dbb8..f827043094 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala
@@ -116,8 +116,8 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis {
case _ =>
}
- debug.patmat("sharedPrefix: "+ sharedPrefix)
- debug.patmat("suffix: "+ sharedPrefix)
+ debug.patmat(s"sharedPrefix: $sharedPrefix")
+ debug.patmat(s"suffix: $suffix")
// if the shared prefix contains interesting conditions (!= True)
// and the last of such interesting shared conditions reuses another treemaker's test
// replace the whole sharedPrefix by a ReusingCondTreeMaker
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala
index a2afb76b0e..bf3bc6b26e 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala
@@ -110,25 +110,29 @@ trait MatchTranslation {
// example check: List[Int] <:< ::[Int]
private def extractorStep(): TranslationStep = {
- def paramType = extractor.aligner.wholeType
import extractor.treeMaker
- // chain a type-testing extractor before the actual extractor call
- // it tests the type, checks the outer pointer and casts to the expected type
- // TODO: the outer check is mandated by the spec for case classes, but we do it for user-defined unapplies as well [SPEC]
- // (the prefix of the argument passed to the unapply must equal the prefix of the type of the binder)
- lazy val typeTest = TypeTestTreeMaker(binder, binder, paramType, paramType)(pos, extractorArgTypeTest = true)
- // check whether typetest implies binder is not null,
- // even though the eventual null check will be on typeTest.nextBinder
- // it'll be equal to binder casted to paramType anyway (and the type test is on binder)
- def extraction: TreeMaker = treeMaker(typeTest.nextBinder, typeTest impliesBinderNonNull binder, pos)
// paramType = the type expected by the unapply
// TODO: paramType may contain unbound type params (run/t2800, run/t3530)
- val makers = (
+ val makers = {
+ val paramType = extractor.aligner.wholeType
// Statically conforms to paramType
if (this ensureConformsTo paramType) treeMaker(binder, false, pos) :: Nil
- else typeTest :: extraction :: Nil
- )
+ else {
+ // chain a type-testing extractor before the actual extractor call
+ // it tests the type, checks the outer pointer and casts to the expected type
+ // TODO: the outer check is mandated by the spec for case classes, but we do it for user-defined unapplies as well [SPEC]
+ // (the prefix of the argument passed to the unapply must equal the prefix of the type of the binder)
+ val typeTest = TypeTestTreeMaker(binder, binder, paramType, paramType)(pos, extractorArgTypeTest = true)
+ val binderKnownNonNull = typeTest impliesBinderNonNull binder
+
+ // check whether typetest implies binder is not null,
+ // even though the eventual null check will be on typeTest.nextBinder
+ // it'll be equal to binder casted to paramType anyway (and the type test is on binder)
+ typeTest :: treeMaker(typeTest.nextBinder, binderKnownNonNull, pos) :: Nil
+ }
+ }
+
step(makers: _*)(extractor.subBoundTrees: _*)
}
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala
index e0fcc05de2..3ace61411f 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala
@@ -337,17 +337,15 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging {
def eqTest(pat: Tree, testedBinder: Symbol) = REF(testedBinder) OBJ_EQ pat
def outerTest(testedBinder: Symbol, expectedTp: Type): Tree = {
- val expectedOuter = expectedTp.prefix match {
- case ThisType(clazz) => This(clazz)
- case NoType => mkTRUE // fallback for SI-6183
- case pre => REF(pre.prefix, pre.termSymbol)
+ val expectedPrefix = expectedTp.prefix
+ if (expectedPrefix eq NoType) mkTRUE // fallback for SI-6183
+ else {
+ // ExplicitOuter replaces `Select(q, outerSym) OBJ_EQ expectedPrefix` by `Select(q, outerAccessor(outerSym.owner)) OBJ_EQ expectedPrefix`
+ // if there's an outer accessor, otherwise the condition becomes `true` -- TODO: can we improve needsOuterTest so there's always an outerAccessor?
+ val outerFor = expectedTp.typeSymbol
+ val outerMarker = outerFor.newMethod(vpmName.outer, newFlags = SYNTHETIC | ARTIFACT) setInfo expectedPrefix
+ Select(codegen._asInstanceOf(testedBinder, expectedTp), outerMarker) OBJ_EQ gen.mkAttributedQualifier(expectedPrefix)
}
-
- // ExplicitOuter replaces `Select(q, outerSym) OBJ_EQ expectedPrefix` by `Select(q, outerAccessor(outerSym.owner)) OBJ_EQ expectedPrefix`
- // if there's an outer accessor, otherwise the condition becomes `true` -- TODO: can we improve needsOuterTest so there's always an outerAccessor?
- val outer = expectedTp.typeSymbol.newMethod(vpmName.outer, newFlags = SYNTHETIC | ARTIFACT) setInfo expectedTp.prefix
-
- (Select(codegen._asInstanceOf(testedBinder, expectedTp), outer)) OBJ_EQ expectedOuter
}
}