Skip to content

Commit

Permalink
simplify dependencies between patmat components, remove self types
Browse files Browse the repository at this point in the history
  • Loading branch information
adriaanm committed Mar 4, 2013
1 parent 5d54cf9 commit ebaa34e
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 41 deletions.
9 changes: 7 additions & 2 deletions src/compiler/scala/tools/nsc/transform/patmat/Logic.scala
Expand Up @@ -287,7 +287,11 @@ trait Logic extends Debugging {
def findModelFor(f: Formula): Model
def findAllModelsFor(f: Formula): List[Model]
}
}

// naive CNF translation and simple DPLL solver
trait SimpleSolver extends Logic {
import PatternMatchingStats._
trait CNF extends PropositionalLogic {

/** Override Array creation for efficiency (to not go through reflection). */
Expand Down Expand Up @@ -397,7 +401,8 @@ trait Logic extends Debugging {
}
}

trait DPLLSolver extends CNF {
// simple solver using DPLL
trait Solver extends CNF {
// a literal is a (possibly negated) variable
def Lit(sym: Sym, pos: Boolean = true) = new Lit(sym, pos)
class Lit(val sym: Sym, val pos: Boolean) {
Expand Down Expand Up @@ -516,7 +521,7 @@ trait Logic extends Debugging {
}
}

trait ScalaLogic extends Logic { self: PatternMatching =>
trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis {
trait TreesAndTypesDomain extends PropositionalLogic with CheckableTreeAndTypeAnalysis {
type Type = global.Type
type Tree = global.Tree
Expand Down
23 changes: 17 additions & 6 deletions src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
Expand Up @@ -125,7 +125,7 @@ trait TreeAndTypeAnalysis extends Debugging {
}
}

trait MatchAnalysis extends TreeAndTypeAnalysis { self: PatternMatching =>
trait MatchAnalysis extends TreeAndTypeAnalysis with ScalaLogic with MatchTreeMaking {
import PatternMatchingStats._
import global.{Tree, Type, Symbol, CaseDef, atPos,
Select, Block, ThisType, SingleType, NoPrefix, NoType, definitions, needsOuterTest,
Expand All @@ -141,7 +141,7 @@ trait MatchAnalysis extends TreeAndTypeAnalysis { self: PatternMatching =>
* Represent a match as a formula in propositional logic that encodes whether the match matches (abstractly: we only consider types)
*
*/
trait TreeMakerApproximation extends TreeMakers with PropositionalLogic with TreesAndTypesDomain with CheckableTreeAndTypeAnalysis { self: CodegenCore =>
trait TreeMakerApproximation extends TreeMakers with TreesAndTypesDomain {
object Test {
var currId = 0
}
Expand Down Expand Up @@ -348,7 +348,7 @@ trait MatchAnalysis extends TreeAndTypeAnalysis { self: PatternMatching =>
}
}

trait SymbolicMatchAnalysis extends TreeMakerApproximation { self: CodegenCore =>
trait MatchAnalyses extends TreeMakerApproximation {
def uncheckedWarning(pos: Position, msg: String) = global.currentUnit.uncheckedWarning(pos, msg)
def warn(pos: Position, ex: AnalysisBudget.Exception, kind: String) = uncheckedWarning(pos, s"Cannot check match for $kind.\n${ex.advice}")

Expand Down Expand Up @@ -498,7 +498,7 @@ trait MatchAnalysis extends TreeAndTypeAnalysis { self: PatternMatching =>

// a way to construct a value that will make the match fail: a constructor invocation, a constant, an object of some type)
class CounterExample {
protected[SymbolicMatchAnalysis] def flattenConsArgs: List[CounterExample] = Nil
protected[MatchAnalyses] def flattenConsArgs: List[CounterExample] = Nil
def coveredBy(other: CounterExample): Boolean = this == other || other == WildcardExample
}
case class ValueExample(c: ValueConst) extends CounterExample { override def toString = c.toString }
Expand All @@ -513,11 +513,11 @@ trait MatchAnalysis extends TreeAndTypeAnalysis { self: PatternMatching =>
}
}
case class ListExample(ctorArgs: List[CounterExample]) extends CounterExample {
protected[SymbolicMatchAnalysis] override def flattenConsArgs: List[CounterExample] = ctorArgs match {
protected[MatchAnalyses] override def flattenConsArgs: List[CounterExample] = ctorArgs match {
case hd :: tl :: Nil => hd :: tl.flattenConsArgs
case _ => Nil
}
protected[SymbolicMatchAnalysis] lazy val elems = flattenConsArgs
protected[MatchAnalyses] lazy val elems = flattenConsArgs

override def coveredBy(other: CounterExample): Boolean =
other match {
Expand Down Expand Up @@ -691,5 +691,16 @@ trait MatchAnalysis extends TreeAndTypeAnalysis { self: PatternMatching =>
// this is the variable we want a counter example for
VariableAssignment(scrutVar).toCounterExample()
}

def analyzeCases(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type, unchecked: Boolean): Unit = {
unreachableCase(prevBinder, cases, pt) foreach { caseIndex =>
reportUnreachable(cases(caseIndex).last.pos)
}
if (!unchecked) {
val counterExamples = exhaustive(prevBinder, cases, pt)
if (counterExamples.nonEmpty)
reportMissingCases(prevBinder.pos, counterExamples)
}
}
}
}
Expand Up @@ -17,7 +17,7 @@ import scala.reflect.internal.util.NoPosition
* We have two modes in which to emit trees: optimized (the default)
* and pure (aka "virtualized": match is parametric in its monad).
*/
trait MatchCodeGen { self: PatternMatching =>
trait MatchCodeGen extends Interface {
import PatternMatchingStats._
import global.{nme, treeInfo, definitions, gen, Tree, Type, Symbol, NoSymbol,
appliedType, NoType, MethodType, newTermName, Name,
Expand Down
Expand Up @@ -19,7 +19,7 @@ import scala.reflect.internal.util.NoPosition
*
* TODO: split out match analysis
*/
trait MatchOptimization { self: PatternMatching =>
trait MatchOptimization extends MatchTreeMaking with MatchAnalysis {
import PatternMatchingStats._
import global.{Tree, Type, Symbol, NoSymbol, CaseDef, atPos,
ConstantType, Literal, Constant, gen, EmptyTree,
Expand Down Expand Up @@ -205,7 +205,7 @@ trait MatchOptimization { self: PatternMatching =>


//// DCE
trait DeadCodeElimination extends TreeMakers { self: CodegenCore =>
trait DeadCodeElimination extends TreeMakers {
// TODO: non-trivial dead-code elimination
// e.g., the following match should compile to a simple instanceof:
// case class Ident(name: String)
Expand All @@ -217,7 +217,7 @@ trait MatchOptimization { self: PatternMatching =>
}

//// SWITCHES -- TODO: operate on Tests rather than TreeMakers
trait SwitchEmission extends TreeMakers with OptimizedMatchMonadInterface { self: CodegenCore =>
trait SwitchEmission extends TreeMakers with OptimizedMatchMonadInterface {
import treeInfo.isGuardedCase

abstract class SwitchMaker {
Expand Down Expand Up @@ -589,25 +589,11 @@ trait MatchOptimization { self: PatternMatching =>
}
}




trait MatchOptimizations extends CommonSubconditionElimination
with DeadCodeElimination
with SwitchEmission
with OptimizedCodegen
with SymbolicMatchAnalysis
with DPLLSolver { self: TreeMakers =>
override def optimizeCases(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type, unchecked: Boolean): (List[List[TreeMaker]], List[Tree]) = {
unreachableCase(prevBinder, cases, pt) foreach { caseIndex =>
reportUnreachable(cases(caseIndex).last.pos)
}
if (!unchecked) {
val counterExamples = exhaustive(prevBinder, cases, pt)
if (counterExamples.nonEmpty)
reportMissingCases(prevBinder.pos, counterExamples)
}

with OptimizedCodegen {
override def optimizeCases(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type): (List[List[TreeMaker]], List[Tree]) = {
val optCases = doCSE(prevBinder, doDCE(prevBinder, cases, pt), pt)
val toHoist = (
for (treeMakers <- optCases)
Expand Down
Expand Up @@ -24,7 +24,7 @@ trait MatchTranslation { self: PatternMatching =>
repeatedToSeq, isRepeatedParamType, getProductArgs}
import global.analyzer.{ErrorUtils, formalTypes}

trait MatchTranslator extends MatchMonadInterface { self: TreeMakers with CodegenCore =>
trait MatchTranslator extends TreeMakers {
import typer.context

// Why is it so difficult to say "here's a name and a context, give me any
Expand Down
Expand Up @@ -18,7 +18,7 @@ import scala.reflect.internal.util.NoPosition
* The IR is mostly concerned with sequencing, substitution, and rendering all necessary conditions,
* mostly agnostic to whether we're in optimized/pure (virtualized) mode.
*/
trait MatchTreeMaking { self: PatternMatching =>
trait MatchTreeMaking extends MatchCodeGen with Debugging {
import PatternMatchingStats._
import global.{Tree, Type, Symbol, CaseDef, atPos, settings,
Select, Block, ThisType, SingleType, NoPrefix, NoType, needsOuterTest,
Expand All @@ -30,9 +30,9 @@ trait MatchTreeMaking { self: PatternMatching =>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// the making of the trees
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
trait TreeMakers extends TypedSubstitution { self: CodegenCore =>
def optimizeCases(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type, unchecked: Boolean): (List[List[TreeMaker]], List[Tree]) =
(cases, Nil)
trait TreeMakers extends TypedSubstitution with CodegenCore {
def optimizeCases(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type): (List[List[TreeMaker]], List[Tree])
def analyzeCases(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type, unchecked: Boolean): Unit

def emitSwitch(scrut: Tree, scrutSym: Symbol, cases: List[List[TreeMaker]], pt: Type, matchFailGenOverride: Option[Tree => Tree], unchecked: Boolean): Option[Tree] =
None
Expand Down Expand Up @@ -550,7 +550,9 @@ trait MatchTreeMaking { self: PatternMatching =>
}) None
else matchFailGen

val (cases, toHoist) = optimizeCases(scrutSym, casesNoSubstOnly, pt, unchecked)
analyzeCases(scrutSym, casesNoSubstOnly, pt, unchecked)

val (cases, toHoist) = optimizeCases(scrutSym, casesNoSubstOnly, pt)

val matchRes = codegen.matcher(scrut, scrutSym, pt)(cases map combineExtractors, synthCatchAll)

Expand Down
Expand Up @@ -34,13 +34,14 @@ import scala.reflect.internal.util.Position
* - recover GADT typing by locally inserting implicit witnesses to type equalities derived from the current case, and considering these witnesses during subtyping (?)
* - recover exhaustivity/unreachability of user-defined extractors by partitioning the types they match on using an HList or similar type-level structure
*/
trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
trait PatternMatching extends Transform with TypingTransformers
with Debugging
with Interface
with MatchTranslation
with MatchTreeMaking
with MatchCodeGen
with ScalaLogic
with SimpleSolver
with MatchAnalysis
with MatchOptimization {
import global._
Expand Down Expand Up @@ -78,23 +79,28 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
}
}

class PureMatchTranslator(val typer: analyzer.Typer, val matchStrategy: Tree) extends MatchTranslator with TreeMakers with PureCodegen
class OptimizingMatchTranslator(val typer: analyzer.Typer) extends MatchTranslator with TreeMakers with MatchOptimizations
class PureMatchTranslator(val typer: analyzer.Typer, val matchStrategy: Tree) extends MatchTranslator with PureCodegen {
def optimizeCases(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type) = (cases, Nil)
def analyzeCases(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type, unchecked: Boolean): Unit = {}
}

class OptimizingMatchTranslator(val typer: analyzer.Typer) extends MatchTranslator
with MatchOptimizations
with MatchAnalyses
with Solver
}

trait HasGlobal {
trait Debugging {
val global: Global
}

trait Debugging extends HasGlobal {
// 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
@inline final def patmat(s: => String) = if (printPatmat) println(s)
}
}

trait Interface { self: ast.TreeDSL with HasGlobal =>
trait Interface extends ast.TreeDSL {
import global.{newTermName, analyzer, Type, ErrorType, Symbol, Tree}
import analyzer.Typer

Expand Down

0 comments on commit ebaa34e

Please sign in to comment.