Skip to content

Commit

Permalink
Merge pull request #3233 from dotty-staging/fix-gadts
Browse files Browse the repository at this point in the history
Fix GADT-related memory leak
  • Loading branch information
smarter authored Oct 4, 2017
2 parents 08582c9 + cf15ca2 commit 443bdb1
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 33 deletions.
9 changes: 5 additions & 4 deletions compiler/src/dotty/tools/dotc/Bench.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
/* NSC -- new Scala compiler
* Copyright 2005-2013 LAMP/EPFL
* @author Martin Odersky
*/
package dotty.tools
package dotc

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

Expand Down
10 changes: 7 additions & 3 deletions compiler/src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@ object Contexts {
def setRunInfo(runInfo: RunInfo): this.type = { this.runInfo = runInfo; this }
def setDiagnostics(diagnostics: Option[StringBuilder]): this.type = { this.diagnostics = diagnostics; this }
def setGadt(gadt: GADTMap): this.type = { this.gadt = gadt; this }
def setFreshGADTBounds: this.type = setGadt(new GADTMap(gadt.bounds))
def setTypeComparerFn(tcfn: Context => TypeComparer): this.type = { this.typeComparer = tcfn(this); this }
def setSearchHistory(searchHistory: SearchHistory): this.type = { this.searchHistory = searchHistory; this }
def setFreshNames(freshNames: FreshNameCreator): this.type = { this.freshNames = freshNames; this }
Expand All @@ -493,7 +494,6 @@ object Contexts {
def setSetting[T](setting: Setting[T], value: T): this.type =
setSettings(setting.updateIn(sstate, value))

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

def setDebug = setSetting(base.settings.debug, true)
}
Expand Down Expand Up @@ -532,7 +532,7 @@ object Contexts {
moreProperties = Map.empty
typeComparer = new TypeComparer(this)
searchHistory = new SearchHistory(0, Map())
gadt = new GADTMap(SimpleMap.Empty)
gadt = EmptyGADTMap
}

@sharable object NoContext extends Context {
Expand Down Expand Up @@ -694,10 +694,14 @@ object Contexts {
implicit val ctx: Context = initctx
}

class GADTMap(initBounds: SimpleMap[Symbol, TypeBounds]) {
class GADTMap(initBounds: SimpleMap[Symbol, TypeBounds]) extends util.DotClass {
private var myBounds = initBounds
def setBounds(sym: Symbol, b: TypeBounds): Unit =
myBounds = myBounds.updated(sym, b)
def bounds = myBounds
}

@sharable object EmptyGADTMap extends GADTMap(SimpleMap.Empty) {
override def setBounds(sym: Symbol, b: TypeBounds) = unsupported("EmptyGADTMap.setBounds")
}
}
21 changes: 11 additions & 10 deletions compiler/src/dotty/tools/dotc/transform/PostTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,9 @@ import reporting.diagnostic.messages.SuperCallsNotAllowedInline
* mini-phase or subfunction of a macro phase equally well. But taken by themselves
* they do not warrant their own group of miniphases before pickling.
*/
class PostTyper extends MacroTransform with SymTransformer { thisTransformer =>


class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTransformer =>
import tpd._

def transformSym(ref: SymDenotation)(implicit ctx: Context): SymDenotation = {
if (ref.is(BindDefinedType) && ctx.gadt.bounds.contains(ref.symbol)) {
ref.copySymDenotation(info = ctx.gadt.bounds.apply(ref.symbol) & ref.info)
} else ref
}

/** the following two members override abstract members in Transform */
override def phaseName: String = "posttyper"

Expand Down Expand Up @@ -264,7 +256,7 @@ class PostTyper extends MacroTransform with SymTransformer { thisTransformer =>
case tree @ Annotated(annotated, annot) =>
cpy.Annotated(tree)(transform(annotated), transformAnnot(annot))
case tree: AppliedTypeTree =>
Checking.checkAppliedType(tree)
Checking.checkAppliedType(tree, boundsCheck = !ctx.mode.is(Mode.Pattern))
super.transform(tree)
case SingletonTypeTree(ref) =>
Checking.checkRealizable(ref.tpe, ref.pos.focus)
Expand All @@ -289,6 +281,15 @@ class PostTyper extends MacroTransform with SymTransformer { thisTransformer =>
case _ =>
}
super.transform(tree)
case Typed(Ident(nme.WILDCARD), _) =>
super.transform(tree)(ctx.addMode(Mode.Pattern))
// The added mode signals that bounds in a pattern need not
// conform to selector bounds. I.e. assume
// type Tree[T >: Null <: Type]
// One is still allowed to write
// case x: Tree[_]
// (which translates to)
// case x: (_: Tree[_])
case tree =>
super.transform(tree)
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ object Checking {
* Unreducible applications correspond to general existentials, and we
* cannot handle those.
*/
def checkAppliedType(tree: AppliedTypeTree)(implicit ctx: Context) = {
def checkAppliedType(tree: AppliedTypeTree, boundsCheck: Boolean)(implicit ctx: Context) = {
val AppliedTypeTree(tycon, args) = tree
// If `args` is a list of named arguments, return corresponding type parameters,
// otherwise return type parameters unchanged
Expand All @@ -81,7 +81,7 @@ object Checking {
val bounds = tparams.map(_.paramInfoAsSeenFrom(tycon.tpe).bounds)
def instantiate(bound: Type, args: List[Type]) =
HKTypeLambda.fromParams(tparams, bound).appliedTo(args)
checkBounds(orderedArgs, bounds, instantiate)
if (boundsCheck) checkBounds(orderedArgs, bounds, instantiate)

def checkWildcardApply(tp: Type, pos: Position): Unit = tp match {
case tp @ AppliedType(tycon, args) if args.exists(_.isInstanceOf[TypeBounds]) =>
Expand Down
5 changes: 4 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,10 @@ trait ImplicitRunInfo { self: RunInfo =>
override def default(key: TermRef) = 0
}

def clear() = implicitScopeCache.clear()
def clear() = {
implicitScopeCache.clear()
useCount.clear()
}
}

/** The implicit resolution part of type checking */
Expand Down
22 changes: 9 additions & 13 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -921,16 +921,21 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def typedCase(tree: untpd.CaseDef, pt: Type, selType: Type, gadtSyms: Set[Symbol])(implicit ctx: Context): CaseDef = track("typedCase") {
val originalCtx = ctx

val gadtCtx = ctx.fresh.setFreshGADTBounds
for (sym <- gadtSyms)
if (!gadtCtx.gadt.bounds.contains(sym))
gadtCtx.gadt.setBounds(sym, TypeBounds.empty)

/** - replace all references to symbols associated with wildcards by their GADT bounds
* - enter all symbols introduced by a Bind in current scope
*/
val indexPattern = new TreeMap {
val elimWildcardSym = new TypeMap {
def apply(t: Type) = t match {
case ref: TypeRef if ref.name == tpnme.WILDCARD && ctx.gadt.bounds.contains(ref.symbol) =>
ctx.gadt.bounds(ref.symbol)
case TypeAlias(ref: TypeRef) if ref.name == tpnme.WILDCARD && ctx.gadt.bounds.contains(ref.symbol) =>
ctx.gadt.bounds(ref.symbol)
case ref: TypeRef if ref.name == tpnme.WILDCARD && gadtCtx.gadt.bounds.contains(ref.symbol) =>
gadtCtx.gadt.bounds(ref.symbol)
case TypeAlias(ref: TypeRef) if ref.name == tpnme.WILDCARD && gadtCtx.gadt.bounds.contains(ref.symbol) =>
gadtCtx.gadt.bounds(ref.symbol)
case _ =>
mapOver(t)
}
Expand All @@ -955,15 +960,6 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
assignType(cpy.CaseDef(tree)(pat1, guard1, body1), body1)
}

val gadtCtx =
if (gadtSyms.isEmpty) ctx
else {
val c = ctx.fresh.setFreshGADTBounds
for (sym <- gadtSyms)
if (!c.gadt.bounds.contains(sym))
c.gadt.setBounds(sym, TypeBounds.empty)
c
}
val pat1 = typedPattern(tree.pat, selType)(gadtCtx)
caseRest(pat1)(gadtCtx.fresh.setNewScope)
}
Expand Down

0 comments on commit 443bdb1

Please sign in to comment.