Skip to content

Commit c3443dc

Browse files
Revert "wip"
This reverts commit b105108.
1 parent 99f73fa commit c3443dc

File tree

8 files changed

+135
-111
lines changed

8 files changed

+135
-111
lines changed

compiler/src/dotty/tools/dotc/core/Normalize.scala

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,10 +262,9 @@ private final class NormalizeMap(implicit ctx: Context) extends TypeMap {
262262
case Left(cond1) => Stuck( TypeOf.If.derived(tp)(cond1, thenb, elseb) )
263263
}
264264

265-
// case tp @ TypeOf.Match(_, _) =>
266-
// apply(tp.translated)
267-
// new PatternMatcher.Translator(NoType, null)(ctx.enterTypeOf())
268-
// .evaluateMatch(tp.tree.asInstanceOf[Match], normalizeBoolType).getOrElse(Stuck(tp))
265+
case tp @ TypeOf.Match(selector, cases) =>
266+
new PatternMatcher.Translator(NoType, null)(ctx.enterTypeOf())
267+
.evaluateMatch(tp.tree.asInstanceOf[Match], normalizeBoolType).getOrElse(Stuck(tp))
269268

270269
case tp =>
271270
mapOver(tp) match {

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 39 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4212,7 +4212,7 @@ object Types {
42124212
// ----- TypeOf -------------------------------------------------------------------------
42134213

42144214
/** Type that represents the precise type of a given term.
4215-
* Precision is only kept for Apply, TypeApply and If trees.
4215+
* Precision is only kept for Apply, TypeApply, If and Match trees.
42164216
*
42174217
* The idea behind this type is to be able to compute more precise types
42184218
* when more information is available.
@@ -4226,6 +4226,7 @@ object Types {
42264226
* TypeOf(u, Apply(fun, args)) ~ SuspendedApply(u, fun, args)
42274227
* TypeOf(u, TypeApply(fun, args)) ~ SuspendedTypeApply(u, fun, args)
42284228
* TypeOf(u, If(cond, thenp, elsep)) ~ SuspendedIf(u, cond, thenp, elsep)
4229+
* TypeOf(u, Match(selector, cases)) ~ SuspendedMatch(u, selector, cases)
42294230
*
42304231
* Where u is the type that the tree would have had otherwise.
42314232
*
@@ -4254,13 +4255,16 @@ object Types {
42544255
}
42554256
case nil => args2.isEmpty
42564257
}
4258+
// FIXME: compareArgs is incorrect for Match. Add compareCaseDef.
42574259
(this.tree, that.tree) match {
42584260
case (t1: Apply, t2: Apply) =>
42594261
(t1.fun.tpe eql t2.fun.tpe) && compareArgs(t1.args, t2.args)
42604262
case (t1: TypeApply, t2: TypeApply) =>
42614263
(t1.fun.tpe eql t2.fun.tpe) && compareArgs(t1.args, t2.args)
42624264
case (t1: If, t2: If) =>
42634265
(t1.cond.tpe eql t2.cond.tpe) && (t1.thenp.tpe eql t2.thenp.tpe) && (t1.elsep.tpe eql t2.elsep.tpe)
4266+
case (t1: Match, t2: Match) =>
4267+
(t1.selector.tpe eql t2.selector.tpe) && compareArgs(t1.cases, t2.cases)
42644268
case (t1, t2) =>
42654269
false
42664270
}
@@ -4273,6 +4277,7 @@ object Types {
42734277
override def computeHash(bs: Hashable.Binders) = {
42744278
val delta = tree match {
42754279
case _: If => 11
4280+
case _: Match => 17
42764281
case _: Apply => 23
42774282
case _: TypeApply => 29
42784283
}
@@ -4290,7 +4295,6 @@ object Types {
42904295

42914296
def apply(underlyingTp: Type, tree: untpd.Tree)(implicit ctx: Context): TypeOf = {
42924297
assert(!ctx.erasedTypes)
4293-
assert(isLegalTopLevelTree(tree.asInstanceOf[Tree]))
42944298
val tree1 = tree.clone.asInstanceOf[Tree]
42954299
// This is a safety net to keep us from touching a TypeOf's tree's type.
42964300
// Assuming we never look at this type, it would be safe to simply reuse
@@ -4304,7 +4308,7 @@ object Types {
43044308
def unapply(to: TypeOf): Option[(Type, Tree)] = Some((to.underlyingTp, to.tree))
43054309

43064310
def isLegalTopLevelTree(tree: Tree): Boolean = tree match {
4307-
case _: TypeApply | _: Apply | _: If => true
4311+
case _: TypeApply | _: Apply | _: If | _: Match => true
43084312
case _ => false
43094313
}
43104314

@@ -4346,16 +4350,6 @@ object Types {
43464350
tp
43474351

43484352
object If {
4349-
/** For explicit creation in patmat */
4350-
def apply(condTp: Type, thenTp: Type, elseTp: Type)(implicit ctx: Context): TypeOf = {
4351-
val thenTree = dummyTreeOfType(thenTp)
4352-
val elseTree = dummyTreeOfType(elseTp)
4353-
val ifTree = untpd.If(dummyTreeOfType(condTp), thenTree, elseTree)
4354-
ctx.typeAssigner.assignType(ifTree, thenTree, elseTree)(ctx.enterTypeOf()).tpe
4355-
.asInstanceOf[TypeOf]
4356-
}
4357-
4358-
/** For unpickling */
43594353
def apply(underlyingTp: Type, condTp: Type, thenTp: Type, elseTp: Type)(implicit ctx: Context): TypeOf =
43604354
TypeOf(underlyingTp, untpd.If(
43614355
dummyTreeOfType(condTp),
@@ -4380,35 +4374,32 @@ object Types {
43804374
}
43814375

43824376
object Match {
4383-
def apply(underlyingTp: Type, tree: Match)(implicit ctx: Context): Type =
4384-
new transform.PatternMatcher.Translator(NoType, null)(ctx.enterTypeOf())
4385-
.typeTranslateMatch(tree)
4386-
// def apply(underlyingTp: Type, selectorTp: Type,
4387-
// caseTriples: List[(Type, Type, Type)])(implicit ctx: Context): TypeOf =
4388-
// TypeOf(underlyingTp, untpd.Match(
4389-
// dummyTreeOfType(selectorTp),
4390-
// caseTriples.map { case (patTp, guardTp, bodyTp) =>
4391-
// ast.tpd.CaseDef(
4392-
// dummyTreeOfType(patTp),
4393-
// if (guardTp.exists) dummyTreeOfType(guardTp) else EmptyTree,
4394-
// dummyTreeOfType(bodyTp))
4395-
// }
4396-
// ))
4397-
4398-
// def unapply(to: TypeOf): Option[(Type, List[(Type, Type, Type)])] = to.tree match {
4399-
// case Trees.Match(selector, cases) =>
4400-
// val caseTriples = cases.map { cse => (cse.pat.tpe, cse.guard.tpe, cse.body.tpe) }
4401-
// Some((selector.tpe, caseTriples))
4402-
// case _ => None
4403-
// }
4404-
4405-
// def derived(to: TypeOf)(selectorTp: Type, caseTriples: List[(Type, Type, Type)])(implicit ctx: Context): Type =
4406-
// finalizeDerived(to, to.tree match {
4407-
// case Trees.Match(selector, cases) =>
4408-
// val ctx1 = ctx.enterTypeOf()
4409-
// val cases1 = casesWithTpes(cases, caseTriples)(ctx1)
4410-
// cpy.Match(to.tree)(treeWithTpe(selector, selectorTp), cases1)(ctx1)
4411-
// })
4377+
def apply(underlyingTp: Type, selectorTp: Type,
4378+
caseTriples: List[(Type, Type, Type)])(implicit ctx: Context): TypeOf =
4379+
TypeOf(underlyingTp, untpd.Match(
4380+
dummyTreeOfType(selectorTp),
4381+
caseTriples.map { case (patTp, guardTp, bodyTp) =>
4382+
ast.tpd.CaseDef(
4383+
dummyTreeOfType(patTp),
4384+
if (guardTp.exists) dummyTreeOfType(guardTp) else EmptyTree,
4385+
dummyTreeOfType(bodyTp))
4386+
}
4387+
))
4388+
4389+
def unapply(to: TypeOf): Option[(Type, List[(Type, Type, Type)])] = to.tree match {
4390+
case Trees.Match(selector, cases) =>
4391+
val caseTriples = cases.map { cse => (cse.pat.tpe, cse.guard.tpe, cse.body.tpe) }
4392+
Some((selector.tpe, caseTriples))
4393+
case _ => None
4394+
}
4395+
4396+
def derived(to: TypeOf)(selectorTp: Type, caseTriples: List[(Type, Type, Type)])(implicit ctx: Context): Type =
4397+
finalizeDerived(to, to.tree match {
4398+
case Trees.Match(selector, cases) =>
4399+
val ctx1 = ctx.enterTypeOf()
4400+
val cases1 = casesWithTpes(cases, caseTriples)(ctx1)
4401+
cpy.Match(to.tree)(treeWithTpe(selector, selectorTp), cases1)(ctx1)
4402+
})
44124403
}
44134404

44144405
object Apply {
@@ -4527,6 +4518,9 @@ object Types {
45274518
object Generic {
45284519
def unapply(to: TypeOf): Option[List[Type]] = to.tree match {
45294520
case Trees.If(cond, thenb, elseb) => Some(cond.tpe :: thenb.tpe :: elseb.tpe :: Nil)
4521+
case Trees.Match(selector, cases) =>
4522+
val caseTriplesFlattened = cases.flatMap { cse => List(cse.pat.tpe, cse.guard.tpe, cse.body.tpe) }
4523+
Some(selector.tpe :: caseTriplesFlattened)
45304524
case Trees.Apply(fn, args) => Some(fn.tpe :: args.map(_.tpe))
45314525
case Trees.TypeApply(fn, args) => Some(fn.tpe :: args.map(_.tpe))
45324526
}
@@ -4693,6 +4687,9 @@ object Types {
46934687
TypeOf.Apply.derived(tp)(this(tree.fun.tpe), tree.args.map(t => this(t.tpe)))
46944688
case tree: If =>
46954689
TypeOf.If.derived(tp)(this(tree.cond.tpe), this(tree.thenp.tpe), this(tree.elsep.tpe))
4690+
case tree: Match =>
4691+
val caseTriples = tree.cases.map { cse => (this(cse.pat.tpe), this(cse.guard.tpe), this(cse.body.tpe)) }
4692+
TypeOf.Match.derived(tp)(this(tree.selector.tpe), caseTriples)
46964693
case tree =>
46974694
throw new AssertionError(s"TypeOf shouldn't contain $tree as top-level node.")
46984695
}

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,12 +158,19 @@ class TreePickler(pickler: TastyPickler) {
158158
withLength {
159159
val treeKind = to.tree match {
160160
case _: If => TypeOfTags.If
161+
case _: Match => TypeOfTags.Match
161162
case _: Apply => TypeOfTags.Apply
162163
case _: TypeApply => TypeOfTags.TypeApply
163164
}
164165
writeByte(treeKind)
165166
pickleType(to.underlying, richTypes = true)
166167
to match {
168+
case TypeOf.Match(selectorTp, caseTriples) =>
169+
pickleType(selectorTp, richTypes = true)
170+
caseTriples.foreach {
171+
case (patTp, NoType, bodyTp) => writeByte(2); pickleTypes(patTp :: bodyTp :: Nil)
172+
case (patTp, guardTp, bodyTp) => writeByte(3); pickleTypes(patTp :: guardTp :: bodyTp :: Nil)
173+
}
167174
case TypeOf.Generic(types) =>
168175
pickleTypes(types)
169176
}

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -296,15 +296,26 @@ class TreeUnpickler(reader: TastyReader,
296296
val treeKind = readByte()
297297
val underlying = readType()
298298
val TT = TypeOfTags
299-
val types = until(end)(readType())
300-
(treeKind, types) match {
301-
case (TT.If, List(cond, thenb, elseb)) =>
302-
TypeOf.If(underlying, cond, thenb, elseb)
303-
case (TT.Apply, fn :: args) =>
304-
TypeOf.Apply(underlying, fn, args)
305-
case (TT.TypeApply, fn :: args) =>
306-
TypeOf.TypeApply(underlying, fn, args)
307-
case _ => throw new AssertionError(s"Inconsistant types in TypeOf: $types")
299+
if (treeKind == TT.Match) {
300+
val selectorTp = readType()
301+
val caseTriples = until(end) {
302+
readByte() match {
303+
case 2 => (readType(), NoType, readType())
304+
case 3 => (readType(), readType(), readType())
305+
}
306+
}
307+
TypeOf.Match(underlying, selectorTp, caseTriples)
308+
} else {
309+
val types = until(end)(readType())
310+
(treeKind, types) match {
311+
case (TT.If, List(cond, thenb, elseb)) =>
312+
TypeOf.If(underlying, cond, thenb, elseb)
313+
case (TT.Apply, fn :: args) =>
314+
TypeOf.Apply(underlying, fn, args)
315+
case (TT.TypeApply, fn :: args) =>
316+
TypeOf.TypeApply(underlying, fn, args)
317+
case _ => throw new AssertionError(s"Inconsistant types in TypeOf: $types")
318+
}
308319
}
309320
}
310321

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

Lines changed: 33 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ object PatternMatcher {
261261
/** Plan for matching the sequence in `getResult` against sequence elements
262262
* and a possible last varargs argument `args`.
263263
*/
264-
def unapplySeqPlan(getResult: Symbol, args: List[Tree]): Plan = args.lastOption match { //XXXX
264+
def unapplySeqPlan(getResult: Symbol, args: List[Tree]): Plan = args.lastOption match {
265265
case Some(VarArgPattern(arg)) =>
266266
val matchRemaining =
267267
if (args.length == 1) {
@@ -325,7 +325,7 @@ object PatternMatcher {
325325
}
326326

327327
// begin patternPlan
328-
swapBind(tree) match { //XXXX
328+
swapBind(tree) match {
329329
case Typed(pat, tpt) =>
330330
TestPlan(TypeTest(tpt), scrutinee, tree.pos,
331331
letAbstract(ref(scrutinee).asInstance(tpt.tpe)) { casted =>
@@ -509,7 +509,7 @@ object PatternMatcher {
509509
def mergeTests(plan: Plan): Plan = {
510510
class SubstituteIdent(from: TermSymbol, to: TermSymbol) extends PlanTransform {
511511
override val treeMap = new TreeMap {
512-
override def transform(tree: Tree)(implicit ctx: Context) = tree match { //XXXX
512+
override def transform(tree: Tree)(implicit ctx: Context) = tree match {
513513
case tree: Ident if tree.symbol == from => ref(to)
514514
case _ => super.transform(tree)
515515
}
@@ -592,7 +592,7 @@ object PatternMatcher {
592592

593593
object Inliner extends PlanTransform {
594594
override val treeMap = new TreeMap {
595-
override def transform(tree: Tree)(implicit ctx: Context) = tree match { //XXXX
595+
override def transform(tree: Tree)(implicit ctx: Context) = tree match {
596596
case tree: Ident =>
597597
val sym = tree.symbol
598598
if (toDrop(sym)) transform(initializer(sym))
@@ -692,8 +692,8 @@ object PatternMatcher {
692692

693693
@tailrec
694694
private def canFallThrough(plan: Plan): Boolean = plan match {
695-
case _: ReturnPlan | _: ResultPlan => false
696-
case _: TestPlan | _: LabeledPlan => true
695+
case _:ReturnPlan | _:ResultPlan => false
696+
case _:TestPlan | _:LabeledPlan => true
697697
case LetPlan(_, body) => canFallThrough(body)
698698
case SeqPlan(_, tail) => canFallThrough(tail)
699699
}
@@ -709,7 +709,7 @@ object PatternMatcher {
709709
(tpe isRef defn.ShortClass) ||
710710
(tpe isRef defn.CharClass)
711711

712-
def isIntConst(tree: Tree) = tree match { ///XXXX
712+
def isIntConst(tree: Tree) = tree match {
713713
case Literal(const) => const.isIntRange
714714
case _ => false
715715
}
@@ -943,21 +943,17 @@ object PatternMatcher {
943943
Labeled(resultLabel, result)
944944
}
945945

946+
946947
/** Evaluate pattern match to a precise type, if possible, and return NoType otherwise. */
947-
// def evaluateMatch(tree: Match, evalBoolType: Type => Either[Type, Boolean]): Option[Type] = {
948-
// val plan = matchPlan(tree)
949-
// println
950-
// println
951-
// patmatch.println(i"Plan for $tree: ${show(plan)}")
952-
// val result = evaluate(plan, evalBoolType)
953-
// /*patmatch.*/println(i"Plan evaluation: $result")
954-
// result
955-
// }
956-
957-
def typeTranslateMatch(tree: Match): Type =
958-
typeTranslatePlan(matchPlan(tree))
959-
960-
private def typeTranslatePlan(plan0: Plan): Type = {
948+
def evaluateMatch(tree: Match, evalBoolType: Type => Either[Type, Boolean]): Option[Type] = {
949+
val plan = matchPlan(tree)
950+
patmatch.println(i"Plan for $tree: ${show(plan)}")
951+
val result = evaluate(plan, evalBoolType)
952+
patmatch.println(i"Plan evaluation: $result")
953+
result
954+
}
955+
956+
private def evaluate(plan0: Plan, evalBoolType: Type => Either[Type, Boolean]): Option[Type] = {
961957
assert(ctx.isDependent)
962958

963959
def nextPlan(label: Symbol): Plan = {
@@ -973,40 +969,32 @@ object PatternMatcher {
973969
rec(label, plan0, None).get
974970
}
975971

976-
def evalTest(testPlan: TestPlan): Type = testPlan match {
977-
case TestPlan(test, scrutinee, _, _) =>
972+
def evalTest(testPlan: TestPlan): Option[Boolean] = testPlan match {
973+
case TestPlan(test, scrut, _, _) =>
978974
test match {
979-
case TypeTest(tpt) =>
980-
// Like emitCondition(test) with the crazy outer stuff and
981-
// patmet specific isInstanceOfPM gone.
982-
val expectedTp = tpt.tpe
983-
expectedTp.dealias match {
984-
case expectedTp: SingletonType =>
985-
scrutinee.isInstance(expectedTp).tpe
986-
case _ =>
987-
scrutinee.select(defn.Any_isInstanceOf).appliedToType(expectedTp).tpe
988-
}
989-
case NonNullTest => ConstantType(Constants.Constant(false))
990-
case _ => emitCondition(testPlan).tpe
975+
case TypeTest(tpt) => Normalize.erasedTypeTest(scrut.tpe, tpt.tpe) // FIXME: unsound
976+
case NonNullTest => Some(false)
977+
case _ => evalBoolType(emitCondition(testPlan).tpe).toOption
991978
}
992979
}
993980

994-
def evalPlan(plan: Plan, nexts: List[Plan]): Type =
981+
@tailrec def evalPlan(plan: Plan, nexts: List[Plan]): Option[Type] =
995982
plan match {
996983
case LetPlan(sym, body) => evalPlan(body, nexts)
997984
case LabeledPlan(label, expr) => evalPlan(expr, nexts)
998985
case SeqPlan(head, tail) => evalPlan(head, tail :: nexts)
999986
case ReturnPlan(label) => evalPlan(nextPlan(label), nexts)
1000-
case ResultPlan(tree) => tree.tpe
987+
case ResultPlan(tree) => Some(tree.tpe)
1001988
case plan: TestPlan =>
1002-
val condTp = evalTest(plan)
1003-
val thenTp = evalPlan(plan.onSuccess, nexts)
1004-
val elseTp =
1005-
nexts match {
1006-
case head :: tail => evalPlan(head, tail)
1007-
case _ => throw new AssertionError("Malformed Plan")
1008-
}
1009-
TypeOf.If(condTp, thenTp, elseTp)
989+
evalTest(plan) match {
990+
case None => None
991+
case Some(true) => evalPlan(plan.onSuccess, nexts)
992+
case Some(false) =>
993+
nexts match {
994+
case head :: tail => evalPlan(head, tail)
995+
case _ => throw new AssertionError("Malformed Plan")
996+
}
997+
}
1010998
}
1011999

10121000
evalPlan(plan0, Nil)

compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -500,11 +500,10 @@ trait TypeAssigner {
500500

501501
def assignType(tree: untpd.Match, scrutinee: Tree, cases: List[CaseDef])(implicit ctx: Context): Match = {
502502
val underlying = ctx.typeComparer.lub(cases.tpes)
503-
val typed = tree.withType(underlying)
504503
if (!ctx.erasedTypes && ctx.isDependent)
505-
tree.clone.withType(TypeOf.Match(underlying, typed))
504+
tree.withType(TypeOf(underlying, tree))
506505
else
507-
typed
506+
tree.withType(underlying)
508507
}
509508

510509
def assignType(tree: untpd.Labeled)(implicit ctx: Context): Labeled =

0 commit comments

Comments
 (0)