Skip to content

Commit ef7e32c

Browse files
authored
Merge branch 'main' into fix/Wunused/non_miniphase_traverser
2 parents 529040c + d99d9bf commit ef7e32c

File tree

67 files changed

+864
-312
lines changed

Some content is hidden

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

67 files changed

+864
-312
lines changed

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ package ast
44
import core.Contexts._
55
import core.Decorators._
66
import util.Spans._
7-
import Trees.{MemberDef, DefTree, WithLazyField}
7+
import Trees.{MemberDef, DefTree, WithLazyFields}
88
import dotty.tools.dotc.core.Types.AnnotatedType
99
import dotty.tools.dotc.core.Types.ImportType
1010
import dotty.tools.dotc.core.Types.Type
@@ -106,16 +106,14 @@ object NavigateAST {
106106
// FIXME: We shouldn't be manually forcing trees here, we should replace
107107
// our usage of `productIterator` by something in `Positioned` that takes
108108
// care of low-level details like this for us.
109-
p match {
110-
case p: WithLazyField[?] =>
111-
p.forceIfLazy
109+
p match
110+
case p: WithLazyFields => p.forceFields()
112111
case _ =>
113-
}
114112
val iterator = p match
115113
case defdef: DefTree[?] =>
116114
p.productIterator ++ defdef.mods.productIterator
117115
case _ =>
118-
p.productIterator
116+
p.productIterator
119117
childPath(iterator, p :: path)
120118
}
121119
else {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ trait TreeInfo[T <: Untyped] { self: Trees.Instance[T] =>
313313
*/
314314
def parentsKind(parents: List[Tree])(using Context): FlagSet = parents match {
315315
case Nil => NoInitsInterface
316-
case Apply(_, _ :: _) :: _ => EmptyFlags
316+
case Apply(_, _ :: _) :: _ | Block(_, _) :: _ => EmptyFlags
317317
case _ :: parents1 => parentsKind(parents1)
318318
}
319319

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,10 @@ class TreeMapWithImplicits extends tpd.TreeMapWithPreciseStatContexts {
5555
transform(tree.tpt),
5656
transform(tree.rhs)(using nestedScopeCtx(tree.paramss.flatten)))
5757
}
58-
case impl @ Template(constr, parents, self, _) =>
58+
case impl @ Template(constr, _, self, _) =>
5959
cpy.Template(tree)(
6060
transformSub(constr),
61-
transform(parents)(using ctx.superCallContext),
61+
transform(impl.parents)(using ctx.superCallContext),
6262
Nil,
6363
transformSelf(self),
6464
transformStats(impl.body, tree.symbol))

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,11 @@ class TreeTypeMap(
9292
cpy.Inlined(tree)(call, bindings1, expanded1)
9393

9494
override def transform(tree: tpd.Tree)(using Context): tpd.Tree = treeMap(tree) match {
95-
case impl @ Template(constr, parents, self, _) =>
95+
case impl @ Template(constr, _, self, _) =>
9696
val tmap = withMappedSyms(localSyms(impl :: self :: Nil))
9797
cpy.Template(impl)(
9898
constr = tmap.transformSub(constr),
99-
parents = parents.mapconserve(transform),
99+
parents = impl.parents.mapconserve(transform),
100100
self = tmap.transformSub(self),
101101
body = impl.body mapconserve
102102
(tmap.transform(_)(using ctx.withOwner(mapOwner(impl.symbol.owner))))

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

Lines changed: 42 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -407,12 +407,12 @@ object Trees {
407407
}
408408

409409
/** A ValDef or DefDef tree */
410-
abstract class ValOrDefDef[+T <: Untyped](implicit @constructorOnly src: SourceFile) extends MemberDef[T] with WithLazyField[Tree[T]] {
410+
abstract class ValOrDefDef[+T <: Untyped](implicit @constructorOnly src: SourceFile) extends MemberDef[T], WithLazyFields {
411411
type ThisTree[+T <: Untyped] <: ValOrDefDef[T]
412412
def name: TermName
413413
def tpt: Tree[T]
414-
def unforcedRhs: LazyTree[T] = unforced
415-
def rhs(using Context): Tree[T] = forceIfLazy
414+
def unforcedRhs: LazyTree[T]
415+
def rhs(using Context): Tree[T]
416416
}
417417

418418
trait ValOrTypeDef[+T <: Untyped] extends MemberDef[T]:
@@ -808,8 +808,10 @@ object Trees {
808808
extends ValOrDefDef[T], ValOrTypeDef[T] {
809809
type ThisTree[+T <: Untyped] = ValDef[T]
810810
assert(isEmpty || (tpt ne genericEmptyTree))
811-
def unforced: LazyTree[T] = preRhs
812-
protected def force(x: Tree[T @uncheckedVariance]): Unit = preRhs = x
811+
812+
def unforcedRhs: LazyTree[T] = preRhs
813+
def forceFields()(using Context): Unit = preRhs = force(preRhs)
814+
def rhs(using Context): Tree[T] = { forceFields(); preRhs.asInstanceOf[Tree[T]] }
813815
}
814816

815817
/** mods def name[tparams](vparams_1)...(vparams_n): tpt = rhs */
@@ -818,8 +820,10 @@ object Trees {
818820
extends ValOrDefDef[T] {
819821
type ThisTree[+T <: Untyped] = DefDef[T]
820822
assert(tpt ne genericEmptyTree)
821-
def unforced: LazyTree[T] = preRhs
822-
protected def force(x: Tree[T @uncheckedVariance]): Unit = preRhs = x
823+
824+
def unforcedRhs: LazyTree[T] = preRhs
825+
def forceFields()(using Context): Unit = preRhs = force(preRhs)
826+
def rhs(using Context): Tree[T] = { forceFields(); preRhs.asInstanceOf[Tree[T]] }
823827

824828
def leadingTypeParams(using Context): List[TypeDef[T]] = paramss match
825829
case (tparams @ (tparam: TypeDef[_]) :: _) :: _ => tparams.asInstanceOf[List[TypeDef[T]]]
@@ -855,16 +859,20 @@ object Trees {
855859
* if this is of class untpd.DerivingTemplate.
856860
* Typed templates only have parents.
857861
*/
858-
case class Template[+T <: Untyped] private[ast] (constr: DefDef[T], parentsOrDerived: List[Tree[T]], self: ValDef[T], private var preBody: LazyTreeList[T])(implicit @constructorOnly src: SourceFile)
859-
extends DefTree[T] with WithLazyField[List[Tree[T]]] {
862+
case class Template[+T <: Untyped] private[ast] (constr: DefDef[T], private var preParentsOrDerived: LazyTreeList[T], self: ValDef[T], private var preBody: LazyTreeList[T])(implicit @constructorOnly src: SourceFile)
863+
extends DefTree[T] with WithLazyFields {
860864
type ThisTree[+T <: Untyped] = Template[T]
861-
def unforcedBody: LazyTreeList[T] = unforced
862-
def unforced: LazyTreeList[T] = preBody
863-
protected def force(x: List[Tree[T @uncheckedVariance]]): Unit = preBody = x
864-
def body(using Context): List[Tree[T]] = forceIfLazy
865865

866-
def parents: List[Tree[T]] = parentsOrDerived // overridden by DerivingTemplate
867-
def derived: List[untpd.Tree] = Nil // overridden by DerivingTemplate
866+
def forceFields()(using Context): Unit =
867+
preParentsOrDerived = force(preParentsOrDerived)
868+
preBody = force(preBody)
869+
870+
def unforcedBody: LazyTreeList[T] = preBody
871+
def body(using Context): List[Tree[T]] = { forceFields(); preBody.asInstanceOf[List[Tree[T]]] }
872+
def parentsOrDerived(using Context): List[Tree[T]] = { forceFields(); preParentsOrDerived.asInstanceOf[List[Tree[T]]] }
873+
874+
def parents(using Context): List[Tree[T]] = parentsOrDerived // overridden by DerivingTemplate
875+
def derived: List[untpd.Tree] = Nil // overridden by DerivingTemplate
868876
}
869877

870878

@@ -1008,30 +1016,27 @@ object Trees {
10081016

10091017
// ----- Lazy trees and tree sequences
10101018

1011-
/** A tree that can have a lazy field
1012-
* The field is represented by some private `var` which is
1013-
* accessed by `unforced` and `force`. Forcing the field will
1014-
* set the `var` to the underlying value.
1015-
*/
1016-
trait WithLazyField[+T <: AnyRef] {
1017-
def unforced: T | Lazy[T]
1018-
protected def force(x: T @uncheckedVariance): Unit
1019-
def forceIfLazy(using Context): T = unforced match {
1020-
case lzy: Lazy[T @unchecked] =>
1021-
val x = lzy.complete
1022-
force(x)
1023-
x
1024-
case x: T @ unchecked => x
1025-
}
1026-
}
1027-
10281019
/** A base trait for lazy tree fields.
10291020
* These can be instantiated with Lazy instances which
10301021
* can delay tree construction until the field is first demanded.
10311022
*/
1032-
trait Lazy[+T <: AnyRef] {
1023+
trait Lazy[+T <: AnyRef]:
10331024
def complete(using Context): T
1034-
}
1025+
1026+
/** A tree that can have a lazy fields.
1027+
* Such fields are variables of type `T | Lazy[T]`, for some tyope `T`.
1028+
*/
1029+
trait WithLazyFields:
1030+
1031+
/** If `x` is lazy, computes the underlying value */
1032+
protected def force[T <: AnyRef](x: T | Lazy[T])(using Context): T = x match
1033+
case x: Lazy[T] @unchecked => x.complete
1034+
case x: T @unchecked => x
1035+
1036+
/** Assigns all lazy fields their underlying non-lazy value. */
1037+
def forceFields()(using Context): Unit
1038+
1039+
end WithLazyFields
10351040

10361041
// ----- Generic Tree Instances, inherited from `tpt` and `untpd`.
10371042

@@ -1355,7 +1360,7 @@ object Trees {
13551360
DefDef(tree: Tree)(name, paramss, tpt, rhs)
13561361
def TypeDef(tree: TypeDef)(name: TypeName = tree.name, rhs: Tree = tree.rhs)(using Context): TypeDef =
13571362
TypeDef(tree: Tree)(name, rhs)
1358-
def Template(tree: Template)(constr: DefDef = tree.constr, parents: List[Tree] = tree.parents, derived: List[untpd.Tree] = tree.derived, self: ValDef = tree.self, body: LazyTreeList = tree.unforcedBody)(using Context): Template =
1363+
def Template(tree: Template)(using Context)(constr: DefDef = tree.constr, parents: List[Tree] = tree.parents, derived: List[untpd.Tree] = tree.derived, self: ValDef = tree.self, body: LazyTreeList = tree.unforcedBody): Template =
13591364
Template(tree: Tree)(constr, parents, derived, self, body)
13601365
def Hole(tree: Hole)(isTerm: Boolean = tree.isTerm, idx: Int = tree.idx, args: List[Tree] = tree.args, content: Tree = tree.content, tpt: Tree = tree.tpt)(using Context): Hole =
13611366
Hole(tree: Tree)(isTerm, idx, args, content, tpt)
@@ -1618,8 +1623,8 @@ object Trees {
16181623
inContext(localCtx(tree)) {
16191624
this(x, rhs)
16201625
}
1621-
case tree @ Template(constr, parents, self, _) if tree.derived.isEmpty =>
1622-
this(this(this(this(x, constr), parents), self), tree.body)
1626+
case tree @ Template(constr, _, self, _) if tree.derived.isEmpty =>
1627+
this(this(this(this(x, constr), tree.parents), self), tree.body)
16231628
case Import(expr, _) =>
16241629
this(x, expr)
16251630
case Export(expr, _) =>

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
5454
*/
5555
class DerivingTemplate(constr: DefDef, parentsOrDerived: List[Tree], self: ValDef, preBody: LazyTreeList, derivedCount: Int)(implicit @constructorOnly src: SourceFile)
5656
extends Template(constr, parentsOrDerived, self, preBody) {
57-
override val parents = parentsOrDerived.dropRight(derivedCount)
57+
private val myParents = parentsOrDerived.dropRight(derivedCount)
58+
override def parents(using Context) = myParents
5859
override val derived = parentsOrDerived.takeRight(derivedCount)
5960
}
6061

@@ -415,6 +416,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
415416
def Template(constr: DefDef, parents: List[Tree], derived: List[Tree], self: ValDef, body: LazyTreeList)(implicit src: SourceFile): Template =
416417
if (derived.isEmpty) new Template(constr, parents, self, body)
417418
else new DerivingTemplate(constr, parents ++ derived, self, body, derived.length)
419+
def Template(constr: DefDef, parents: LazyTreeList, self: ValDef, body: LazyTreeList)(implicit src: SourceFile): Template =
420+
new Template(constr, parents, self, body)
418421
def Import(expr: Tree, selectors: List[ImportSelector])(implicit src: SourceFile): Import = new Import(expr, selectors)
419422
def Export(expr: Tree, selectors: List[ImportSelector])(implicit src: SourceFile): Export = new Export(expr, selectors)
420423
def PackageDef(pid: RefTree, stats: List[Tree])(implicit src: SourceFile): PackageDef = new PackageDef(pid, stats)

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,11 @@ extension (tp: Type)
166166
case CapturingType(_, _) => true
167167
case _ => false
168168

169+
def isEventuallyCapturingType(using Context): Boolean =
170+
tp match
171+
case EventuallyCapturingType(_, _) => true
172+
case _ => false
173+
169174
/** Is type known to be always pure by its class structure,
170175
* so that adding a capture set to it would not make sense?
171176
*/

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ object CapturingType:
4848
EventuallyCapturingType.unapply(tp)
4949
else None
5050

51+
/** Check whether a type is uncachable when computing `baseType`.
52+
* - Avoid caching all the types during the setup phase, since at that point
53+
* the capture set variables are not fully installed yet.
54+
* - Avoid caching capturing types when IgnoreCaptures mode is set, since the
55+
* capture sets may be thrown away in the computed base type.
56+
*/
57+
def isUncachable(tp: Type)(using Context): Boolean =
58+
ctx.phase == Phases.checkCapturesPhase &&
59+
(Setup.isDuringSetup || ctx.mode.is(Mode.IgnoreCaptures) && tp.isEventuallyCapturingType)
60+
5161
end CapturingType
5262

5363
/** An extractor for types that will be capturing types at phase CheckCaptures. Also

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

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import config.Printers.{capt, recheckr}
1010
import config.{Config, Feature}
1111
import ast.{tpd, untpd, Trees}
1212
import Trees.*
13-
import typer.RefChecks.{checkAllOverrides, checkSelfAgainstParents}
13+
import typer.RefChecks.{checkAllOverrides, checkSelfAgainstParents, OverridingPairsChecker}
1414
import typer.Checking.{checkBounds, checkAppliedTypesIn}
1515
import util.{SimpleIdentitySet, EqHashMap, SrcPos}
1616
import transform.SymUtils.*
@@ -141,25 +141,12 @@ class CheckCaptures extends Recheck, SymTransformer:
141141

142142
override def run(using Context): Unit =
143143
if Feature.ccEnabled then
144-
checkOverrides.traverse(ctx.compilationUnit.tpdTree)
145144
super.run
146145

147146
override def transformSym(sym: SymDenotation)(using Context): SymDenotation =
148147
if Synthetics.needsTransform(sym) then Synthetics.transformFromCC(sym)
149148
else super.transformSym(sym)
150149

151-
/** Check overrides again, taking capture sets into account.
152-
* TODO: Can we avoid doing overrides checks twice?
153-
* We need to do them here since only at this phase CaptureTypes are relevant
154-
* But maybe we can then elide the check during the RefChecks phase under captureChecking?
155-
*/
156-
def checkOverrides = new TreeTraverser:
157-
def traverse(t: Tree)(using Context) =
158-
t match
159-
case t: Template => checkAllOverrides(ctx.owner.asClass)
160-
case _ =>
161-
traverseChildren(t)
162-
163150
class CaptureChecker(ictx: Context) extends Rechecker(ictx):
164151
import ast.tpd.*
165152

@@ -668,8 +655,11 @@ class CheckCaptures extends Recheck, SymTransformer:
668655
case _ =>
669656
expected
670657

671-
/** Adapt `actual` type to `expected` type by inserting boxing and unboxing conversions */
672-
def adaptBoxed(actual: Type, expected: Type, pos: SrcPos)(using Context): Type =
658+
/** Adapt `actual` type to `expected` type by inserting boxing and unboxing conversions
659+
*
660+
* @param alwaysConst always make capture set variables constant after adaptation
661+
*/
662+
def adaptBoxed(actual: Type, expected: Type, pos: SrcPos, alwaysConst: Boolean = false)(using Context): Type =
673663

674664
/** Adapt function type `actual`, which is `aargs -> ares` (possibly with dependencies)
675665
* to `expected` type.
@@ -746,7 +736,8 @@ class CheckCaptures extends Recheck, SymTransformer:
746736
else
747737
((parent, cs, tp.isBoxed), reconstruct)
748738
case actual =>
749-
((actual, CaptureSet(), false), reconstruct)
739+
val res = if tp.isFromJavaObject then tp else actual
740+
((res, CaptureSet(), false), reconstruct)
750741

751742
def adapt(actual: Type, expected: Type, covariant: Boolean): Type = trace(adaptInfo(actual, expected, covariant), recheckr, show = true) {
752743
if expected.isInstanceOf[WildcardType] then actual
@@ -806,9 +797,9 @@ class CheckCaptures extends Recheck, SymTransformer:
806797
}
807798
if !insertBox then // unboxing
808799
markFree(criticalSet, pos)
809-
recon(CapturingType(parent1, cs1, !actualIsBoxed))
800+
recon(CapturingType(parent1, if alwaysConst then CaptureSet(cs1.elems) else cs1, !actualIsBoxed))
810801
else
811-
recon(CapturingType(parent1, cs1, actualIsBoxed))
802+
recon(CapturingType(parent1, if alwaysConst then CaptureSet(cs1.elems) else cs1, actualIsBoxed))
812803
}
813804

814805
var actualw = actual.widenDealias
@@ -827,12 +818,49 @@ class CheckCaptures extends Recheck, SymTransformer:
827818
else actual
828819
end adaptBoxed
829820

821+
/** Check overrides again, taking capture sets into account.
822+
* TODO: Can we avoid doing overrides checks twice?
823+
* We need to do them here since only at this phase CaptureTypes are relevant
824+
* But maybe we can then elide the check during the RefChecks phase under captureChecking?
825+
*/
826+
def checkOverrides = new TreeTraverser:
827+
class OverridingPairsCheckerCC(clazz: ClassSymbol, self: Type, srcPos: SrcPos)(using Context) extends OverridingPairsChecker(clazz, self) {
828+
/** Check subtype with box adaptation.
829+
* This function is passed to RefChecks to check the compatibility of overriding pairs.
830+
* @param sym symbol of the field definition that is being checked
831+
*/
832+
override def checkSubType(actual: Type, expected: Type)(using Context): Boolean =
833+
val expected1 = alignDependentFunction(addOuterRefs(expected, actual), actual.stripCapturing)
834+
val actual1 =
835+
val saved = curEnv
836+
try
837+
curEnv = Env(clazz, nestedInOwner = true, capturedVars(clazz), isBoxed = false, outer0 = curEnv)
838+
val adapted = adaptBoxed(actual, expected1, srcPos, alwaysConst = true)
839+
actual match
840+
case _: MethodType =>
841+
// We remove the capture set resulted from box adaptation for method types,
842+
// since class methods are always treated as pure, and their captured variables
843+
// are charged to the capture set of the class (which is already done during
844+
// box adaptation).
845+
adapted.stripCapturing
846+
case _ => adapted
847+
finally curEnv = saved
848+
actual1 frozen_<:< expected1
849+
}
850+
851+
def traverse(t: Tree)(using Context) =
852+
t match
853+
case t: Template =>
854+
checkAllOverrides(ctx.owner.asClass, OverridingPairsCheckerCC(_, _, t))
855+
case _ =>
856+
traverseChildren(t)
857+
830858
override def checkUnit(unit: CompilationUnit)(using Context): Unit =
831-
Setup(preRecheckPhase, thisPhase, recheckDef)
832-
.traverse(ctx.compilationUnit.tpdTree)
859+
Setup(preRecheckPhase, thisPhase, recheckDef)(ctx.compilationUnit.tpdTree)
833860
//println(i"SETUP:\n${Recheck.addRecheckedTypes.transform(ctx.compilationUnit.tpdTree)}")
834861
withCaptureSetsExplained {
835862
super.checkUnit(unit)
863+
checkOverrides.traverse(unit.tpdTree)
836864
checkSelfTypes(unit.tpdTree)
837865
postCheck(unit.tpdTree)
838866
if ctx.settings.YccDebug.value then

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import ast.tpd
1111
import transform.Recheck.*
1212
import CaptureSet.IdentityCaptRefMap
1313
import Synthetics.isExcluded
14+
import util.Property
1415

1516
/** A tree traverser that prepares a compilation unit to be capture checked.
1617
* It does the following:
@@ -484,4 +485,14 @@ extends tpd.TreeTraverser:
484485
capt.println(i"update info of ${tree.symbol} from $info to $newInfo")
485486
case _ =>
486487
end traverse
488+
489+
def apply(tree: Tree)(using Context): Unit =
490+
traverse(tree)(using ctx.withProperty(Setup.IsDuringSetupKey, Some(())))
487491
end Setup
492+
493+
object Setup:
494+
val IsDuringSetupKey = new Property.Key[Unit]
495+
496+
def isDuringSetup(using Context): Boolean =
497+
ctx.property(IsDuringSetupKey).isDefined
498+

0 commit comments

Comments
 (0)