Skip to content

Commit 08392d3

Browse files
committed
Comments and some polishing for PatternMatcher
1 parent ec3019e commit 08392d3

File tree

1 file changed

+54
-15
lines changed

1 file changed

+54
-15
lines changed

src/dotty/tools/dotc/transform/PatternMatcher.scala

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,10 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
4848

4949
private var _id = 0 // left for debuging
5050

51+
// TODO: tpd._ is imported. Why not write (tree: Match)? (Same for the other occurrences of tpd below).
5152
override def transformMatch(tree: tpd.Match)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
52-
val translated = new Translator()(ctx).translator.translateMatch(tree)
53-
translated.ensureConforms(tree.tpe)
53+
val translated = new Translator()(ctx).translator.translateMatch(tree)
54+
translated.ensureConforms(tree.tpe)
5455
}
5556

5657
class Translator(implicit ctx: Context) {
@@ -79,6 +80,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
7980
def matcher(scrut: Tree, scrutSym: Symbol, restpe: Type)(cases: List[Casegen => Tree], matchFailGen: Option[Symbol => Tree]): Tree
8081

8182
// local / context-free
83+
// TODO Would be good to have some comments what these methods do
8284
def _asInstanceOf(b: Symbol, tp: Type): Tree
8385
def _equals(checker: Tree, binder: Symbol): Tree
8486
def _isInstanceOf(b: Symbol, tp: Type): Tree
@@ -91,6 +93,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
9193
trait Casegen extends AbsCodegen {
9294
def one(res: Tree): Tree
9395

96+
// TODO Would be good to have also some comments what these methods do
9497
def flatMap(prev: Tree, b: Symbol, next: Tree): Tree
9598
def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, next: Tree): Tree
9699
def flatMapGuard(cond: Tree, next: Tree): Tree
@@ -102,7 +105,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
102105
def codegen: AbsCodegen
103106

104107
abstract class CommonCodegen extends AbsCodegen {
105-
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
108+
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 // TODO move that comment to tupleSel in the base class
106109
def index(tgt: Tree)(i: Int): Tree = {
107110
if (i > 0) tgt.select(defn.Seq_apply).appliedTo(Literal(Constant(i)))
108111
else tgt.select(defn.Seq_head).appliedToNone
@@ -114,9 +117,14 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
114117
// for name-based matching, but this was an expedient route for the basics.
115118
def drop(tgt: Tree)(n: Int): Tree = {
116119
def callDirect = tgt.select(nme.drop).appliedTo(Literal(Constant(n)))
117-
def callRuntime = ref(ctx.definitions.traversableDropMethod).appliedTo(tgt, Literal(Constant(n)))
120+
def callRuntime = ref(defn.traversableDropMethod).appliedTo(tgt, Literal(Constant(n)))
121+
// TODO: Replace ctx.definitions elsewhere with just `defn`.
118122

119-
def needsRuntime = (tgt.tpe ne null) && tgt.tpe.baseTypeRef(ctx.definitions.SeqType.classSymbol).member(nme.drop).exists /*typeOfMemberNamedDrop(tgt.tpe) == NoType*/
123+
def needsRuntime = /* Useless test: this is always true (tgt.tpe ne null) && */
124+
tgt.tpe.baseTypeRef(defn.SeqClass).member(nme.drop).exists /*typeOfMemberNamedDrop(tgt.tpe) == NoType*/
125+
// TODO: I think the test above is the same as simply
126+
// tgt.tpe derivesFrom defn.SeqClass
127+
// If it derives from SeqClass, it will surely have a drop method, no?
120128

121129
if (needsRuntime) callRuntime else callDirect
122130
}
@@ -135,7 +143,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
135143
def apply(from: Symbol, to: Tree) = new Substitution(List(from), List(to))
136144
// requires sameLength(from, to)
137145
def apply(from: List[Symbol], to: List[Tree]) =
138-
if (from nonEmpty) new Substitution(from, to) else EmptySubstitution
146+
if (from.nonEmpty) new Substitution(from, to) else EmptySubstitution
139147
}
140148

141149
class Substitution(val from: List[Symbol], val to: List[Tree]) {
@@ -149,12 +157,18 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
149157
else*/
150158

151159
var replaced = 0
152-
val toAdapted = (from zip to) map {
153-
case (orig, nw) =>
154-
nw.ensureConforms(AndType(orig.info, nw.tpe))
160+
161+
// val toAdapted = (from zip to) map {
162+
// case (orig, nw) =>
163+
// nw.ensureConforms(AndType(orig.info, nw.tpe))
164+
// TODO: Use orig.info & nw.tpe instead of the AndType. The former will do simplifications, the latter will not.
165+
// But since this seems to be performance sensitive, we should use the code below.
166+
// }
167+
val toAdapted = to.zipWithConserve(from) { (nw, orig) =>
168+
if (nw.tpe <:< orig.info) nw else nw.ensureConforms(orig.info & nw.tpe)
155169
}
156170

157-
val identReplace: tpd.Tree => tpd.Tree = _ match {
171+
val identReplace: tpd.Tree => tpd.Tree = _ match { // TODO: Make identReplace a tpd.Ident => tpd.Tree
158172
case t:Ident =>
159173
def subst(from: List[Symbol], to: List[Tree]): Tree =
160174
if (from.isEmpty) t
@@ -226,7 +240,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
226240
// must compute catchAll after caseLabels (side-effects nextCase)
227241
// catchAll.isEmpty iff no synthetic default case needed (the (last) user-defined case is a default)
228242
// if the last user-defined case is a default, it will never jump to the next case; it will go immediately to matchEnd
229-
val catchAllDef = matchFailGen.map { matchFailGen => matchFailGen(scrutSym)}
243+
val catchAllDef = matchFailGen.map(_(scrutSym))
230244
.getOrElse(Throw(New(defn.MatchErrorType, List(ref(scrutSym)))))
231245

232246
val matchFail = newSynthCaseLabel(ctx.freshName("matchFail"), MethodType(Nil, restpe))
@@ -333,9 +347,12 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
333347
def emitTypeSwitch(bindersAndCases: List[(Symbol, List[TreeMaker])], pt: Type): Option[List[CaseDef]] =
334348
None // todo
335349

350+
// TODO Would be good to have some explanation here what a TreeMaker is. What's it for? What are its attributes?
336351
abstract class TreeMaker{
337352
def pos: Position
338353

354+
private[this] var currSub: Substitution = null
355+
339356
/** captures the scope and the value of the bindings in patterns
340357
* important *when* the substitution happens (can't accumulate and do at once after the full matcher has been constructed)
341358
*/
@@ -352,7 +369,6 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
352369
}
353370
else currSub = outerSubst >> substitution
354371
}
355-
private[this] var currSub: Substitution = null
356372

357373
/** The substitution that specifies the trees that compute the values of the subpattern binders.
358374
*
@@ -419,6 +435,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
419435
// unless we're optimizing, emit local variable bindings for all subpatterns of extractor/case class patterns
420436
protected val debugInfoEmitVars = true //!settings.optimise.value
421437

438+
// TODO Explain what this is for, similarly to what's done for ExtractorTreeMaker
422439
sealed trait PreserveSubPatBinders extends TreeMaker {
423440
val subPatBinders: List[Symbol]
424441
val subPatRefs: List[Tree]
@@ -932,15 +949,24 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
932949

933950
trait MatchTranslator extends TreeMakers with ScalacPatternExpanders {
934951

952+
/* I think the commented out code
935953
def isBackquoted(x: Ident) = x.isInstanceOf[BackquotedIdent]
936954
937955
def isVarPattern(pat: Tree): Boolean = pat match {
938956
case x: Ident => !isBackquoted(x) && nme.isVariableName(x.name)
939957
case _ => false
940958
}
959+
is better written like this:
960+
*/
961+
def isVarPattern(pat: Tree): Boolean = pat match {
962+
case x: BackquotedIdent => false
963+
case x: Ident => nme.isVariableName(x.name)
964+
case _ => false
965+
}
941966

942967
/** A conservative approximation of which patterns do not discern anything.
943968
* They are discarded during the translation.
969+
* TODO: Why is x a wildcard pattern but x @ _ is not?
944970
*/
945971
object WildcardPattern {
946972
def unapply(pat: Tree): Boolean = pat match {
@@ -971,6 +997,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
971997
}
972998

973999
// Always map repeated params to sequences
1000+
// TODO But repeated params don't exist where PM is running. Why the method?
9741001
private def setVarInfo(sym: Symbol, info: Type) ={
9751002
//setInfo debug.patmatResult(s"changing ${sym.defString} to")(repeatedToSeq(info))
9761003
// if(info!= NoType && !(sym.info =:= info))
@@ -986,11 +1013,12 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
9861013
case _ => BoundTree(freshSym(tree.pos, pt, prefix = "p"), tree)
9871014
}
9881015

1016+
// TODO: Again would be nice to document what this class is for.
9891017
final case class BoundTree(binder: Symbol, tree: Tree) {
9901018
private lazy val extractor = ExtractorCall(tree, binder)
9911019

9921020
def pos = tree.pos
993-
def tpe = binder.info.dealias.widen // the type of the variable bound to the pattern
1021+
def tpe = binder.info.widenDealias // the type of the variable bound to the pattern
9941022
def pt = unbound match {
9951023
// case Star(tpt) => this glbWith seqType(tpt.tpe) dd todo:
9961024
case TypeBound(tpe) => tpe
@@ -1010,6 +1038,9 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
10101038
object TypeBound {
10111039
def unapply(tree: Tree): Option[Type] = tree match {
10121040
case Typed(_, _) if tree.tpe != null => Some(tree.tpe)
1041+
// Should be: if tree.hasType (tree.tpe is always != null, where a tree is untyped, you'd get an exception when calling .tpe)
1042+
// But probably it's better to do without the extractor altogether. tree.typeOpt fulfils the same fucntion, and
1043+
// is more efficient.
10131044
case _ => None
10141045
}
10151046
}
@@ -1088,6 +1119,8 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
10881119
// accessors) TODO: get to the bottom of this -- I assume it happens when type checking
10891120
// infers a weird type for an unapply call. By going back to the parameterType for the
10901121
// extractor call we get a saner type, so let's just do that for now.
1122+
// TODO: This is now just a more convoluted and cumbersome version of tpd.ensureConforms. We should use the latter.
1123+
// All setInfo defs and calls can be dropped.
10911124
def ensureConformsTo(paramType: Type): Boolean = (
10921125
(tpe =:= paramType)
10931126
|| (tpe <:< paramType) && setInfo(paramType)
@@ -1116,7 +1149,12 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
11161149

11171150
def elimAnonymousClass(t: Type) = t match {
11181151
case t:TypeRef if t.symbol.isAnonymousClass =>
1119-
t.symbol.asClass.typeRef.asSeenFrom(t.prefix, t.symbol.owner)
1152+
val res =
1153+
t.symbol.asClass.typeRef.asSeenFrom(t.prefix, t.symbol.owner)
1154+
// what does this do? Is this not always the same as `t` itself?
1155+
// It is in our test runs. See assertion below which never fires.
1156+
assert(res =:= t)
1157+
res
11201158
case _ =>
11211159
t
11221160
}
@@ -1131,6 +1169,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
11311169
isDefaultCase(cdef)
11321170
}
11331171

1172+
// TODO: This method is redundant. Use thiz.derivesFrom(that) instead.
11341173
def isNonBottomSubClass(thiz: Symbol, that: Symbol)(implicit ctx: Context): Boolean = (
11351174
(thiz eq that) || thiz.isError || that.isError ||
11361175
thiz.info.baseClasses.contains(that)
@@ -1612,7 +1651,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
16121651
* arbitrary types here, and NoPattern and NoType arbitrary values.
16131652
*/
16141653
def NoPattern: Pattern
1615-
def NoType: Type
1654+
def NoType: Type // TODO Why parameterize over NoType? It looks like it is always core.Types.NoType.
16161655

16171656
/** It's not optimal that we're carrying both sequence and repeated
16181657
* type here, but the implementation requires more unraveling before

0 commit comments

Comments
 (0)