Skip to content

Commit 9498a2c

Browse files
committed
Allow inline matches to bind type variables
Use SmartGADTMap and Constraint#approximation to infer and extract type values. Widen pattern-bound types in ProtoTypes so implicit search can find relevant candidates. When dropping unused bindings in Inliner, insert type bindings with a single pre-pass to correctly handle updating singleton types. Previously Select trees retained old type values, which prevented pickler roundtripping.
1 parent caac6b9 commit 9498a2c

12 files changed

+345
-155
lines changed

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

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -724,15 +724,18 @@ object Contexts {
724724
def addBound(sym: Symbol, bound: Type, isUpper: Boolean)(implicit ctx: Context): Boolean
725725
def bounds(sym: Symbol)(implicit ctx: Context): TypeBounds
726726
def contains(sym: Symbol)(implicit ctx: Context): Boolean
727+
def approximation(sym: Symbol, fromBelow: Boolean)(implicit ctx: Context): Type
727728
def debugBoundsDescription(implicit ctx: Context): String
728729
def fresh: GADTMap
730+
def restore(other: GADTMap): Unit
731+
def isEmpty: Boolean
729732
}
730733

731734
final class SmartGADTMap private (
732-
private[this] var myConstraint: Constraint,
733-
private[this] var mapping: SimpleIdentityMap[Symbol, TypeVar],
734-
private[this] var reverseMapping: SimpleIdentityMap[TypeParamRef, Symbol],
735-
private[this] var boundCache: SimpleIdentityMap[Symbol, TypeBounds]
735+
private var myConstraint: Constraint,
736+
private var mapping: SimpleIdentityMap[Symbol, TypeVar],
737+
private var reverseMapping: SimpleIdentityMap[TypeParamRef, Symbol],
738+
private var boundCache: SimpleIdentityMap[Symbol, TypeBounds]
736739
) extends GADTMap with ConstraintHandling[Context] {
737740
import dotty.tools.dotc.config.Printers.{gadts, gadtsConstr}
738741

@@ -833,13 +836,30 @@ object Contexts {
833836

834837
override def contains(sym: Symbol)(implicit ctx: Context): Boolean = mapping(sym) ne null
835838

839+
override def approximation(sym: Symbol, fromBelow: Boolean)(implicit ctx: Context): Type = {
840+
val res = removeTypeVars(approximation(tvar(sym).origin, fromBelow = fromBelow))
841+
gadts.println(i"approximating $sym ~> $res")
842+
res
843+
}
844+
836845
override def fresh: GADTMap = new SmartGADTMap(
837846
myConstraint,
838847
mapping,
839848
reverseMapping,
840849
boundCache
841850
)
842851

852+
def restore(other: GADTMap): Unit = other match {
853+
case other: SmartGADTMap =>
854+
this.myConstraint = other.myConstraint
855+
this.mapping = other.mapping
856+
this.reverseMapping = other.reverseMapping
857+
this.boundCache = other.boundCache
858+
case _ => ;
859+
}
860+
861+
override def isEmpty: Boolean = mapping.size == 0
862+
843863
// ---- Private ----------------------------------------------------------
844864

845865
private[this] def tvar(sym: Symbol)(implicit ctx: Context): TypeVar = {
@@ -916,7 +936,12 @@ object Contexts {
916936
override def addBound(sym: Symbol, bound: Type, isUpper: Boolean)(implicit ctx: Context): Boolean = unsupported("EmptyGADTMap.addBound")
917937
override def bounds(sym: Symbol)(implicit ctx: Context): TypeBounds = null
918938
override def contains(sym: Symbol)(implicit ctx: Context) = false
939+
override def approximation(sym: Symbol, fromBelow: Boolean)(implicit ctx: Context): Type = unsupported("EmptyGADTMap.approximation")
919940
override def debugBoundsDescription(implicit ctx: Context): String = "EmptyGADTMap"
920941
override def fresh = new SmartGADTMap
942+
override def restore(other: GADTMap): Unit = {
943+
if (!other.isEmpty) sys.error("cannot restore a non-empty GADTMap")
944+
}
945+
override def isEmpty: Boolean = true
921946
}
922947
}

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

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ object Implicits {
346346
* @param level The level where the reference was found
347347
* @param tstate The typer state to be committed if this alternative is chosen
348348
*/
349-
case class SearchSuccess(tree: Tree, ref: TermRef, level: Int)(val tstate: TyperState) extends SearchResult with Showable
349+
case class SearchSuccess(tree: Tree, ref: TermRef, level: Int)(val tstate: TyperState, val gstate: GADTMap) extends SearchResult with Showable
350350

351351
/** A failed search */
352352
case class SearchFailure(tree: Tree) extends SearchResult {
@@ -880,6 +880,7 @@ trait Implicits { self: Typer =>
880880
result0 match {
881881
case result: SearchSuccess =>
882882
result.tstate.commit()
883+
ctx.gadt.restore(result.gstate)
883884
implicits.println(i"success: $result")
884885
implicits.println(i"committing ${result.tstate.constraint} yielding ${ctx.typerState.constraint} in ${ctx.typerState}")
885886
result
@@ -1004,7 +1005,7 @@ trait Implicits { self: Typer =>
10041005
val generated2 =
10051006
if (cand.isExtension) Applications.ExtMethodApply(generated1).withType(generated1.tpe)
10061007
else generated1
1007-
SearchSuccess(generated2, ref, cand.level)(ctx.typerState)
1008+
SearchSuccess(generated2, ref, cand.level)(ctx.typerState, ctx.gadt)
10081009
}
10091010
}}
10101011

@@ -1016,7 +1017,8 @@ trait Implicits { self: Typer =>
10161017
SearchFailure(new DivergingImplicit(cand.ref, pt.widenExpr, argument))
10171018
else {
10181019
val history = ctx.searchHistory.nest(cand, pt)
1019-
val result = typedImplicit(cand, contextual)(nestedContext().setNewTyperState().setSearchHistory(history))
1020+
val result =
1021+
typedImplicit(cand, contextual)(nestedContext().setNewTyperState().setFreshGADTBounds.setSearchHistory(history))
10201022
result match {
10211023
case res: SearchSuccess =>
10221024
ctx.searchHistory.defineBynameImplicit(pt.widenExpr, res)
@@ -1118,7 +1120,9 @@ trait Implicits { self: Typer =>
11181120
result match {
11191121
case _: SearchFailure =>
11201122
SearchSuccess(ref(defn.Not_value), defn.Not_value.termRef, 0)(
1121-
ctx.typerState.fresh().setCommittable(true))
1123+
ctx.typerState.fresh().setCommittable(true),
1124+
ctx.gadt
1125+
)
11221126
case _: SearchSuccess =>
11231127
NoMatchingImplicitsFailure
11241128
}
@@ -1188,7 +1192,7 @@ trait Implicits { self: Typer =>
11881192
// other candidates need to be considered.
11891193
ctx.searchHistory.recursiveRef(pt) match {
11901194
case ref: TermRef =>
1191-
SearchSuccess(tpd.ref(ref).withPos(pos.startPos), ref, 0)(ctx.typerState)
1195+
SearchSuccess(tpd.ref(ref).withPos(pos.startPos), ref, 0)(ctx.typerState, ctx.gadt)
11921196
case _ =>
11931197
val eligible =
11941198
if (contextual) ctx.implicits.eligible(wildProto)
@@ -1428,7 +1432,7 @@ final class SearchRoot extends SearchHistory {
14281432
implicitDictionary.get(tpe) match {
14291433
case Some((ref, _)) =>
14301434
implicitDictionary.put(tpe, (ref, result.tree))
1431-
SearchSuccess(tpd.ref(ref).withPos(result.tree.pos), result.ref, result.level)(result.tstate)
1435+
SearchSuccess(tpd.ref(ref).withPos(result.tree.pos), result.ref, result.level)(result.tstate, result.gstate)
14321436
case None => result
14331437
}
14341438
}
@@ -1529,7 +1533,7 @@ final class SearchRoot extends SearchHistory {
15291533

15301534
val blk = Block(classDef :: inst :: Nil, res)
15311535

1532-
success.copy(tree = blk)(success.tstate)
1536+
success.copy(tree = blk)(success.tstate, success.gstate)
15331537
}
15341538
}
15351539
}

0 commit comments

Comments
 (0)