Skip to content

Commit

Permalink
Extend opaque companion context to inlined code
Browse files Browse the repository at this point in the history
The GADT bounds set in an opaque companion also need to be established for
any inlined code coming from the companion.

Test case in opaque-immutable-array.scala.
  • Loading branch information
odersky committed Mar 12, 2018
1 parent 7b67237 commit 5de563b
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 12 deletions.
7 changes: 5 additions & 2 deletions compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1017,8 +1017,11 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
/** A key to be used in a context property that tracks enclosing inlined calls */
private val InlinedCalls = new Property.Key[List[Tree]]

override def inlineContext(call: Tree)(implicit ctx: Context): Context =
ctx.fresh.setProperty(InlinedCalls, call :: enclosingInlineds)
override def inlineContext(call: Tree)(implicit ctx: Context): Context = {
val ictx = ctx.fresh.setProperty(InlinedCalls, call :: enclosingInlineds)
def stopAt(owner: Symbol) = owner.is(Package) || ctx.owner.isContainedIn(owner)
(ictx /: call.symbol.ownersIterator.takeWhile(!stopAt(_)))(ctx.handleOpaqueCompanion)
}

/** All enclosing calls that are currently inlined, from innermost to outermost */
def enclosingInlineds(implicit ctx: Context): List[Tree] =
Expand Down
30 changes: 20 additions & 10 deletions compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -101,22 +101,32 @@ trait NamerContextOps { this: Context =>
if (owner.exists) freshCtx.setOwner(owner) else freshCtx
}

/** If `owner` is a companion object of an opaque type, record the alias
* in the GADT bounds of `freshCtx.
*/
def handleOpaqueCompanion(freshCtx: FreshContext, owner: Symbol): FreshContext = {
if (owner.is(Module)) {
val opaq = owner.companionOpaqueType
val alias = opaq.opaqueAlias
if (alias.exists) {
println(i"set GADT bounds of $opaq : $alias")
val result = freshCtx.setFreshGADTBounds
result.gadt.setBounds(opaq, TypeAlias(alias))
result
}
else freshCtx
}
else freshCtx
}

/** A new context for the interior of a class */
def inClassContext(selfInfo: DotClass /* Should be Type | Symbol*/): Context = {
var localCtx: FreshContext = ctx.fresh.setNewScope
val localCtx: FreshContext = ctx.fresh.setNewScope
selfInfo match {
case sym: Symbol if sym.exists && sym.name != nme.WILDCARD => localCtx.scope.openForMutations.enter(sym)
case _ =>
}
if (ctx.owner.is(Module)) {
val opaq = ctx.owner.companionOpaqueType
val alias = opaq.opaqueAlias
if (alias.exists) {
localCtx = localCtx.setFreshGADTBounds
localCtx.gadt.setBounds(opaq, TypeAlias(alias))
}
}
localCtx
handleOpaqueCompanion(localCtx, ctx.owner)
}

def packageContext(tree: untpd.PackageDef, pkg: Symbol): Context =
Expand Down
File renamed without changes.
43 changes: 43 additions & 0 deletions tests/pos/opaque-immutable-array.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
object ia {

import java.util.Arrays

opaque type IArray[A1] = Array[A1]

object IArray {
@inline final def initialize[A](body: => Array[A]): IArray[A] = body

@inline final def size[A](ia: IArray[A]): Int = ia.length
@inline final def get[A](ia: IArray[A], i: Int): A = ia(i)

// return a sorted copy of the array
def sorted[A <: AnyRef : math.Ordering](ia: IArray[A]): IArray[A] = {
val arr = Arrays.copyOf(ia, ia.length)
scala.util.Sorting.quickSort(arr)
arr
}

// use a standard java method to search a sorted IArray.
// (note that this doesn't mutate the array).
def binarySearch(ia: IArray[Long], elem: Long): Int =
Arrays.binarySearch(ia, elem)
}

// same as IArray.binarySearch but implemented by-hand.
//
// given a sorted IArray, returns index of `elem`,
// or a negative value if not found.
def binaryIndexOf(ia: IArray[Long], elem: Long): Int = {
var lower: Int = 0
var upper: Int = IArray.size(ia)
while (lower <= upper) {
val middle = (lower + upper) >>> 1
val n = IArray.get(ia, middle)

if (n == elem) return middle
else if (n < elem) lower = middle + 1
else upper = middle - 1
}
-lower - 1
}
}

0 comments on commit 5de563b

Please sign in to comment.