@@ -194,6 +194,11 @@ object CheckCaptures:
194
194
check.traverse(tp)
195
195
end disallowBadRootsIn
196
196
197
+ private def contributesFreshToClass (sym : Symbol )(using Context ): Boolean =
198
+ sym.isField
199
+ && ! sym.isOneOf(DeferredOrTermParamOrAccessor )
200
+ && ! sym.hasAnnotation(defn.UntrackedCapturesAnnot )
201
+
197
202
private def ownerStr (owner : Symbol )(using Context ): String =
198
203
if owner.isAnonymousFunction then " enclosing function" else owner.show
199
204
@@ -918,8 +923,7 @@ class CheckCaptures extends Recheck, SymTransformer:
918
923
val fieldClassifiers =
919
924
for
920
925
sym <- cls.info.decls.toList
921
- if sym.isField && ! sym.isOneOf(DeferredOrTermParamOrAccessor )
922
- && ! sym.hasAnnotation(defn.UntrackedCapturesAnnot )
926
+ if contributesFreshToClass(sym)
923
927
case fresh : FreshCap <- sym.info.spanCaptureSet.elems
924
928
.filter(_.isTerminalCapability)
925
929
.map(_.stripReadOnly)
@@ -1160,15 +1164,15 @@ class CheckCaptures extends Recheck, SymTransformer:
1160
1164
def checkInferredResult (tp : Type , tree : ValOrDefDef )(using Context ): Type =
1161
1165
val sym = tree.symbol
1162
1166
1163
- def canUseInferred = // If canUseInferred is false, all capturing types in the type of `sym` need to be given explicitly
1164
- sym.isLocalToCompilationUnit // Symbols that can't be seen outside the compilation unit can always have inferred types
1165
- || ctx.owner.enclosingPackageClass.isEmptyPackage
1166
- // We make an exception for symbols in the empty package.
1167
- // these could theoretically be accessed from other files in the empty package, but
1168
- // usually it would be too annoying to require explicit types.
1169
- || sym.name.is( DefaultGetterName ) // Default getters are exempted since otherwise it would be
1170
- // too annoying. This is a hole since a defualt getter's result type
1171
- // might leak into a type variable.
1167
+ def isExemptFromChecks =
1168
+ ctx.owner.enclosingPackageClass.isEmptyPackage
1169
+ // We make an exception for symbols in the empty package.
1170
+ // these could theoretically be accessed from other files in the empty package, but
1171
+ // usually it would be too annoying to require explicit types.
1172
+ || sym.name.is( DefaultGetterName )
1173
+ // Default getters are exempted since otherwise it would be
1174
+ // too annoying. This is a hole since a defualt getter's result type
1175
+ // might leak into a type variable.
1172
1176
1173
1177
def fail (tree : Tree , expected : Type , addenda : Addenda ): Unit =
1174
1178
def maybeResult = if sym.is(Method ) then " result" else " "
@@ -1191,14 +1195,28 @@ class CheckCaptures extends Recheck, SymTransformer:
1191
1195
|must conform to this type. """
1192
1196
1193
1197
tree.tpt match
1194
- case tpt : InferredTypeTree if ! canUseInferred =>
1195
- val expected = tpt.tpe.dropAllRetains
1196
- todoAtPostCheck += { () =>
1197
- withCapAsRoot :
1198
- testAdapted(tp, expected, tree.rhs, addenda(expected))(fail)
1199
- // The check that inferred <: expected is done after recheck so that it
1200
- // does not interfere with normal rechecking by constraining capture set variables.
1201
- }
1198
+ case tpt : InferredTypeTree if ! isExemptFromChecks =>
1199
+ if ! sym.isLocalToCompilationUnit
1200
+ // Symbols that can't be seen outside the compilation unit can have inferred types
1201
+ // except for the else clause below.
1202
+ then
1203
+ val expected = tpt.tpe.dropAllRetains
1204
+ todoAtPostCheck += { () =>
1205
+ withCapAsRoot :
1206
+ testAdapted(tp, expected, tree.rhs, addenda(expected))(fail)
1207
+ // The check that inferred <: expected is done after recheck so that it
1208
+ // does not interfere with normal rechecking by constraining capture set variables.
1209
+ }
1210
+ else if sym.is(Private ) && ! sym.isLocalToCompilationUnitIgnoringPrivate
1211
+ && contributesFreshToClass(sym)
1212
+ // Private symbols capturing a root capability need explicit types
1213
+ // so that we can compute field constributions to class instance
1214
+ // capture sets across compilation units.
1215
+ then
1216
+ report.error(
1217
+ em """ $sym needs an explicit type because it captures a root capability in its type ${tree.tpt.nuType}.
1218
+ |Fields of publicily accessible classes that capture a root capability need to be given an explicit type. """ ,
1219
+ tpt.srcPos)
1202
1220
case _ =>
1203
1221
tp
1204
1222
end checkInferredResult
0 commit comments