Skip to content

Commit 54aea78

Browse files
committed
Don't dealias TypeRefs when transforming explicit types
1 parent 4ffbda9 commit 54aea78

File tree

7 files changed

+29
-35
lines changed

7 files changed

+29
-35
lines changed

compiler/src/dotty/tools/dotc/cc/CaptureOps.scala

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ import collection.mutable
1616

1717
private val Captures: Key[CaptureSet] = Key()
1818

19+
/** RetainingType will be boxed when it gets turned into a capturing type */
20+
private val NeedsBox: Key[Unit] = Key()
21+
1922
object ccConfig:
2023

2124
/** Switch whether unpickled function types and byname types should be mapped to
@@ -234,7 +237,7 @@ extension (tp: Type)
234237
case _ =>
235238
false
236239

237-
def isCapabilityClassRef(using Context) = tp match
240+
def isCapabilityClassRef(using Context) = tp.dealiasKeepAnnots match
238241
case _: TypeRef | _: AppliedType => tp.typeSymbol.hasAnnotation(defn.CapabilityAnnot)
239242
case _ => false
240243

@@ -255,7 +258,7 @@ extension (cls: ClassSymbol)
255258
defn.pureBaseClasses.contains(bc)
256259
|| bc.givenSelfType.dealiasKeepAnnots.match
257260
case CapturingType(_, refs) => refs.isAlwaysEmpty
258-
case RetainingType(_, refs) => refs.isEmpty // TODO: Better: test at phase cc instead?
261+
case RetainingType(_, refs) => refs.isEmpty
259262
case selfType => selfType.exists && selfType.captureSet.isAlwaysEmpty
260263
else None
261264

@@ -372,4 +375,4 @@ extension (tp: AnnotatedType)
372375
/** Is this a boxed capturing type? */
373376
def isBoxed(using Context): Boolean = tp.annot match
374377
case ann: CaptureAnnotation => ann.boxed
375-
case _ => false
378+
case ann => ann.tree.hasAttachment(NeedsBox)

compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ object CheckCaptures:
156156
else recur(encl.owner.enclosingMethodOrClass)
157157
recur(encl)
158158
def traverse(t: Type) =
159-
t match
159+
t.dealiasKeepAnnots match
160160
case t: TypeRef =>
161161
capt.println(i"disallow $t, $tp, $what, ${t.symbol.is(Sealed)}")
162162
t.info match
@@ -724,13 +724,6 @@ class CheckCaptures extends Recheck, SymTransformer:
724724
markFree(res.boxedCaptureSet, tree.srcPos)
725725
res
726726

727-
/** If `tree` is a reference or an application where the result type refers
728-
* to an enclosing class or method parameter of the reference, check that the result type
729-
* does not capture the universal capability. This is justified since the
730-
* result type would have to be implicitly unboxed.
731-
* TODO: Can we find a cleaner way to achieve this? Logically, this should be part
732-
* of simulated boxing and unboxing.
733-
*/
734727
override def recheckFinish(tpe: Type, tree: Tree, pt: Type)(using Context): Type =
735728
def needsUniversalCheck = tree match
736729
case _: RefTree | _: Apply | _: TypeApply => tree.symbol.unboxesResult

compiler/src/dotty/tools/dotc/cc/Setup.scala

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,14 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
121121
* convert it to be boxed.
122122
*/
123123
private def box(tp: Type)(using Context): Type =
124-
def recur(tp: Type): Type = tp.dealias match
125-
case tp @ CapturingType(parent, refs) if !tp.isBoxed =>
126-
tp.boxed
124+
def recur(tp: Type): Type = tp.dealiasKeepAnnots match
125+
case tp @ CapturingType(parent, refs) =>
126+
if tp.isBoxed then tp else tp.boxed
127+
case tp @ AnnotatedType(parent, ann) =>
128+
if ann.symbol == defn.RetainsAnnot then
129+
ann.tree.putAttachment(NeedsBox, ())
130+
tp
131+
else tp.derivedAnnotatedType(box(parent), ann)
127132
case tp1 @ AppliedType(tycon, args) if defn.isNonRefinedFunction(tp1) =>
128133
val res = args.last
129134
val boxedRes = recur(res)
@@ -229,7 +234,6 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
229234
resType = this(tp.resType))
230235
case tp: TypeLambda =>
231236
// Don't recurse into parameter bounds, just cleanup any stray retains annotations
232-
// !!! TODO we should also map roots to rootvars here
233237
tp.derivedLambdaType(
234238
paramInfos = tp.paramInfos.mapConserve(_.dropAllRetains.bounds),
235239
resType = this(tp.resType))
@@ -291,18 +295,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
291295
val t2 = expandCapabilityClass(t)
292296
if t2 ne t then return t2
293297
t match
294-
case t: TypeRef =>
295-
val sym = t.symbol
296-
if sym.isClass then t
297-
else t.info match
298-
case TypeAlias(alias) =>
299-
val transformed = this(alias)
300-
// TODO: Do we need an eager expansion, presumably, we need that only for normalizeCaptures
301-
if transformed ne alias then transformed else t
302-
//.showing(i"EXPAND $t with ${t.info} to $result in ${t.symbol.owner}/${ctx.owner}")
303-
case _ =>
304-
recur(t)
305-
case t @ AppliedType(tycon: TypeProxy, args) if true =>
298+
case t @ AppliedType(tycon: TypeProxy, args) =>
306299
tycon.underlying match
307300
case TypeAlias(aliasTycon) =>
308301
val args1 =
@@ -327,7 +320,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
327320
for tpt <- tptToCheck do
328321
checkQualifiedRoots(ann.tree)
329322
checkWellformedLater(parent1, ann.tree, tpt)
330-
CapturingType(parent1, ann.tree.toCaptureSet)
323+
CapturingType(parent1, ann.tree.toCaptureSet, boxed = ann.tree.hasAttachment(NeedsBox))
331324
else
332325
t.derivedAnnotatedType(this(parent), ann)
333326
case Box(t1) =>
@@ -632,6 +625,11 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
632625
needsVariable(parent)
633626
&& refs.isConst // if refs is a variable, no need to add another
634627
&& !refs.containsRoot // if refs is {cap}, an added variable would not change anything
628+
case RetainingType(parent, refs) =>
629+
needsVariable(parent)
630+
&& !refs.tpes.exists:
631+
case ref: TermRef => ref.isUniversalRootCapability
632+
case _ => false
635633
case AnnotatedType(parent, _) =>
636634
needsVariable(parent)
637635
case _ =>

tests/neg-custom-args/captures/boundschecks2.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ object test {
88

99
val foo: C[Tree^] = ??? // error
1010
type T = C[Tree^] // error
11-
val bar: T -> T = ??? // error
11+
val bar: T -> T = ???
1212
val baz: C[Tree^] -> Unit = ??? // error
1313
}

tests/neg-custom-args/captures/outer-var.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
| Found: () ->{q} Unit
2929
| Required: () ->{p} Unit
3030
|
31-
| Note that reference (q : () => Unit), defined in method inner
31+
| Note that reference (q : Proc), defined in method inner
3232
| cannot be included in outer capture set {p} of variable y which is associated with method test
3333
|
3434
| longer explanation available when compiling with `-explain`

tests/neg-custom-args/captures/outer-var.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ type Cap = CC^
33

44
type Proc = () => Unit
55

6-
def test(p: Proc) =
6+
def test(p: Proc, q: () => Unit) =
77
var x: () ->{cap[test]} Unit = p
8-
var y = p
8+
var y = p // OK, y has type () ->{p} Proc
99

1010
def inner(q: Proc) =
1111
x = q // error

tests/neg-custom-args/captures/vars.check

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
-- Error: tests/neg-custom-args/captures/vars.scala:22:14 --------------------------------------------------------------
22
22 | a = x => g(x) // error
33
| ^^^^
4-
| reference (cap3 : CC^) is not included in the allowed capture set {cap1} of variable a
4+
| reference (cap3 : Cap) is not included in the allowed capture set {cap1} of variable a
55
|
6-
| Note that reference (cap3 : CC^), defined in method scope
6+
| Note that reference (cap3 : Cap), defined in method scope
77
| cannot be included in outer capture set {cap1} of variable a which is associated with method test
88
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/vars.scala:23:8 ------------------------------------------
99
23 | a = g // error
1010
| ^
1111
| Found: (x: String) ->{cap3} String
1212
| Required: (x$0: String) ->{cap1} String
1313
|
14-
| Note that reference (cap3 : CC^), defined in method scope
14+
| Note that reference (cap3 : Cap), defined in method scope
1515
| cannot be included in outer capture set {cap1} of variable a which is associated with method test
1616
|
1717
| longer explanation available when compiling with `-explain`

0 commit comments

Comments
 (0)