Skip to content

Commit eb21d24

Browse files
committed
Fix GADT-related memory leak
There was a confusion which led to the wrong gadt map being used for pattern-bound variables if there was no other GADT variable in the enclosing method. This led to the outermost gadt map in the initial context being populated with type bounds which never went away.
1 parent a516a4e commit eb21d24

File tree

3 files changed

+18
-25
lines changed

3 files changed

+18
-25
lines changed

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

+6-3
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ object Contexts {
476476
def setRunInfo(runInfo: RunInfo): this.type = { this.runInfo = runInfo; this }
477477
def setDiagnostics(diagnostics: Option[StringBuilder]): this.type = { this.diagnostics = diagnostics; this }
478478
def setGadt(gadt: GADTMap): this.type = { this.gadt = gadt; this }
479+
def setFreshGADTBounds: this.type = setGadt(new GADTMap(gadt.bounds))
479480
def setTypeComparerFn(tcfn: Context => TypeComparer): this.type = { this.typeComparer = tcfn(this); this }
480481
def setSearchHistory(searchHistory: SearchHistory): this.type = { this.searchHistory = searchHistory; this }
481482
def setFreshNames(freshNames: FreshNameCreator): this.type = { this.freshNames = freshNames; this }
@@ -493,7 +494,6 @@ object Contexts {
493494
def setSetting[T](setting: Setting[T], value: T): this.type =
494495
setSettings(setting.updateIn(sstate, value))
495496

496-
def setFreshGADTBounds: this.type = { this.gadt = new GADTMap(gadt.bounds); this }
497497

498498
def setDebug = setSetting(base.settings.debug, true)
499499
}
@@ -532,7 +532,7 @@ object Contexts {
532532
moreProperties = Map.empty
533533
typeComparer = new TypeComparer(this)
534534
searchHistory = new SearchHistory(0, Map())
535-
gadt = new GADTMap(SimpleMap.Empty)
535+
gadt = new GADTMap(SimpleMap.Empty) // EmptyGADTMap
536536
}
537537

538538
@sharable object NoContext extends Context {
@@ -694,10 +694,13 @@ object Contexts {
694694
implicit val ctx: Context = initctx
695695
}
696696

697-
class GADTMap(initBounds: SimpleMap[Symbol, TypeBounds]) {
697+
class GADTMap(initBounds: SimpleMap[Symbol, TypeBounds]) extends util.DotClass {
698698
private var myBounds = initBounds
699699
def setBounds(sym: Symbol, b: TypeBounds): Unit =
700700
myBounds = myBounds.updated(sym, b)
701701
def bounds = myBounds
702702
}
703+
object EmptyGADTMap extends GADTMap(SimpleMap.Empty) {
704+
override def setBounds(sym: Symbol, b: TypeBounds) = unsupported("EmptyGADTMap.setBound")
705+
}
703706
}

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

+3-9
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,9 @@ import reporting.diagnostic.messages.SuperCallsNotAllowedInline
5454
* mini-phase or subfunction of a macro phase equally well. But taken by themselves
5555
* they do not warrant their own group of miniphases before pickling.
5656
*/
57-
class PostTyper extends MacroTransform with SymTransformer { thisTransformer =>
58-
59-
57+
class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTransformer =>
6058
import tpd._
6159

62-
def transformSym(ref: SymDenotation)(implicit ctx: Context): SymDenotation = {
63-
if (ref.is(BindDefinedType) && ctx.gadt.bounds.contains(ref.symbol)) {
64-
ref.copySymDenotation(info = ctx.gadt.bounds.apply(ref.symbol) & ref.info)
65-
} else ref
66-
}
67-
6860
/** the following two members override abstract members in Transform */
6961
override def phaseName: String = "posttyper"
7062

@@ -289,6 +281,8 @@ class PostTyper extends MacroTransform with SymTransformer { thisTransformer =>
289281
case _ =>
290282
}
291283
super.transform(tree)
284+
case Typed(Ident(nme.WILDCARD), _) =>
285+
tree // skip checking pattern type
292286
case tree =>
293287
super.transform(tree)
294288
}

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

+9-13
Original file line numberDiff line numberDiff line change
@@ -921,16 +921,21 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
921921
def typedCase(tree: untpd.CaseDef, pt: Type, selType: Type, gadtSyms: Set[Symbol])(implicit ctx: Context): CaseDef = track("typedCase") {
922922
val originalCtx = ctx
923923

924+
val gadtCtx = ctx.fresh.setFreshGADTBounds
925+
for (sym <- gadtSyms)
926+
if (!gadtCtx.gadt.bounds.contains(sym))
927+
gadtCtx.gadt.setBounds(sym, TypeBounds.empty)
928+
924929
/** - replace all references to symbols associated with wildcards by their GADT bounds
925930
* - enter all symbols introduced by a Bind in current scope
926931
*/
927932
val indexPattern = new TreeMap {
928933
val elimWildcardSym = new TypeMap {
929934
def apply(t: Type) = t match {
930-
case ref: TypeRef if ref.name == tpnme.WILDCARD && ctx.gadt.bounds.contains(ref.symbol) =>
931-
ctx.gadt.bounds(ref.symbol)
932-
case TypeAlias(ref: TypeRef) if ref.name == tpnme.WILDCARD && ctx.gadt.bounds.contains(ref.symbol) =>
933-
ctx.gadt.bounds(ref.symbol)
935+
case ref: TypeRef if ref.name == tpnme.WILDCARD && gadtCtx.gadt.bounds.contains(ref.symbol) =>
936+
gadtCtx.gadt.bounds(ref.symbol)
937+
case TypeAlias(ref: TypeRef) if ref.name == tpnme.WILDCARD && gadtCtx.gadt.bounds.contains(ref.symbol) =>
938+
gadtCtx.gadt.bounds(ref.symbol)
934939
case _ =>
935940
mapOver(t)
936941
}
@@ -955,15 +960,6 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
955960
assignType(cpy.CaseDef(tree)(pat1, guard1, body1), body1)
956961
}
957962

958-
val gadtCtx =
959-
if (gadtSyms.isEmpty) ctx
960-
else {
961-
val c = ctx.fresh.setFreshGADTBounds
962-
for (sym <- gadtSyms)
963-
if (!c.gadt.bounds.contains(sym))
964-
c.gadt.setBounds(sym, TypeBounds.empty)
965-
c
966-
}
967963
val pat1 = typedPattern(tree.pat, selType)(gadtCtx)
968964
caseRest(pat1)(gadtCtx.fresh.setNewScope)
969965
}

0 commit comments

Comments
 (0)