Skip to content

Commit df124be

Browse files
committed
Make implicit match work
- perform implicit search in real Typer, not ReTyper - use existing symbols for match bindings - handle anonymous implicit bindings
1 parent 84fe952 commit df124be

File tree

6 files changed

+57
-38
lines changed

6 files changed

+57
-38
lines changed

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

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,18 @@ class PatternMatcher extends MiniPhase {
2828
override def phaseName: String = PatternMatcher.name
2929
override def runsAfter: Set[String] = Set(ElimRepeated.name)
3030

31-
override def transformMatch(tree: Match)(implicit ctx: Context): Tree = {
32-
val translated = new Translator(tree.tpe, this).translateMatch(tree)
31+
override def transformMatch(tree: Match)(implicit ctx: Context): Tree =
32+
if (tree.isInstanceOf[InlineMatch]) tree
33+
else {
34+
val translated = new Translator(tree.tpe, this).translateMatch(tree)
3335

34-
// check exhaustivity and unreachability
35-
val engine = new patmat.SpaceEngine
36-
engine.checkExhaustivity(tree)
37-
engine.checkRedundancy(tree)
36+
// check exhaustivity and unreachability
37+
val engine = new patmat.SpaceEngine
38+
engine.checkExhaustivity(tree)
39+
engine.checkRedundancy(tree)
3840

39-
translated.ensureConforms(tree.tpe)
40-
}
41+
translated.ensureConforms(tree.tpe)
42+
}
4143
}
4244

4345
object PatternMatcher {

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

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -672,33 +672,30 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
672672
* @return optionally, if match can be reduced to a matching case: A pair of
673673
* bindings for all pattern-bound variables and the RHS of the case.
674674
*/
675-
def reduceInlineMatch(mtch: untpd.Match, scrutinee: Tree, scrutType: Type, typer: Typer)(implicit ctx: Context): MatchRedux = {
675+
def reduceInlineMatch(scrutinee: Tree, scrutType: Type, cases: List[untpd.CaseDef], typer: Typer)(implicit ctx: Context): MatchRedux = {
676676

677-
val isImplicit = mtch.selector.isEmpty
677+
val isImplicit = scrutType.isRef(defn.ImplicitScrutineeTypeSym)
678678
val gadtSyms = typer.gadtSyms(scrutType)
679679

680680
/** Try to match pattern `pat` against scrutinee reference `scrut`. If successful add
681681
* bindings for variables bound in this pattern to `bindingsBuf`.
682682
*/
683683
def reducePattern(bindingsBuf: mutable.ListBuffer[MemberDef], scrut: TermRef, pat: Tree)(implicit ctx: Context): Boolean = {
684684

685-
def newBinding(name: TermName, flags: FlagSet, rhs: Tree): Symbol = {
686-
val info = if (flags `is` Implicit) rhs.tpe.widen else rhs.tpe.widenTermRefExpr
687-
val sym = newSym(name, flags, info).asTerm
685+
def newBinding(sym: TermSymbol, rhs: Tree): Unit =
688686
bindingsBuf += ValDef(sym, constToLiteral(rhs))
689-
sym
690-
}
691687

692-
def searchImplicit(name: TermName, tpt: Tree) = {
693-
val evidence = typer.inferImplicitArg(tpt.tpe, tpt.pos)
688+
def searchImplicit(sym: TermSymbol, tpt: Tree) = {
689+
val evTyper = new Typer
690+
val evidence = evTyper.inferImplicitArg(tpt.tpe, tpt.pos)(ctx.fresh.setTyper(evTyper))
694691
evidence.tpe match {
695692
case fail: Implicits.AmbiguousImplicits =>
696-
ctx.error(typer.missingArgMsg(evidence, tpt.tpe, ""), tpt.pos)
693+
ctx.error(evTyper.missingArgMsg(evidence, tpt.tpe, ""), tpt.pos)
697694
true // hard error: return true to stop implicit search here
698695
case fail: Implicits.SearchFailureType =>
699696
false
700697
case _ =>
701-
if (name != nme.WILDCARD) newBinding(name, Implicit, evidence)
698+
newBinding(sym, evidence)
702699
true
703700
}
704701
}
@@ -718,8 +715,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
718715
}
719716
val boundVars = getBoundVars(Nil, tpt)
720717
for (bv <- boundVars) ctx.gadt.setBounds(bv, bv.info.bounds)
721-
if (isImplicit) searchImplicit(nme.WILDCARD, tpt)
722-
else scrut <:< tpt.tpe && {
718+
scrut <:< tpt.tpe && {
723719
for (bv <- boundVars) {
724720
bv.info = TypeAlias(ctx.gadt.bounds(bv).lo)
725721
// FIXME: This is very crude. We should approximate with lower or higher bound depending
@@ -732,10 +728,10 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
732728
reducePattern(bindingsBuf, scrut, pat1)
733729
}
734730
case pat @ Bind(name: TermName, Typed(_, tpt)) if isImplicit =>
735-
searchImplicit(name, tpt)
731+
searchImplicit(pat.symbol.asTerm, tpt)
736732
case pat @ Bind(name: TermName, body) =>
737733
reducePattern(bindingsBuf, scrut, body) && {
738-
if (name != nme.WILDCARD) newBinding(name, EmptyFlags, ref(scrut))
734+
if (name != nme.WILDCARD) newBinding(pat.symbol.asTerm, ref(scrut))
739735
true
740736
}
741737
case Ident(nme.WILDCARD) =>
@@ -757,7 +753,8 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
757753
def reduceSubPatterns(pats: List[Tree], selectors: List[Tree]): Boolean = (pats, selectors) match {
758754
case (Nil, Nil) => true
759755
case (pat :: pats1, selector :: selectors1) =>
760-
val elem = newBinding(InlineBinderName.fresh(), Synthetic, selector)
756+
val elem = newSym(InlineBinderName.fresh(), Synthetic, selector.tpe.widenTermRefExpr).asTerm
757+
newBinding(elem, selector)
761758
reducePattern(bindingsBuf, elem.termRef, pat) &&
762759
reduceSubPatterns(pats1, selectors1)
763760
case _ => false
@@ -816,7 +813,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
816813
case cdef :: cases1 => reduceCase(cdef) `orElse` recur(cases1)
817814
}
818815

819-
recur(mtch.cases)
816+
recur(cases)
820817
}
821818
}
822819

@@ -868,18 +865,20 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
868865
errorTree(tree, em"""cannot reduce inline if
869866
| its condition ${tree.cond}
870867
| is not a constant value.""")
871-
val if1 = untpd.cpy.If(tree)(cond = untpd.TypedSplice(cond1))
872-
super.typedIf(if1, pt)
868+
else {
869+
val if1 = untpd.cpy.If(tree)(cond = untpd.TypedSplice(cond1))
870+
super.typedIf(if1, pt)
871+
}
873872
}
874873

875874
override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree =
876875
constToLiteral(betaReduce(super.typedApply(tree, pt)))
877876

878-
override def typedMatchFinish(tree: untpd.Match, sel: Tree, selType: Type, pt: Type)(implicit ctx: Context) =
877+
override def typedMatchFinish(tree: untpd.Match, sel: Tree, selType: Type, cases: List[untpd.CaseDef], pt: Type)(implicit ctx: Context) =
879878
if (!tree.isInline || ctx.owner.isInlineMethod) // don't reduce match of nested inline method yet
880-
super.typedMatchFinish(tree, sel, selType, pt)
879+
super.typedMatchFinish(tree, sel, selType, cases, pt)
881880
else
882-
reduceInlineMatch(tree, sel, sel.tpe, this) match {
881+
reduceInlineMatch(sel, selType, cases, this) match {
883882
case Some((caseBindings, rhs)) =>
884883
var rhsCtx = ctx.fresh.setNewScope
885884
for (binding <- caseBindings) {
@@ -896,7 +895,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
896895
| patterns : ${tree.cases.map(patStr).mkString("\n ")}."""
897896
else
898897
em"""cannot reduce inline match with
899-
| scrutinee: $sel : ${sel.tpe}
898+
| scrutinee: $sel : ${selType}
900899
| patterns : ${tree.cases.map(patStr).mkString("\n ")}."""
901900
errorTree(tree, msg)
902901
}

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -971,7 +971,13 @@ class Typer extends Namer
971971
case EmptyTree =>
972972
if (tree.isInline) {
973973
checkInInlineContext("implicit match", tree.pos)
974-
typedMatchFinish(tree, tpd.EmptyTree, defn.ImplicitScrutineeTypeRef, pt)
974+
val cases1 = tree.cases.mapconserve {
975+
case cdef @ CaseDef(pat @ Typed(Ident(nme.WILDCARD), _), _, _) =>
976+
// case _ : T --> case evidence$n : T
977+
cpy.CaseDef(cdef)(pat = untpd.Bind(EvidenceParamName.fresh(), pat))
978+
case cdef => cdef
979+
}
980+
typedMatchFinish(tree, tpd.EmptyTree, defn.ImplicitScrutineeTypeRef, cases1, pt)
975981
}
976982
else {
977983
val (protoFormals, _) = decomposeProtoFunction(pt, 1)
@@ -982,13 +988,13 @@ class Typer extends Namer
982988
if (tree.isInline) checkInInlineContext("inline match", tree.pos)
983989
val sel1 = typedExpr(tree.selector)
984990
val selType = fullyDefinedType(sel1.tpe, "pattern selector", tree.pos).widen
985-
typedMatchFinish(tree, sel1, selType, pt)
991+
typedMatchFinish(tree, sel1, selType, tree.cases, pt)
986992
}
987993
}
988994

989995
// Overridden in InlineTyper for inline matches
990-
def typedMatchFinish(tree: untpd.Match, sel: Tree, selType: Type, pt: Type)(implicit ctx: Context): Tree = {
991-
val cases1 = harmonic(harmonize)(typedCases(tree.cases, selType, pt.notApplied))
996+
def typedMatchFinish(tree: untpd.Match, sel: Tree, selType: Type, cases: List[untpd.CaseDef], pt: Type)(implicit ctx: Context): Tree = {
997+
val cases1 = harmonic(harmonize)(typedCases(cases, selType, pt.notApplied))
992998
.asInstanceOf[List[CaseDef]]
993999
assignType(cpy.Match(tree)(sel, cases1), sel, cases1)
9941000
}

compiler/test/dotc/pos-test-pickling.blacklist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,4 @@ t7264
4343
t7532b
4444
t8062
4545
typeclass-encoding2.scala
46+
typelevel0.scala

tests/run/implicitMatch.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
1+
class scala.collection.immutable.TreeSet
2+
class scala.collection.immutable.HashSet
3+
class scala.collection.immutable.TreeSet
4+
class scala.collection.immutable.HashSet
15
B

tests/invalid/run/implicitMatch.scala renamed to tests/run/implicitMatch.scala

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@ object Test extends App {
22
import collection.immutable.TreeSet
33
import collection.immutable.HashSet
44

5-
inline def f[T]() = implicit match {
5+
inline def f1[T]() = implicit match {
66
case ord: Ordering[T] => new TreeSet[T]
77
case _ => new HashSet[T]
88
}
99

10+
inline def f2[T]() = implicit match {
11+
case _: Ordering[T] => new TreeSet[T]
12+
case _ => new HashSet[T]
13+
}
14+
1015
class A
1116
class B
1217
implicit val b: B = new B
@@ -18,8 +23,10 @@ object Test extends App {
1823

1924
implicitly[Ordering[String]]
2025

21-
f[String]()
22-
f[AnyRef]()
26+
println(f1[String]().getClass)
27+
println(f1[AnyRef]().getClass)
28+
println(f2[String]().getClass)
29+
println(f2[AnyRef]().getClass)
2330
implicitly[B]
2431
g
2532

0 commit comments

Comments
 (0)