diff options
author | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2014-09-09 16:01:13 +0200 |
---|---|---|
committer | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2014-09-17 18:07:17 +0200 |
commit | 278d6cbe2b77241ef1dcb6b4208d5c041ca3c72b (patch) | |
tree | 0eee1fca8333c823540110f0451e240b05a1e2f6 /src/dotty/tools/dotc/transform/PatternMatcher.scala | |
parent | 00dbbe65d4e6653220977ce466b728f70c6de477 (diff) | |
download | dotty-278d6cbe2b77241ef1dcb6b4208d5c041ca3c72b.tar.gz dotty-278d6cbe2b77241ef1dcb6b4208d5c041ca3c72b.tar.bz2 dotty-278d6cbe2b77241ef1dcb6b4208d5c041ca3c72b.zip |
Everything except unapplySeq doesn't explode.
That doesn't mean that it works.
Diffstat (limited to 'src/dotty/tools/dotc/transform/PatternMatcher.scala')
-rw-r--r-- | src/dotty/tools/dotc/transform/PatternMatcher.scala | 115 |
1 files changed, 47 insertions, 68 deletions
diff --git a/src/dotty/tools/dotc/transform/PatternMatcher.scala b/src/dotty/tools/dotc/transform/PatternMatcher.scala index aed69352d..dff6d7b6a 100644 --- a/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -34,64 +34,39 @@ import scala.reflect.internal.util.Collections class PatternMatcher extends MiniPhaseTransform { import dotty.tools.dotc.ast.tpd._ + + /** List of names of phases that should precede this phase */ + override def runsAfter: Set[String] = Set("elimrepeated") + def name: String = "patternMatcher" var _id = 0 override def transformMatch(tree: tpd.Match)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = { - val origTp = tree.tpe - // setType origTp intended for CPS -- TODO: is it necessary? val translated = new Translator()(ctx).translator.translateMatch(tree) translated } class Translator(implicit ctx: Context) { - def translator = { new OptimizingMatchTranslator/*(localTyper)*/ } class OptimizingMatchTranslator extends MatchOptimizer/*(val typer: analyzer.Typer)*/ with MatchTranslator - 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.*/ - ctx.debuglog(s) - final def patmatResult[T](s: => String)(result: T): T = { - /*if (printPatmat) Console.err.*/ - ctx.debuglog(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) + ctx.newSymbol(ctx.owner, ctx.freshName(prefix).toTermName, Flags.Synthetic, tp, coord = pos) def newSynthCaseLabel(name: String, tpe:Type) = ctx.newSymbol(ctx.owner, ctx.freshName(name).toTermName, Flags.Label, tpe) //NoSymbol.newLabel(freshName(name), NoPosition) setFlag treeInfo.SYNTH_CASE_FLAGS @@ -175,12 +150,6 @@ class PatternMatcher extends MiniPhaseTransform { // since about half of the typedSubst's end up being no-ops, the check below shaves off 5% of the time spent in typedSubst /*if (!tree.exists { case i@Ident(_) => from contains i.symbol case _ => false}) tree else*/ (new TreeMap { - /*private def typedIfOrigTyped(to: Tree, origTp: Type): Tree = - if (origTp == null || origTp == NoType) to - // important: only type when actually substing and when original tree was typed - // (don't need to use origTp as the expected type, though, and can't always do this anyway due to unknown type params stemming from polymorphic extractors) - else typer.typed(to)*/ - override def transform(tree: Tree)(implicit ctx: Context): Tree = { def subst(from: List[Symbol], to: List[Tree]): Tree = if (from.isEmpty) tree @@ -341,11 +310,11 @@ class PatternMatcher extends MiniPhaseTransform { def analyzeCases(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type, suppression: Suppression): Unit = {} def emitSwitch(scrut: Tree, scrutSym: Symbol, cases: List[List[TreeMaker]], pt: Type, matchFailGenOverride: Option[Symbol => Tree], unchecked: Boolean): Option[Tree] = - None + None // todo // for catch (no need to customize match failure) def emitTypeSwitch(bindersAndCases: List[(Symbol, List[TreeMaker])], pt: Type): Option[List[CaseDef]] = - None + None // todo abstract class TreeMaker{ def pos: Position @@ -645,7 +614,7 @@ class PatternMatcher extends MiniPhaseTransform { } } - object pureTypeTestChecker extends TypeTestCondStrategy { + /*object pureTypeTestChecker extends TypeTestCondStrategy { type Result = Boolean def typeTest(testedBinder: Symbol, expectedTp: Type): Result = true @@ -656,7 +625,7 @@ class PatternMatcher extends MiniPhaseTransform { def eqTest(pat: Tree, testedBinder: Symbol): Result = false def and(a: Result, b: Result): Result = false // we don't and type tests, so the conjunction must include at least one false def tru = true - } + }*/ def nonNullImpliedByTestChecker(binder: Symbol) = new TypeTestCondStrategy { type Result = Boolean @@ -802,9 +771,13 @@ class PatternMatcher extends MiniPhaseTransform { val res = codegen._asInstanceOf(testedBinder, nextBinderTp) // is this purely a type test, e.g. no outer check, no equality tests (used in switch emission) - def isPureTypeTest = renderCondition(pureTypeTestChecker) + //def isPureTypeTest = renderCondition(pureTypeTestChecker) - def impliesBinderNonNull(binder: Symbol) = renderCondition(nonNullImpliedByTestChecker(binder)) + def impliesBinderNonNull(binder: Symbol):Boolean = + // @odersky: scalac is able to infer in this method that nonNullImpliedByTestChecker.Result, + // dotty instead infers type projection TreeMakers.this.TypeTestTreeMaker.TypeTestCondStrategy#Result + // which in turn doesn't typecheck in this method. Can you please explain why? + renderCondition(nonNullImpliedByTestChecker(binder)).asInstanceOf[Boolean] override def toString = "TT"+((expectedTp, testedBinder.name, nextBinderTp)) } @@ -836,7 +809,7 @@ class PatternMatcher extends MiniPhaseTransform { ((casegen: Casegen) => combineExtractors(altTreeMakers :+ TrivialTreeMaker(casegen.one(Literal(Constant(true)))))(casegen)) ) - val findAltMatcher = codegenAlt.matcher(EmptyTree, NoSymbol, ctx.definitions.BooleanType)(combinedAlts, Some(x => Literal(Constant(false)))) + val findAltMatcher = codegenAlt.matcher(EmptyTree, NoSymbol, ctx.definitions.BooleanType)(combinedAlts, Some((x: Symbol) => Literal(Constant(false)))) codegenAlt.ifThenElseZero(findAltMatcher, substitution(next)) } } @@ -854,7 +827,6 @@ class PatternMatcher extends MiniPhaseTransform { def combineExtractors(treeMakers: List[TreeMaker])(casegen: Casegen): Tree = treeMakers.foldRight(EmptyTree: Tree)((a, b) => a.chainBefore(b)(casegen)) - def removeSubstOnly(makers: List[TreeMaker]) = makers filterNot (_.isInstanceOf[SubstOnlyTreeMaker]) // a foldLeft to accumulate the localSubstitution left-to-right @@ -920,7 +892,7 @@ class PatternMatcher extends MiniPhaseTransform { val (cases, toHoist) = optimizeCases(scrutSym, casesNoSubstOnly, pt) - val matchRes = codegen.matcher(scrut, scrutSym, pt)(cases map combineExtractors, synthCatchAll) + val matchRes = codegen.matcher(scrut, scrutSym, pt)(cases.map(x => combineExtractors(x) _), synthCatchAll) if (toHoist isEmpty) matchRes else Block(toHoist, matchRes) } else { @@ -1043,6 +1015,7 @@ class PatternMatcher extends MiniPhaseTransform { case TypeBound(tpe) => tpe case tree => tree.tpe } + def glbWith(other: Type) = ctx.typeComparer.glb(tpe :: other :: Nil)// .normalize object SymbolAndTypeBound { @@ -1086,7 +1059,7 @@ class PatternMatcher extends MiniPhaseTransform { // 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) + 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) @@ -1247,7 +1220,7 @@ class PatternMatcher extends MiniPhaseTransform { // there's no need to check the scrutinee for null -- "throw null" becomes "throw new NullPointerException" // try to simplify to a type-based switch, or fall back to a catch-all case that runs a normal pattern match // unlike translateMatch, we type our result before returning it - def translateTry(caseDefs: List[CaseDef], pt: Type, pos: Position): List[CaseDef] = + /*def translateTry(caseDefs: List[CaseDef], pt: Type, pos: Position): List[CaseDef] = // if they're already simple enough to be handled by the back-end, we're done if (caseDefs forall isCatchCase) caseDefs else { @@ -1274,13 +1247,13 @@ class PatternMatcher extends MiniPhaseTransform { CaseDef( Bind(exSym, Ident(??? /*nme.WILDCARD*/)), // TODO: does this need fixing upping? EmptyTree, - combineCasesNoSubstOnly(ref(exSym), scrutSym, casesNoSubstOnly, pt, matchOwner, Some(scrut => Throw(ref(exSym)))) + combineCasesNoSubstOnly(ref(exSym), scrutSym, casesNoSubstOnly, pt, matchOwner, Some((scrut: Symbol) => Throw(ref(exSym)))) ) ) } /*typer.typedCases(*/catches/*, ctx.definitions.ThrowableType, WildcardType)*/ - } + }*/ /** The translation of `pat if guard => body` has two aspects: * 1) the substitution due to the variables bound by patterns @@ -1381,17 +1354,19 @@ class PatternMatcher extends MiniPhaseTransform { // TODO: check unargs == args def apply(tree: Tree, binder: Symbol): ExtractorCall = tree match { case UnApply(unfun, implicits, args) => - val synth = if(implicits.isEmpty) unfun.appliedTo(ref(binder)) else unfun.appliedTo(ref(binder)).appliedToArgs(implicits) - new ExtractorCallRegular(alignPatterns(synth), synth, args, tree.tpe) // extractor + val synth = if (implicits.isEmpty) unfun.appliedTo(ref(binder)) else unfun.appliedTo(ref(binder)).appliedToArgs(implicits) + new ExtractorCallRegular(alignPatterns(tree, synth.tpe), synth, args, synth.tpe) // extractor case Typed(UnApply(unfun, implicits, args), tpt) => - val synth = /*Typed(*/if(implicits.isEmpty) unfun.appliedTo(ref(binder)) else unfun.appliedTo(ref(binder)).appliedToArgs(implicits)//, tpt) - new ExtractorCallRegular(alignPatterns(synth), synth, args, tree.tpe) // extractor - case Apply(fun, args) => new ExtractorCallProd(alignPatterns(tree), fun, args, fun.tpe) // case class + val synth = /*Typed(*/ if (implicits.isEmpty) unfun.appliedTo(ref(binder)) else unfun.appliedTo(ref(binder)).appliedToArgs(implicits) //, tpt) + new ExtractorCallRegular(alignPatterns(tree, synth.tpe), synth, args, tree.tpe) // extractor + case Apply(fun, args) => new ExtractorCallProd(alignPatterns(tree, tree.tpe), fun, args, fun.tpe) // case class } } abstract class ExtractorCall(val aligner: PatternAligned) { + import aligner._ + def args: List[Tree] // don't go looking for selectors if we only expect one pattern @@ -1402,9 +1377,12 @@ class PatternMatcher extends MiniPhaseTransform { case _ => or } - def typeOfMemberNamedGet(tp: Type) = typeArgOfBaseTypeOr(tp, defn.OptionClass)(tp.member(nme.get).info) - - def resultInMonad = resultType //if (isBool) defn.UnitType else typeOfMemberNamedGet(resultType) + def resultInMonad = if (aligner.isBool) defn.UnitType else { + val getTp = extractorMemberType(resultType, nme.get) + if ((extractorMemberType(resultType, nme.isDefined) isRef defn.BooleanClass) && getTp.exists) + getTp + else resultType + } def resultType: Type /** Create the TreeMaker that embodies this extractor call @@ -1444,8 +1422,8 @@ class PatternMatcher extends MiniPhaseTransform { // codegen.drop(seqTree(binder))(nbIndexingIndices)))).toList protected def seqTree(binder: Symbol) = tupleSel(binder)(firstIndexingBinder + 1) protected def tupleSel(binder: Symbol)(i: Int): Tree = { - val accessors = if(defn.isProductSubType(binder.info)) productSelectors(binder.info) else binder.info.caseAccessors - if (accessors.isDefinedAt(i-1)) ref(binder).select(accessors(i-1)) + val accessors = if (defn.isProductSubType(binder.info)) productSelectors(binder.info) else binder.info.caseAccessors + if (accessors.isDefinedAt(i - 1)) ref(binder).select(accessors(i - 1)) else codegen.tupleSel(binder)(i) // this won't type check for case classes, as they do not inherit ProductN } @@ -1778,7 +1756,7 @@ class PatternMatcher extends MiniPhaseTransform { } def typeOfMemberNamedHead(tpe: Type): Type = tpe.select(nme.head) def typeOfMemberNamedApply(tpe: Type): Type = tpe.select(nme.apply) - def typeOfMemberNamedGet(tpe: Type): Type = tpe.select(nme.get) + def elementTypeOf(tpe: Type) = { val seq = tpe //repeatedToSeq(tpe) @@ -1823,7 +1801,7 @@ class PatternMatcher extends MiniPhaseTransform { * Unfortunately the MethodType does not carry the information of whether * it was unapplySeq, so we have to funnel that information in separately. */ - def unapplyMethodTypes(tree:Tree, fun: Tree, args:List[Tree], isSeq: Boolean): Extractor = { + def unapplyMethodTypes(tree:Tree, fun: Tree, args:List[Tree], resultType:Type, isSeq: Boolean): Extractor = { _id = _id + 1 if(_id == 3) println("here") @@ -1843,6 +1821,7 @@ class PatternMatcher extends MiniPhaseTransform { } } } + object alignPatterns extends ScalacPatternExpander { /** Converts a T => (A, B, C) extractor to a T => ((A, B, CC)) extractor. */ @@ -1872,7 +1851,7 @@ class PatternMatcher extends MiniPhaseTransform { aligned } - def apply(tree:Tree, sel: Tree, args: List[Tree]): Aligned = { + def apply(tree:Tree, sel: Tree, args: List[Tree], resultType: Type): Aligned = { val fn = sel match { case Unapplied(fn) => fn case _ => sel @@ -1881,8 +1860,8 @@ class PatternMatcher extends MiniPhaseTransform { val isSeq = sel.symbol.name == nme.unapplySeq val isUnapply = sel.symbol.name == nme.unapply val extractor = sel.symbol.name match { - case nme.unapply => unapplyMethodTypes(tree, /*fn*/sel, args, isSeq = false) - case nme.unapplySeq => unapplyMethodTypes(tree, /*fn*/sel, args, isSeq = true) + case nme.unapply => unapplyMethodTypes(tree, /*fn*/sel, args, resultType, isSeq = false) + case nme.unapplySeq => unapplyMethodTypes(tree, /*fn*/sel, args, resultType, isSeq = true) case _ => applyMethodTypes(/*fn*/sel.tpe) } @@ -1901,10 +1880,10 @@ class PatternMatcher extends MiniPhaseTransform { validateAligned(fn, Aligned(patterns, normalizedExtractor)) } - def apply(tree: Tree): Aligned = tree match { - case Typed(tree, _) => apply(tree) - case Apply(fn, args) => apply(tree, fn, args) - case UnApply(fn, implicits, args) => apply(tree, fn, args) + def apply(tree: Tree, resultType: Type): Aligned = tree match { + case Typed(tree, _) => apply(tree, resultType) + case Apply(fn, args) => apply(tree, fn, args, resultType) + case UnApply(fn, implicits, args) => apply(tree, fn, args, resultType) } } } |