Skip to content

Commit 443bdb1

Browse files
authored
Merge pull request #3233 from dotty-staging/fix-gadts
Fix GADT-related memory leak
2 parents 08582c9 + cf15ca2 commit 443bdb1

File tree

6 files changed

+38
-33
lines changed

6 files changed

+38
-33
lines changed

compiler/src/dotty/tools/dotc/Bench.scala

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
/* NSC -- new Scala compiler
2-
* Copyright 2005-2013 LAMP/EPFL
3-
* @author Martin Odersky
4-
*/
51
package dotty.tools
62
package dotc
73

@@ -24,6 +20,11 @@ object Bench extends Driver {
2420
val start = System.nanoTime()
2521
val r = super.doCompile(compiler, fileNames)
2622
println(s"time elapsed: ${(System.nanoTime - start) / 1000000}ms")
23+
if (ctx.settings.prompt.value) {
24+
print("hit <return> to continue >")
25+
System.in.read()
26+
println()
27+
}
2728
r
2829
}
2930

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

+7-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 = EmptyGADTMap
536536
}
537537

538538
@sharable object NoContext extends Context {
@@ -694,10 +694,14 @@ 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+
704+
@sharable object EmptyGADTMap extends GADTMap(SimpleMap.Empty) {
705+
override def setBounds(sym: Symbol, b: TypeBounds) = unsupported("EmptyGADTMap.setBounds")
706+
}
703707
}

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

+11-10
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

@@ -264,7 +256,7 @@ class PostTyper extends MacroTransform with SymTransformer { thisTransformer =>
264256
case tree @ Annotated(annotated, annot) =>
265257
cpy.Annotated(tree)(transform(annotated), transformAnnot(annot))
266258
case tree: AppliedTypeTree =>
267-
Checking.checkAppliedType(tree)
259+
Checking.checkAppliedType(tree, boundsCheck = !ctx.mode.is(Mode.Pattern))
268260
super.transform(tree)
269261
case SingletonTypeTree(ref) =>
270262
Checking.checkRealizable(ref.tpe, ref.pos.focus)
@@ -289,6 +281,15 @@ class PostTyper extends MacroTransform with SymTransformer { thisTransformer =>
289281
case _ =>
290282
}
291283
super.transform(tree)
284+
case Typed(Ident(nme.WILDCARD), _) =>
285+
super.transform(tree)(ctx.addMode(Mode.Pattern))
286+
// The added mode signals that bounds in a pattern need not
287+
// conform to selector bounds. I.e. assume
288+
// type Tree[T >: Null <: Type]
289+
// One is still allowed to write
290+
// case x: Tree[_]
291+
// (which translates to)
292+
// case x: (_: Tree[_])
292293
case tree =>
293294
super.transform(tree)
294295
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ object Checking {
6868
* Unreducible applications correspond to general existentials, and we
6969
* cannot handle those.
7070
*/
71-
def checkAppliedType(tree: AppliedTypeTree)(implicit ctx: Context) = {
71+
def checkAppliedType(tree: AppliedTypeTree, boundsCheck: Boolean)(implicit ctx: Context) = {
7272
val AppliedTypeTree(tycon, args) = tree
7373
// If `args` is a list of named arguments, return corresponding type parameters,
7474
// otherwise return type parameters unchanged
@@ -81,7 +81,7 @@ object Checking {
8181
val bounds = tparams.map(_.paramInfoAsSeenFrom(tycon.tpe).bounds)
8282
def instantiate(bound: Type, args: List[Type]) =
8383
HKTypeLambda.fromParams(tparams, bound).appliedTo(args)
84-
checkBounds(orderedArgs, bounds, instantiate)
84+
if (boundsCheck) checkBounds(orderedArgs, bounds, instantiate)
8585

8686
def checkWildcardApply(tp: Type, pos: Position): Unit = tp match {
8787
case tp @ AppliedType(tycon, args) if args.exists(_.isInstanceOf[TypeBounds]) =>

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,10 @@ trait ImplicitRunInfo { self: RunInfo =>
491491
override def default(key: TermRef) = 0
492492
}
493493

494-
def clear() = implicitScopeCache.clear()
494+
def clear() = {
495+
implicitScopeCache.clear()
496+
useCount.clear()
497+
}
495498
}
496499

497500
/** The implicit resolution part of type checking */

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)