Skip to content

Commit 5d8ea09

Browse files
committed
Allow constraining type parameters of all enclosing functions
gadtSyms/gadtContext became redundant, so they were removed. The logic in typedDefDef was adjusted to only create a fresh context when necessary.
1 parent 3d71367 commit 5d8ea09

File tree

5 files changed

+47
-47
lines changed

5 files changed

+47
-47
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -403,9 +403,9 @@ class TreeChecker extends Phase with SymTransformer {
403403
}
404404
}
405405

406-
override def typedCase(tree: untpd.CaseDef, selType: Type, pt: Type, gadtSyms: Set[Symbol])(implicit ctx: Context): CaseDef = {
406+
override def typedCase(tree: untpd.CaseDef, selType: Type, pt: Type)(implicit ctx: Context): CaseDef = {
407407
withPatSyms(tpd.patVars(tree.pat.asInstanceOf[tpd.Tree])) {
408-
super.typedCase(tree, selType, pt, gadtSyms)
408+
super.typedCase(tree, selType, pt)
409409
}
410410
}
411411

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,6 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
688688
def reduceInlineMatch(scrutinee: Tree, scrutType: Type, cases: List[CaseDef], typer: Typer)(implicit ctx: Context): MatchRedux = {
689689

690690
val isImplicit = scrutinee.isEmpty
691-
val gadtSyms = typer.gadtSyms(scrutType)
692691

693692
/** Try to match pattern `pat` against scrutinee reference `scrut`. If successful add
694693
* bindings for variables bound in this pattern to `bindingsBuf`.
@@ -869,7 +868,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
869868
}
870869
}
871870
if (!isImplicit) caseBindingsBuf += scrutineeBinding
872-
val gadtCtx = typer.gadtContext(gadtSyms).addMode(Mode.GADTflexible)
871+
val gadtCtx = ctx.fresh.setFreshGADTBounds.addMode(Mode.GADTflexible)
873872
val fromBuf = mutable.ListBuffer.empty[TypeSymbol]
874873
val toBuf = mutable.ListBuffer.empty[TypeSymbol]
875874
if (reducePattern(caseBindingsBuf, fromBuf, toBuf, scrutineeSym.termRef, cdef.pat)(gadtCtx) && guardOK) {

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

Lines changed: 33 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,37 +1038,8 @@ class Typer extends Namer
10381038
assignType(cpy.Match(tree)(sel, cases1), sel, cases1)
10391039
}
10401040

1041-
/** gadtSyms = "all type parameters of enclosing methods that appear
1042-
* non-variantly in the selector type" todo: should typevars
1043-
* which appear with variances +1 and -1 (in different
1044-
* places) be considered as well?
1045-
*/
1046-
def gadtSyms(selType: Type)(implicit ctx: Context): Set[Symbol] = trace(i"GADT syms of $selType", gadts) {
1047-
val accu = new TypeAccumulator[Set[Symbol]] {
1048-
def apply(tsyms: Set[Symbol], t: Type): Set[Symbol] = {
1049-
val tsyms1 = t match {
1050-
case tr: TypeRef if (tr.symbol is TypeParam) && tr.symbol.owner.isTerm && variance == 0 =>
1051-
tsyms + tr.symbol
1052-
case _ =>
1053-
tsyms
1054-
}
1055-
foldOver(tsyms1, t)
1056-
}
1057-
}
1058-
accu(Set.empty, selType)
1059-
}
1060-
1061-
/** Context with fresh GADT bounds for all gadtSyms */
1062-
def gadtContext(gadtSyms: Set[Symbol])(implicit ctx: Context): Context = {
1063-
val gadtCtx = ctx.fresh.setFreshGADTBounds
1064-
for (sym <- gadtSyms)
1065-
if (!gadtCtx.gadt.contains(sym)) gadtCtx.gadt.addEmptyBounds(sym)
1066-
gadtCtx
1067-
}
1068-
10691041
def typedCases(cases: List[untpd.CaseDef], selType: Type, pt: Type)(implicit ctx: Context): List[CaseDef] = {
1070-
val gadts = gadtSyms(selType)
1071-
cases.mapconserve(typedCase(_, selType, pt, gadts))
1042+
cases.mapconserve(typedCase(_, selType, pt))
10721043
}
10731044

10741045
/** - strip all instantiated TypeVars from pattern types.
@@ -1096,9 +1067,9 @@ class Typer extends Namer
10961067
}
10971068

10981069
/** Type a case. */
1099-
def typedCase(tree: untpd.CaseDef, selType: Type, pt: Type, gadtSyms: Set[Symbol])(implicit ctx: Context): CaseDef = track("typedCase") {
1070+
def typedCase(tree: untpd.CaseDef, selType: Type, pt: Type)(implicit ctx: Context): CaseDef = track("typedCase") {
11001071
val originalCtx = ctx
1101-
val gadtCtx = gadtContext(gadtSyms)
1072+
val gadtCtx: Context = ctx.fresh.setFreshGADTBounds
11021073

11031074
def caseRest(pat: Tree)(implicit ctx: Context) = {
11041075
val pat1 = indexPattern(tree).transform(pat)
@@ -1535,19 +1506,38 @@ class Typer extends Namer
15351506
if (sym is Implicit) checkImplicitConversionDefOK(sym)
15361507
val tpt1 = checkSimpleKinded(typedType(tpt))
15371508

1538-
var rhsCtx = ctx
1539-
if (sym.isConstructor && !sym.isPrimaryConstructor && tparams1.nonEmpty) {
1540-
// for secondary constructors we need a context that "knows"
1541-
// that their type parameters are aliases of the class type parameters.
1542-
// See pos/i941.scala
1543-
rhsCtx = ctx.fresh.setFreshGADTBounds
1544-
(tparams1, sym.owner.typeParams).zipped.foreach { (tdef, tparam) =>
1545-
val tr = tparam.typeRef
1546-
rhsCtx.gadt.addBound(tdef.symbol, tr, isUpper = false)
1547-
rhsCtx.gadt.addBound(tdef.symbol, tr, isUpper = true)
1509+
val rhsCtx: Context = {
1510+
var _result: FreshContext = null
1511+
def resultCtx(): FreshContext = {
1512+
if (_result == null) _result = ctx.fresh
1513+
_result
1514+
}
1515+
1516+
if (tparams1.nonEmpty) {
1517+
resultCtx().setFreshGADTBounds
1518+
if (!sym.isConstructor) {
1519+
// if we're _not_ in a constructor, allow constraining type parameters
1520+
tparams1.foreach { tdef =>
1521+
val tb @ TypeBounds(lo, hi) = tdef.symbol.info.bounds
1522+
resultCtx().gadt.addBound(tdef.symbol, lo, isUpper = false)
1523+
resultCtx().gadt.addBound(tdef.symbol, hi, isUpper = true)
1524+
}
1525+
} else if (!sym.isPrimaryConstructor) {
1526+
// otherwise, for secondary constructors we need a context that "knows"
1527+
// that their type parameters are aliases of the class type parameters.
1528+
// See pos/i941.scala
1529+
(tparams1, sym.owner.typeParams).zipped.foreach { (tdef, tparam) =>
1530+
val tr = tparam.typeRef
1531+
resultCtx().gadt.addBound(tdef.symbol, tr, isUpper = false)
1532+
resultCtx().gadt.addBound(tdef.symbol, tr, isUpper = true)
1533+
}
1534+
}
15481535
}
1536+
1537+
if (sym.isInlineMethod) resultCtx().addMode(Mode.InlineableBody)
1538+
1539+
if (_result ne null) _result else ctx
15491540
}
1550-
if (sym.isInlineMethod) rhsCtx = rhsCtx.addMode(Mode.InlineableBody)
15511541
val rhs1 = typedExpr(ddef.rhs, tpt1.tpe)(rhsCtx)
15521542

15531543
if (sym.isInlineMethod) PrepareInlineable.registerInlineInfo(sym, ddef.rhs, _ => rhs1)

tests/pos/gadt-all-params.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
object `gadt-all-params` {
2+
enum Expr[T] {
3+
case UnitLit extends Expr[Unit]
4+
}
5+
6+
def foo[T >: TT <: TT, TT](e: Expr[T]): T = e match {
7+
case Expr.UnitLit => ()
8+
}
9+
}

tests/run/tasty-extractors-3.check

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Type.SymRef(IsClassSymbol(<scala.Any>), Type.ThisType(Type.SymRef(IsPackageSymbo
1010

1111
Type.SymRef(IsTypeSymbol(<Test$._$_$T>), NoPrefix())
1212

13+
Type.SymRef(IsTypeSymbol(<Test$._$_$T>), NoPrefix())
14+
1315
TypeBounds(Type.SymRef(IsClassSymbol(<scala.Int>), Type.SymRef(IsPackageSymbol(<scala>), Type.ThisType(Type.SymRef(IsPackageSymbol(<<root>>), NoPrefix())))), Type.SymRef(IsClassSymbol(<scala.Int>), Type.SymRef(IsPackageSymbol(<scala>), Type.ThisType(Type.SymRef(IsPackageSymbol(<<root>>), NoPrefix())))))
1416

1517
Type.SymRef(IsClassSymbol(<scala.Int>), Type.SymRef(IsPackageSymbol(<scala>), Type.ThisType(Type.SymRef(IsPackageSymbol(<<root>>), NoPrefix()))))

0 commit comments

Comments
 (0)