Skip to content

Commit 4942724

Browse files
committed
Revert "Implement sealed type variables"
This reverts commit 05bce38. # Conflicts: # compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala # compiler/src/dotty/tools/dotc/cc/Setup.scala # library/src/scala/caps.scala # tests/neg-custom-args/captures/capt-test.scala # tests/neg-custom-args/captures/capt1.check # tests/neg-custom-args/captures/ctest.scala # tests/neg-custom-args/captures/filevar.scala # tests/neg-custom-args/captures/heal-tparam-cs.scala # tests/neg-custom-args/captures/i15049.scala # tests/neg-custom-args/captures/i15772.check # tests/neg-custom-args/captures/i15923.scala # tests/neg-custom-args/captures/lazylists-exceptions.check # tests/neg-custom-args/captures/real-try.check # tests/neg-custom-args/captures/real-try.scala # tests/neg-custom-args/captures/sealed-leaks.scala # tests/neg-custom-args/captures/stack-alloc.scala # tests/neg-custom-args/captures/try.check # tests/neg-custom-args/captures/try.scala # tests/neg-custom-args/captures/try3.scala # tests/neg-custom-args/captures/usingLogFile.check # tests/neg-custom-args/captures/usingLogFile.scala # tests/neg-custom-args/captures/vars.check # tests/neg-custom-args/captures/vars.scala # tests/pos-custom-args/captures/vars1.scala
1 parent 95fbe8a commit 4942724

File tree

19 files changed

+63
-141
lines changed

19 files changed

+63
-141
lines changed

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

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -173,21 +173,6 @@ object CheckCaptures:
173173
val srcTree = if ann.span.exists then ann else tpt
174174
report.warning(em"redundant capture: $remaining already accounts for $ref", srcTree.srcPos)
175175

176-
/** Report an error if some part of `tp` contains the root capability in its capture set */
177-
def disallowRootCapabilitiesIn(tp: Type, what: String, have: String, addendum: String, pos: SrcPos)(using Context) =
178-
val check = new TypeTraverser:
179-
def traverse(t: Type) =
180-
if variance >= 0 then
181-
t.captureSet.disallowRootCapability: () =>
182-
def part = if t eq tp then "" else i"the part $t of "
183-
report.error(
184-
em"""$what cannot $have $tp since
185-
|${part}that type captures the root capability `cap`.
186-
|$addendum""",
187-
pos)
188-
traverseChildren(t)
189-
check.traverse(tp)
190-
191176
/** Attachment key for bodies of closures, provided they are values */
192177
val ClosureBodyValue = Property.Key[Unit]
193178

@@ -693,17 +678,11 @@ class CheckCaptures extends Recheck, SymTransformer:
693678
val tryOwner = ccState.tryBlockOwner.remove(tree).getOrElse(ctx.owner)
694679
val saved = curEnv
695680
curEnv = Env(tryOwner, EnvKind.Regular, CaptureSet.Var(curEnv.owner), curEnv)
696-
val tp = try
681+
try
697682
inContext(ctx.withOwner(tryOwner)):
698683
super.recheckTry(tree, pt)
699684
finally
700685
curEnv = saved
701-
if allowUniversalInBoxed && Feature.enabled(Feature.saferExceptions) then
702-
disallowRootCapabilitiesIn(tp,
703-
"Result of `try`", "have type",
704-
"This is often caused by a locally generated exception capability leaking as part of its result.",
705-
tree.srcPos)
706-
tp
707686

708687
/* Currently not needed, since capture checking takes place after ElimByName.
709688
* Keep around in case we need to get back to it

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

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -356,29 +356,11 @@ extends tpd.TreeTraverser:
356356
mapRoots
357357
)
358358
capt.println(i"mapped $tree = ${tpt.knownType}")
359-
if allowUniversalInBoxed && tree.symbol.is(Mutable)
360-
&& !tree.symbol.hasAnnotation(defn.UncheckedCapturesAnnot)
361-
then
362-
CheckCaptures.disallowRootCapabilitiesIn(tpt.knownType,
363-
i"Mutable variable ${tree.symbol.name}", "have type",
364-
"This restriction serves to prevent local capabilities from escaping the scope where they are defined.",
365-
tree.srcPos)
366359
traverse(tree.rhs)
367360
case tree @ TypeApply(fn, args) =>
368361
traverse(fn)
369362
for case arg: TypeTree <- args do
370363
transformTT(arg, boxed = true, exact = false, mapRoots = true) // type arguments in type applications are boxed
371-
372-
if allowUniversalInBoxed then
373-
val polyType = atPhase(preRecheckPhase):
374-
fn.tpe.widen.asInstanceOf[TypeLambda]
375-
for case (arg: TypeTree, pinfo, pname) <- args.lazyZip(polyType.paramInfos).lazyZip((polyType.paramNames)) do
376-
if pinfo.bounds.hi.hasAnnotation(defn.Caps_SealedAnnot) then
377-
def where = if fn.symbol.exists then i" in an argument of ${fn.symbol}" else ""
378-
CheckCaptures.disallowRootCapabilitiesIn(arg.knownType,
379-
i"Sealed type variable $pname", "be instantiated to",
380-
i"This is often caused by a local capability$where\nleaking as part of its result.",
381-
tree.srcPos)
382364
case tree: Template =>
383365
inContext(ctx.withOwner(tree.symbol.owner)):
384366
traverseChildren(tree)

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -977,7 +977,6 @@ class Definitions {
977977
@tu lazy val Caps_unsafeBox: Symbol = CapsUnsafeModule.requiredMethod("unsafeBox")
978978
@tu lazy val Caps_unsafeUnbox: Symbol = CapsUnsafeModule.requiredMethod("unsafeUnbox")
979979
@tu lazy val Caps_unsafeBoxFunArg: Symbol = CapsUnsafeModule.requiredMethod("unsafeBoxFunArg")
980-
@tu lazy val Caps_SealedAnnot: ClassSymbol = requiredClass("scala.caps.Sealed")
981980

982981
@tu lazy val PureClass: Symbol = requiredClass("scala.Pure")
983982

@@ -1028,7 +1027,6 @@ class Definitions {
10281027
@tu lazy val UncheckedAnnot: ClassSymbol = requiredClass("scala.unchecked")
10291028
@tu lazy val UncheckedStableAnnot: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedStable")
10301029
@tu lazy val UncheckedVarianceAnnot: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedVariance")
1031-
@tu lazy val UncheckedCapturesAnnot: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedCaptures")
10321030
@tu lazy val VolatileAnnot: ClassSymbol = requiredClass("scala.volatile")
10331031
@tu lazy val WithPureFunsAnnot: ClassSymbol = requiredClass("scala.annotation.internal.WithPureFuns")
10341032
@tu lazy val CaptureCheckedAnnot: ClassSymbol = requiredClass("scala.annotation.internal.CaptureChecked")

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4082,15 +4082,10 @@ object Types {
40824082

40834083
protected def toPInfo(tp: Type)(using Context): PInfo
40844084

4085-
/** If `tparam` is a sealed type parameter symbol of a polymorphic method, add
4086-
* a @caps.Sealed annotation to the upperbound in `tp`.
4087-
*/
4088-
protected def addSealed(tparam: ParamInfo, tp: Type)(using Context): Type = tp
4089-
40904085
def fromParams[PI <: ParamInfo.Of[N]](params: List[PI], resultType: Type)(using Context): Type =
40914086
if (params.isEmpty) resultType
40924087
else apply(params.map(_.paramName))(
4093-
tl => params.map(param => toPInfo(addSealed(param, tl.integrate(params, param.paramInfo)))),
4088+
tl => params.map(param => toPInfo(tl.integrate(params, param.paramInfo))),
40944089
tl => tl.integrate(params, resultType))
40954090
}
40964091

@@ -4412,16 +4407,6 @@ object Types {
44124407
resultTypeExp: PolyType => Type)(using Context): PolyType =
44134408
unique(new PolyType(paramNames)(paramInfosExp, resultTypeExp))
44144409

4415-
override protected def addSealed(tparam: ParamInfo, tp: Type)(using Context): Type =
4416-
tparam match
4417-
case tparam: Symbol if tparam.is(Sealed) =>
4418-
tp match
4419-
case tp @ TypeBounds(lo, hi) =>
4420-
tp.derivedTypeBounds(lo,
4421-
AnnotatedType(hi, Annotation(defn.Caps_SealedAnnot, tparam.span)))
4422-
case _ => tp
4423-
case _ => tp
4424-
44254410
def unapply(tl: PolyType): Some[(List[LambdaParam], Type)] =
44264411
Some((tl.typeParams, tl.resType))
44274412
}

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3179,9 +3179,7 @@ object Parsers {
31793179
* id [HkTypeParamClause] TypeParamBounds
31803180
*
31813181
* DefTypeParamClause::= ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
3182-
* DefTypeParam ::= {Annotation}
3183-
* [`sealed`] -- under captureChecking
3184-
* id [HkTypeParamClause] TypeParamBounds
3182+
* DefTypeParam ::= {Annotation} id [HkTypeParamClause] TypeParamBounds
31853183
*
31863184
* TypTypeParamClause::= ‘[’ TypTypeParam {‘,’ TypTypeParam} ‘]’
31873185
* TypTypeParam ::= {Annotation} id [HkTypePamClause] TypeBounds
@@ -3191,25 +3189,24 @@ object Parsers {
31913189
*/
31923190
def typeParamClause(ownerKind: ParamOwner): List[TypeDef] = inBrackets {
31933191

3194-
def checkVarianceOK(): Boolean =
3195-
val ok = ownerKind != ParamOwner.Def && ownerKind != ParamOwner.TypeParam
3196-
if !ok then syntaxError(em"no `+/-` variance annotation allowed here")
3197-
in.nextToken()
3198-
ok
3192+
def variance(vflag: FlagSet): FlagSet =
3193+
if ownerKind == ParamOwner.Def || ownerKind == ParamOwner.TypeParam then
3194+
syntaxError(em"no `+/-` variance annotation allowed here")
3195+
in.nextToken()
3196+
EmptyFlags
3197+
else
3198+
in.nextToken()
3199+
vflag
31993200

32003201
def typeParam(): TypeDef = {
32013202
val isAbstractOwner = ownerKind == ParamOwner.Type || ownerKind == ParamOwner.TypeParam
32023203
val start = in.offset
3203-
var mods = annotsAsMods() | Param
3204-
if ownerKind == ParamOwner.Class then mods |= PrivateLocal
3205-
if Feature.ccEnabled && in.token == SEALED then
3206-
if ownerKind == ParamOwner.Def then mods |= Sealed
3207-
else syntaxError(em"`sealed` modifier only allowed for method type parameters")
3208-
in.nextToken()
3209-
if isIdent(nme.raw.PLUS) && checkVarianceOK() then
3210-
mods |= Covariant
3211-
else if isIdent(nme.raw.MINUS) && checkVarianceOK() then
3212-
mods |= Contravariant
3204+
val mods =
3205+
annotsAsMods()
3206+
| (if (ownerKind == ParamOwner.Class) Param | PrivateLocal else Param)
3207+
| (if isIdent(nme.raw.PLUS) then variance(Covariant)
3208+
else if isIdent(nme.raw.MINUS) then variance(Contravariant)
3209+
else EmptyFlags)
32133210
atSpan(start, nameStart) {
32143211
val name =
32153212
if (isAbstractOwner && in.token == USCORE) {

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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -517,12 +517,7 @@ object Checking {
517517
// note: this is not covered by the next test since terms can be abstract (which is a dual-mode flag)
518518
// but they can never be one of ClassOnlyFlags
519519
if !sym.isClass && sym.isOneOf(ClassOnlyFlags) then
520-
val illegal = sym.flags & ClassOnlyFlags
521-
if sym.is(TypeParam) && illegal == Sealed && Feature.ccEnabled && cc.allowUniversalInBoxed then
522-
if !sym.owner.is(Method) then
523-
fail(em"only method type parameters can be sealed")
524-
else
525-
fail(em"only classes can be ${illegal.flagsString}")
520+
fail(em"only classes can be ${(sym.flags & ClassOnlyFlags).flagsString}")
526521
if (sym.is(AbsOverride) && !sym.owner.is(Trait))
527522
fail(AbstractOverrideOnlyInTraits(sym))
528523
if sym.is(Trait) then

library/src/scala/caps.scala

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,3 @@ import annotation.experimental
4444
def unsafeBoxFunArg: T => U = f
4545

4646
end unsafe
47-
48-
/** An annotation that expresses the sealed modifier on a type parameter
49-
* Should not be directly referred to in source
50-
*/
51-
@deprecated("The Sealed annotation should not be directly used in source code.\nUse the `sealed` modifier on type parameters instead.")
52-
class Sealed extends annotation.Annotation

tests/neg-custom-args/captures/heal-tparam-cs.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import language.experimental.captureChecking
22

33
trait Cap { def use(): Unit }
44

5-
def localCap[sealed T](op: (c: Cap^{cap}) => T): T = ???
5+
def localCap[T](op: (lcap: caps.Root) ?-> (c: Cap^{lcap}) => T): T = ???
66

77
def main(io: Cap^{cap}, net: Cap^{cap}): Unit = {
88

@@ -11,7 +11,7 @@ def main(io: Cap^{cap}, net: Cap^{cap}): Unit = {
1111
}
1212

1313
val test2: (c: Cap^{cap}) -> () ->{cap} Unit =
14-
localCap { c => // should work
14+
localCap { c => // error, was: should work
1515
(c1: Cap^{cap}) => () => { c1.use() }
1616
}
1717

@@ -25,7 +25,7 @@ def main(io: Cap^{cap}, net: Cap^{cap}): Unit = {
2525
(c1: Cap^{io}) => () => { c1.use() }
2626
}
2727

28-
def localCap2[sealed T](op: (c: Cap^{io}) => T): T = ???
28+
def localCap2[T](op: (c: Cap^{io}) => T): T = ???
2929

3030
val test5: () ->{io} Unit =
3131
localCap2 { c => // ok
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/usingLogFile-alt.scala:21:24 -----------------------------
2-
21 | usingLogger(file)(l => () => l.log("test")) // error
3-
| ^^^^^^^^^^^^^^^^^^^^^^^^
4-
| Found: (l: Test.Logger{val f: java.io.OutputStream^?}^{file}) ->? box () ->? Unit
5-
| Required: (x$0: Test.Logger^{file}) ->{'cap[..<root>](from instantiating usingLogger)} box () ->? Unit
1+
-- Error: tests/neg-custom-args/captures/usingLogFile-alt.scala:18:2 ---------------------------------------------------
2+
18 | usingFile( // error
3+
| ^^^^^^^^^
4+
| reference (file : java.io.OutputStream^{lcap}) is not included in the allowed capture set {x$0, x$0²}
65
|
7-
| Note that reference (cap[Logger] : caps.Root), defined at level 1
8-
| cannot be included in outer capture set ?, defined at level 0 in package <root>
6+
| Note that reference (file : java.io.OutputStream^{lcap}), defined at level 4
7+
| cannot be included in outer capture set {x$0, x$0}, defined at level 0 in package <root>
98
|
10-
| longer explanation available when compiling with `-explain`
9+
| where: x$0 is a reference to a value parameter
10+
| x$0² is a reference to a value parameter

tests/neg-custom-args/captures/usingLogFile-alt.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@ object Test:
77
class Logger(f: OutputStream^):
88
def log(msg: String): Unit = ???
99

10-
def usingFile[sealed T](name: String, op: OutputStream^ => T): T =
10+
def usingFile[T](name: String, op: (lcap: caps.Root) ?-> OutputStream^{lcap} => T): T =
1111
val f = new FileOutputStream(name)
1212
val result = op(f)
1313
f.close()
1414
result
1515

16-
def usingLogger[sealed T](f: OutputStream^)(op: Logger^{f} => T): T = ???
16+
def usingLogger[T](f: OutputStream^)(op: Logger^{f} => T): T = ???
1717

18-
usingFile(
18+
usingFile( // error
1919
"foo",
2020
file => {
21-
usingLogger(file)(l => () => l.log("test")) // error
21+
usingLogger(file)(l => () => l.log("test"))
2222
}
2323
)

0 commit comments

Comments
 (0)