Skip to content

Commit d56080e

Browse files
committed
Introduce precise refined types
They don't need an intersection when computing member types. Previously we did that for augmented constructor types through the refinedOverride annotation. But that does not apply to RefinedTypes with capset variables created in Setup. That's why we still needed withCollapsedFresh to avoid non-sensical types in intersections.
1 parent 133ab74 commit d56080e

File tree

7 files changed

+41
-30
lines changed

7 files changed

+41
-30
lines changed

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -467,8 +467,7 @@ extension (tp: Type)
467467
acc(false, tp)
468468

469469
def refinedOverride(name: Name, rinfo: Type)(using Context): Type =
470-
RefinedType(tp, name,
471-
AnnotatedType(rinfo, Annotation(defn.RefineOverrideAnnot, util.Spans.NoSpan)))
470+
RefinedType.precise(tp, name, rinfo)
472471

473472
def dropUseAndConsumeAnnots(using Context): Type =
474473
tp.dropAnnot(defn.UseAnnot).dropAnnot(defn.ConsumeAnnot)

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,8 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
358358
if shared.isEmpty then i"${CaptureSet(shared)}"
359359
else shared.nth(0) match
360360
case fresh: FreshCap =>
361-
if fresh.hiddenSet.owner.exists then i"{$fresh of ${fresh.hiddenSet.owner}}" else i"$fresh"
361+
val where = if ctx.settings.YccVerbose.value then "" else i" of ${fresh.ccOwnerStr}"
362+
i"{$fresh$where}"
362363
case _ =>
363364
i"${CaptureSet(shared)}"
364365

@@ -574,9 +575,9 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
574575
case Select(This(_), _) => tree
575576
case Select(prefix, _) => pathRoot(prefix)
576577
case _ => tree
577-
578+
578579
val rootSym = pathRoot(tree).symbol
579-
580+
580581
def findClashing(prevDefs: List[DefInfo]): Option[DefInfo] = prevDefs match
581582
case prevDef :: prevDefs1 =>
582583
if prevDef.symbol == rootSym then Some(prevDef)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
273273
then
274274
val getterType =
275275
mapInferred(inCaptureRefinement = true)(tp.memberInfo(getter)).strippedDealias
276-
RefinedType(core, getter.name,
276+
RefinedType.precise(core, getter.name,
277277
CapturingType(getterType,
278278
CaptureSet.ProperVar(ctx.owner, isRefining = true)))
279279
.showing(i"add capture refinement $tp --> $result", capt)

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,7 +1086,6 @@ class Definitions {
10861086
@tu lazy val UseAnnot: ClassSymbol = requiredClass("scala.caps.use")
10871087
@tu lazy val ReserveAnnot: ClassSymbol = requiredClass("scala.caps.reserve")
10881088
@tu lazy val ConsumeAnnot: ClassSymbol = requiredClass("scala.caps.internal.consume")
1089-
@tu lazy val RefineOverrideAnnot: ClassSymbol = requiredClass("scala.caps.internal.refineOverride")
10901089
@tu lazy val VolatileAnnot: ClassSymbol = requiredClass("scala.volatile")
10911090
@tu lazy val LanguageFeatureMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.languageFeature")
10921091
@tu lazy val BeanGetterMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.beanGetter")
@@ -1130,7 +1129,7 @@ class Definitions {
11301129

11311130
// Set of annotations that are not printed in types except under -Yprint-debug
11321131
@tu lazy val SilentAnnots: Set[Symbol] =
1133-
Set(InlineParamAnnot, ErasedParamAnnot, RefineOverrideAnnot, SilentIntoAnnot, UseAnnot, ConsumeAnnot)
1132+
Set(InlineParamAnnot, ErasedParamAnnot, SilentIntoAnnot, UseAnnot, ConsumeAnnot)
11341133

11351134
// A list of annotations that are commonly used to indicate that a field/method argument or return
11361135
// type is not null. These annotations are used by the nullification logic in JavaNullInterop to

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

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -914,12 +914,10 @@ object Types extends TypeUtils {
914914
pdenot.asSingleDenotation.derivedSingleDenotation(pdenot.symbol, jointInfo)
915915
}
916916
else
917-
val overridingRefinement = rinfo match
918-
case AnnotatedType(rinfo1, ann) if ann.symbol == defn.RefineOverrideAnnot => rinfo1
919-
case _ if pdenot.symbol.is(Tracked) => rinfo
920-
case _ => NoType
921-
if overridingRefinement.exists then
922-
pdenot.asSingleDenotation.derivedSingleDenotation(pdenot.symbol, overridingRefinement)
917+
val overridingRefinement =
918+
tp.isPrecise || pdenot.symbol.is(Tracked)
919+
if overridingRefinement then
920+
pdenot.asSingleDenotation.derivedSingleDenotation(pdenot.symbol, rinfo)
923921
else
924922
val isRefinedMethod = rinfo.isInstanceOf[MethodOrPoly]
925923
val joint = CCState.withCollapsedFresh:
@@ -3259,6 +3257,12 @@ object Types extends TypeUtils {
32593257
else assert(refinedInfo.isInstanceOf[TypeType], this)
32603258
assert(!refinedName.is(NameKinds.ExpandedName), this)
32613259

3260+
/** If true we know that refinedInfo is always more precise than the info for
3261+
* field `refinedName` in parent, so no type intersection needs to be computed
3262+
* for the type of this field.
3263+
*/
3264+
def isPrecise: Boolean = false
3265+
32623266
override def underlying(using Context): Type = parent
32633267

32643268
private def badInst =
@@ -3270,6 +3274,7 @@ object Types extends TypeUtils {
32703274
(parent: Type = this.parent, refinedName: Name = this.refinedName, refinedInfo: Type = this.refinedInfo)
32713275
(using Context): Type =
32723276
if ((parent eq this.parent) && (refinedName eq this.refinedName) && (refinedInfo eq this.refinedInfo)) this
3277+
else if isPrecise then RefinedType.precise(parent, refinedName, refinedInfo)
32733278
else RefinedType(parent, refinedName, refinedInfo)
32743279

32753280
/** Add this refinement to `parent`, provided `refinedName` is a member of `parent`. */
@@ -3302,6 +3307,10 @@ object Types extends TypeUtils {
33023307
class CachedRefinedType(parent: Type, refinedName: Name, refinedInfo: Type)
33033308
extends RefinedType(parent, refinedName, refinedInfo)
33043309

3310+
class PreciseRefinedType(parent: Type, refinedName: Name, refinedInfo: Type)
3311+
extends RefinedType(parent, refinedName, refinedInfo):
3312+
override def isPrecise = true
3313+
33053314
object RefinedType {
33063315
@tailrec def make(parent: Type, names: List[Name], infos: List[Type])(using Context): Type =
33073316
if (names.isEmpty) parent
@@ -3311,6 +3320,10 @@ object Types extends TypeUtils {
33113320
assert(!ctx.erasedTypes)
33123321
unique(new CachedRefinedType(parent, name, info)).checkInst
33133322
}
3323+
3324+
def precise(parent: Type, name: Name, info: Type)(using Context): RefinedType =
3325+
assert(!ctx.erasedTypes)
3326+
unique(new PreciseRefinedType(parent, name, info)).checkInst
33143327
}
33153328

33163329
/** A recursive type. Instances should be constructed via the companion object.

library/src/scala/caps/package.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ object internal:
145145
* info from the parent type, so no intersection needs to be formed.
146146
* This could be useful for tracked parameters as well.
147147
*/
148+
@deprecated
148149
final class refineOverride extends annotation.StaticAnnotation
149150

150151
/** An annotation used internally for root capability wrappers of `cap` that

tests/neg-custom-args/captures/sep-pairs-unboxed.check

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,29 +45,27 @@
4545
| Hidden footprint of current argument : {two.fst}
4646
| Capture set of second argument : {two*}
4747
| Footprint set of second argument : {two*}
48-
| The two sets overlap at : {two.cap of class Pair}
48+
| The two sets overlap at : {cap of a new instance of class Pair}
4949
|
5050
|where: ^ refers to a fresh root capability classified as Mutable in the type of value fst
5151
| ^² refers to a fresh root capability classified as Mutable created in value twisted when checking argument to parameter fst of constructor PairPair
52-
-- Error: tests/neg-custom-args/captures/sep-pairs-unboxed.scala:47:24 -------------------------------------------------
52+
-- Error: tests/neg-custom-args/captures/sep-pairs-unboxed.scala:47:33 -------------------------------------------------
5353
47 | val twisted = swapped(two, two.snd) // error
54-
| ^^^
55-
|Separation failure: argument of type (two : Pair{val fst: Ref^; val snd: Ref^²}^³)
54+
| ^^^^^^^
55+
|Separation failure: argument of type (two.snd : Ref^)
5656
|to method swapped: (@consume x: Pair^, @consume y: Ref^): PairPair^
57-
|corresponds to capture-polymorphic formal parameter x of type Pair^⁴
58-
|and hides capabilities {two}.
59-
|Some of these overlap with the captures of the second argument with type (two.snd : Ref^).
57+
|corresponds to capture-polymorphic formal parameter y of type Ref^²
58+
|and hides capabilities {two.snd}.
59+
|Some of these overlap with the captures of the first argument with type (two : Pair{val fst: Ref^; val snd: Ref^}^).
6060
|
61-
| Hidden set of current argument : {two}
62-
| Hidden footprint of current argument : {two}
63-
| Capture set of second argument : {two.snd}
64-
| Footprint set of second argument : {two.snd}
65-
| The two sets overlap at : {two.snd}
61+
| Hidden set of current argument : {two.snd}
62+
| Hidden footprint of current argument : {two.snd}
63+
| Capture set of first argument : {two*}
64+
| Footprint set of first argument : {two*}
65+
| The two sets overlap at : {cap of a new instance of class Pair}
6666
|
67-
|where: ^ refers to a fresh root capability classified as Mutable in the type of value fst
68-
| ^² refers to a fresh root capability classified as Mutable in the type of value snd
69-
| ^³ refers to a fresh root capability in the type of value two
70-
| ^⁴ refers to a fresh root capability created in value twisted when checking argument to parameter x of method swapped
67+
|where: ^ refers to a fresh root capability classified as Mutable in the type of value snd
68+
| ^² refers to a fresh root capability classified as Mutable created in value twisted when checking argument to parameter y of method swapped
7169
-- Error: tests/neg-custom-args/captures/sep-pairs-unboxed.scala:58:26 -------------------------------------------------
7270
58 | val twoOther = Pair(two.fst, two.snd) // error // error
7371
| ^^^^^^^

0 commit comments

Comments
 (0)