Skip to content

Commit ec24836

Browse files
authored
Merge branch 'main' into inlined-position
2 parents 40d44d3 + 45e08cb commit ec24836

File tree

177 files changed

+13474
-765
lines changed

Some content is hidden

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

177 files changed

+13474
-765
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ object projects:
372372
sbtTestCommand = """set deriving/scalacOptions -= "-Xfatal-warnings"; set typeable/scalacOptions -= "-Xfatal-warnings"; test""",
373373
// selectively disable -Xfatal-warnings due to deprecations
374374
sbtDocCommand = forceDoc("typeable", "deriving", "data"),
375-
scalacOptions = Nil // disable -Ysafe-init, due to -Xfatal-warnings
375+
scalacOptions = SbtCommunityProject.scalacOptions.filter(_ != "-Ysafe-init"), // due to -Xfatal-warnings
376376
)
377377

378378
lazy val xmlInterpolator = SbtCommunityProject(
@@ -682,7 +682,7 @@ object projects:
682682
sbtTestCommand = "runCommunityBuild",
683683
sbtPublishCommand = "publishLocal",
684684
dependencies = List(scalatest),
685-
scalacOptions = List("-language:implicitConversions"), // disabled -Ysafe-init, due to bug in macro
685+
scalacOptions = SbtCommunityProject.scalacOptions.filter(_ != "-Xcheck-macros") :+ "-language:implicitConversions", // disabled -Xcheck-macros, due to bug in macro
686686
)
687687

688688
lazy val onnxScala = SbtCommunityProject(

compiler/src/dotty/tools/backend/jvm/CodeGen.scala

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import scala.tools.asm
3030
import scala.tools.asm.tree._
3131
import tpd._
3232
import dotty.tools.io.AbstractFile
33+
import dotty.tools.dotc.util
3334
import dotty.tools.dotc.util.NoSourcePosition
3435

3536

@@ -106,7 +107,7 @@ class CodeGen(val int: DottyBackendInterface, val primitives: DottyPrimitives)(
106107
}
107108

108109
// Creates a callback that will be evaluated in PostProcessor after creating a file
109-
private def onFileCreated(cls: ClassNode, claszSymbol: Symbol, sourceFile: interfaces.SourceFile): AbstractFile => Unit = clsFile => {
110+
private def onFileCreated(cls: ClassNode, claszSymbol: Symbol, sourceFile: util.SourceFile): AbstractFile => Unit = clsFile => {
110111
val (fullClassName, isLocal) = atPhase(sbtExtractDependenciesPhase) {
111112
(ExtractDependencies.classNameAsString(claszSymbol), claszSymbol.isLocal)
112113
}
@@ -115,12 +116,9 @@ class CodeGen(val int: DottyBackendInterface, val primitives: DottyPrimitives)(
115116
if (ctx.compilerCallback != null)
116117
ctx.compilerCallback.onClassGenerated(sourceFile, convertAbstractFile(clsFile), className)
117118

118-
if (ctx.sbtCallback != null) {
119-
val jSourceFile = sourceFile.jfile.orElse(null)
120-
val cb = ctx.sbtCallback
121-
if (isLocal) cb.generatedLocalClass(jSourceFile, clsFile.file)
122-
else cb.generatedNonLocalClass(jSourceFile, clsFile.file, className, fullClassName)
123-
}
119+
ctx.withIncCallback: cb =>
120+
if (isLocal) cb.generatedLocalClass(sourceFile, clsFile.jpath)
121+
else cb.generatedNonLocalClass(sourceFile, clsFile.jpath, className, fullClassName)
124122
}
125123

126124
/** Convert a `dotty.tools.io.AbstractFile` into a

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,7 +1014,7 @@ object desugar {
10141014
* if the type has a pattern variable name
10151015
*/
10161016
def quotedPatternTypeDef(tree: TypeDef)(using Context): TypeDef = {
1017-
assert(ctx.mode.is(Mode.QuotedPattern))
1017+
assert(ctx.mode.isQuotedPattern)
10181018
if tree.name.isVarPattern && !tree.isBackquoted then
10191019
val patternTypeAnnot = New(ref(defn.QuotedRuntimePatterns_patternTypeAnnot.typeRef)).withSpan(tree.span)
10201020
val mods = tree.mods.withAddedAnnotation(patternTypeAnnot)
@@ -1363,7 +1363,7 @@ object desugar {
13631363
case tree: ValDef => valDef(tree)
13641364
case tree: TypeDef =>
13651365
if (tree.isClassDef) classDef(tree)
1366-
else if (ctx.mode.is(Mode.QuotedPattern)) quotedPatternTypeDef(tree)
1366+
else if (ctx.mode.isQuotedPattern) quotedPatternTypeDef(tree)
13671367
else tree
13681368
case tree: DefDef =>
13691369
if (tree.name.isConstructorName) tree // was already handled by enclosing classDef

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,8 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
954954
def isStructuralTermSelectOrApply(tree: Tree)(using Context): Boolean = {
955955
def isStructuralTermSelect(tree: Select) =
956956
def hasRefinement(qualtpe: Type): Boolean = qualtpe.dealias match
957+
case defn.PolyOrErasedFunctionOf(_) =>
958+
false
957959
case RefinedType(parent, rname, rinfo) =>
958960
rname == tree.name || hasRefinement(parent)
959961
case tp: TypeProxy =>
@@ -966,10 +968,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
966968
false
967969
!tree.symbol.exists
968970
&& tree.isTerm
969-
&& {
970-
val qualType = tree.qualifier.tpe
971-
hasRefinement(qualType) && !defn.isPolyOrErasedFunctionType(qualType)
972-
}
971+
&& hasRefinement(tree.qualifier.tpe)
973972
def loop(tree: Tree): Boolean = tree match
974973
case TypeApply(fun, _) =>
975974
loop(fun)

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,9 @@ object Trees {
673673
*/
674674
case class Inlined[+T <: Untyped] private[ast] (call: tpd.Tree, bindings: List[MemberDef[T]], expansion: Tree[T])(implicit @constructorOnly src: SourceFile)
675675
extends Tree[T] {
676+
677+
def inlinedFromOuterScope: Boolean = call.isEmpty
678+
676679
type ThisTree[+T <: Untyped] = Inlined[T]
677680
override def isTerm = expansion.isTerm
678681
override def isType = expansion.isType
@@ -1486,7 +1489,7 @@ object Trees {
14861489
* innermost enclosing call for which the inlined version is currently
14871490
* processed.
14881491
*/
1489-
protected def inlineContext(call: tpd.Tree)(using Context): Context = ctx
1492+
protected def inlineContext(tree: Inlined)(using Context): Context = ctx
14901493

14911494
/** The context to use when mapping or accumulating over a tree */
14921495
def localCtx(tree: Tree)(using Context): Context
@@ -1557,7 +1560,7 @@ object Trees {
15571560
case SeqLiteral(elems, elemtpt) =>
15581561
cpy.SeqLiteral(tree)(transform(elems), transform(elemtpt))
15591562
case tree @ Inlined(call, bindings, expansion) =>
1560-
cpy.Inlined(tree)(call, transformSub(bindings), transform(expansion)(using inlineContext(call)))
1563+
cpy.Inlined(tree)(call, transformSub(bindings), transform(expansion)(using inlineContext(tree)))
15611564
case TypeTree() =>
15621565
tree
15631566
case SingletonTypeTree(ref) =>
@@ -1700,8 +1703,8 @@ object Trees {
17001703
this(this(this(x, block), handler), finalizer)
17011704
case SeqLiteral(elems, elemtpt) =>
17021705
this(this(x, elems), elemtpt)
1703-
case Inlined(call, bindings, expansion) =>
1704-
this(this(x, bindings), expansion)(using inlineContext(call))
1706+
case tree @ Inlined(call, bindings, expansion) =>
1707+
this(this(x, bindings), expansion)(using inlineContext(tree))
17051708
case TypeTree() =>
17061709
x
17071710
case SingletonTypeTree(ref) =>

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1392,17 +1392,17 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
13921392
* EmptyTree calls (for parameters) cancel the next-enclosing call in the list instead of being added to it.
13931393
* We assume parameters are never nested inside parameters.
13941394
*/
1395-
override def inlineContext(call: Tree)(using Context): Context = {
1395+
override def inlineContext(tree: Inlined)(using Context): Context = {
13961396
// We assume enclosingInlineds is already normalized, and only process the new call with the head.
13971397
val oldIC = enclosingInlineds
13981398

13991399
val newIC =
1400-
if call.isEmpty then
1400+
if tree.inlinedFromOuterScope then
14011401
oldIC match
14021402
case t1 :: ts2 => ts2
14031403
case _ => oldIC
14041404
else
1405-
call :: oldIC
1405+
tree.call :: oldIC
14061406

14071407
val ctx1 = ctx.fresh.setProperty(InlinedCalls, newIC)
14081408
if oldIC.isEmpty then ctx1.setProperty(InlinedTrees, new Counter) else ctx1

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ import config.Feature
1515
private val Captures: Key[CaptureSet] = Key()
1616
private val BoxedType: Key[BoxedTypeCache] = Key()
1717

18+
/** Switch whether unpickled function types and byname types should be mapped to
19+
* impure types. With the new gradual typing using Fluid capture sets, this should
20+
* be no longer needed. Also, it has bad interactions with pickling tests.
21+
*/
22+
private val adaptUnpickledFunctionTypes = false
23+
1824
/** The arguments of a @retains or @retainsByName annotation */
1925
private[cc] def retainedElems(tree: Tree)(using Context): List[Tree] = tree match
2026
case Apply(_, Typed(SeqLiteral(elems, _), _) :: Nil) => elems
@@ -49,7 +55,7 @@ extension (tree: Tree)
4955
* a by name parameter type, turning the latter into an impure by name parameter type.
5056
*/
5157
def adaptByNameArgUnderPureFuns(using Context): Tree =
52-
if Feature.pureFunsEnabledSomewhere then
58+
if adaptUnpickledFunctionTypes && Feature.pureFunsEnabledSomewhere then
5359
val rbn = defn.RetainsByNameAnnot
5460
Annotated(tree,
5561
New(rbn.typeRef).select(rbn.primaryConstructor).appliedTo(
@@ -145,7 +151,7 @@ extension (tp: Type)
145151
*/
146152
def adaptFunctionTypeUnderPureFuns(using Context): Type = tp match
147153
case AppliedType(fn, args)
148-
if Feature.pureFunsEnabledSomewhere && defn.isFunctionClass(fn.typeSymbol) =>
154+
if adaptUnpickledFunctionTypes && Feature.pureFunsEnabledSomewhere && defn.isFunctionClass(fn.typeSymbol) =>
149155
val fname = fn.typeSymbol.name
150156
defn.FunctionType(
151157
fname.functionArity,

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,20 @@ object CaptureSet:
356356
override def toString = elems.toString
357357
end Const
358358

359+
/** A special capture set that gets added to the types of symbols that were not
360+
* themselves capture checked, in order to admit arbitrary corresponding capture
361+
* sets in subcapturing comparisons. Similar to platform types for explicit
362+
* nulls, this provides more lenient checking against compilation units that
363+
* were not yet compiled with capture checking on.
364+
*/
365+
object Fluid extends Const(emptySet):
366+
override def isAlwaysEmpty = false
367+
override def addNewElems(elems: Refs, origin: CaptureSet)(using Context, VarState) = CompareResult.OK
368+
override def accountsFor(x: CaptureRef)(using Context): Boolean = true
369+
override def mightAccountFor(x: CaptureRef)(using Context): Boolean = true
370+
override def toString = "<fluid>"
371+
end Fluid
372+
359373
/** The subclass of captureset variables with given initial elements */
360374
class Var(initialElems: Refs = emptySet) extends CaptureSet:
361375

@@ -863,7 +877,7 @@ object CaptureSet:
863877
case CapturingType(parent, refs) =>
864878
recur(parent) ++ refs
865879
case tpd @ RefinedType(parent, _, rinfo: MethodType)
866-
if followResult && defn.isFunctionType(tpd) =>
880+
if followResult && defn.isFunctionNType(tpd) =>
867881
ofType(parent, followResult = false) // pick up capture set from parent type
868882
++ (recur(rinfo.resType) // add capture set of result
869883
-- CaptureSet(rinfo.paramRefs.filter(_.isTracked)*)) // but disregard bound parameters

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

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -290,14 +290,46 @@ class CheckCaptures extends Recheck, SymTransformer:
290290
def includeCallCaptures(sym: Symbol, pos: SrcPos)(using Context): Unit =
291291
if sym.exists && curEnv.isOpen then markFree(capturedVars(sym), pos)
292292

293+
private def handleBackwardsCompat(tp: Type, sym: Symbol, initialVariance: Int = 1)(using Context): Type =
294+
val fluidify = new TypeMap with IdempotentCaptRefMap:
295+
variance = initialVariance
296+
def apply(t: Type): Type = t match
297+
case t: MethodType =>
298+
mapOver(t)
299+
case t: TypeLambda =>
300+
t.derivedLambdaType(resType = this(t.resType))
301+
case CapturingType(_, _) =>
302+
t
303+
case _ =>
304+
val t1 = t match
305+
case t @ RefinedType(parent, rname, rinfo: MethodType) if defn.isFunctionType(t) =>
306+
t.derivedRefinedType(parent, rname, this(rinfo))
307+
case _ =>
308+
mapOver(t)
309+
if variance > 0 then t1
310+
else Setup.decorate(t1, Function.const(CaptureSet.Fluid))
311+
312+
def isPreCC(sym: Symbol): Boolean =
313+
sym.isTerm && sym.maybeOwner.isClass
314+
&& !sym.owner.is(CaptureChecked)
315+
&& !defn.isFunctionSymbol(sym.owner)
316+
317+
if isPreCC(sym) then
318+
val tpw = tp.widen
319+
val fluidTp = fluidify(tpw)
320+
if fluidTp eq tpw then tp
321+
else fluidTp.showing(i"fluid for ${sym.showLocated}, ${sym.is(JavaDefined)}: $tp --> $result", capt)
322+
else tp
323+
end handleBackwardsCompat
324+
293325
override def recheckIdent(tree: Ident)(using Context): Type =
294326
if tree.symbol.is(Method) then
295327
if tree.symbol.info.isParameterless then
296328
// there won't be an apply; need to include call captures now
297329
includeCallCaptures(tree.symbol, tree.srcPos)
298330
else
299331
markFree(tree.symbol, tree.srcPos)
300-
super.recheckIdent(tree)
332+
handleBackwardsCompat(super.recheckIdent(tree), tree.symbol)
301333

302334
/** A specialized implementation of the selection rule.
303335
*
@@ -327,7 +359,7 @@ class CheckCaptures extends Recheck, SymTransformer:
327359
val selType = recheckSelection(tree, qualType, name, disambiguate)
328360
val selCs = selType.widen.captureSet
329361
if selCs.isAlwaysEmpty || selType.widen.isBoxedCapturing || qualType.isBoxedCapturing then
330-
selType
362+
handleBackwardsCompat(selType, tree.symbol)
331363
else
332364
val qualCs = qualType.captureSet
333365
capt.println(i"pick one of $qualType, ${selType.widen}, $qualCs, $selCs in $tree")
@@ -362,7 +394,16 @@ class CheckCaptures extends Recheck, SymTransformer:
362394
val argType0 = f(recheckStart(arg, pt))
363395
val argType = super.recheckFinish(argType0, arg, pt)
364396
super.recheckFinish(argType, tree, pt)
365-
if meth == defn.Caps_unsafeBox then
397+
398+
if meth == defn.Caps_unsafeAssumePure then
399+
val arg :: Nil = tree.args: @unchecked
400+
val argType0 = recheck(arg, pt.capturing(CaptureSet.universal))
401+
val argType =
402+
if argType0.captureSet.isAlwaysEmpty then argType0
403+
else argType0.widen.stripCapturing
404+
capt.println(i"rechecking $arg with ${pt.capturing(CaptureSet.universal)}: $argType")
405+
super.recheckFinish(argType, tree, pt)
406+
else if meth == defn.Caps_unsafeBox then
366407
mapArgUsing(_.forceBoxStatus(true))
367408
else if meth == defn.Caps_unsafeUnbox then
368409
mapArgUsing(_.forceBoxStatus(false))
@@ -662,8 +703,10 @@ class CheckCaptures extends Recheck, SymTransformer:
662703
/** Turn `expected` into a dependent function when `actual` is dependent. */
663704
private def alignDependentFunction(expected: Type, actual: Type)(using Context): Type =
664705
def recur(expected: Type): Type = expected.dealias match
665-
case expected @ CapturingType(eparent, refs) =>
666-
CapturingType(recur(eparent), refs, boxed = expected.isBoxed)
706+
case expected0 @ CapturingType(eparent, refs) =>
707+
val eparent1 = recur(eparent)
708+
if eparent1 eq eparent then expected
709+
else CapturingType(eparent1, refs, boxed = expected0.isBoxed)
667710
case expected @ defn.FunctionOf(args, resultType, isContextual)
668711
if defn.isNonRefinedFunction(expected) && defn.isFunctionNType(actual) && !defn.isNonRefinedFunction(actual) =>
669712
val expected1 = toDepFun(args, resultType, isContextual)
@@ -883,7 +926,7 @@ class CheckCaptures extends Recheck, SymTransformer:
883926
* But maybe we can then elide the check during the RefChecks phase under captureChecking?
884927
*/
885928
def checkOverrides = new TreeTraverser:
886-
class OverridingPairsCheckerCC(clazz: ClassSymbol, self: Type, srcPos: SrcPos)(using Context) extends OverridingPairsChecker(clazz, self) {
929+
class OverridingPairsCheckerCC(clazz: ClassSymbol, self: Type, srcPos: SrcPos)(using Context) extends OverridingPairsChecker(clazz, self):
887930
/** Check subtype with box adaptation.
888931
* This function is passed to RefChecks to check the compatibility of overriding pairs.
889932
* @param sym symbol of the field definition that is being checked
@@ -905,7 +948,11 @@ class CheckCaptures extends Recheck, SymTransformer:
905948
case _ => adapted
906949
finally curEnv = saved
907950
actual1 frozen_<:< expected1
908-
}
951+
952+
override def adjustInfo(tp: Type, member: Symbol)(using Context): Type =
953+
handleBackwardsCompat(tp, member, initialVariance = 0)
954+
//.showing(i"adjust $other: $tp --> $result")
955+
end OverridingPairsCheckerCC
909956

910957
def traverse(t: Tree)(using Context) =
911958
t match

0 commit comments

Comments
 (0)