From b3d9dfa9857aeb937a987536b3e2029d3be0030b Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sun, 18 Aug 2013 15:14:47 -0700 Subject: An unapplySeq-via-String test. There are a lot of details yet to be ironed out when it comes to sequences, but at least here's a little evidence that the basic mechanisms work. --- .../tools/nsc/transform/patmat/MatchCodeGen.scala | 13 +++++++++- .../scala/reflect/internal/Definitions.scala | 3 ++- test/files/run/string-extractor.check | 4 +++ test/files/run/string-extractor.scala | 30 ++++++++++++++++++++++ 4 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 test/files/run/string-extractor.check create mode 100644 test/files/run/string-extractor.scala diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala index 2bd14d923a..8de8eb7d92 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala @@ -65,7 +65,18 @@ trait MatchCodeGen extends Interface { def fun(arg: Symbol, body: Tree): Tree = Function(List(ValDef(arg)), body) 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)) - def drop(tgt: Tree)(n: Int): Tree = gen.mkMethodCall(traversableDropMethod, tgt :: LIT(n) :: Nil) + + 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) + ) // 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/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 19458361e1..4aca81bedd 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -725,7 +725,8 @@ trait Definitions extends api.StandardDefinitions { // this method is about a type member which just happens to be named get. def typeOfMemberNamedGet(tp: Type) = resultOfMatchingMethod(tp, nme.get)() def typeOfMemberNamedHead(tp: Type) = resultOfMatchingMethod(tp, nme.head)() - def typeOfMemberNamedApply(tp: Type) = resultOfMatchingMethod(tp, nme.apply)() + def typeOfMemberNamedApply(tp: Type) = resultOfMatchingMethod(tp, nme.apply)(IntTpe) + def typeOfMemberNamedDrop(tp: Type) = resultOfMatchingMethod(tp, nme.drop)(IntTpe) def typeOfMemberNamedGetOrSelf(tp: Type) = typeOfMemberNamedGet(tp) orElse tp def typesOfSelectors(tp: Type) = getterMemberTypes(tp, productSelectors(tp)) def typesOfCaseAccessors(tp: Type) = getterMemberTypes(tp, tp.typeSymbol.caseFieldAccessors) diff --git a/test/files/run/string-extractor.check b/test/files/run/string-extractor.check new file mode 100644 index 0000000000..7268e44da9 --- /dev/null +++ b/test/files/run/string-extractor.check @@ -0,0 +1,4 @@ +by +BY +oTheClown +nope diff --git a/test/files/run/string-extractor.scala b/test/files/run/string-extractor.scala new file mode 100644 index 0000000000..4fb977df0b --- /dev/null +++ b/test/files/run/string-extractor.scala @@ -0,0 +1,30 @@ +final class StringExtract(val s: String) extends AnyVal { + def isEmpty = (s eq null) || (s == "") + def get = 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): StringExtract = new StringExtract(s drop n) + + override def toString = s +} + +object Bippy { + def unapplySeq(x: Any): StringExtract = new StringExtract("" + x) +} + +object Test { + def f(x: Any) = x match { + case Bippy('B' | 'b', 'O' | 'o', 'B' | 'b', xs @ _*) => xs + case _ => "nope" + } + + def main(args: Array[String]): Unit = { + println(f("Bobby")) + println(f("BOBBY")) + println(f("BoBoTheClown")) + println(f("TomTomTheClown")) + } +} -- cgit v1.2.3