Skip to content

Commit 157c5fa

Browse files
committed
Extend opaque companion context to inlined code
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.
1 parent 5c28ca1 commit 157c5fa

File tree

4 files changed

+68
-12
lines changed

4 files changed

+68
-12
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,8 +1017,11 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
10171017
/** A key to be used in a context property that tracks enclosing inlined calls */
10181018
private val InlinedCalls = new Property.Key[List[Tree]]
10191019

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

10231026
/** All enclosing calls that are currently inlined, from innermost to outermost */
10241027
def enclosingInlineds(implicit ctx: Context): List[Tree] =

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

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,22 +101,32 @@ trait NamerContextOps { this: Context =>
101101
if (owner.exists) freshCtx.setOwner(owner) else freshCtx
102102
}
103103

104+
/** If `owner` is a companion object of an opaque type, record the alias
105+
* in the GADT bounds of `freshCtx.
106+
*/
107+
def handleOpaqueCompanion(freshCtx: FreshContext, owner: Symbol): FreshContext = {
108+
if (owner.is(Module)) {
109+
val opaq = owner.companionOpaqueType
110+
val alias = opaq.opaqueAlias
111+
if (alias.exists) {
112+
println(i"set GADT bounds of $opaq : $alias")
113+
val result = freshCtx.setFreshGADTBounds
114+
result.gadt.setBounds(opaq, TypeAlias(alias))
115+
result
116+
}
117+
else freshCtx
118+
}
119+
else freshCtx
120+
}
121+
104122
/** A new context for the interior of a class */
105123
def inClassContext(selfInfo: DotClass /* Should be Type | Symbol*/): Context = {
106-
var localCtx: FreshContext = ctx.fresh.setNewScope
124+
val localCtx: FreshContext = ctx.fresh.setNewScope
107125
selfInfo match {
108126
case sym: Symbol if sym.exists && sym.name != nme.WILDCARD => localCtx.scope.openForMutations.enter(sym)
109127
case _ =>
110128
}
111-
if (ctx.owner.is(Module)) {
112-
val opaq = ctx.owner.companionOpaqueType
113-
val alias = opaq.opaqueAlias
114-
if (alias.exists) {
115-
localCtx = localCtx.setFreshGADTBounds
116-
localCtx.gadt.setBounds(opaq, TypeAlias(alias))
117-
}
118-
}
119-
localCtx
129+
handleOpaqueCompanion(localCtx, ctx.owner)
120130
}
121131

122132
def packageContext(tree: untpd.PackageDef, pkg: Symbol): Context =
File renamed without changes.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
object ia {
2+
3+
import java.util.Arrays
4+
5+
opaque type IArray[A1] = Array[A1]
6+
7+
object IArray {
8+
@inline final def initialize[A](body: => Array[A]): IArray[A] = body
9+
10+
@inline final def size[A](ia: IArray[A]): Int = ia.length
11+
@inline final def get[A](ia: IArray[A], i: Int): A = ia(i)
12+
13+
// return a sorted copy of the array
14+
def sorted[A <: AnyRef : math.Ordering](ia: IArray[A]): IArray[A] = {
15+
val arr = Arrays.copyOf(ia, ia.length)
16+
scala.util.Sorting.quickSort(arr)
17+
arr
18+
}
19+
20+
// use a standard java method to search a sorted IArray.
21+
// (note that this doesn't mutate the array).
22+
def binarySearch(ia: IArray[Long], elem: Long): Int =
23+
Arrays.binarySearch(ia, elem)
24+
}
25+
26+
// same as IArray.binarySearch but implemented by-hand.
27+
//
28+
// given a sorted IArray, returns index of `elem`,
29+
// or a negative value if not found.
30+
def binaryIndexOf(ia: IArray[Long], elem: Long): Int = {
31+
var lower: Int = 0
32+
var upper: Int = IArray.size(ia)
33+
while (lower <= upper) {
34+
val middle = (lower + upper) >>> 1
35+
val n = IArray.get(ia, middle)
36+
37+
if (n == elem) return middle
38+
else if (n < elem) lower = middle + 1
39+
else upper = middle - 1
40+
}
41+
-lower - 1
42+
}
43+
}

0 commit comments

Comments
 (0)