diff options
author | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2014-09-09 15:24:59 +0200 |
---|---|---|
committer | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2014-09-17 18:07:16 +0200 |
commit | 4c62011df6584e4ebe98a012a3b1a438679f8735 (patch) | |
tree | faa11b3b6c67d3e9443562f140a5b6ea576a530e /src/dotty/tools/dotc/transform/PatternMatcher.scala | |
parent | fa5212f8e3fb3be08a92b921b87553b5827b1417 (diff) | |
download | dotty-4c62011df6584e4ebe98a012a3b1a438679f8735.tar.gz dotty-4c62011df6584e4ebe98a012a3b1a438679f8735.tar.bz2 dotty-4c62011df6584e4ebe98a012a3b1a438679f8735.zip |
CommonCodegen for patMat
Diffstat (limited to 'src/dotty/tools/dotc/transform/PatternMatcher.scala')
-rw-r--r-- | src/dotty/tools/dotc/transform/PatternMatcher.scala | 144 |
1 files changed, 140 insertions, 4 deletions
diff --git a/src/dotty/tools/dotc/transform/PatternMatcher.scala b/src/dotty/tools/dotc/transform/PatternMatcher.scala index a6846a405..32655da21 100644 --- a/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -9,17 +9,153 @@ import core.Symbols._ import core.Types._ import core.Constants._ import core.StdNames._ +import core.transform.Erasure.isUnboundedGeneric import typer.ErrorReporting._ import ast.Trees._ +import dotty.tools.dotc.util.Positions.Position +import dotty.tools.dotc.core.Decorators._ +import dotty.tools.dotc.core.Flags + /** This transform eliminates patterns. Right now it's a dummy. * Awaiting the real pattern matcher. */ class PatternMatcher extends MiniPhaseTransform { - import ast.tpd._ + import dotty.tools.dotc.ast.tpd._ + + implicit val ctx: Context = ??? + + def name: String = "patternMatcher" + + /*override def transformCaseDef(tree: CaseDef)(implicit ctx: Context, info: TransformerInfo): Tree = + cpy.CaseDef(tree, Literal(Constant("<eliminated pattern>")), tree.guard, tree.body)*/ + + + /*case Try(block, catches, finalizer) => + treeCopy.Try(tree, transform(block), translator.translateTry(transformTrees(catches).asInstanceOf[List[CaseDef]], tree.tpe, tree.pos), transform(finalizer)) + case _ => super.transform(tree)*/ + /*override def transformMatch(tree: tpd.Match)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = { + case Match(sel, cases) => + val origTp = tree.tpe + // setType origTp intended for CPS -- TODO: is it necessary? + val translated = translator.translateMatch(treeCopy.Match(tree, transform(sel), transformTrees(cases).asInstanceOf[List[CaseDef]])) + try { + localTyper.typed(translated) setType origTp + } catch { + case x: (Types#TypeError) => + // TODO: this should never happen; error should've been reported during type checking + unit.error(tree.pos, "error during expansion of this match (this is a scalac bug).\nThe underlying error was: "+ x.msg) + translated + } + }*/ + + + def translator = { + new OptimizingMatchTranslator/*(localTyper)*/ + } + + class OptimizingMatchTranslator/*(val typer: analyzer.Typer)*/ /*extends MatchTranslator + with MatchOptimizer*/ + + trait Debugging { + + // TODO: the inliner fails to inline the closures to debug.patmat unless the method is nested in an object + object debug { + //val printPatmat = global.settings.Ypatmatdebug.value + final def patmat(s: => String) = /*if (printPatmat) Console.err.*/ + println(s) + final def patmatResult[T](s: => String)(result: T): T = { + /*if (printPatmat) Console.err.*/ + println(s + ": " + result) + result + } + } + } + + trait MatchMonadInterface { + // val typer: Typer + def matchOwner(implicit ctx: Context) = ctx.owner + def pureType(tp: Type): Type = tp + + def reportUnreachable(pos: Position) = { + ctx.warning("unreachable code", pos) + } + def reportMissingCases(pos: Position, counterExamples: List[String]) = { + val ceString = + if (counterExamples.tail.isEmpty) "input: " + counterExamples.head + else "inputs: " + counterExamples.mkString(", ") + + ctx.warning("match may not be exhaustive.\nIt would fail on the following "+ ceString, pos) + } + } + + trait CodegenCore extends MatchMonadInterface { + private var ctr = 0 + def freshName(prefix: String) = ctx.freshName(prefix).toTermName + + // assert(owner ne null); assert(owner ne NoSymbol) + def freshSym(pos: Position, tp: Type = NoType, prefix: String = "x") = + ctx.newSymbol(ctx.owner, freshName(prefix) ,Flags.Synthetic, tp, coord = pos) + + def newSynthCaseLabel(name: String) = ??? + //NoSymbol.newLabel(freshName(name), NoPosition) setFlag treeInfo.SYNTH_CASE_FLAGS + + // codegen relevant to the structure of the translation (how extractors are combined) + trait AbsCodegen { + def matcher(scrut: Tree, scrutSym: Symbol, restpe: Type)(cases: List[Casegen => Tree], matchFailGen: Option[Tree => Tree]): Tree + + // local / context-free + def _asInstanceOf(b: Symbol, tp: Type): Tree + def _equals(checker: Tree, binder: Symbol): Tree + def _isInstanceOf(b: Symbol, tp: Type): Tree + def drop(tgt: Tree)(n: Int): Tree + def index(tgt: Tree)(i: Int): Tree + def mkZero(tp: Type): Tree + def tupleSel(binder: Symbol)(i: Int): Tree + } + + // structure + trait Casegen extends AbsCodegen { + def one(res: Tree): Tree + + def flatMap(prev: Tree, b: Symbol, next: Tree): Tree + def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, next: Tree): Tree + def flatMapGuard(cond: Tree, next: Tree): Tree + def ifThenElseZero(c: Tree, thenp: Tree): Tree = + If(c, thenp, zero) + protected def zero: Tree + } + + def codegen: AbsCodegen + + abstract class CommonCodegen extends AbsCodegen { + def fun(arg: TermSymbol, body: Tree): Tree = + DefDef(arg, body) + + def tupleSel(binder: Symbol)(i: Int): Tree = ref(binder).select(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.appliedTo(Literal(Constant(i))) + + // 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 = tgt.select(nme.drop).appliedTo(Literal(Constant(n))) + def callRuntime = ref(ctx.definitions.traversableDropMethod).appliedTo(tgt, Literal(Constant(n))) + + def needsRuntime = (tgt.tpe ne null) && tgt.tpe.baseTypeRef(ctx.definitions.SeqType.classSymbol).member(nme.drop).exists /*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.select(defn.Any_equals).appliedTo(ref(binder)) - override def phaseName: String = "patternMatcher" + // the force is needed mainly to deal with the GADT typing hack (we can't detect it otherwise as tp nor pt need contain an abstract type, we're just casting wildly) + def _asInstanceOf(b: Symbol, tp: Type): Tree = if (b.info <:< tp) ref(b) else ref(b).select(defn.Any_asInstanceOf).appliedToType(tp) + def _isInstanceOf(b: Symbol, tp: Type): Tree = ref(b).select(defn.Any_isInstanceOf).appliedToType(tp) - override def transformCaseDef(tree: CaseDef)(implicit ctx: Context, info: TransformerInfo): Tree = - cpy.CaseDef(tree)(Literal(Constant("<eliminated pattern>")), tree.guard, tree.body) + def mkZero(tp: Type): Tree = initValue(tp) + } + } }
\ No newline at end of file |