Skip to content

Commit 6dfeaa7

Browse files
committed
Changes to compiler codebase so that it passes capture checking
1 parent 57527c4 commit 6dfeaa7

File tree

95 files changed

+593
-1092
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+593
-1092
lines changed

compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ class BootstrappedOnlyCompilationTests {
3636
).checkCompile()
3737
}
3838

39+
@Test def posWithCompilerCC: Unit =
40+
implicit val testGroup: TestGroup = TestGroup("compilePosWithCompilerCC")
41+
aggregateTests(
42+
compileDir("tests/pos-with-compiler-cc/dotc", withCompilerOptions.and("-language:experimental.captureChecking"))
43+
).checkCompile()
44+
3945
@Test def posWithCompiler: Unit = {
4046
implicit val testGroup: TestGroup = TestGroup("compilePosWithCompiler")
4147
aggregateTests(

tests/pos-with-compiler-cc/dotc/Run.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import java.nio.charset.StandardCharsets
3131
import scala.collection.mutable
3232
import scala.util.control.NonFatal
3333
import scala.io.Codec
34+
import caps.unsafe.unsafeUnbox
3435

3536
/** A compiler run. Exports various methods to compile source files */
3637
class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with ConstraintRunInfo {
@@ -270,7 +271,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
270271
Rewrites.writeBack()
271272
suppressions.runFinished(hasErrors = ctx.reporter.hasErrors)
272273
while (finalizeActions.nonEmpty) {
273-
val action = finalizeActions.remove(0)
274+
val action = finalizeActions.remove(0).unsafeUnbox
274275
action()
275276
}
276277
compiling = false

tests/pos-with-compiler-cc/dotc/ast/Desugar.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,7 @@ object desugar {
673673
else (Nil, Nil)
674674
}
675675

676-
var parents1 = parents
676+
var parents1: List[untpd.Tree] = parents // !cc! need explicit type to make capture checking pass
677677
if (isEnumCase && parents.isEmpty)
678678
parents1 = enumClassTypeRef :: Nil
679679
if (isNonEnumCase)
@@ -1779,7 +1779,10 @@ object desugar {
17791779
val elems = segments flatMap {
17801780
case ts: Thicket => ts.trees.tail
17811781
case t => Nil
1782-
} map {
1782+
} map { (t: Tree) => t match
1783+
// !cc! explicitly typed parameter (t: Tree) is needed since otherwise
1784+
// we get an error similar to #16268. (The explicit type constrains the type of `segments`
1785+
// which is otherwise List[{*} tree])
17831786
case Block(Nil, EmptyTree) => Literal(Constant(())) // for s"... ${} ..."
17841787
case Block(Nil, expr) => expr // important for interpolated string as patterns, see i1773.scala
17851788
case t => t

tests/pos-with-compiler-cc/dotc/ast/Positioned.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import annotation.internal.sharable
1515

1616
/** A base class for things that have positions (currently: modifiers and trees)
1717
*/
18-
abstract class Positioned(implicit @constructorOnly src: SourceFile) extends SrcPos, Product, Cloneable {
18+
abstract class Positioned(implicit @constructorOnly src: SourceFile) extends SrcPos, Product, Cloneable, caps.Pure {
1919
import Positioned.{ids, nextId, debugId}
2020

2121
private var mySpan: Span = _

tests/pos-with-compiler-cc/dotc/ast/TreeTypeMap.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Types._, Contexts._, Flags._
77
import Symbols._, Annotations._, Trees._, Symbols._, Constants.Constant
88
import Decorators._
99
import dotty.tools.dotc.transform.SymUtils._
10+
import language.experimental.pureFunctions
1011

1112
/** A map that applies three functions and a substitution together to a tree and
1213
* makes sure they are coordinated so that the result is well-typed. The functions are
@@ -32,8 +33,8 @@ import dotty.tools.dotc.transform.SymUtils._
3233
* set, we would get a data race assertion error.
3334
*/
3435
class TreeTypeMap(
35-
val typeMap: Type => Type = IdentityTypeMap,
36-
val treeMap: tpd.Tree => tpd.Tree = identity _,
36+
val typeMap: Type -> Type = IdentityTypeMap,
37+
val treeMap: tpd.Tree -> tpd.Tree = identity[tpd.Tree](_), // !cc! need explicit instantiation of default argument
3738
val oldOwners: List[Symbol] = Nil,
3839
val newOwners: List[Symbol] = Nil,
3940
val substFrom: List[Symbol] = Nil,
@@ -42,8 +43,8 @@ class TreeTypeMap(
4243
import tpd._
4344

4445
def copy(
45-
typeMap: Type => Type,
46-
treeMap: tpd.Tree => tpd.Tree,
46+
typeMap: Type -> Type,
47+
treeMap: tpd.Tree -> tpd.Tree,
4748
oldOwners: List[Symbol],
4849
newOwners: List[Symbol],
4950
substFrom: List[Symbol],

tests/pos-with-compiler-cc/dotc/ast/Trees.scala

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import annotation.internal.sharable
1616
import annotation.unchecked.uncheckedVariance
1717
import annotation.constructorOnly
1818
import Decorators._
19+
import annotation.retains
20+
import language.experimental.pureFunctions
1921

2022
object Trees {
2123

@@ -46,7 +48,7 @@ object Trees {
4648
* nodes.
4749
*/
4850
abstract class Tree[-T >: Untyped](implicit @constructorOnly src: SourceFile)
49-
extends Positioned, SrcPos, Product, Attachment.Container, printing.Showable {
51+
extends Positioned, SrcPos, Product, Attachment.Container, printing.Showable, caps.Pure {
5052

5153
if (Stats.enabled) ntrees += 1
5254

@@ -433,7 +435,7 @@ object Trees {
433435
def isBackquoted: Boolean = hasAttachment(Backquoted)
434436
}
435437

436-
class SearchFailureIdent[-T >: Untyped] private[ast] (name: Name, expl: => String)(implicit @constructorOnly src: SourceFile)
438+
class SearchFailureIdent[-T >: Untyped] private[ast] (name: Name, expl: -> String)(implicit @constructorOnly src: SourceFile)
437439
extends Ident[T](name) {
438440
def explanation = expl
439441
override def toString: String = s"SearchFailureIdent($explanation)"
@@ -1520,7 +1522,7 @@ object Trees {
15201522
}
15211523
}
15221524

1523-
abstract class TreeAccumulator[X] { self =>
1525+
abstract class TreeAccumulator[X] { self: TreeAccumulator[X] @retains(caps.*) =>
15241526
// Ties the knot of the traversal: call `foldOver(x, tree))` to dive in the `tree` node.
15251527
def apply(x: X, tree: Tree)(using Context): X
15261528

tests/pos-with-compiler-cc/dotc/ast/tpd.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import typer.ConstFold
1818

1919
import scala.annotation.tailrec
2020
import scala.collection.mutable.ListBuffer
21+
import language.experimental.pureFunctions
2122

2223
/** Some creators for typed trees */
2324
object tpd extends Trees.Instance[Type] with TypedTreeInfo {
@@ -1454,7 +1455,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
14541455
* @return The symbols imported.
14551456
*/
14561457
def importedSymbols(imp: Import,
1457-
selectorPredicate: untpd.ImportSelector => Boolean = util.common.alwaysTrue)
1458+
selectorPredicate: untpd.ImportSelector -> Boolean = util.common.alwaysTrue)
14581459
(using Context): List[Symbol] =
14591460
imp.selectors.find(selectorPredicate) match
14601461
case Some(sel) => importedSymbols(imp.expr, sel.name)

tests/pos-with-compiler-cc/dotc/ast/untpd.scala

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import util.Spans.Span
1111
import annotation.constructorOnly
1212
import annotation.internal.sharable
1313
import Decorators._
14+
import annotation.retains
15+
import language.experimental.pureFunctions
1416

1517
object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
1618

@@ -149,7 +151,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
149151
case class CapturingTypeTree(refs: List[Tree], parent: Tree)(implicit @constructorOnly src: SourceFile) extends TypTree
150152

151153
/** Short-lived usage in typer, does not need copy/transform/fold infrastructure */
152-
case class DependentTypeTree(tp: List[Symbol] => Type)(implicit @constructorOnly src: SourceFile) extends Tree
154+
case class DependentTypeTree(tp: List[Symbol] -> Type)(implicit @constructorOnly src: SourceFile) extends Tree
153155

154156
@sharable object EmptyTypeIdent extends Ident(tpnme.EMPTY)(NoSource) with WithoutTypeOrPos[Untyped] {
155157
override def isEmpty: Boolean = true
@@ -369,7 +371,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
369371
// ------ Creation methods for untyped only -----------------
370372

371373
def Ident(name: Name)(implicit src: SourceFile): Ident = new Ident(name)
372-
def SearchFailureIdent(name: Name, explanation: => String)(implicit src: SourceFile): SearchFailureIdent = new SearchFailureIdent(name, explanation)
374+
def SearchFailureIdent(name: Name, explanation: -> String)(implicit src: SourceFile): SearchFailureIdent = new SearchFailureIdent(name, explanation)
373375
def Select(qualifier: Tree, name: Name)(implicit src: SourceFile): Select = new Select(qualifier, name)
374376
def SelectWithSig(qualifier: Tree, name: Name, sig: Signature)(implicit src: SourceFile): Select = new SelectWithSig(qualifier, name, sig)
375377
def This(qual: Ident)(implicit src: SourceFile): This = new This(qual)
@@ -731,7 +733,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
731733
}
732734
}
733735

734-
abstract class UntypedTreeAccumulator[X] extends TreeAccumulator[X] { self =>
736+
abstract class UntypedTreeAccumulator[X] extends TreeAccumulator[X] {
737+
self: UntypedTreeAccumulator[X] @retains(caps.*) =>
735738
override def foldMoreCases(x: X, tree: Tree)(using Context): X = tree match {
736739
case ModuleDef(name, impl) =>
737740
this(x, impl)

tests/pos-with-compiler-cc/dotc/cc/CaptureSet.scala

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import util.{SimpleIdentitySet, Property}
1616
import util.common.alwaysTrue
1717
import scala.collection.mutable
1818
import config.Config.ccAllowUnsoundMaps
19+
import language.experimental.pureFunctions
1920

2021
/** A class for capture sets. Capture sets can be constants or variables.
2122
* Capture sets support inclusion constraints <:< where <:< is subcapturing.
@@ -37,7 +38,7 @@ import config.Config.ccAllowUnsoundMaps
3738
* if the mapped function is either a bijection or if it is idempotent
3839
* on capture references (c.f. doc comment on `map` below).
3940
*/
40-
sealed abstract class CaptureSet extends Showable:
41+
sealed abstract class CaptureSet extends Showable, caps.Pure:
4142
import CaptureSet.*
4243

4344
/** The elements of this capture set. For capture variables,
@@ -222,7 +223,7 @@ sealed abstract class CaptureSet extends Showable:
222223
/** The largest subset (via <:<) of this capture set that only contains elements
223224
* for which `p` is true.
224225
*/
225-
def filter(p: CaptureRef => Boolean)(using Context): CaptureSet =
226+
def filter(p: CaptureRef -> Boolean)(using Context): CaptureSet =
226227
if this.isConst then
227228
val elems1 = elems.filter(p)
228229
if elems1 == elems then this
@@ -377,8 +378,10 @@ object CaptureSet:
377378
def isConst = isSolved
378379
def isAlwaysEmpty = false
379380

380-
/** A handler to be invoked if the root reference `*` is added to this set */
381-
var rootAddedHandler: () => Context ?=> Unit = () => ()
381+
/** A handler to be invoked if the root reference `*` is added to this set
382+
* The handler is pure in the sense that it will only output diagnostics.
383+
*/
384+
var rootAddedHandler: () -> Context ?-> Unit = () => ()
382385

383386
var description: String = ""
384387

@@ -426,7 +429,7 @@ object CaptureSet:
426429
else
427430
CompareResult.fail(this)
428431

429-
override def disallowRootCapability(handler: () => Context ?=> Unit)(using Context): this.type =
432+
override def disallowRootCapability(handler: () -> Context ?-> Unit)(using Context): this.type =
430433
rootAddedHandler = handler
431434
super.disallowRootCapability(handler)
432435

@@ -618,7 +621,7 @@ object CaptureSet:
618621

619622
/** A variable with elements given at any time as { x <- source.elems | p(x) } */
620623
class Filtered private[CaptureSet]
621-
(val source: Var, p: CaptureRef => Boolean)(using @constructorOnly ctx: Context)
624+
(val source: Var, p: CaptureRef -> Boolean)(using @constructorOnly ctx: Context)
622625
extends DerivedVar(source.elems.filter(p)):
623626

624627
override def addNewElems(newElems: Refs, origin: CaptureSet)(using Context, VarState): CompareResult =

tests/pos-with-compiler-cc/dotc/cc/CheckCaptures.scala

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import CaptureSet.{withCaptureSetsExplained, IdempotentCaptRefMap}
2121
import StdNames.nme
2222
import NameKinds.DefaultGetterName
2323
import reporting.trace
24+
import language.experimental.pureFunctions
2425

2526
/** The capture checker */
2627
object CheckCaptures:
@@ -719,20 +720,21 @@ class CheckCaptures extends Recheck, SymTransformer:
719720
* the innermost capturing type. The outer capture annotations can be
720721
* reconstructed with the returned function.
721722
*/
722-
def destructCapturingType(tp: Type, reconstruct: Type => Type = x => x): ((Type, CaptureSet, Boolean), Type => Type) =
723+
def destructCapturingType(tp: Type, reconstruct: Type -> Type = (x: Type) => x) // !cc! need monomorphic default argument
724+
: (Type, CaptureSet, Boolean, Type -> Type) =
723725
tp.dealias match
724726
case tp @ CapturingType(parent, cs) =>
725727
if parent.dealias.isCapturingType then
726728
destructCapturingType(parent, res => reconstruct(tp.derivedCapturingType(res, cs)))
727729
else
728-
((parent, cs, tp.isBoxed), reconstruct)
730+
(parent, cs, tp.isBoxed, reconstruct)
729731
case actual =>
730-
((actual, CaptureSet(), false), reconstruct)
732+
(actual, CaptureSet(), false, reconstruct)
731733

732734
def adapt(actual: Type, expected: Type, covariant: Boolean): Type = trace(adaptInfo(actual, expected, covariant), recheckr, show = true) {
733735
if expected.isInstanceOf[WildcardType] then actual
734736
else
735-
val ((parent, cs, actualIsBoxed), recon) = destructCapturingType(actual)
737+
val (parent, cs, actualIsBoxed, recon: (Type -> Type)) = destructCapturingType(actual)
736738

737739
val needsAdaptation = actualIsBoxed != expected.isBoxedCapturing
738740
val insertBox = needsAdaptation && covariant != actualIsBoxed

0 commit comments

Comments
 (0)