Skip to content

Fix #1765: Context bounds and denotation handling #1768

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 10, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -142,16 +142,21 @@ object desugar {
val DefDef(name, tparams, vparamss, tpt, rhs) = meth
val mods = meth.mods
val epbuf = new ListBuffer[ValDef]
val tparams1 = tparams mapConserve {
case tparam @ TypeDef(_, ContextBounds(tbounds, cxbounds)) =>
def desugarContextBounds(rhs: Tree): Tree = rhs match {
case ContextBounds(tbounds, cxbounds) =>
for (cxbound <- cxbounds) {
val paramFlags: FlagSet = if (isPrimaryConstructor) PrivateLocalParamAccessor else Param
val epname = ctx.freshName(nme.EVIDENCE_PARAM_PREFIX).toTermName
epbuf += ValDef(epname, cxbound, EmptyTree).withFlags(paramFlags | Implicit)
}
cpy.TypeDef(tparam)(rhs = tbounds)
case tparam =>
tparam
tbounds
case PolyTypeTree(tparams, body) =>
cpy.PolyTypeTree(rhs)(tparams, desugarContextBounds(body))
case _ =>
rhs
}
val tparams1 = tparams mapConserve { tdef =>
cpy.TypeDef(tdef)(rhs = desugarContextBounds(tdef.rhs))
}

val meth1 = addEvidenceParams(cpy.DefDef(meth)(tparams = tparams1), epbuf.toList)
Expand Down
22 changes: 19 additions & 3 deletions compiler/src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ object Denotations {
def atSignature(sig: Signature, site: Type = NoPrefix, relaxed: Boolean = false)(implicit ctx: Context): Denotation

/** The variant of this denotation that's current in the given context.
* If no such denotation exists, returns the denotation with each alternative
* If no such denotation exists, returns the denotation with each alternative
* at its first point of definition.
*/
def current(implicit ctx: Context): Denotation
Expand Down Expand Up @@ -744,6 +744,20 @@ object Denotations {
else NoDenotation
}

/** The next defined denotation (following `nextInRun`) or an arbitrary
* undefined denotation, if all denotations in a `nextinRun` cycle are
* undefined.
*/
private def nextDefined: SingleDenotation = {
var p1 = this
var p2 = nextInRun
while (p1.validFor == Nowhere && (p1 ne p2)) {
p1 = p1.nextInRun
p2 = p2.nextInRun.nextInRun
}
p1
}

/** Produce a denotation that is valid for the given context.
* Usually called when !(validFor contains ctx.period)
* (even though this is not a precondition).
Expand All @@ -763,8 +777,9 @@ object Denotations {
// can happen if we sit on a stale denotation which has been replaced
// wholesale by an installAfter; in this case, proceed to the next
// denotation and try again.
if (validFor == Nowhere && nextInRun.validFor != Nowhere) return nextInRun.current
assert(false)
val nxt = nextDefined
if (nxt.validFor != Nowhere) return nxt
assert(false, this)
}

if (valid.runId != currentPeriod.runId)
Expand Down Expand Up @@ -905,6 +920,7 @@ object Denotations {
prev.nextInRun = this
this.nextInRun = old.nextInRun
old.validFor = Nowhere
old.nextInRun = this
}

def staleSymbolError(implicit ctx: Context) = {
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Periods.scala
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ object Periods {
final val FirstPhaseId = 1

/** The number of bits needed to encode a phase identifier. */
final val PhaseWidth = 6
final val PhaseWidth = 7
final val PhaseMask = (1 << PhaseWidth) - 1
final val MaxPossiblePhaseId = PhaseMask
}
8 changes: 5 additions & 3 deletions compiler/src/dotty/tools/dotc/transform/Memoize.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ import Decorators._
}
tree match {
case ddef: DefDef
if !ddef.symbol.is(Deferred) && ddef.rhs == EmptyTree =>
if !ddef.symbol.is(Deferred) &&
!ddef.symbol.isConstructor && // constructors bodies are added later at phase Constructors
ddef.rhs == EmptyTree =>
errorLackImplementation(ddef)
case tdef: TypeDef
if tdef.symbol.isClass && !tdef.symbol.is(Deferred) && tdef.rhs == EmptyTree =>
Expand Down Expand Up @@ -89,10 +91,10 @@ import Decorators._
}

lazy val field = sym.field.orElse(newField).asTerm

def adaptToField(tree: Tree) =
if (tree.isEmpty) tree else tree.ensureConforms(field.info.widen)

if (sym.is(Accessor, butNot = NoFieldNeeded))
if (sym.isGetter) {
def skipBlocks(t: Tree): Tree = t match {
Expand Down
21 changes: 21 additions & 0 deletions tests/pos/i1765.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
trait T[X]

trait U[X]

trait TC[M[_]] {
def foo[M[_]: TC, A](ma: U[A]) = ()
implicit val TCofT: TC[T] = new TC[T] {}
implicit def any2T[A](a: A): T[A] = new T[A] {}
implicit def any2U[A](a: A): U[A] = new U[A] {}
val x = foo[T, Int](1)
val y = ()
}

// Minimized version exhibiting an assertion violation in Denotation#current at phase lambdalift:
trait TC2 {
// implicit val TCofT: TC2[T] = new TC2[T] {}
val TCofT: Object = {
class C extends TC2
new Object
}
}