Skip to content

Commit 33afaa2

Browse files
authored
Merge pull request #4916 from dotty-staging/fix-transparent-3
Fixes to transparent to enable generic tuples
2 parents 6ee3c62 + 103237e commit 33afaa2

File tree

6 files changed

+436
-30
lines changed

6 files changed

+436
-30
lines changed

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

Lines changed: 88 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import Symbols._
1111
import Types._
1212
import Decorators._
1313
import Constants._
14-
import StdNames.nme
14+
import StdNames._
1515
import Contexts.Context
1616
import Names.{Name, TermName, EmptyTermName}
1717
import NameOps._
@@ -602,7 +602,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
602602
newOwners = ctx.owner :: Nil,
603603
substFrom = ddef.vparamss.head.map(_.symbol),
604604
substTo = argSyms)
605-
Block(bindingsBuf.toList, expander.transform(ddef.rhs))
605+
seq(bindingsBuf.toList, expander.transform(ddef.rhs))
606606
case _ => tree
607607
}
608608
case _ => tree
@@ -629,7 +629,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
629629
/** Try to match pattern `pat` against scrutinee reference `scrut`. If successful add
630630
* bindings for variables bound in this pattern to `bindingsBuf`.
631631
*/
632-
def reducePattern(bindingsBuf: mutable.ListBuffer[MemberDef], scrut: TermRef, pat: Tree): Boolean = {
632+
def reducePattern(bindingsBuf: mutable.ListBuffer[MemberDef], scrut: TermRef, pat: Tree)(implicit ctx: Context): Boolean = {
633633
val isImplicit = scrut.info == defn.ImplicitScrutineeTypeRef
634634

635635
def newBinding(name: TermName, flags: FlagSet, rhs: Tree): Symbol = {
@@ -655,8 +655,32 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
655655

656656
pat match {
657657
case Typed(pat1, tpt) =>
658+
val getBoundVars = new TreeAccumulator[List[TypeSymbol]] {
659+
def apply(syms: List[TypeSymbol], t: Tree)(implicit ctx: Context) = {
660+
val syms1 = t match {
661+
case t: Bind if t.symbol.isType && t.name != tpnme.WILDCARD =>
662+
t.symbol.asType :: syms
663+
case _ =>
664+
syms
665+
}
666+
foldOver(syms1, t)
667+
}
668+
}
669+
val boundVars = getBoundVars(Nil, tpt)
670+
for (bv <- boundVars) ctx.gadt.setBounds(bv, bv.info.bounds)
658671
if (isImplicit) searchImplicit(nme.WILDCARD, tpt)
659-
else scrut <:< tpt.tpe && reducePattern(bindingsBuf, scrut, pat1)
672+
else scrut <:< tpt.tpe && {
673+
for (bv <- boundVars) {
674+
bv.info = TypeAlias(ctx.gadt.bounds(bv).lo)
675+
// FIXME: This is very crude. We should approximate with lower or higher bound depending
676+
// on variance, and we should also take care of recursive bounds. Basically what
677+
// ConstraintHandler#approximation does. However, this only works for constrained paramrefs
678+
// not GADT-bound variables. Hopefully we will get some way to improve this when we
679+
// re-implement GADTs in terms of constraints.
680+
bindingsBuf += TypeDef(bv)
681+
}
682+
reducePattern(bindingsBuf, scrut, pat1)
683+
}
660684
case pat @ Bind(name: TermName, Typed(_, tpt)) if isImplicit =>
661685
searchImplicit(name, tpt)
662686
case pat @ Bind(name: TermName, body) =>
@@ -706,16 +730,19 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
706730
val scrutineeBinding = normalizeBinding(ValDef(scrutineeSym, scrutinee))
707731

708732
def reduceCase(cdef: untpd.CaseDef): MatchRedux = {
709-
def guardOK = cdef.guard.isEmpty || {
710-
typer.typed(cdef.guard, defn.BooleanType) match {
733+
val caseBindingsBuf = new mutable.ListBuffer[MemberDef]()
734+
def guardOK(implicit ctx: Context) = cdef.guard.isEmpty || {
735+
val guardCtx = ctx.fresh.setNewScope
736+
caseBindingsBuf.foreach(binding => guardCtx.enter(binding.symbol))
737+
typer.typed(cdef.guard, defn.BooleanType)(guardCtx) match {
711738
case ConstantValue(true) => true
712739
case _ => false
713740
}
714741
}
715-
val caseBindingsBuf = new mutable.ListBuffer[MemberDef]()
716742
if (scrutType != defn.ImplicitScrutineeTypeRef) caseBindingsBuf += scrutineeBinding
717-
val pat1 = typer.typedPattern(cdef.pat, scrutType)(typer.gadtContext(gadtSyms))
718-
if (reducePattern(caseBindingsBuf, scrutineeSym.termRef, pat1) && guardOK)
743+
val gadtCtx = typer.gadtContext(gadtSyms).addMode(Mode.GADTflexible)
744+
val pat1 = typer.typedPattern(cdef.pat, scrutType)(gadtCtx)
745+
if (reducePattern(caseBindingsBuf, scrutineeSym.termRef, pat1)(gadtCtx) && guardOK)
719746
Some((caseBindingsBuf.toList, cdef.body))
720747
else
721748
None
@@ -809,6 +836,8 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
809836
def dropUnusedDefs(bindings: List[MemberDef], tree: Tree)(implicit ctx: Context): (List[MemberDef], Tree) = {
810837
val refCount = newMutableSymbolMap[Int]
811838
val bindingOfSym = newMutableSymbolMap[MemberDef]
839+
val dealiased = new java.util.IdentityHashMap[Type, Type]()
840+
812841
def isInlineable(binding: MemberDef) = binding match {
813842
case DefDef(_, Nil, Nil, _, _) => true
814843
case vdef @ ValDef(_, _, _) => isPureExpr(vdef.rhs)
@@ -818,6 +847,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
818847
refCount(binding.symbol) = 0
819848
bindingOfSym(binding.symbol) = binding
820849
}
850+
821851
val countRefs = new TreeTraverser {
822852
override def traverse(t: Tree)(implicit ctx: Context) = {
823853
def updateRefCount(sym: Symbol, inc: Int) =
@@ -844,6 +874,45 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
844874
}
845875
} && !boundSym.is(TransparentImplicitMethod)
846876

877+
val (termBindings, typeBindings) = bindings.partition(_.symbol.isTerm)
878+
879+
/** drop any referenced type symbols from the given set of type symbols */
880+
val dealiasTypeBindings = new TreeMap {
881+
val boundTypes = typeBindings.map(_.symbol).toSet
882+
883+
val dealias = new TypeMap {
884+
override def apply(tp: Type) = dealiased.get(tp) match {
885+
case null =>
886+
val tp1 = mapOver {
887+
tp match {
888+
case tp: TypeRef if boundTypes.contains(tp.symbol) =>
889+
val TypeAlias(alias) = tp.info
890+
alias
891+
case _ => tp
892+
}
893+
}
894+
dealiased.put(tp, tp1)
895+
tp1
896+
case tp1 => tp1
897+
}
898+
}
899+
900+
override def transform(t: Tree)(implicit ctx: Context) = {
901+
val dealiasedType = dealias(t.tpe)
902+
val t1 = t match {
903+
case t: RefTree =>
904+
if (boundTypes.contains(t.symbol)) TypeTree(dealiasedType).withPos(t.pos)
905+
else t.withType(dealiasedType)
906+
case t: DefTree =>
907+
t.symbol.info = dealias(t.symbol.info)
908+
t
909+
case _ =>
910+
t.withType(dealiasedType)
911+
}
912+
super.transform(t1)
913+
}
914+
}
915+
847916
val inlineBindings = new TreeMap {
848917
override def transform(t: Tree)(implicit ctx: Context) = t match {
849918
case t: RefTree =>
@@ -859,17 +928,23 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
859928
case t: Apply =>
860929
val t1 = super.transform(t)
861930
if (t1 `eq` t) t else reducer.betaReduce(t1)
931+
case Block(Nil, expr) =>
932+
super.transform(expr)
862933
case _ =>
863934
super.transform(t)
864935
}
865936
}
866937

867-
val retained = bindings.filterConserve(binding => retain(binding.symbol))
868-
if (retained `eq` bindings) {
869-
(bindings, tree)
938+
val dealiasedTermBindings =
939+
termBindings.mapconserve(dealiasTypeBindings.transform).asInstanceOf[List[MemberDef]]
940+
val dealiasedTree = dealiasTypeBindings.transform(tree)
941+
942+
val retained = dealiasedTermBindings.filterConserve(binding => retain(binding.symbol))
943+
if (retained `eq` dealiasedTermBindings) {
944+
(dealiasedTermBindings, dealiasedTree)
870945
}
871946
else {
872-
val expanded = inlineBindings.transform(tree)
947+
val expanded = inlineBindings.transform(dealiasedTree)
873948
dropUnusedDefs(retained, expanded)
874949
}
875950
}

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ object PrepareTransparent {
4949
def markTopLevelMatches(meth: Symbol, tree: untpd.Tree)(implicit ctx: Context): Unit = tree match {
5050
case tree: untpd.Match =>
5151
tree.putAttachment(TopLevelMatch, ())
52-
tree.cases.foreach(markTopLevelMatches(meth, _))
52+
for (cdef <- tree.cases) markTopLevelMatches(meth, cdef.body)
5353
case tree: untpd.Block =>
5454
markTopLevelMatches(meth, tree.expr)
5555
case _ =>
@@ -76,12 +76,14 @@ object PrepareTransparent {
7676
* by excluding all symbols properly contained in the inlined method.
7777
*
7878
* Constant vals don't need accessors since they are inlined in FirstTransform.
79+
* Transparent methods don't need accessors since they are inlined in Typer.
7980
*/
8081
def needsAccessor(sym: Symbol)(implicit ctx: Context) =
8182
sym.isTerm &&
8283
(sym.is(AccessFlags) || sym.privateWithin.exists) &&
8384
!sym.isContainedIn(inlineSym) &&
84-
!(sym.isStable && sym.info.widenTermRefExpr.isInstanceOf[ConstantType])
85+
!(sym.isStable && sym.info.widenTermRefExpr.isInstanceOf[ConstantType]) &&
86+
!sym.is(TransparentMethod)
8587

8688
def preTransform(tree: Tree)(implicit ctx: Context): Tree
8789

compiler/src/dotty/tools/dotc/util/Set.scala

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
/* NSC -- new Scala compiler
2-
* Copyright 2005-2012 LAMP/EPFL
3-
* @author Martin Odersky
4-
*/
51
package dotty.tools.dotc.util
62

73
/** A common class for lightweight sets.

tests/run/TupleAbstract.check

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
()
2+
(1)
3+
(A,1)
4+
(2,A,1)
5+
(B,2,A,1)
6+
(3,B,2,A,1)
7+
(C,3,B,2,A,1)
8+
(4,C,3,B,2,A,1)
9+
(D,4,C,3,B,2,A,1)
10+
h1 = 1
11+
h2 = A
12+
h7 = 4
13+
h8 = D
14+
t1 = ()
15+
t2 = (1)
16+
t7 = (C,3,B,2,A,1)
17+
t8 = (4,C,3,B,2,A,1)
18+
a1_0 = 1
19+
a2_0 = A
20+
a3_1 = A
21+
a4_3 = 1
22+
a6_4 = A
23+
a8_0 = D
24+
c0_0 = ()
25+
c0_1 = (1)
26+
c1_0 = (1)
27+
c0_4 = (B,2,A,1)
28+
c4_0 = (B,2,A,1)
29+
c1_1 = (1,1)
30+
c1_8 = (1,D,4,C,3,B,2,A,1)
31+
c2_1 = (A,1,1)
32+
c2_2 = (A,1,A,1)
33+
c2_3 = (A,1,2,A,1)
34+
c3_3 = (2,A,1,2,A,1)

0 commit comments

Comments
 (0)