Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More additions to the standard library #18799

Merged
merged 89 commits into from
Nov 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
3640ff4
Don't recheck inherited trait parameters during capture checking
odersky Oct 30, 2023
b65fd3a
Add SeqView to stdlib
odersky Oct 30, 2023
0ada1d4
Add IndexedSeqView to lib
odersky Oct 30, 2023
dbd0c0e
Add CheckedIndexedView to stdlib
odersky Oct 30, 2023
8a60bc2
Add ArrayBuffer (unchecked) to stdlib
odersky Oct 30, 2023
61bf139
Rename annotation source file
odersky Oct 30, 2023
6b91167
Also count @Sealed annotated abstract types as sealed
odersky Oct 30, 2023
d3876ad
Add ArrayBuffer and GrowableBuilder to stdlib
odersky Oct 30, 2023
75c2058
Coarse restriction to disallow local roots in external types
odersky Oct 30, 2023
bb0b774
Require array element types to be sealed
odersky Oct 31, 2023
6b5e494
Add ArrayBuilder.scala in unchanged form to stdlib
odersky Oct 31, 2023
609549c
Make ArrayBuilder capture checked
odersky Oct 31, 2023
d76f092
Add ArrayDeque.scala in unchanged for to stdlib
odersky Oct 31, 2023
e33fc7d
Make ArrayDeque capture checked
odersky Oct 31, 2023
37b41b6
Add Stepper.scala and ArraySeq.scala in unchanged form to stdlib
odersky Oct 31, 2023
ec70a23
Make Stepper capture checked
odersky Oct 31, 2023
24b8a4c
Don't generate capture set variables for self types of pure classes
odersky Oct 31, 2023
6ba065e
Make ArraySeq capture checked
odersky Oct 31, 2023
bb65046
Add mutable/IndexedSeq.scala to stdlib
odersky Oct 31, 2023
c811e35
Add Queue.scala to stdlib
odersky Oct 31, 2023
f0a1241
Add PriorityQueue.scala to stdlib
odersky Oct 31, 2023
4ac2139
Make PriorityQueue capture checked
odersky Oct 31, 2023
4795ef8
Add Stack.scala and ReusableBuilder.scala to stdlib
odersky Oct 31, 2023
0bf1903
Add Set.scala to stdlib
odersky Oct 31, 2023
35e7166
Make collection/Set capture checked
odersky Oct 31, 2023
14b5093
Add mutable/immutable Set to stdlib
odersky Oct 31, 2023
1f414a3
Make mutable/immutable Set capture checked
odersky Oct 31, 2023
f92c881
Add BitSet classes to stdlib (capture checked)
odersky Oct 31, 2023
6a831aa
Add SortedSet classes to stdlib
odersky Oct 31, 2023
3b6b684
Add Factory.scala to stdlib
odersky Oct 31, 2023
5852a76
Make Factory capture checked
odersky Oct 31, 2023
c9cb044
Avoid reporting post check messages several times
odersky Oct 31, 2023
0a350ea
Add SortedSet and BitSet to stdlib (capture checked)
odersky Oct 31, 2023
06744c2
Add BuildFrom.scala to stdlib
odersky Oct 31, 2023
51c9385
Make BuildFrom capture checked
odersky Oct 31, 2023
238317c
Add WithFilter.scala to stdlib
odersky Nov 1, 2023
1b757b9
Make WithFilter capture checked
odersky Nov 1, 2023
4956e6d
Add ArrayOps to stdlib
odersky Nov 1, 2023
7273c4d
Don't flag wildcard array arguments for not being sealed
odersky Nov 1, 2023
b67422e
Fix isPureClass test
odersky Nov 1, 2023
c64c057
Make sealed an annotation
odersky Nov 1, 2023
2083af3
Make ArrayOps capture checked
odersky Nov 1, 2023
9909d95
Add LazyZipOps and some other files to stdlib
odersky Nov 1, 2023
caeac20
Add mutable/TreeSet.scala to stdlib
odersky Nov 1, 2023
1f4f875
Add mutable and concurrent Map to stdlib
odersky Nov 1, 2023
3dc0eae
Add HashMaps to stdlib
odersky Nov 1, 2023
20f3a97
Add LongMap + friends to stdlib
odersky Nov 1, 2023
ae605d6
Add WeakHashMap and MultiMap to stdlib
odersky Nov 1, 2023
b0d3bbc
Add UnrolledBuffer to stdlib
odersky Nov 1, 2023
09e0868
Add mutable TreeMap and RedBlackTree to stdlib
odersky Nov 1, 2023
0888c40
Add mutable SortedMap and SeqMap to stdlib
odersky Nov 1, 2023
a76129f
Add AnyRefMap to stdlib
odersky Nov 1, 2023
73f9474
Add CollisionProofHashMap to stdlib
odersky Nov 1, 2023
ffbaf1f
Avoid infinite recursions when checking F-bounded types
odersky Nov 1, 2023
7304ba6
Add HashTable.scala to stdlib
odersky Nov 1, 2023
f3ed83b
Add HashSet to stdlib
odersky Nov 1, 2023
7d2f133
Add OpenHashMap to stdlib
odersky Nov 1, 2023
9021cfd
Add MapView to stdlib
odersky Nov 1, 2023
cb66516
Add StrictOptimizedMapOps to stdlib
odersky Nov 1, 2023
be20a7c
Add collection/SortedMap to stdlib
odersky Nov 1, 2023
766b020
Add more Ops classes to stdlib
odersky Nov 1, 2023
36975c1
Add remaining collection classes to stdlib
odersky Nov 1, 2023
b899f8d
Add immutable ArraySeq to stdlib
odersky Nov 2, 2023
1f3fe9e
Add immutable HashSet and HashMap to stdlib
odersky Nov 2, 2023
528c249
Add immutable IntMap and LongMap to stdlib
odersky Nov 2, 2023
02c6281
Add immutable ListSet and ListMap to stdlib
odersky Nov 2, 2023
2cb34e5
Add immutable Map to stdlib
odersky Nov 2, 2023
a1fc706
Add Range classes to stdlib
odersky Nov 2, 2023
5817d40
Add immutable Queue to stdlib
odersky Nov 2, 2023
c16afe5
Add immutable RedBlackTree to stdlib
odersky Nov 2, 2023
d526e10
Add immutable SeqMap to stdlib
odersky Nov 2, 2023
26dde72
Add immutable SortedMap to stdlib
odersky Nov 2, 2023
a08460d
Add immutable StrictOptimizedSeqOps to stdlib
odersky Nov 2, 2023
c66c833
Add Vector and VectorMap to stdlib
odersky Nov 2, 2023
eea6bca
Add immutable TreeSet and TreeMap to stdlib
odersky Nov 2, 2023
4625afc
Add immutable TreeSeqMap to stdlib
odersky Nov 2, 2023
9ba2c39
Add unchecked LazyList to stdlib
odersky Nov 2, 2023
bf58e2b
Survive "cannot establish a reference" errors in TreeTypeMap
odersky Nov 2, 2023
6ae16a4
Add checked LazyList to stdlib
odersky Nov 2, 2023
0acfb8c
Rename LazyList to LazyListIterable
odersky Nov 2, 2023
fd88dc1
Allow deep subtypes when compiling stdlib test
odersky Nov 3, 2023
9ae3ee7
Add generic/IsSeq to stdlib
odersky Nov 3, 2023
f8f2050
Make SubstRecThis typemap idempotent
odersky Nov 3, 2023
b19f981
Capturecheck all files in generic
odersky Nov 3, 2023
868d65b
Drop an unsafeAssumePure in Iterator
odersky Nov 3, 2023
f4066c0
Better error message for capture errors involving self types
odersky Nov 3, 2023
e22744d
Add sealed refs test and fix check files of other tests
odersky Nov 4, 2023
cfec1d0
Simplify CapturedVars phase
odersky Nov 4, 2023
5e49b12
Refine isParametric tests
odersky Nov 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ class TreeTypeMap(
tree1.withType(mapType(tree1.tpe)) match {
case id: Ident =>
if needsSelect(id.tpe) then
ref(id.tpe.asInstanceOf[TermRef]).withSpan(id.span)
try ref(id.tpe.asInstanceOf[TermRef]).withSpan(id.span)
catch case ex: TypeError => super.transform(id)
else
super.transform(id)
case sel: Select =>
Expand Down
12 changes: 11 additions & 1 deletion compiler/src/dotty/tools/dotc/cc/CaptureOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,12 @@ extension (tp: Type)
case _: TypeRef | _: AppliedType => tp.typeSymbol.hasAnnotation(defn.CapabilityAnnot)
case _ => false

def isSealed(using Context): Boolean = tp match
case tp: TypeParamRef => tp.underlying.isSealed
case tp: TypeBounds => tp.hi.hasAnnotation(defn.Caps_SealedAnnot)
case tp: TypeRef => tp.symbol.is(Sealed) || tp.info.isSealed // TODO: drop symbol flag?
case _ => false

/** Drop @retains annotations everywhere */
def dropAllRetains(using Context): Type = // TODO we should drop retains from inferred types before unpickling
val tm = new TypeMap:
Expand All @@ -225,7 +231,11 @@ extension (cls: ClassSymbol)
&& bc.givenSelfType.dealiasKeepAnnots.match
case CapturingType(_, refs) => refs.isAlwaysEmpty
case RetainingType(_, refs) => refs.isEmpty
case selfType => selfType.exists && selfType.captureSet.isAlwaysEmpty
case selfType =>
isCaptureChecking // At Setup we have not processed self types yet, so
// unless a self type is explicitly given, we can't tell
// and err on the side of impure.
&& selfType.exists && selfType.captureSet.isAlwaysEmpty

extension (sym: Symbol)

Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/cc/CaptureSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,7 @@ object CaptureSet:
upper.isAlwaysEmpty || upper.isConst && upper.elems.size == 1 && upper.elems.contains(r1)
if variance > 0 || isExact then upper
else if variance < 0 then CaptureSet.empty
else if ctx.mode.is(Mode.Printing) then upper
else assert(false, i"trying to add $upper from $r via ${tm.getClass} in a non-variant setting")

/** Apply `f` to each element in `xs`, and join result sets with `++` */
Expand Down
187 changes: 148 additions & 39 deletions compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ import typer.RefChecks.{checkAllOverrides, checkSelfAgainstParents, OverridingPa
import typer.Checking.{checkBounds, checkAppliedTypesIn}
import typer.ErrorReporting.{Addenda, err}
import typer.ProtoTypes.{AnySelectionProto, LhsProto}
import util.{SimpleIdentitySet, EqHashMap, SrcPos, Property}
import util.{SimpleIdentitySet, EqHashMap, EqHashSet, SrcPos, Property}
import transform.SymUtils.*
import transform.{Recheck, PreRecheck}
import transform.{Recheck, PreRecheck, CapturedVars}
import Recheck.*
import scala.collection.mutable
import CaptureSet.{withCaptureSetsExplained, IdempotentCaptRefMap, CompareResult}
import StdNames.nme
import NameKinds.DefaultGetterName
import NameKinds.{DefaultGetterName, WildcardParamName}
import reporting.trace

/** The capture checker */
Expand Down Expand Up @@ -147,33 +147,49 @@ object CheckCaptures:
private def disallowRootCapabilitiesIn(tp: Type, carrier: Symbol, what: String, have: String, addendum: String, pos: SrcPos)(using Context) =
val check = new TypeTraverser:

private val seen = new EqHashSet[TypeRef]

/** Check that there is at least one method containing carrier and defined
* in the scope of tparam. E.g. this is OK:
* def f[T] = { ... var x: T ... }
* So is this:
* class C[T] { def f() = { class D { var x: T }}}
* But this is not OK:
* class C[T] { object o { var x: T }}
*/
extension (tparam: Symbol) def isParametricIn(carrier: Symbol): Boolean =
val encl = carrier.owner.enclosingMethodOrClass
if encl.isClass then tparam.isParametricIn(encl)
else
def recur(encl: Symbol): Boolean =
if tparam.owner == encl then true
else if encl.isStatic || !encl.exists then false
else recur(encl.owner.enclosingMethodOrClass)
recur(encl)
carrier.exists && {
val encl = carrier.owner.enclosingMethodOrClass
if encl.isClass then tparam.isParametricIn(encl)
else
def recur(encl: Symbol): Boolean =
if tparam.owner == encl then true
else if encl.isStatic || !encl.exists then false
else recur(encl.owner.enclosingMethodOrClass)
recur(encl)
}

def traverse(t: Type) =
t.dealiasKeepAnnots match
case t: TypeRef =>
capt.println(i"disallow $t, $tp, $what, ${t.symbol.is(Sealed)}")
t.info match
case TypeBounds(_, hi)
if !t.symbol.is(Sealed) && !t.symbol.isParametricIn(carrier) =>
if hi.isAny then
report.error(
em"""$what cannot $have $tp since
|that type refers to the type variable $t, which is not sealed.
|$addendum""",
pos)
else
traverse(hi)
case _ =>
traverseChildren(t)
if !seen.contains(t) then
capt.println(i"disallow $t, $tp, $what, ${t.isSealed}")
seen += t
t.info match
case TypeBounds(_, hi) if !t.isSealed && !t.symbol.isParametricIn(carrier) =>
if hi.isAny then
val detailStr =
if t eq tp then "variable"
else i"refers to the type variable $t, which"
report.error(
em"""$what cannot $have $tp since
|that type $detailStr is not sealed.
|$addendum""",
pos)
else
traverse(hi)
case _ =>
traverseChildren(t)
case AnnotatedType(_, ann) if ann.symbol == defn.UncheckedCapturesAnnot =>
()
case t =>
Expand Down Expand Up @@ -260,11 +276,12 @@ class CheckCaptures extends Recheck, SymTransformer:
pos, provenance)

/** Check subcapturing `cs1 <: cs2`, report error on failure */
def checkSubset(cs1: CaptureSet, cs2: CaptureSet, pos: SrcPos, provenance: => String = "")(using Context) =
def checkSubset(cs1: CaptureSet, cs2: CaptureSet, pos: SrcPos,
provenance: => String = "", cs1description: String = "")(using Context) =
checkOK(
cs1.subCaptures(cs2, frozen = false),
if cs1.elems.size == 1 then i"reference ${cs1.elems.toList.head} is not"
else i"references $cs1 are not all",
if cs1.elems.size == 1 then i"reference ${cs1.elems.toList.head}$cs1description is not"
else i"references $cs1$cs1description are not all",
pos, provenance)

/** The current environment */
Expand Down Expand Up @@ -542,10 +559,10 @@ class CheckCaptures extends Recheck, SymTransformer:
val TypeApply(fn, args) = tree
val polyType = atPhase(thisPhase.prev):
fn.tpe.widen.asInstanceOf[TypeLambda]
for case (arg: TypeTree, pinfo, pname) <- args.lazyZip(polyType.paramInfos).lazyZip((polyType.paramNames)) do
if pinfo.bounds.hi.hasAnnotation(defn.Caps_SealedAnnot) then
for case (arg: TypeTree, formal, pname) <- args.lazyZip(polyType.paramRefs).lazyZip((polyType.paramNames)) do
if formal.isSealed then
def where = if fn.symbol.exists then i" in an argument of ${fn.symbol}" else ""
disallowRootCapabilitiesIn(arg.knownType, fn.symbol,
disallowRootCapabilitiesIn(arg.knownType, NoSymbol,
i"Sealed type variable $pname", "be instantiated to",
i"This is often caused by a local capability$where\nleaking as part of its result.",
tree.srcPos)
Expand Down Expand Up @@ -586,13 +603,58 @@ class CheckCaptures extends Recheck, SymTransformer:
openClosures = openClosures.tail
end recheckClosureBlock

/** Maps mutable variables to the symbols that capture them (in the
* CheckCaptures sense, i.e. symbol is referred to from a different method
* than the one it is defined in).
*/
private val capturedBy = util.HashMap[Symbol, Symbol]()

/** Maps anonymous functions appearing as function arguments to
* the function that is called.
*/
private val anonFunCallee = util.HashMap[Symbol, Symbol]()

/** Populates `capturedBy` and `anonFunCallee`. Called by `checkUnit`.
*/
private def collectCapturedMutVars(using Context) = new TreeTraverser:
def traverse(tree: Tree)(using Context) = tree match
case id: Ident =>
val sym = id.symbol
if sym.is(Mutable, butNot = Method) && sym.owner.isTerm then
val enclMeth = ctx.owner.enclosingMethod
if sym.enclosingMethod != enclMeth then
capturedBy(sym) = enclMeth
case Apply(fn, args) =>
for case closureDef(mdef) <- args do
anonFunCallee(mdef.symbol) = fn.symbol
traverseChildren(tree)
case Inlined(_, bindings, expansion) =>
traverse(bindings)
traverse(expansion)
case mdef: DefDef =>
if !mdef.symbol.isInlineMethod then traverseChildren(tree)
case _ =>
traverseChildren(tree)

override def recheckValDef(tree: ValDef, sym: Symbol)(using Context): Type =
try
if sym.is(Module) then sym.info // Modules are checked by checking the module class
else
if sym.is(Mutable) && !sym.hasAnnotation(defn.UncheckedCapturesAnnot) then
disallowRootCapabilitiesIn(tree.tpt.knownType, sym,
i"mutable $sym", "have type", "", sym.srcPos)
val (carrier, addendum) = capturedBy.get(sym) match
case Some(encl) =>
val enclStr =
if encl.isAnonymousFunction then
val location = anonFunCallee.get(encl) match
case Some(meth) if meth.exists => i" argument in a call to $meth"
case _ => ""
s"an anonymous function$location"
else encl.show
(NoSymbol, i"\nNote that $sym does not count as local since it is captured by $enclStr")
case _ =>
(sym, "")
disallowRootCapabilitiesIn(
tree.tpt.knownType, carrier, i"Mutable $sym", "have type", addendum, sym.srcPos)
checkInferredResult(super.recheckValDef(tree, sym), tree)
finally
if !sym.is(Param) then
Expand Down Expand Up @@ -680,9 +742,15 @@ class CheckCaptures extends Recheck, SymTransformer:
if !param.hasAnnotation(defn.ConstructorOnlyAnnot) then
checkSubset(param.termRef.captureSet, thisSet, param.srcPos) // (3)
for pureBase <- cls.pureBaseClass do // (4)
def selfType = impl.body
.collect:
case TypeDef(tpnme.SELF, rhs) => rhs
.headOption
.getOrElse(tree)
.orElse(tree)
checkSubset(thisSet,
CaptureSet.empty.withDescription(i"of pure base class $pureBase"),
tree.srcPos)
selfType.srcPos, cs1description = " captured by this self type")
super.recheckClassDef(tree, impl, cls)
finally
curEnv = saved
Expand Down Expand Up @@ -1122,6 +1190,8 @@ class CheckCaptures extends Recheck, SymTransformer:

override def needsCheck(overriding: Symbol, overridden: Symbol)(using Context): Boolean =
!setup.isPreCC(overriding) && !setup.isPreCC(overridden)

override def checkInheritedTraitParameters: Boolean = false
end OverridingPairsCheckerCC

def traverse(t: Tree)(using Context) =
Expand Down Expand Up @@ -1158,11 +1228,12 @@ class CheckCaptures extends Recheck, SymTransformer:
private val setup: SetupAPI = thisPhase.prev.asInstanceOf[Setup]

override def checkUnit(unit: CompilationUnit)(using Context): Unit =
setup.setupUnit(ctx.compilationUnit.tpdTree, completeDef)
setup.setupUnit(unit.tpdTree, completeDef)
collectCapturedMutVars.traverse(unit.tpdTree)

if ctx.settings.YccPrintSetup.value then
val echoHeader = "[[syntax tree at end of cc setup]]"
val treeString = show(ctx.compilationUnit.tpdTree)
val treeString = show(unit.tpdTree)
report.echo(s"$echoHeader\n$treeString\n")

withCaptureSetsExplained:
Expand Down Expand Up @@ -1298,6 +1369,39 @@ class CheckCaptures extends Recheck, SymTransformer:
checker.traverse(tree.knownType)
end healTypeParam

def checkNoLocalRootIn(sym: Symbol, info: Type, pos: SrcPos)(using Context): Unit =
val check = new TypeTraverser:
def traverse(tp: Type) = tp match
case tp: TermRef if tp.isLocalRootCapability =>
if tp.localRootOwner == sym then
report.error(i"local root $tp cannot appear in type of $sym", pos)
case tp: ClassInfo =>
traverseChildren(tp)
for mbr <- tp.decls do
if !mbr.is(Private) then checkNoLocalRootIn(sym, mbr.info, mbr.srcPos)
case _ =>
traverseChildren(tp)
check.traverse(info)

def checkArraysAreSealedIn(tp: Type, pos: SrcPos)(using Context): Unit =
val check = new TypeTraverser:
def traverse(t: Type): Unit =
t match
case AppliedType(tycon, arg :: Nil) if tycon.typeSymbol == defn.ArrayClass =>
if !(pos.span.isSynthetic && ctx.reporter.errorsReported)
&& !arg.typeSymbol.name.is(WildcardParamName)
then
CheckCaptures.disallowRootCapabilitiesIn(arg, NoSymbol,
"Array", "have element type",
"Since arrays are mutable, they have to be treated like variables,\nso their element type must be sealed.",
pos)
traverseChildren(t)
case defn.RefinedFunctionOf(rinfo: MethodType) =>
traverse(rinfo)
case _ =>
traverseChildren(t)
check.traverse(tp)

/** Perform the following kinds of checks
* - Check all explicitly written capturing types for well-formedness using `checkWellFormedPost`.
* - Check that arguments of TypeApplys and AppliedTypes conform to their bounds.
Expand All @@ -1309,10 +1413,11 @@ class CheckCaptures extends Recheck, SymTransformer:
val lctx = tree match
case _: DefTree | _: TypeDef if tree.symbol.exists => ctx.withOwner(tree.symbol)
case _ => ctx
traverseChildren(tree)(using lctx)
check(tree)
trace(i"post check $tree"):
traverseChildren(tree)(using lctx)
check(tree)
def check(tree: Tree)(using Context) = tree match
case t @ TypeApply(fun, args) =>
case TypeApply(fun, args) =>
fun.knownType.widen match
case tl: PolyType =>
val normArgs = args.lazyZip(tl.paramInfos).map: (arg, bounds) =>
Expand All @@ -1321,6 +1426,10 @@ class CheckCaptures extends Recheck, SymTransformer:
checkBounds(normArgs, tl)
args.lazyZip(tl.paramNames).foreach(healTypeParam(_, _, fun.symbol))
case _ =>
case _: ValOrDefDef | _: TypeDef =>
checkNoLocalRootIn(tree.symbol, tree.symbol.info, tree.symbol.srcPos)
case tree: TypeTree =>
checkArraysAreSealedIn(tree.tpe, tree.srcPos)
case _ =>
end check
end checker
Expand Down
5 changes: 4 additions & 1 deletion compiler/src/dotty/tools/dotc/cc/Setup.scala
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,9 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
tree.symbol match
case cls: ClassSymbol =>
val cinfo @ ClassInfo(prefix, _, ps, decls, selfInfo) = cls.classInfo
if (selfInfo eq NoType) || cls.is(ModuleClass) && !cls.isStatic then
if ((selfInfo eq NoType) || cls.is(ModuleClass) && !cls.isStatic)
&& !cls.isPureClass
then
// add capture set to self type of nested classes if no self type is given explicitly.
val newSelfType = CapturingType(cinfo.selfType, CaptureSet.Var(cls))
val ps1 = inContext(ctx.withOwner(cls)):
Expand Down Expand Up @@ -705,4 +707,5 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:

def postCheck()(using Context): Unit =
for chk <- todoAtPostCheck do chk(ctx)
todoAtPostCheck.clear()
end Setup
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1443,7 +1443,7 @@ class Definitions {
/** Base classes that are assumed to be pure for the purposes of capture checking.
* Every class inheriting from a pure baseclass is pure.
*/
@tu lazy val pureBaseClasses = Set(defn.ThrowableClass)
@tu lazy val pureBaseClasses = Set(ThrowableClass, PureClass)

/** Non-inheritable lasses that are assumed to be pure for the purposes of capture checking,
*/
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Substituters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ object Substituters:
def apply(tp: Type): Type = substThis(tp, from, to, this)(using mapCtx)
}

final class SubstRecThisMap(from: Type, to: Type)(using Context) extends DeepTypeMap {
final class SubstRecThisMap(from: Type, to: Type)(using Context) extends DeepTypeMap, IdempotentCaptRefMap {
def apply(tp: Type): Type = substRecThis(tp, from, to, this)(using mapCtx)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ trait UniqueMessagePositions extends Reporter {
||
dia.pos.exists
&& !ctx.settings.YshowSuppressedErrors.value
&& (dia.pos.start to dia.pos.end).exists(pos =>
positions.get((ctx.source, pos)).exists(_.hides(dia)))
&& (dia.pos.start to dia.pos.end).exists: offset =>
positions.get((ctx.source, offset)).exists(_.hides(dia))

override def markReported(dia: Diagnostic)(using Context): Unit =
if dia.pos.exists then
for (pos <- dia.pos.start to dia.pos.end)
positions.get(ctx.source, pos) match
for offset <- dia.pos.start to dia.pos.end do
positions.get((ctx.source, offset)) match
case Some(dia1) if dia1.hides(dia) =>
case _ => positions((ctx.source, pos)) = dia
case _ => positions((ctx.source, offset)) = dia
super.markReported(dia)
}
Loading
Loading