@@ -194,6 +194,11 @@ object CheckCaptures:
194194 check.traverse(tp)
195195 end disallowBadRootsIn
196196
197+ private def contributesFreshToClass (sym : Symbol )(using Context ): Boolean =
198+ sym.isField
199+ && ! sym.isOneOf(DeferredOrTermParamOrAccessor )
200+ && ! sym.hasAnnotation(defn.UntrackedCapturesAnnot )
201+
197202 private def ownerStr (owner : Symbol )(using Context ): String =
198203 if owner.isAnonymousFunction then " enclosing function" else owner.show
199204
@@ -918,8 +923,7 @@ class CheckCaptures extends Recheck, SymTransformer:
918923 val fieldClassifiers =
919924 for
920925 sym <- cls.info.decls.toList
921- if sym.isField && ! sym.isOneOf(DeferredOrTermParamOrAccessor )
922- && ! sym.hasAnnotation(defn.UntrackedCapturesAnnot )
926+ if contributesFreshToClass(sym)
923927 case fresh : FreshCap <- sym.info.spanCaptureSet.elems
924928 .filter(_.isTerminalCapability)
925929 .map(_.stripReadOnly)
@@ -1160,15 +1164,15 @@ class CheckCaptures extends Recheck, SymTransformer:
11601164 def checkInferredResult (tp : Type , tree : ValOrDefDef )(using Context ): Type =
11611165 val sym = tree.symbol
11621166
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.
11721176
11731177 def fail (tree : Tree , expected : Type , addenda : Addenda ): Unit =
11741178 def maybeResult = if sym.is(Method ) then " result" else " "
@@ -1191,14 +1195,28 @@ class CheckCaptures extends Recheck, SymTransformer:
11911195 |must conform to this type. """
11921196
11931197 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)
12021220 case _ =>
12031221 tp
12041222 end checkInferredResult
0 commit comments