From 6d4e71c111226591a4eeb5b77efac689ef1dd79a Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sun, 18 Aug 2013 15:36:18 -0700 Subject: Refinement of name-based unapplySeq. Can't finnesse the drop method. Call it blindly for now, even though in the long run you won't have to write drop. --- .../tools/nsc/transform/patmat/MatchCodeGen.scala | 22 ++++++++-------- test/files/run/string-extractor.check | 5 ++++ test/files/run/string-extractor.scala | 30 ++++++++++++++++++++++ 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala index 8de8eb7d92..1b49b335c8 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala @@ -66,17 +66,17 @@ trait MatchCodeGen extends Interface { def tupleSel(binder: Symbol)(i: Int): Tree = (REF(binder) DOT nme.productAccessorName(i)) // make tree that accesses the i'th component of the tuple referenced by binder def index(tgt: Tree)(i: Int): Tree = tgt APPLY (LIT(i)) - private def definesDrop(tgt: Tree) = (tgt.tpe ne null) && (typeOfMemberNamedDrop(tgt.tpe) != NoType) - - // Right now this calls a direct drop member if it sees one, otherwise calls - // into the drop helper in ScalaRunTime. You should not actually have to write - // a method called drop for things to work, it's just not finished yet. - def drop(tgt: Tree)(n: Int): Tree = ( - if (definesDrop(tgt)) - Apply(Select(tgt, nme.drop), LIT(n) :: Nil) - else - gen.mkMethodCall(traversableDropMethod, tgt :: LIT(n) :: Nil) - ) + // Right now this blindly calls drop on the result of the unapplySeq + // unless it verifiably has no drop method (this is the case in particular + // with Array.) You should not actually have to write a method called drop + // for name-based matching, but this was an expedient route for the basics. + def drop(tgt: Tree)(n: Int): Tree = { + def callDirect = fn(tgt, nme.drop, LIT(n)) + def callRuntime = Apply(REF(traversableDropMethod), tgt :: LIT(n) :: Nil) + def needsRuntime = (tgt.tpe ne null) && (typeOfMemberNamedDrop(tgt.tpe) == NoType) + + if (needsRuntime) callRuntime else callDirect + } // NOTE: checker must be the target of the ==, that's the patmat semantics for ya def _equals(checker: Tree, binder: Symbol): Tree = checker MEMBER_== REF(binder) diff --git a/test/files/run/string-extractor.check b/test/files/run/string-extractor.check index 7268e44da9..47f3722c86 100644 --- a/test/files/run/string-extractor.check +++ b/test/files/run/string-extractor.check @@ -2,3 +2,8 @@ by BY oTheClown nope +1: ob +2: obby +2: OBBY +3: BOBO +3: TomTomTheClown diff --git a/test/files/run/string-extractor.scala b/test/files/run/string-extractor.scala index 4fb977df0b..c0fe911ff3 100644 --- a/test/files/run/string-extractor.scala +++ b/test/files/run/string-extractor.scala @@ -11,9 +11,26 @@ final class StringExtract(val s: String) extends AnyVal { override def toString = s } +final class ThreeStringExtract(val s: String) extends AnyVal { + def isEmpty = (s eq null) || (s == "") + def get: (List[Int], Double, ThreeStringExtract) = ((s.length :: Nil, s.length.toDouble, this)) + def length = s.length + def lengthCompare(n: Int) = s.length compare n + def apply(idx: Int): Char = s charAt idx + def head: Char = s charAt 0 + def tail: String = s drop 1 + def drop(n: Int): ThreeStringExtract = new ThreeStringExtract(s drop n) + + override def toString = s +} + + object Bippy { def unapplySeq(x: Any): StringExtract = new StringExtract("" + x) } +object TripleBippy { + def unapplySeq(x: Any): ThreeStringExtract = new ThreeStringExtract("" + x) +} object Test { def f(x: Any) = x match { @@ -21,10 +38,23 @@ object Test { case _ => "nope" } + def g(x: Any): String = x match { + case TripleBippy(3 :: Nil, 3.0, 'b', chars @ _*) => "1: " + chars + case TripleBippy(5 :: Nil, 5.0, 'b' | 'B', chars @ _*) => "2: " + chars + case TripleBippy(_, _, chars @ _*) => "3: " + chars + case _ => "nope" + } + def main(args: Array[String]): Unit = { println(f("Bobby")) println(f("BOBBY")) println(f("BoBoTheClown")) println(f("TomTomTheClown")) + + println(g("bob")) + println(g("bobby")) + println(g("BOBBY")) + println(g("BOBO")) + println(g("TomTomTheClown")) } } -- cgit v1.2.3