@@ -573,7 +573,7 @@ class CheckCaptures extends Recheck, SymTransformer:
573
573
override def recheckValDef (tree : ValDef , sym : Symbol )(using Context ): Type =
574
574
try
575
575
if sym.is(Module ) then sym.info // Modules are checked by checking the module class
576
- else super .recheckValDef(tree, sym)
576
+ else checkInferredResult( super .recheckValDef(tree, sym), tree )
577
577
finally
578
578
if ! sym.is(Param ) then
579
579
// Parameters with inferred types belong to anonymous methods. We need to wait
@@ -589,11 +589,46 @@ class CheckCaptures extends Recheck, SymTransformer:
589
589
val localSet = capturedVars(sym)
590
590
if ! localSet.isAlwaysEmpty then
591
591
curEnv = Env (sym, EnvKind .Regular , localSet, curEnv)
592
- try super .recheckDefDef(tree, sym)
592
+ try checkInferredResult( super .recheckDefDef(tree, sym), tree )
593
593
finally
594
594
interpolateVarsIn(tree.tpt)
595
595
curEnv = saved
596
596
597
+ def checkInferredResult (tp : Type , tree : ValOrDefDef )(using Context ): Type =
598
+ val sym = tree.symbol
599
+
600
+ def isLocal =
601
+ sym.owner.ownersIterator.exists(_.isTerm)
602
+ || sym.accessBoundary(defn.RootClass ).isContainedIn(sym.topLevelClass)
603
+
604
+ def canUseInferred = // If canUseInferred is false, all capturing types in the type of `sym` need to be given explicitly
605
+ sym.is(Private ) // private symbols can always have inferred types
606
+ || sym.name.is(DefaultGetterName ) // default getters are exempted since otherwise it would be
607
+ // too annoying. This is a hole since a defualt getter's result type
608
+ // might leak into a type variable.
609
+ || // non-local symbols cannot have inferred types since external capture types are not inferred
610
+ isLocal // local symbols still need explicit types if
611
+ && ! sym.owner.is(Trait ) // they are defined in a trait, since we do OverridingPairs checking before capture inference
612
+
613
+ def addenda (expected : Type ) = new Addenda :
614
+ override def toAdd (using Context ) =
615
+ def result = if tree.isInstanceOf [ValDef ] then " " else " result"
616
+ i """
617
+ |
618
+ |Note that the expected type $expected
619
+ |is the previously inferred $result type of $sym
620
+ |which is also the type seen in separately compiled sources.
621
+ |The new inferred type $tp
622
+ |must conform to this type. """ :: Nil
623
+
624
+ tree.tpt match
625
+ case tpt : InferredTypeTree if ! canUseInferred =>
626
+ val expected = tpt.tpe.dropAllRetains
627
+ checkConformsExpr(tp, expected, tree.rhs, addenda(expected))
628
+ case _ =>
629
+ tp
630
+ end checkInferredResult
631
+
597
632
/** Class-specific capture set relations:
598
633
* 1. The capture set of a class includes the capture sets of its parents.
599
634
* 2. The capture set of the self type of a class includes the capture set of the class.
@@ -1148,9 +1183,6 @@ class CheckCaptures extends Recheck, SymTransformer:
1148
1183
1149
1184
/** Perform the following kinds of checks
1150
1185
* - Check all explicitly written capturing types for well-formedness using `checkWellFormedPost`.
1151
- * - Check that externally visible `val`s or `def`s have empty capture sets. If not,
1152
- * suggest an explicit type. This is so that separate compilation (where external
1153
- * symbols have empty capture sets) gives the same results as joint compilation.
1154
1186
* - Check that arguments of TypeApplys and AppliedTypes conform to their bounds.
1155
1187
* - Heal ill-formed capture sets of type parameters. See `healTypeParam`.
1156
1188
*/
@@ -1169,41 +1201,6 @@ class CheckCaptures extends Recheck, SymTransformer:
1169
1201
case AnnotatedType (parent, annot) if annot.symbol == defn.RetainsAnnot =>
1170
1202
checkWellformedPost(parent, annot.tree, tree)
1171
1203
case _ =>
1172
- case t : ValOrDefDef
1173
- if t.tpt.isInstanceOf [InferredTypeTree ] && ! Synthetics .isExcluded(t.symbol) =>
1174
- val sym = t.symbol
1175
- val isLocal =
1176
- sym.owner.ownersIterator.exists(_.isTerm)
1177
- || sym.accessBoundary(defn.RootClass ).isContainedIn(sym.topLevelClass)
1178
- def canUseInferred = // If canUseInferred is false, all capturing types in the type of `sym` need to be given explicitly
1179
- sym.is(Private ) // Private symbols can always have inferred types
1180
- || sym.name.is(DefaultGetterName ) // Default getters are exempted since otherwise it would be
1181
- // too annoying. This is a hole since a defualt getter's result type
1182
- // might leak into a type variable.
1183
- || // non-local symbols cannot have inferred types since external capture types are not inferred
1184
- isLocal // local symbols still need explicit types if
1185
- && ! sym.owner.is(Trait ) // they are defined in a trait, since we do OverridingPairs checking before capture inference
1186
- || // If there are overridden symbols, their types form an upper bound
1187
- sym.allOverriddenSymbols.nonEmpty // for the inferred type. In this case, separate compilation would
1188
- // not be a soundness issue.
1189
- def isNotPureThis (ref : CaptureRef ) = ref match {
1190
- case ref : ThisType => ! ref.cls.isPureClass
1191
- case _ => true
1192
- }
1193
- if ! canUseInferred then
1194
- val inferred = t.tpt.knownType
1195
- def checkPure (tp : Type ) = tp match
1196
- case CapturingType (_, refs : CaptureSet .Var )
1197
- if ! refs.elems.filter(isNotPureThis).isEmpty =>
1198
- val resultStr = if t.isInstanceOf [DefDef ] then " result" else " "
1199
- report.error(
1200
- em """ Non-local $sym cannot have an inferred $resultStr type
1201
- | $inferred
1202
- |with non-empty capture set $refs.
1203
- |The type needs to be declared explicitly. """ .withoutDisambiguation(),
1204
- t.srcPos)
1205
- case _ =>
1206
- inferred.foreachPart(checkPure, StopAt .Static )
1207
1204
case t @ TypeApply (fun, args) =>
1208
1205
fun.knownType.widen match
1209
1206
case tl : PolyType =>
0 commit comments