Skip to content

Commit 53996ab

Browse files
committed
Tweak: Exclude default getters from "must be explicitly defined" requirements
Default getters always have an inferred result type. If that type captures capabilities, we used to get an error that an inferred non pure type needs to be explicitly defined. But usually, a default getter type does not matter. So we make an exception and allow it. Note that this could be a hole, for instance in a situation like this: ```scala def f[X](x: X = foo): X = ... ``` If `foo`'s inferred type is `{*} T`, and there is a call to `f()` in the same compilation unit `X` will be instantiated to `{*} T` and this will also be the result for `f`. But if the call is in a different compilation unit, it will only see `foo: T`, and the result of `f` is typed `T`. A better solution would be to demand that default getter's types are pure, but only if the getter type can leak into the type of the function to which it belongs. The problem is that currently that's very hard to do because when we see a default getter it's difficult to discover to which parameter from which function it belongs. Therefore, for the moment we leave the hole open, hoping for a better solution to default getters in the future.
1 parent 701a4ae commit 53996ab

File tree

1 file changed

+9
-5
lines changed

1 file changed

+9
-5
lines changed

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import Recheck.*
1818
import scala.collection.mutable
1919
import CaptureSet.{withCaptureSetsExplained, IdempotentCaptRefMap}
2020
import StdNames.nme
21+
import NameKinds.DefaultGetterName
2122
import reporting.trace
2223

2324
/** The capture checker */
@@ -885,11 +886,14 @@ class CheckCaptures extends Recheck, SymTransformer:
885886
val isLocal =
886887
sym.owner.ownersIterator.exists(_.isTerm)
887888
|| sym.accessBoundary(defn.RootClass).isContainedIn(sym.topLevelClass)
888-
def canUseInferred = // If canUseInferred is false, all capturing types in the type of `sym` need to be given explicitly
889-
sym.is(Private) // private symbols can always have inferred types
890-
|| // non-local symbols cannot have inferred types since external capture types are not inferred
891-
isLocal // local symbols still need explicit types if
892-
&& !sym.owner.is(Trait) // they are defined in a trait, since we do OverridingPairs checking before capture inference
889+
def canUseInferred = // If canUseInferred is false, all capturing types in the type of `sym` need to be given explicitly
890+
sym.is(Private) // private symbols can always have inferred types
891+
|| sym.name.is(DefaultGetterName) // default getters are exempted since otherwise it would be
892+
// too annoying. This is a hole since a defualt getter's result type
893+
// might leak into a type variable.
894+
|| // non-local symbols cannot have inferred types since external capture types are not inferred
895+
isLocal // local symbols still need explicit types if
896+
&& !sym.owner.is(Trait) // they are defined in a trait, since we do OverridingPairs checking before capture inference
893897
def isNotPureThis(ref: CaptureRef) = ref match {
894898
case ref: ThisType => !ref.cls.isPureClass
895899
case _ => true

0 commit comments

Comments
 (0)