Skip to content

Commit 25a3773

Browse files
authored
Merge pull request #6218 from dotty-staging/inliner-fixes
Inliner improvements
2 parents c3e88b7 + 1929522 commit 25a3773

12 files changed

+1079
-82
lines changed

compiler/src/dotty/tools/dotc/config/Printers.scala

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ object Printers {
3434
val quotePickling: Printer = noPrinter
3535
val plugins: Printer = noPrinter
3636
val simplify: Printer = noPrinter
37+
val staging: Printer = noPrinter
3738
val subtyping: Printer = noPrinter
3839
val tailrec: Printer = noPrinter
3940
val transforms: Printer = noPrinter

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package transform
33

44
import dotty.tools.dotc.ast.Trees._
55
import dotty.tools.dotc.ast.{TreeMapWithImplicits, TreeTypeMap, tpd, untpd}
6+
import dotty.tools.dotc.config.Printers.staging
67
import dotty.tools.dotc.core.Constants._
78
import dotty.tools.dotc.core.Decorators._
89
import dotty.tools.dotc.core.Flags._
@@ -71,7 +72,7 @@ abstract class TreeMapWithStages(@constructorOnly ictx: Context) extends TreeMap
7172
override def transform(tree: Tree)(implicit ctx: Context): Tree = {
7273
if (tree.source != ctx.source && tree.source.exists)
7374
transform(tree)(ctx.withSource(tree.source))
74-
else reporting.trace(i"StagingTransformer.transform $tree at $level", show = true) {
75+
else reporting.trace(i"StagingTransformer.transform $tree at $level", staging, show = true) {
7576
def mapOverTree(lastEntered: List[Symbol]) =
7677
try super.transform(tree)
7778
finally

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ object ErrorReporting {
8181
if (tree.tpe.widen.exists)
8282
i"${exprStr(tree)} does not take ${kind}parameters"
8383
else {
84-
new FatalError("").printStackTrace()
84+
//new FatalError("").printStackTrace() //DEBUG
8585
i"undefined: $tree # ${tree.uniqueId}: ${tree.tpe.toString} at ${ctx.phase}"
8686
}
8787

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -773,7 +773,7 @@ trait Implicits { self: Typer =>
773773
success(Literal(c))
774774
case TypeRef(_, sym) if sym == defn.UnitClass =>
775775
success(Literal(Constant(())))
776-
case n: NamedType =>
776+
case n: TermRef =>
777777
success(ref(n))
778778
case tp =>
779779
EmptyTree

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

+77-76
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
239239
/** A buffer for bindings that define proxies for actual arguments */
240240
private val bindingsBuf = new mutable.ListBuffer[ValOrDefDef]
241241

242-
private def newSym(name: Name, flags: FlagSet, info: Type): Symbol =
242+
private def newSym(name: Name, flags: FlagSet, info: Type)(implicit ctx: Context): Symbol =
243243
ctx.newSymbol(ctx.owner, name, flags, info, coord = call.span)
244244

245245
/** A binding for the parameter of an inline method. This is a `val` def for
@@ -732,35 +732,40 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
732732
val gadtSyms = typer.gadtSyms(scrutType)
733733

734734
/** Try to match pattern `pat` against scrutinee reference `scrut`. If successful add
735-
* bindings for variables bound in this pattern to `bindingsBuf`.
735+
* bindings for variables bound in this pattern to `caseBindingMap`.
736736
*/
737737
def reducePattern(
738-
bindingsBuf: mutable.ListBuffer[ValOrDefDef],
739-
fromBuf: mutable.ListBuffer[TypeSymbol],
740-
toBuf: mutable.ListBuffer[TypeSymbol],
738+
caseBindingMap: mutable.ListBuffer[(Symbol, MemberDef)],
741739
scrut: TermRef,
742740
pat: Tree
743741
)(implicit ctx: Context): Boolean = {
744742

745743
/** Create a binding of a pattern bound variable with matching part of
746744
* scrutinee as RHS and type that corresponds to RHS.
747745
*/
748-
def newBinding(sym: TermSymbol, rhs: Tree): Unit = {
749-
sym.info = rhs.tpe.widenTermRefExpr
750-
bindingsBuf += ValDef(sym, constToLiteral(rhs)).withSpan(sym.span)
746+
def newTermBinding(sym: TermSymbol, rhs: Tree): Unit = {
747+
val copied = sym.copy(info = rhs.tpe.widenTermRefExpr, coord = sym.coord).asTerm
748+
caseBindingMap += ((sym, ValDef(copied, constToLiteral(rhs)).withSpan(sym.span)))
749+
}
750+
751+
def newTypeBinding(sym: TypeSymbol, alias: Type): Unit = {
752+
val copied = sym.copy(info = TypeAlias(alias), coord = sym.coord).asType
753+
caseBindingMap += ((sym, TypeDef(copied)))
751754
}
752755

753756
def searchImplicit(sym: TermSymbol, tpt: Tree) = {
754757
val evTyper = new Typer
755-
val evidence = evTyper.inferImplicitArg(tpt.tpe, tpt.span)(ctx.fresh.setTyper(evTyper))
758+
val evCtx = ctx.fresh.setTyper(evTyper)
759+
val evidence = evTyper.inferImplicitArg(tpt.tpe, tpt.span)(evCtx)
756760
evidence.tpe match {
757761
case fail: Implicits.AmbiguousImplicits =>
758762
ctx.error(evTyper.missingArgMsg(evidence, tpt.tpe, ""), tpt.sourcePos)
759763
true // hard error: return true to stop implicit search here
760764
case fail: Implicits.SearchFailureType =>
761765
false
762766
case _ =>
763-
newBinding(sym, evidence)
767+
//inliner.println(i"inferred implicit $sym: ${sym.info} with $evidence: ${evidence.tpe.widen}, ${evCtx.gadt.constraint}, ${evCtx.typerState.constraint}")
768+
newTermBinding(sym, evidence)
764769
true
765770
}
766771
}
@@ -810,27 +815,25 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
810815
extractBindVariance(SimpleIdentityMap.Empty, tpt.tpe)
811816
}
812817

818+
def addTypeBindings(typeBinds: TypeBindsMap)(implicit ctx: Context): Unit =
819+
typeBinds.foreachBinding { case (sym, shouldBeMinimized) =>
820+
newTypeBinding(sym, ctx.gadt.approximation(sym, fromBelow = shouldBeMinimized))
821+
}
822+
813823
def registerAsGadtSyms(typeBinds: TypeBindsMap)(implicit ctx: Context): Unit =
814824
typeBinds.foreachBinding { case (sym, _) =>
815825
val TypeBounds(lo, hi) = sym.info.bounds
816826
ctx.gadt.addBound(sym, lo, isUpper = false)
817827
ctx.gadt.addBound(sym, hi, isUpper = true)
818828
}
819829

820-
def addTypeBindings(typeBinds: TypeBindsMap)(implicit ctx: Context): Unit =
821-
typeBinds.foreachBinding { case (sym, shouldBeMinimized) =>
822-
val copied = sym.copy(info = TypeAlias(ctx.gadt.approximation(sym, fromBelow = shouldBeMinimized))).asType
823-
fromBuf += sym
824-
toBuf += copied
825-
}
826-
827830
pat match {
828831
case Typed(pat1, tpt) =>
829832
val typeBinds = getTypeBindsMap(pat1, tpt)
830833
registerAsGadtSyms(typeBinds)
831834
scrut <:< tpt.tpe && {
832835
addTypeBindings(typeBinds)
833-
reducePattern(bindingsBuf, fromBuf, toBuf, scrut, pat1)
836+
reducePattern(caseBindingMap, scrut, pat1)
834837
}
835838
case pat @ Bind(name: TermName, Typed(_, tpt)) if isImplicit =>
836839
val typeBinds = getTypeBindsMap(tpt, tpt)
@@ -840,8 +843,8 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
840843
true
841844
}
842845
case pat @ Bind(name: TermName, body) =>
843-
reducePattern(bindingsBuf, fromBuf, toBuf, scrut, body) && {
844-
if (name != nme.WILDCARD) newBinding(pat.symbol.asTerm, ref(scrut))
846+
reducePattern(caseBindingMap, scrut, body) && {
847+
if (name != nme.WILDCARD) newTermBinding(pat.symbol.asTerm, ref(scrut))
845848
true
846849
}
847850
case Ident(nme.WILDCARD) =>
@@ -864,8 +867,8 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
864867
case (Nil, Nil) => true
865868
case (pat :: pats1, selector :: selectors1) =>
866869
val elem = newSym(InlineBinderName.fresh(), Synthetic, selector.tpe.widenTermRefExpr).asTerm
867-
newBinding(elem, selector)
868-
reducePattern(bindingsBuf, fromBuf, toBuf, elem.termRef, pat) &&
870+
caseBindingMap += ((NoSymbol, ValDef(elem, constToLiteral(selector)).withSpan(elem.span)))
871+
reducePattern(caseBindingMap, elem.termRef, pat) &&
869872
reduceSubPatterns(pats1, selectors1)
870873
case _ => false
871874
}
@@ -892,7 +895,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
892895
false
893896
}
894897
case Inlined(EmptyTree, Nil, ipat) =>
895-
reducePattern(bindingsBuf, fromBuf, toBuf, scrut, ipat)
898+
reducePattern(caseBindingMap, scrut, ipat)
896899
case _ => false
897900
}
898901
}
@@ -902,32 +905,34 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
902905
val scrutineeBinding = normalizeBinding(ValDef(scrutineeSym, scrutinee))
903906

904907
def reduceCase(cdef: CaseDef): MatchRedux = {
905-
val caseBindingsBuf = new mutable.ListBuffer[ValOrDefDef]()
906-
def guardOK(implicit ctx: Context) = cdef.guard.isEmpty || {
907-
val guardCtx = ctx.fresh.setNewScope
908-
caseBindingsBuf.foreach(binding => guardCtx.enter(binding.symbol))
909-
typer.typed(cdef.guard, defn.BooleanType)(guardCtx) match {
910-
case ConstantValue(true) => true
911-
case _ => false
908+
val caseBindingMap = new mutable.ListBuffer[(Symbol, MemberDef)]()
909+
910+
def substBindings(
911+
bindings: List[(Symbol, MemberDef)],
912+
bbuf: mutable.ListBuffer[MemberDef],
913+
from: List[Symbol], to: List[Symbol]): (List[MemberDef], List[Symbol], List[Symbol]) =
914+
bindings match {
915+
case (sym, binding) :: rest =>
916+
bbuf += binding.subst(from, to).asInstanceOf[MemberDef]
917+
if (sym.exists) substBindings(rest, bbuf, sym :: from, binding.symbol :: to)
918+
else substBindings(rest, bbuf, from, to)
919+
case Nil => (bbuf.toList, from, to)
912920
}
913-
}
914-
if (!isImplicit) caseBindingsBuf += scrutineeBinding
921+
922+
if (!isImplicit) caseBindingMap += ((NoSymbol, scrutineeBinding))
915923
val gadtCtx = typer.gadtContext(gadtSyms).addMode(Mode.GADTflexible)
916-
val fromBuf = mutable.ListBuffer.empty[TypeSymbol]
917-
val toBuf = mutable.ListBuffer.empty[TypeSymbol]
918-
if (reducePattern(caseBindingsBuf, fromBuf, toBuf, scrutineeSym.termRef, cdef.pat)(gadtCtx) && guardOK) {
919-
val caseBindings = caseBindingsBuf.toList
920-
val from = fromBuf.toList
921-
val to = toBuf.toList
922-
if (from.isEmpty) Some((caseBindings, cdef.body))
923-
else {
924-
val Block(stats, expr) = tpd.Block(caseBindings, cdef.body).subst(from, to)
925-
val typeDefs = to.collect { case sym if sym.name != tpnme.WILDCARD => tpd.TypeDef(sym).withSpan(sym.span) }
926-
Some((typeDefs ::: stats.asInstanceOf[List[MemberDef]], expr))
924+
if (reducePattern(caseBindingMap, scrutineeSym.termRef, cdef.pat)(gadtCtx)) {
925+
val (caseBindings, from, to) = substBindings(caseBindingMap.toList, mutable.ListBuffer(), Nil, Nil)
926+
val guardOK = cdef.guard.isEmpty || {
927+
typer.typed(cdef.guard.subst(from, to), defn.BooleanType) match {
928+
case ConstantValue(true) => true
929+
case _ => false
930+
}
927931
}
932+
if (guardOK) Some((caseBindings, cdef.body.subst(from, to)))
933+
else None
928934
}
929-
else
930-
None
935+
else None
931936
}
932937

933938
def recur(cases: List[CaseDef]): MatchRedux = cases match {
@@ -1053,8 +1058,29 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
10531058
*/
10541059
def dropUnusedDefs(bindings: List[MemberDef], tree: Tree)(implicit ctx: Context): (List[MemberDef], Tree) = {
10551060
// inlining.println(i"drop unused $bindings%, % in $tree")
1056-
1057-
def inlineTermBindings(termBindings: List[MemberDef], tree: Tree)(implicit ctx: Context): (List[MemberDef], Tree) = {
1061+
val (termBindings, typeBindings) = bindings.partition(_.symbol.isTerm)
1062+
if (typeBindings.nonEmpty) {
1063+
val typeBindingsSet = typeBindings.foldLeft[SimpleIdentitySet[Symbol]](SimpleIdentitySet.empty)(_ + _.symbol)
1064+
val inlineTypeBindings = new TreeTypeMap(
1065+
typeMap = new TypeMap() {
1066+
override def apply(tp: Type): Type = tp match {
1067+
case tr: TypeRef if tr.prefix.eq(NoPrefix) && typeBindingsSet.contains(tr.symbol) =>
1068+
val TypeAlias(res) = tr.info
1069+
res
1070+
case tp => mapOver(tp)
1071+
}
1072+
},
1073+
treeMap = {
1074+
case ident: Ident if ident.isType && typeBindingsSet.contains(ident.symbol) =>
1075+
val TypeAlias(r) = ident.symbol.info
1076+
TypeTree(r).withSpan(ident.span)
1077+
case tree => tree
1078+
}
1079+
)
1080+
val Block(termBindings1, tree1) = inlineTypeBindings(Block(termBindings, tree))
1081+
dropUnusedDefs(termBindings1.asInstanceOf[List[ValOrDefDef]], tree1)
1082+
}
1083+
else {
10581084
val refCount = newMutableSymbolMap[Int]
10591085
val bindingOfSym = newMutableSymbolMap[MemberDef]
10601086

@@ -1063,7 +1089,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
10631089
case vdef @ ValDef(_, _, _) => isPureExpr(vdef.rhs)
10641090
case _ => false
10651091
}
1066-
for (binding <- termBindings if isInlineable(binding)) {
1092+
for (binding <- bindings if isInlineable(binding)) {
10671093
refCount(binding.symbol) = 0
10681094
bindingOfSym(binding.symbol) = binding
10691095
}
@@ -1121,40 +1147,15 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
11211147
}
11221148
}
11231149

1124-
val retained = termBindings.filterConserve(binding => retain(binding.symbol))
1125-
if (retained `eq` termBindings) {
1126-
(termBindings, tree)
1150+
val retained = bindings.filterConserve(binding => retain(binding.symbol))
1151+
if (retained `eq` bindings) {
1152+
(bindings, tree)
11271153
}
11281154
else {
11291155
val expanded = inlineBindings.transform(tree)
11301156
dropUnusedDefs(retained, expanded)
11311157
}
11321158
}
1133-
1134-
val (termBindings, typeBindings) = bindings.partition(_.symbol.isTerm)
1135-
if (typeBindings.isEmpty) inlineTermBindings(termBindings, tree)
1136-
else {
1137-
val typeBindingsSet = typeBindings.foldLeft[SimpleIdentitySet[Symbol]](SimpleIdentitySet.empty)(_ + _.symbol)
1138-
val inlineTypeBindings = new TreeTypeMap(
1139-
typeMap = new TypeMap() {
1140-
override def apply(tp: Type): Type = tp match {
1141-
case tr: TypeRef if tr.prefix.eq(NoPrefix) && typeBindingsSet.contains(tr.symbol) =>
1142-
val TypeAlias(res) = tr.info
1143-
res
1144-
case tp => mapOver(tp)
1145-
}
1146-
},
1147-
treeMap = {
1148-
case ident: Ident if ident.isType && typeBindingsSet.contains(ident.symbol) =>
1149-
val TypeAlias(r) = ident.symbol.info
1150-
TypeTree(r).withSpan(ident.span)
1151-
case tree => tree
1152-
}
1153-
)
1154-
1155-
val Block(termBindings1, tree1) = inlineTypeBindings(Block(termBindings, tree))
1156-
inlineTermBindings(termBindings1.asInstanceOf[List[ValOrDefDef]], tree1)
1157-
}
11581159
}
11591160

11601161
private def expandMacro(body: Tree, span: Span)(implicit ctx: Context) = {

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,8 @@ object RefChecks {
156156
* 1.8.1 M's type is a subtype of O's type, or
157157
* 1.8.2 M is of type []S, O is of type ()T and S <: T, or
158158
* 1.8.3 M is of type ()S, O is of type []T and S <: T, or
159-
* 1.9.1 If M or O are erased, they must both be erased
160-
* 1.9.2 If M or O are extension methods, they must both be extension methods
159+
* 1.9.1 If M is erased, O is erased. If O is erased, M is erased or inline.
160+
* 1.9.2 If M or O are extension methods, they must both be extension methods.
161161
* 1.10 If M is an inline or Scala-2 macro method, O cannot be deferred unless
162162
* there's also a concrete method that M overrides.
163163
* 1.11. If O is a Scala-2 macro, M must be a Scala-2 macro.
@@ -394,7 +394,7 @@ object RefChecks {
394394
overrideError("must be declared lazy to override a lazy value")
395395
} else if (member.is(Erased) && !other.is(Erased)) { // (1.9.1)
396396
overrideError("is erased, cannot override non-erased member")
397-
} else if (other.is(Erased) && !member.is(Erased)) { // (1.9.1)
397+
} else if (other.is(Erased) && !member.is(Erased | Inline)) { // (1.9.1)
398398
overrideError("is not erased, cannot override erased member")
399399
} else if (member.is(Extension) && !other.is(Extension)) { // (1.9.2)
400400
overrideError("is an extension method, cannot override a normal method")

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

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ tuples1a.scala
88
typeclass-derivation1.scala
99
typeclass-derivation2.scala
1010
typeclass-derivation2a.scala
11+
typeclass-derivation2c.scala
1112
typeclass-derivation3.scala
1213
derive-generic.scala
1314
deriving-interesting-prefixes.scala

tests/neg/i6241.scala

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object Test extends App {
2+
inline def v[T] = valueOf[T] // error
3+
4+
println(v[String])
5+
}

tests/pos/implicit-match.scala renamed to tests/pending/pos/implicit-match.scala

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Implicit matches that bind parameters don't work yet.
12
object `implicit-match` {
23
object invariant {
34
case class Box[T](value: T)

0 commit comments

Comments
 (0)