Skip to content

Commit fb0e3bc

Browse files
authored
Merge pull request #5657 from dotty-staging/inline-type-binds
Allow inline matches to bind type variables
2 parents bbf98ac + e772dbb commit fb0e3bc

13 files changed

+372
-159
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 {
@@ -904,6 +904,7 @@ trait Implicits { self: Typer =>
904904
result0 match {
905905
case result: SearchSuccess =>
906906
result.tstate.commit()
907+
ctx.gadt.restore(result.gstate)
907908
implicits.println(i"success: $result")
908909
implicits.println(i"committing ${result.tstate.constraint} yielding ${ctx.typerState.constraint} in ${ctx.typerState}")
909910
result
@@ -1028,7 +1029,7 @@ trait Implicits { self: Typer =>
10281029
val generated2 =
10291030
if (cand.isExtension) Applications.ExtMethodApply(generated1).withType(generated1.tpe)
10301031
else generated1
1031-
SearchSuccess(generated2, ref, cand.level)(ctx.typerState)
1032+
SearchSuccess(generated2, ref, cand.level)(ctx.typerState, ctx.gadt)
10321033
}
10331034
}}
10341035

@@ -1040,7 +1041,8 @@ trait Implicits { self: Typer =>
10401041
SearchFailure(new DivergingImplicit(cand.ref, pt.widenExpr, argument))
10411042
else {
10421043
val history = ctx.searchHistory.nest(cand, pt)
1043-
val result = typedImplicit(cand, contextual)(nestedContext().setNewTyperState().setSearchHistory(history))
1044+
val result =
1045+
typedImplicit(cand, contextual)(nestedContext().setNewTyperState().setFreshGADTBounds.setSearchHistory(history))
10441046
result match {
10451047
case res: SearchSuccess =>
10461048
ctx.searchHistory.defineBynameImplicit(pt.widenExpr, res)
@@ -1142,7 +1144,9 @@ trait Implicits { self: Typer =>
11421144
result match {
11431145
case _: SearchFailure =>
11441146
SearchSuccess(ref(defn.Not_value), defn.Not_value.termRef, 0)(
1145-
ctx.typerState.fresh().setCommittable(true))
1147+
ctx.typerState.fresh().setCommittable(true),
1148+
ctx.gadt
1149+
)
11461150
case _: SearchSuccess =>
11471151
NoMatchingImplicitsFailure
11481152
}
@@ -1212,7 +1216,7 @@ trait Implicits { self: Typer =>
12121216
// other candidates need to be considered.
12131217
ctx.searchHistory.recursiveRef(pt) match {
12141218
case ref: TermRef =>
1215-
SearchSuccess(tpd.ref(ref).withPos(pos.startPos), ref, 0)(ctx.typerState)
1219+
SearchSuccess(tpd.ref(ref).withPos(pos.startPos), ref, 0)(ctx.typerState, ctx.gadt)
12161220
case _ =>
12171221
val eligible =
12181222
if (contextual) ctx.implicits.eligible(wildProto)
@@ -1452,7 +1456,7 @@ final class SearchRoot extends SearchHistory {
14521456
implicitDictionary.get(tpe) match {
14531457
case Some((ref, _)) =>
14541458
implicitDictionary.put(tpe, (ref, result.tree))
1455-
SearchSuccess(tpd.ref(ref).withPos(result.tree.pos), result.ref, result.level)(result.tstate)
1459+
SearchSuccess(tpd.ref(ref).withPos(result.tree.pos), result.ref, result.level)(result.tstate, result.gstate)
14561460
case None => result
14571461
}
14581462
}
@@ -1553,7 +1557,7 @@ final class SearchRoot extends SearchHistory {
15531557

15541558
val blk = Block(classDef :: inst :: Nil, res)
15551559

1556-
success.copy(tree = blk)(success.tstate)
1560+
success.copy(tree = blk)(success.tstate, success.gstate)
15571561
}
15581562
}
15591563
}

0 commit comments

Comments
 (0)