Skip to content

Commit ba40fd1

Browse files
committed
Copy updates to dotc to test version
1 parent 63603a8 commit ba40fd1

File tree

16 files changed

+270
-119
lines changed

16 files changed

+270
-119
lines changed

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6043,14 +6043,10 @@ object Types {
60436043
/** A range of possible types between lower bound `lo` and upper bound `hi`.
60446044
* Only used internally in `ApproximatingTypeMap`.
60456045
*/
6046-
case class Range(lo: Type, hi: Type) extends UncachedGroundType {
6046+
case class Range(lo: Type, hi: Type) extends UncachedGroundType:
60476047
assert(!lo.isInstanceOf[Range])
60486048
assert(!hi.isInstanceOf[Range])
60496049

6050-
override def toText(printer: Printer): Text =
6051-
lo.toText(printer) ~ ".." ~ hi.toText(printer)
6052-
}
6053-
60546050
/** Approximate wildcards by their bounds */
60556051
class AvoidWildcardsMap(using Context) extends ApproximatingTypeMap:
60566052
protected def mapWild(t: WildcardType) =

tests/pos-with-compiler-cc/dotc/cc/CaptureOps.scala

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,16 +166,43 @@ extension (tp: Type)
166166
case CapturingType(_, _) => true
167167
case _ => false
168168

169+
/** Is type known to be always pure by its class structure,
170+
* so that adding a capture set to it would not make sense?
171+
*/
172+
def isAlwaysPure(using Context): Boolean = tp.dealias match
173+
case tp: (TypeRef | AppliedType) =>
174+
val sym = tp.typeSymbol
175+
if sym.isClass then sym.isPureClass
176+
else tp.superType.isAlwaysPure
177+
case CapturingType(parent, refs) =>
178+
parent.isAlwaysPure || refs.isAlwaysEmpty
179+
case tp: TypeProxy =>
180+
tp.superType.isAlwaysPure
181+
case tp: AndType =>
182+
tp.tp1.isAlwaysPure || tp.tp2.isAlwaysPure
183+
case tp: OrType =>
184+
tp.tp1.isAlwaysPure && tp.tp2.isAlwaysPure
185+
case _ =>
186+
false
187+
169188
extension (sym: Symbol)
170189

171-
/** A class is pure if one of its base types has an explicitly declared self type
172-
* with an empty capture set.
190+
/** A class is pure if:
191+
* - one its base types has an explicitly declared self type with an empty capture set
192+
* - or it is a value class
193+
* - or it is Nothing or Null
173194
*/
174195
def isPureClass(using Context): Boolean = sym match
175196
case cls: ClassSymbol =>
197+
val AnyValClass = defn.AnyValClass
176198
cls.baseClasses.exists(bc =>
177-
val selfType = bc.givenSelfType
178-
selfType.exists && selfType.captureSet.isAlwaysEmpty)
199+
bc == AnyValClass
200+
|| {
201+
val selfType = bc.givenSelfType
202+
selfType.exists && selfType.captureSet.isAlwaysEmpty
203+
})
204+
|| cls == defn.NothingClass
205+
|| cls == defn.NullClass
179206
case _ =>
180207
false
181208

tests/pos-with-compiler-cc/dotc/cc/CheckCaptures.scala

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ import config.{Config, Feature}
1111
import ast.{tpd, untpd, Trees}
1212
import Trees.*
1313
import typer.RefChecks.{checkAllOverrides, checkSelfAgainstParents}
14+
import typer.Checking.{checkBounds, checkAppliedTypesIn}
1415
import util.{SimpleIdentitySet, EqHashMap, SrcPos}
1516
import transform.SymUtils.*
1617
import transform.{Recheck, PreRecheck}
1718
import Recheck.*
1819
import scala.collection.mutable
1920
import CaptureSet.{withCaptureSetsExplained, IdempotentCaptRefMap}
2021
import StdNames.nme
22+
import NameKinds.DefaultGetterName
2123
import reporting.trace
2224
import language.experimental.pureFunctions
2325

@@ -336,12 +338,21 @@ class CheckCaptures extends Recheck, SymTransformer:
336338
override def recheckApply(tree: Apply, pt: Type)(using Context): Type =
337339
val meth = tree.fun.symbol
338340
includeCallCaptures(meth, tree.srcPos)
339-
if meth == defn.Caps_unsafeBox || meth == defn.Caps_unsafeUnbox then
341+
def mapArgUsing(f: Type => Type) =
340342
val arg :: Nil = tree.args: @unchecked
341-
val argType0 = recheckStart(arg, pt)
342-
.forceBoxStatus(boxed = meth == defn.Caps_unsafeBox)
343+
val argType0 = f(recheckStart(arg, pt))
343344
val argType = super.recheckFinish(argType0, arg, pt)
344345
super.recheckFinish(argType, tree, pt)
346+
347+
if meth == defn.Caps_unsafeBox then
348+
mapArgUsing(_.forceBoxStatus(true))
349+
else if meth == defn.Caps_unsafeUnbox then
350+
mapArgUsing(_.forceBoxStatus(false))
351+
else if meth == defn.Caps_unsafeBoxFunArg then
352+
mapArgUsing {
353+
case defn.FunctionOf(paramtpe :: Nil, restpe, isContectual, isErased) =>
354+
defn.FunctionOf(paramtpe.forceBoxStatus(true) :: Nil, restpe, isContectual, isErased)
355+
}
345356
else
346357
super.recheckApply(tree, pt) match
347358
case appType @ CapturingType(appType1, refs) =>
@@ -433,7 +444,8 @@ class CheckCaptures extends Recheck, SymTransformer:
433444
block match
434445
case closureDef(mdef) =>
435446
pt.dealias match
436-
case defn.FunctionOf(ptformals, _, _, _) if ptformals.forall(_.captureSet.isAlwaysEmpty) =>
447+
case defn.FunctionOf(ptformals, _, _, _)
448+
if ptformals.nonEmpty && ptformals.forall(_.captureSet.isAlwaysEmpty) =>
437449
// Redo setup of the anonymous function so that formal parameters don't
438450
// get capture sets. This is important to avoid false widenings to `*`
439451
// when taking the base type of the actual closures's dependent function
@@ -443,9 +455,10 @@ class CheckCaptures extends Recheck, SymTransformer:
443455
// First, undo the previous setup which installed a completer for `meth`.
444456
atPhase(preRecheckPhase.prev)(meth.denot.copySymDenotation())
445457
.installAfter(preRecheckPhase)
458+
446459
// Next, update all parameter symbols to match expected formals
447460
meth.paramSymss.head.lazyZip(ptformals).foreach { (psym, pformal) =>
448-
psym.copySymDenotation(info = pformal).installAfter(preRecheckPhase)
461+
psym.updateInfoBetween(preRecheckPhase, thisPhase, pformal.mapExprType)
449462
}
450463
// Next, update types of parameter ValDefs
451464
mdef.paramss.head.lazyZip(ptformals).foreach { (param, pformal) =>
@@ -459,8 +472,7 @@ class CheckCaptures extends Recheck, SymTransformer:
459472
denot.info = mt.companion(ptformals, mdef.tpt.knownType)
460473
.showing(i"simplify info of $meth to $result", capt)
461474
recheckDef(mdef, meth)
462-
meth.copySymDenotation(info = completer, initFlags = meth.flags &~ Touched)
463-
.installAfter(preRecheckPhase)
475+
meth.updateInfoBetween(preRecheckPhase, thisPhase, completer)
464476
case _ =>
465477
case _ =>
466478
super.recheckBlock(block, pt)
@@ -764,7 +776,8 @@ class CheckCaptures extends Recheck, SymTransformer:
764776
// We can't box/unbox the universal capability. Leave `actual` as it is
765777
// so we get an error in checkConforms. This tends to give better error
766778
// messages than disallowing the root capability in `criticalSet`.
767-
capt.println(i"cannot box/unbox $actual vs $expected")
779+
if ctx.settings.YccDebug.value then
780+
println(i"cannot box/unbox $actual vs $expected")
768781
actual
769782
else
770783
// Disallow future addition of `*` to `criticalSet`.
@@ -885,12 +898,14 @@ class CheckCaptures extends Recheck, SymTransformer:
885898
val isLocal =
886899
sym.owner.ownersIterator.exists(_.isTerm)
887900
|| 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 an explicit types if
892-
&& !sym.owner.is(Trait) // - they are defined in a trait, since we do OverridingPairs checking before capture inference
893-
&& !sym.allOverriddenSymbols.nonEmpty // - they override some other symbol, since we do override checking before capture inference
901+
def canUseInferred = // If canUseInferred is false, all capturing types in the type of `sym` need to be given explicitly
902+
sym.is(Private) // private symbols can always have inferred types
903+
|| sym.name.is(DefaultGetterName) // default getters are exempted since otherwise it would be
904+
// too annoying. This is a hole since a defualt getter's result type
905+
// might leak into a type variable.
906+
|| // non-local symbols cannot have inferred types since external capture types are not inferred
907+
isLocal // local symbols still need explicit types if
908+
&& !sym.owner.is(Trait) // they are defined in a trait, since we do OverridingPairs checking before capture inference
894909
def isNotPureThis(ref: CaptureRef) = ref match {
895910
case ref: ThisType => !ref.cls.isPureClass
896911
case _ => true
@@ -908,8 +923,27 @@ class CheckCaptures extends Recheck, SymTransformer:
908923
|The type needs to be declared explicitly.""", t.srcPos)
909924
case _ =>
910925
inferred.foreachPart(checkPure, StopAt.Static)
926+
case t @ TypeApply(fun, args) =>
927+
fun.knownType.widen match
928+
case tl: PolyType =>
929+
val normArgs = args.lazyZip(tl.paramInfos).map { (arg, bounds) =>
930+
arg.withType(arg.knownType.forceBoxStatus(
931+
bounds.hi.isBoxedCapturing | bounds.lo.isBoxedCapturing))
932+
}
933+
checkBounds(normArgs, tl)
934+
case _ =>
911935
case _ =>
912936
}
913-
937+
if !ctx.reporter.errorsReported then
938+
// We dont report errors hre if previous errors were reported, because other
939+
// errors often result in bad applied types, but flagging these bad types gives
940+
// often worse error messages than the original errors.
941+
val checkApplied = new TreeTraverser:
942+
def traverse(t: Tree)(using Context) = t match
943+
case tree: InferredTypeTree =>
944+
case tree: New =>
945+
case tree: TypeTree => checkAppliedTypesIn(tree.withKnownType)
946+
case _ => traverseChildren(t)
947+
checkApplied.traverse(unit)
914948
end CaptureChecker
915949
end CheckCaptures

tests/pos-with-compiler-cc/dotc/cc/Setup.scala

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -120,38 +120,41 @@ extends tpd.TreeTraverser:
120120
case tp: (TypeRef | AppliedType) =>
121121
val sym = tp.typeSymbol
122122
if sym.isClass then
123-
tp.typeSymbol == defn.AnyClass
123+
sym == defn.AnyClass
124124
// we assume Any is a shorthand of {*} Any, so if Any is an upper
125125
// bound, the type is taken to be impure.
126126
else superTypeIsImpure(tp.superType)
127127
case tp: (RefinedOrRecType | MatchType) =>
128128
superTypeIsImpure(tp.underlying)
129129
case tp: AndType =>
130-
superTypeIsImpure(tp.tp1) || canHaveInferredCapture(tp.tp2)
130+
superTypeIsImpure(tp.tp1) || needsVariable(tp.tp2)
131131
case tp: OrType =>
132132
superTypeIsImpure(tp.tp1) && superTypeIsImpure(tp.tp2)
133133
case _ =>
134134
false
135135
}.showing(i"super type is impure $tp = $result", capt)
136136

137137
/** Should a capture set variable be added on type `tp`? */
138-
def canHaveInferredCapture(tp: Type): Boolean = {
138+
def needsVariable(tp: Type): Boolean = {
139139
tp.typeParams.isEmpty && tp.match
140140
case tp: (TypeRef | AppliedType) =>
141141
val tp1 = tp.dealias
142-
if tp1 ne tp then canHaveInferredCapture(tp1)
142+
if tp1 ne tp then needsVariable(tp1)
143143
else
144144
val sym = tp1.typeSymbol
145-
if sym.isClass then !sym.isValueClass && sym != defn.AnyClass
145+
if sym.isClass then
146+
!sym.isPureClass && sym != defn.AnyClass
146147
else superTypeIsImpure(tp1)
147148
case tp: (RefinedOrRecType | MatchType) =>
148-
canHaveInferredCapture(tp.underlying)
149+
needsVariable(tp.underlying)
149150
case tp: AndType =>
150-
canHaveInferredCapture(tp.tp1) && canHaveInferredCapture(tp.tp2)
151+
needsVariable(tp.tp1) && needsVariable(tp.tp2)
151152
case tp: OrType =>
152-
canHaveInferredCapture(tp.tp1) || canHaveInferredCapture(tp.tp2)
153-
case CapturingType(_, refs) =>
154-
refs.isConst && !refs.isUniversal
153+
needsVariable(tp.tp1) || needsVariable(tp.tp2)
154+
case CapturingType(parent, refs) =>
155+
needsVariable(parent)
156+
&& refs.isConst // if refs is a variable, no need to add another
157+
&& !refs.isUniversal // if refs is {*}, an added variable would not change anything
155158
case _ =>
156159
false
157160
}.showing(i"can have inferred capture $tp = $result", capt)
@@ -184,7 +187,7 @@ extends tpd.TreeTraverser:
184187
CapturingType(OrType(parent1, tp2, tp.isSoft), refs1, tp1.isBoxed)
185188
case tp @ OrType(tp1, tp2 @ CapturingType(parent2, refs2)) =>
186189
CapturingType(OrType(tp1, parent2, tp.isSoft), refs2, tp2.isBoxed)
187-
case _ if canHaveInferredCapture(tp) =>
190+
case _ if needsVariable(tp) =>
188191
val cs = tp.dealias match
189192
case CapturingType(_, refs) => CaptureSet.Var(refs.elems)
190193
case _ => CaptureSet.Var()
@@ -385,20 +388,18 @@ extends tpd.TreeTraverser:
385388
return
386389
tree.tpt match
387390
case tpt: TypeTree if tree.symbol.allOverriddenSymbols.hasNext =>
391+
tree.paramss.foreach(traverse)
388392
transformTT(tpt, boxed = false, exact = true)
393+
traverse(tree.rhs)
389394
//println(i"TYPE of ${tree.symbol.showLocated} = ${tpt.knownType}")
390395
case _ =>
391-
traverseChildren(tree)
396+
traverseChildren(tree)
392397
case tree @ ValDef(_, tpt: TypeTree, _) =>
393-
val isVar = tree.symbol.is(Mutable)
394-
val overrides = tree.symbol.allOverriddenSymbols.hasNext
395-
//if overrides then println(i"transforming overriding ${tree.symbol}")
396-
if isVar || overrides then
397-
transformTT(tpt,
398-
boxed = isVar, // types of mutable variables are boxed
399-
exact = overrides // types of symbols that override a parent don't get a capture set
400-
)
401-
traverseChildren(tree)
398+
transformTT(tpt,
399+
boxed = tree.symbol.is(Mutable), // types of mutable variables are boxed
400+
exact = tree.symbol.allOverriddenSymbols.hasNext // types of symbols that override a parent don't get a capture set
401+
)
402+
traverse(tree.rhs)
402403
case tree @ TypeApply(fn, args) =>
403404
traverse(fn)
404405
for case arg: TypeTree <- args do

tests/pos-with-compiler-cc/dotc/core/CheckRealizable.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,15 @@ class CheckRealizable(using Context) {
149149
*/
150150
private def boundsRealizability(tp: Type) = {
151151

152-
val memberProblems = withMode(Mode.CheckBounds) {
152+
val memberProblems = withMode(Mode.CheckBoundsOrSelfType) {
153153
for {
154154
mbr <- tp.nonClassTypeMembers
155155
if !(mbr.info.loBound <:< mbr.info.hiBound)
156156
}
157157
yield new HasProblemBounds(mbr.name, mbr.info)
158158
}
159159

160-
val refinementProblems = withMode(Mode.CheckBounds) {
160+
val refinementProblems = withMode(Mode.CheckBoundsOrSelfType) {
161161
for {
162162
name <- refinedNames(tp)
163163
if (name.isTypeName)

tests/pos-with-compiler-cc/dotc/core/ConstraintHandling.scala

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ trait ConstraintHandling {
5858
*/
5959
protected var comparedTypeLambdas: Set[TypeLambda] = Set.empty
6060

61+
/** Used for match type reduction: If false, we don't recognize an abstract type
62+
* to be a subtype type of any of its base classes. This is in place only at the
63+
* toplevel; it is turned on again when we add parts of the scrutinee to the constraint.
64+
*/
65+
protected var canWidenAbstract: Boolean = true
66+
6167
protected var myNecessaryConstraintsOnly = false
6268
/** When collecting the constraints needed for a particular subtyping
6369
* judgment to be true, we sometimes need to approximate the constraint
@@ -839,13 +845,17 @@ trait ConstraintHandling {
839845
//checkPropagated(s"adding $description")(true) // DEBUG in case following fails
840846
checkPropagated(s"added $description") {
841847
addConstraintInvocations += 1
848+
val saved = canWidenAbstract
849+
canWidenAbstract = true
842850
try bound match
843851
case bound: TypeParamRef if constraint contains bound =>
844852
addParamBound(bound)
845853
case _ =>
846854
val pbound = avoidLambdaParams(bound)
847855
kindCompatible(param, pbound) && addBoundTransitively(param, pbound, !fromBelow)
848-
finally addConstraintInvocations -= 1
856+
finally
857+
canWidenAbstract = saved
858+
addConstraintInvocations -= 1
849859
}
850860
end addConstraint
851861

tests/pos-with-compiler-cc/dotc/core/Definitions.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -962,9 +962,11 @@ class Definitions {
962962
def RuntimeTupleFunctionsModule(using Context): Symbol = requiredModule("scala.runtime.TupledFunctions")
963963

964964
@tu lazy val CapsModule: Symbol = requiredModule("scala.caps")
965-
@tu lazy val Caps_unsafeBox: Symbol = CapsModule.requiredMethod("unsafeBox")
966-
@tu lazy val Caps_unsafeUnbox: Symbol = CapsModule.requiredMethod("unsafeUnbox")
967965
@tu lazy val captureRoot: TermSymbol = CapsModule.requiredValue("*")
966+
@tu lazy val CapsUnsafeModule: Symbol = requiredModule("scala.caps.unsafe")
967+
@tu lazy val Caps_unsafeBox: Symbol = CapsUnsafeModule.requiredMethod("unsafeBox")
968+
@tu lazy val Caps_unsafeUnbox: Symbol = CapsUnsafeModule.requiredMethod("unsafeUnbox")
969+
@tu lazy val Caps_unsafeBoxFunArg: Symbol = CapsUnsafeModule.requiredMethod("unsafeBoxFunArg")
968970

969971
// Annotation base classes
970972
@tu lazy val AnnotationClass: ClassSymbol = requiredClass("scala.annotation.Annotation")

tests/pos-with-compiler-cc/dotc/core/Mode.scala

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,14 @@ object Mode {
7070
/** We are currently unpickling Scala2 info */
7171
val Scala2Unpickling: Mode = newMode(13, "Scala2Unpickling")
7272

73-
/** We are currently checking bounds to be non-empty, so we should not
74-
* do any widening when computing members of refined types.
73+
/** Signifies one of two possible situations:
74+
* 1. We are currently checking bounds to be non-empty, so we should not
75+
* do any widening when computing members of refined types.
76+
* 2. We are currently checking self type conformance, so we should not
77+
* ignore capture sets added to otherwise pure classes (only needed
78+
* for capture checking).
7579
*/
76-
val CheckBounds: Mode = newMode(14, "CheckBounds")
80+
val CheckBoundsOrSelfType: Mode = newMode(14, "CheckBoundsOrSelfType")
7781

7882
/** Use Scala2 scheme for overloading and implicit resolution */
7983
val OldOverloadingResolution: Mode = newMode(15, "OldOverloadingResolution")

tests/pos-with-compiler-cc/dotc/core/TypeComparer.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import typer.ProtoTypes.constrained
2323
import typer.Applications.productSelectorTypes
2424
import reporting.trace
2525
import annotation.constructorOnly
26-
import cc.{CapturingType, derivedCapturingType, CaptureSet, stripCapturing, isBoxedCapturing, boxed, boxedUnlessFun, boxedIfTypeParam}
26+
import cc.{CapturingType, derivedCapturingType, CaptureSet, stripCapturing, isBoxedCapturing, boxed, boxedUnlessFun, boxedIfTypeParam, isAlwaysPure}
2727
import language.experimental.pureFunctions
2828

2929
/** Provides methods to compare types.
@@ -61,8 +61,6 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
6161
/** Indicates whether the subtype check used GADT bounds */
6262
private var GADTused: Boolean = false
6363

64-
protected var canWidenAbstract: Boolean = true
65-
6664
private var myInstance: TypeComparer = this
6765
def currentInstance: TypeComparer = myInstance
6866

@@ -523,7 +521,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
523521
res
524522

525523
case CapturingType(parent1, refs1) =>
526-
if subCaptures(refs1, tp2.captureSet, frozenConstraint).isOK && sameBoxed(tp1, tp2, refs1)
524+
if tp2.isAny then true
525+
else if subCaptures(refs1, tp2.captureSet, frozenConstraint).isOK && sameBoxed(tp1, tp2, refs1)
526+
|| !ctx.mode.is(Mode.CheckBoundsOrSelfType) && tp1.isAlwaysPure
527527
then recur(parent1, tp2)
528528
else thirdTry
529529
case tp1: AnnotatedType if !tp1.isRefining =>

0 commit comments

Comments
 (0)