From 16671a00371df2bdbaf6ae7f51b0ec7191ce94f3 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 2 Dec 2016 16:37:49 +0100 Subject: [PATCH 1/4] Go to 7 bits for phase numbers We were pushing the limit of 64 phases before. --- compiler/src/dotty/tools/dotc/core/Periods.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Periods.scala b/compiler/src/dotty/tools/dotc/core/Periods.scala index 6efadab7f271..29d9d208f43c 100644 --- a/compiler/src/dotty/tools/dotc/core/Periods.scala +++ b/compiler/src/dotty/tools/dotc/core/Periods.scala @@ -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 } From af39d28ed9a30274efaadd26573f43891550dc6d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 2 Dec 2016 16:42:00 +0100 Subject: [PATCH 2/4] Handle hk types with context bounds in desugar With the change to the representation of higher-kinded type definitions, context bounds could be hidden in the body of a type lambda. Need to compensate for that. --- compiler/src/dotty/tools/dotc/ast/Desugar.scala | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index c8b1ed909967..61977be04d1f 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -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) From 131fcf26e65d45bea89989ced209f394457a6d12 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 2 Dec 2016 16:43:09 +0100 Subject: [PATCH 3/4] Fine-tune post-conditions. The previous post-condition failed if a Ycheck was introduced between memoize and constructors. --- compiler/src/dotty/tools/dotc/transform/Memoize.scala | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/Memoize.scala b/compiler/src/dotty/tools/dotc/transform/Memoize.scala index 01c240e3ad18..0314d4ec4b10 100644 --- a/compiler/src/dotty/tools/dotc/transform/Memoize.scala +++ b/compiler/src/dotty/tools/dotc/transform/Memoize.scala @@ -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 => @@ -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 { From a7003bb223fb535f64a3026ff2a5a3e7d3ab7609 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 2 Dec 2016 16:48:11 +0100 Subject: [PATCH 4/4] Fix insertAfter Once the context-bounds desugaring of i1765.scala was fixed, another problem came up: We hit an invalid denotation due to some interaction between mixin and memoize. It turned out that `insertInsteadOf` did not do what its doc comment claimed: it did not store a forwarding pointer `nextInRun` in the overwritten denotation. Once that was fixed we also needed to fix a follow-on erorr that now we could have chains of invalid denotations linked by `nextInRun`. --- .../dotty/tools/dotc/core/Denotations.scala | 22 ++++++++++++++++--- tests/pos/i1765.scala | 21 ++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 tests/pos/i1765.scala diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 6a39c5787947..99c688d50973 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -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 @@ -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). @@ -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) @@ -905,6 +920,7 @@ object Denotations { prev.nextInRun = this this.nextInRun = old.nextInRun old.validFor = Nowhere + old.nextInRun = this } def staleSymbolError(implicit ctx: Context) = { diff --git a/tests/pos/i1765.scala b/tests/pos/i1765.scala new file mode 100644 index 000000000000..d791296381d3 --- /dev/null +++ b/tests/pos/i1765.scala @@ -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 + } +}