Skip to content

Commit 5a41b9c

Browse files
committed
Merge branch 'master' into fix/18645-overloaded-ext-method-compile-error-with-braces
2 parents 5cf6707 + 067ec20 commit 5a41b9c

File tree

118 files changed

+1697
-1119
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

118 files changed

+1697
-1119
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ jobs:
148148
run: ./project/scripts/sbt ";set ThisBuild/Build.scala2Library := Build.Scala2LibraryTasty ;scala3-bootstrapped/testCompilation i5; scala3-bootstrapped/testCompilation tests/run/typelevel-peano.scala; scala3-bootstrapped/testOnly dotty.tools.backend.jvm.DottyBytecodeTests" # only test a subset of test to avoid doubling the CI execution time
149149

150150
- name: Test with Scala 2 library with CC TASTy (fast)
151-
run: ./project/scripts/sbt "scala2-library-cc/compile; scala2-library-cc-tasty/compile" # TODO test all the test configurations in non-CC library (currently disabled due to bug while loading the library)
151+
run: ./project/scripts/sbt "scala2-library-cc/compile; scala2-library-cc-tasty/compile; scala3-bootstrapped/testCompilation i3"
152152

153153
test_scala2_library_tasty:
154154
runs-on: [self-hosted, Linux]

community-build/src/scala/dotty/communitybuild/projects.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ final case class SbtCommunityProject(
140140
case Some(ivyHome) => List(s"-Dsbt.ivy.home=$ivyHome")
141141
case _ => Nil
142142
extraSbtArgs ++ sbtProps ++ List(
143-
"-sbt-version", "1.9.3",
143+
"-sbt-version", "1.9.7",
144144
"-Dsbt.supershell=false",
145145
s"-Ddotty.communitybuild.dir=$communitybuildDir",
146146
s"--addPluginSbtFile=$sbtPluginFilePath"

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,8 +578,9 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
578578
sym.owner.isPrimitiveValueClass
579579
|| sym.owner == defn.StringClass
580580
|| defn.pureMethods.contains(sym)
581+
581582
tree.tpe.isInstanceOf[ConstantType] && tree.symbol != NoSymbol && isKnownPureOp(tree.symbol) // A constant expression with pure arguments is pure.
582-
|| fn.symbol.isStableMember && !fn.symbol.is(Lazy) // constructors of no-inits classes are stable
583+
|| fn.symbol.isStableMember && fn.symbol.isConstructor // constructors of no-inits classes are stable
583584

584585
/** The purity level of this reference.
585586
* @return

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,13 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
118118
* otherwise specified).
119119
*/
120120
def Closure(meth: TermSymbol, rhsFn: List[List[Tree]] => Tree, targs: List[Tree] = Nil, targetType: Type = NoType)(using Context): Block = {
121-
val targetTpt = if (targetType.exists) TypeTree(targetType) else EmptyTree
121+
val targetTpt = if (targetType.exists) TypeTree(targetType, inferred = true) else EmptyTree
122122
val call =
123123
if (targs.isEmpty) Ident(TermRef(NoPrefix, meth))
124124
else TypeApply(Ident(TermRef(NoPrefix, meth)), targs)
125-
Block(
126-
DefDef(meth, rhsFn) :: Nil,
127-
Closure(Nil, call, targetTpt))
125+
var mdef0 = DefDef(meth, rhsFn)
126+
val mdef = cpy.DefDef(mdef0)(tpt = TypeTree(mdef0.tpt.tpe, inferred = true))
127+
Block(mdef :: Nil, Closure(Nil, call, targetTpt))
128128
}
129129

130130
/** A closure whose anonymous function has the given method type */

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

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,14 @@ extension (tree: Tree)
9898
tree.putAttachment(Captures, refs)
9999
refs
100100

101-
/** The arguments of a @retains or @retainsByName annotation */
101+
/** The arguments of a @retains, @retainsCap or @retainsByName annotation */
102102
def retainedElems(using Context): List[Tree] = tree match
103-
case Apply(_, Typed(SeqLiteral(elems, _), _) :: Nil) => elems
104-
case _ => Nil
103+
case Apply(_, Typed(SeqLiteral(elems, _), _) :: Nil) =>
104+
elems
105+
case _ =>
106+
if tree.symbol.maybeOwner == defn.RetainsCapAnnot
107+
then ref(defn.captureRoot.termRef) :: Nil
108+
else Nil
105109

106110
extension (tp: Type)
107111

@@ -207,7 +211,7 @@ extension (tp: Type)
207211
def dropAllRetains(using Context): Type = // TODO we should drop retains from inferred types before unpickling
208212
val tm = new TypeMap:
209213
def apply(t: Type) = t match
210-
case AnnotatedType(parent, annot) if annot.symbol == defn.RetainsAnnot =>
214+
case AnnotatedType(parent, annot) if annot.symbol.isRetains =>
211215
apply(parent)
212216
case _ =>
213217
mapOver(t)
@@ -220,9 +224,31 @@ extension (tp: Type)
220224
* type of `x`. If `x` and `y` are different variables then `{x*}` and `{y*}`
221225
* are unrelated.
222226
*/
223-
def reach(using Context): CaptureRef =
224-
assert(tp.isTrackableRef)
225-
AnnotatedType(tp, Annotation(defn.ReachCapabilityAnnot, util.Spans.NoSpan))
227+
def reach(using Context): CaptureRef = tp match
228+
case tp: CaptureRef if tp.isTrackableRef =>
229+
if tp.isReach then tp else ReachCapability(tp)
230+
231+
/** If `x` is a capture ref, its maybe capability `x?`, represented internally
232+
* as `x @maybeCapability`. `x?` stands for a capability `x` that might or might
233+
* not be part of a capture set. We have `{} <: {x?} <: {x}`. Maybe capabilities
234+
* cannot be propagated between sets. If `a <: b` and `a` acquires `x?` then
235+
* `x` is propagated to `b` as a conservative approximation.
236+
*
237+
* Maybe capabilities should only arise for capture sets that appear in invariant
238+
* position in their surrounding type. They are similar to TypeBunds types, but
239+
* restricted to capture sets. For instance,
240+
*
241+
* Array[C^{x?}]
242+
*
243+
* should be morally equivalent to
244+
*
245+
* Array[_ >: C^{} <: C^{x}]
246+
*
247+
* but it has fewer issues with type inference.
248+
*/
249+
def maybe(using Context): CaptureRef = tp match
250+
case tp: CaptureRef if tp.isTrackableRef =>
251+
if tp.isMaybe then tp else MaybeCapability(tp)
226252

227253
/** If `ref` is a trackable capture ref, and `tp` has only covariant occurrences of a
228254
* universal capture set, replace all these occurrences by `{ref*}`. This implements
@@ -326,6 +352,14 @@ extension (cls: ClassSymbol)
326352

327353
extension (sym: Symbol)
328354

355+
/** This symbol is one of `retains` or `retainsCap` */
356+
def isRetains(using Context): Boolean =
357+
sym == defn.RetainsAnnot || sym == defn.RetainsCapAnnot
358+
359+
/** This symbol is one of `retains`, `retainsCap`, or`retainsByName` */
360+
def isRetainsLike(using Context): Boolean =
361+
isRetains || sym == defn.RetainsByNameAnnot
362+
329363
/** A class is pure if:
330364
* - one its base types has an explicitly declared self type with an empty capture set
331365
* - or it is a value class
@@ -419,12 +453,21 @@ object ReachCapabilityApply:
419453
case Apply(reach, arg :: Nil) if reach.symbol == defn.Caps_reachCapability => Some(arg)
420454
case _ => None
421455

456+
class AnnotatedCapability(annot: Context ?=> ClassSymbol):
457+
def apply(tp: Type)(using Context) =
458+
AnnotatedType(tp, Annotation(annot, util.Spans.NoSpan))
459+
def unapply(tree: AnnotatedType)(using Context): Option[SingletonCaptureRef] = tree match
460+
case AnnotatedType(parent: SingletonCaptureRef, ann) if ann.symbol == annot => Some(parent)
461+
case _ => None
462+
422463
/** An extractor for `ref @annotation.internal.reachCapability`, which is used to express
423464
* the reach capability `ref*` as a type.
424465
*/
425-
object ReachCapability:
426-
def unapply(tree: AnnotatedType)(using Context): Option[SingletonCaptureRef] = tree match
427-
case AnnotatedType(parent: SingletonCaptureRef, ann)
428-
if ann.symbol == defn.ReachCapabilityAnnot => Some(parent)
429-
case _ => None
466+
object ReachCapability extends AnnotatedCapability(defn.ReachCapabilityAnnot)
467+
468+
/** An extractor for `ref @maybeCapability`, which is used to express
469+
* the maybe capability `ref?` as a type.
470+
*/
471+
object MaybeCapability extends AnnotatedCapability(defn.MaybeCapabilityAnnot)
472+
430473

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

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -145,15 +145,16 @@ sealed abstract class CaptureSet extends Showable:
145145

146146
/** x subsumes x
147147
* this subsumes this.f
148-
* x subsumes y ==> x* subsumes y
149-
* x subsumes y ==> x* subsumes y*
148+
* x subsumes y ==> x* subsumes y, x subsumes y?
149+
* x subsumes y ==> x* subsumes y*, x? subsumes y?
150150
*/
151151
extension (x: CaptureRef)
152152
private def subsumes(y: CaptureRef)(using Context): Boolean =
153153
(x eq y)
154154
|| x.isRootCapability
155155
|| y.match
156-
case y: TermRef => !y.isReach && (y.prefix eq x)
156+
case y: TermRef => y.prefix eq x
157+
case MaybeCapability(y1) => x.stripMaybe.subsumes(y1)
157158
case _ => false
158159
|| x.match
159160
case ReachCapability(x1) => x1.subsumes(y.stripReach)
@@ -312,6 +313,8 @@ sealed abstract class CaptureSet extends Showable:
312313
def substParams(tl: BindingType, to: List[Type])(using Context) =
313314
map(Substituters.SubstParamsMap(tl, to))
314315

316+
def maybe(using Context): CaptureSet = map(MaybeMap())
317+
315318
/** Invoke handler if this set has (or later aquires) the root capability `cap` */
316319
def disallowRootCapability(handler: () => Context ?=> Unit)(using Context): this.type =
317320
if isUniversal then handler()
@@ -445,6 +448,8 @@ object CaptureSet:
445448
def isConst = isSolved
446449
def isAlwaysEmpty = false
447450

451+
def isMaybeSet = false // overridden in BiMapped
452+
448453
/** A handler to be invoked if the root reference `cap` is added to this set */
449454
var rootAddedHandler: () => Context ?=> Unit = () => ()
450455

@@ -490,9 +495,10 @@ object CaptureSet:
490495
if elem.isRootCapability then
491496
rootAddedHandler()
492497
newElemAddedHandler(elem)
498+
val normElem = if isMaybeSet then elem else elem.stripMaybe
493499
// assert(id != 5 || elems.size != 3, this)
494500
val res = (CompareResult.OK /: deps): (r, dep) =>
495-
r.andAlso(dep.tryInclude(elem, this))
501+
r.andAlso(dep.tryInclude(normElem, this))
496502
res.orElse:
497503
elems -= elem
498504
res.addToTrace(this)
@@ -508,6 +514,8 @@ object CaptureSet:
508514
levelLimit.isContainedIn(elem.cls.levelOwner)
509515
case ReachCapability(elem1) =>
510516
levelOK(elem1)
517+
case MaybeCapability(elem1) =>
518+
levelOK(elem1)
511519
case _ =>
512520
true
513521

@@ -760,6 +768,7 @@ object CaptureSet:
760768
if source eq origin then supApprox.map(bimap.inverse)
761769
else source.upperApprox(this).map(bimap) ** supApprox
762770

771+
override def isMaybeSet: Boolean = bimap.isInstanceOf[MaybeMap]
763772
override def toString = s"BiMapped$id($source, elems = $elems)"
764773
end BiMapped
765774

@@ -840,8 +849,7 @@ object CaptureSet:
840849
upper.isAlwaysEmpty || upper.isConst && upper.elems.size == 1 && upper.elems.contains(r1)
841850
if variance > 0 || isExact then upper
842851
else if variance < 0 then CaptureSet.empty
843-
else if ctx.mode.is(Mode.Printing) then upper
844-
else assert(false, i"trying to add $upper from $r via ${tm.getClass} in a non-variant setting")
852+
else upper.maybe
845853

846854
/** Apply `f` to each element in `xs`, and join result sets with `++` */
847855
def mapRefs(xs: Refs, f: CaptureRef => CaptureSet)(using Context): CaptureSet =
@@ -980,6 +988,26 @@ object CaptureSet:
980988
/** The current VarState, as passed by the implicit context */
981989
def varState(using state: VarState): VarState = state
982990

991+
/** Maps `x` to `x?` */
992+
private class MaybeMap(using Context) extends BiTypeMap:
993+
994+
def apply(t: Type) = t match
995+
case t: CaptureRef if t.isTrackableRef => t.maybe
996+
case _ => mapOver(t)
997+
998+
override def toString = "Maybe"
999+
1000+
lazy val inverse = new BiTypeMap:
1001+
1002+
def apply(t: Type) = t match
1003+
case t: CaptureRef if t.isMaybe => t.stripMaybe
1004+
case t => mapOver(t)
1005+
1006+
def inverse = MaybeMap.this
1007+
1008+
override def toString = "Maybe.inverse"
1009+
end MaybeMap
1010+
9831011
/* Not needed:
9841012
def ofClass(cinfo: ClassInfo, argTypes: List[Type])(using Context): CaptureSet =
9851013
CaptureSet.empty

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,7 @@ object CapturingType:
5858
case AnnotatedType(parent, ann: CaptureAnnotation)
5959
if isCaptureCheckingOrSetup =>
6060
Some((parent, ann.refs))
61-
case AnnotatedType(parent, ann)
62-
if ann.symbol == defn.RetainsAnnot && isCaptureChecking =>
61+
case AnnotatedType(parent, ann) if ann.symbol.isRetains && isCaptureChecking =>
6362
// There are some circumstances where we cannot map annotated types
6463
// with retains annotations to capturing types, so this second recognizer
6564
// path still has to exist. One example is when checking capture sets

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

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,6 @@ object CheckCaptures:
6868
*/
6969
final class SubstParamsMap(from: BindingType, to: List[Type])(using Context)
7070
extends ApproximatingTypeMap, IdempotentCaptRefMap:
71-
/** This SubstParamsMap is exact if `to` only contains `CaptureRef`s. */
72-
private val isExactSubstitution: Boolean = to.forall(_.isTrackableRef)
73-
74-
/** As long as this substitution is exact, there is no need to create `Range`s when mapping invariant positions. */
75-
override protected def needsRangeIfInvariant(refs: CaptureSet): Boolean = !isExactSubstitution
76-
7771
def apply(tp: Type): Type =
7872
tp match
7973
case tp: ParamRef =>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ object RetainingType:
2323

2424
def unapply(tp: AnnotatedType)(using Context): Option[(Type, List[Tree])] =
2525
val sym = tp.annot.symbol
26-
if sym == defn.RetainsAnnot || sym == defn.RetainsByNameAnnot then
26+
if sym.isRetainsLike then
2727
tp.annot match
2828
case _: CaptureAnnotation =>
2929
assert(ctx.mode.is(Mode.IgnoreCaptures), s"bad retains $tp at ${ctx.phase}")

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
120120
case tp @ CapturingType(parent, refs) =>
121121
if tp.isBoxed then tp else tp.boxed
122122
case tp @ AnnotatedType(parent, ann) =>
123-
if ann.symbol == defn.RetainsAnnot
123+
if ann.symbol.isRetains
124124
then CapturingType(parent, ann.tree.toCaptureSet, boxed = true)
125125
else tp.derivedAnnotatedType(box(parent), ann)
126126
case tp1 @ AppliedType(tycon, args) if defn.isNonRefinedFunction(tp1) =>
@@ -192,7 +192,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
192192

193193
def apply(tp: Type) =
194194
val tp1 = tp match
195-
case AnnotatedType(parent, annot) if annot.symbol == defn.RetainsAnnot =>
195+
case AnnotatedType(parent, annot) if annot.symbol.isRetains =>
196196
// Drop explicit retains annotations
197197
apply(parent)
198198
case tp @ AppliedType(tycon, args) =>
@@ -283,7 +283,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
283283
t.derivedCapturingType(this(parent), refs)
284284
case t @ AnnotatedType(parent, ann) =>
285285
val parent1 = this(parent)
286-
if ann.symbol == defn.RetainsAnnot then
286+
if ann.symbol.isRetains then
287287
for tpt <- tptToCheck do
288288
checkWellformedLater(parent1, ann.tree, tpt)
289289
CapturingType(parent1, ann.tree.toCaptureSet)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ object Contexts {
9595
inline def atPhaseNoEarlier[T](limit: Phase)(inline op: Context ?=> T)(using Context): T =
9696
op(using if !limit.exists || limit <= ctx.phase then ctx else ctx.withPhase(limit))
9797

98-
inline def inMode[T](mode: Mode)(inline op: Context ?=> T)(using ctx: Context): T =
98+
inline private def inMode[T](mode: Mode)(inline op: Context ?=> T)(using ctx: Context): T =
9999
op(using if mode != ctx.mode then ctx.fresh.setMode(mode) else ctx)
100100

101101
inline def withMode[T](mode: Mode)(inline op: Context ?=> T)(using ctx: Context): T =

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

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,10 @@ class Definitions {
535535
List(AnyType), EmptyScope)
536536
@tu lazy val SingletonType: TypeRef = SingletonClass.typeRef
537537

538+
@tu lazy val MaybeCapabilityAnnot: ClassSymbol =
539+
completeClass(enterCompleteClassSymbol(
540+
ScalaPackageClass, tpnme.maybeCapability, Final, List(StaticAnnotationClass.typeRef)))
541+
538542
@tu lazy val CollectionSeqType: TypeRef = requiredClassRef("scala.collection.Seq")
539543
@tu lazy val SeqType: TypeRef = requiredClassRef("scala.collection.immutable.Seq")
540544
@tu lazy val SeqModule: Symbol = requiredModule("scala.collection.immutable.Seq")
@@ -993,7 +997,7 @@ class Definitions {
993997

994998
// Annotation base classes
995999
@tu lazy val AnnotationClass: ClassSymbol = requiredClass("scala.annotation.Annotation")
996-
// @tu lazy val StaticAnnotationClass: ClassSymbol = requiredClass("scala.annotation.StaticAnnotation")
1000+
@tu lazy val StaticAnnotationClass: ClassSymbol = requiredClass("scala.annotation.StaticAnnotation")
9971001
@tu lazy val RefiningAnnotationClass: ClassSymbol = requiredClass("scala.annotation.RefiningAnnotation")
9981002
@tu lazy val JavaAnnotationClass: ClassSymbol = requiredClass("java.lang.annotation.Annotation")
9991003

@@ -1057,6 +1061,7 @@ class Definitions {
10571061
@tu lazy val ReachCapabilityAnnot = requiredClass("scala.annotation.internal.reachCapability")
10581062
@tu lazy val RequiresCapabilityAnnot: ClassSymbol = requiredClass("scala.annotation.internal.requiresCapability")
10591063
@tu lazy val RetainsAnnot: ClassSymbol = requiredClass("scala.annotation.retains")
1064+
@tu lazy val RetainsCapAnnot: ClassSymbol = requiredClass("scala.annotation.retainsCap")
10601065
@tu lazy val RetainsByNameAnnot: ClassSymbol = requiredClass("scala.annotation.retainsByName")
10611066
@tu lazy val PublicInBinaryAnnot: ClassSymbol = requiredClass("scala.annotation.publicInBinary")
10621067

@@ -1171,19 +1176,18 @@ class Definitions {
11711176
}
11721177
}
11731178

1174-
object RefinedFunctionOf {
1179+
object RefinedFunctionOf:
1180+
11751181
/** Matches a refined `PolyFunction`/`FunctionN[...]`/`ContextFunctionN[...]`.
11761182
* Extracts the method type type and apply info.
11771183
*/
1178-
def unapply(tpe: RefinedType)(using Context): Option[MethodOrPoly] = {
1184+
def unapply(tpe: RefinedType)(using Context): Option[MethodOrPoly] =
11791185
tpe.refinedInfo match
11801186
case mt: MethodOrPoly
1181-
if tpe.refinedName == nme.apply
1182-
&& (tpe.parent.derivesFrom(defn.PolyFunctionClass) || isFunctionNType(tpe.parent)) =>
1183-
Some(mt)
1187+
if tpe.refinedName == nme.apply && isFunctionType(tpe.parent) => Some(mt)
11841188
case _ => None
1185-
}
1186-
}
1189+
1190+
end RefinedFunctionOf
11871191

11881192
object PolyFunctionOf {
11891193

@@ -2008,7 +2012,7 @@ class Definitions {
20082012
@tu lazy val ccExperimental: Set[Symbol] = Set(
20092013
CapsModule, CapsModule.moduleClass, PureClass,
20102014
CapabilityAnnot, RequiresCapabilityAnnot,
2011-
RetainsAnnot, RetainsByNameAnnot)
2015+
RetainsAnnot, RetainsCapAnnot, RetainsByNameAnnot)
20122016

20132017
// ----- primitive value class machinery ------------------------------------------
20142018

@@ -2137,7 +2141,8 @@ class Definitions {
21372141
AnyValClass,
21382142
NullClass,
21392143
NothingClass,
2140-
SingletonClass)
2144+
SingletonClass,
2145+
MaybeCapabilityAnnot)
21412146

21422147
@tu lazy val syntheticCoreClasses: List[Symbol] = syntheticScalaClasses ++ List(
21432148
EmptyPackageVal,

0 commit comments

Comments
 (0)