Skip to content

Commit 99f58bb

Browse files
chore: LTS backports (#20855)
2 parents c8e5802 + f87f2cf commit 99f58bb

File tree

173 files changed

+4156
-1221
lines changed

Some content is hidden

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

173 files changed

+4156
-1221
lines changed

compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala

+5-1
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,9 @@ class JSCodeGen()(using genCtx: Context) {
793793
name.name
794794
}.toSet
795795

796+
val staticNames = moduleClass.companionClass.info.allMembers
797+
.collect { case d if d.name.isTermName && d.symbol.isScalaStatic => d.name }.toSet
798+
796799
val members = {
797800
moduleClass.info.membersBasedOnFlags(required = Flags.Method,
798801
excluded = Flags.ExcludedForwarder).map(_.symbol)
@@ -815,6 +818,7 @@ class JSCodeGen()(using genCtx: Context) {
815818
|| hasAccessBoundary
816819
|| isOfJLObject
817820
|| m.hasAnnotation(jsdefn.JSNativeAnnot) || isDefaultParamOfJSNativeDef // #4557
821+
|| staticNames(m.name)
818822
}
819823

820824
val forwarders = for {
@@ -4769,7 +4773,7 @@ class JSCodeGen()(using genCtx: Context) {
47694773
}
47704774

47714775
private def isMethodStaticInIR(sym: Symbol): Boolean =
4772-
sym.is(JavaStatic)
4776+
sym.is(JavaStatic) || sym.isScalaStatic
47734777

47744778
/** Generate a Class[_] value (e.g. coming from classOf[T]) */
47754779
private def genClassConstant(tpe: Type)(implicit pos: Position): js.Tree =

compiler/src/dotty/tools/dotc/Run.scala

+2
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,8 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
342342
runCtx.setProfiler(Profiler())
343343
unfusedPhases.foreach(_.initContext(runCtx))
344344
val fusedPhases = runCtx.base.allPhases
345+
if ctx.settings.explainCyclic.value then
346+
runCtx.setProperty(CyclicReference.Trace, new CyclicReference.Trace())
345347
runCtx.withProgressCallback: cb =>
346348
_progress = Progress(cb, this, fusedPhases.map(_.traversals).sum)
347349
runPhases(allPhases = fusedPhases)(using runCtx)

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

+2
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ trait CommonScalaSettings:
118118
// -explain-types setting is necessary for cross compilation, since it is mentioned in sbt-tpolecat, for instance
119119
// it is otherwise subsumed by -explain, and should be dropped as soon as we can.
120120
val explainTypes: Setting[Boolean] = BooleanSetting("-explain-types", "Explain type errors in more detail (deprecated, use -explain instead).", aliases = List("--explain-types", "-explaintypes"))
121+
val explainCyclic: Setting[Boolean] = BooleanSetting("-explain-cyclic", "Explain cyclic reference errors in more detail.", aliases = List("--explain-cyclic"))
121122
val unchecked: Setting[Boolean] = BooleanSetting("-unchecked", "Enable additional warnings where generated code depends on assumptions.", initialValue = true, aliases = List("--unchecked"))
122123
val language: Setting[List[String]] = MultiStringSetting("-language", "feature", "Enable one or more language features.", aliases = List("--language"))
123124

@@ -347,6 +348,7 @@ private sealed trait YSettings:
347348
val YdebugTypeError: Setting[Boolean] = BooleanSetting("-Ydebug-type-error", "Print the stack trace when a TypeError is caught", false)
348349
val YdebugError: Setting[Boolean] = BooleanSetting("-Ydebug-error", "Print the stack trace when any error is caught.", false)
349350
val YdebugUnpickling: Setting[Boolean] = BooleanSetting("-Ydebug-unpickling", "Print the stack trace when an error occurs when reading Tasty.", false)
351+
val YdebugCyclic: Setting[Boolean] = BooleanSetting("-Ydebug-cyclic", "Print the stack trace when a cyclic reference error occurs.", false)
350352
val YtermConflict: Setting[String] = ChoiceSetting("-Yresolve-term-conflict", "strategy", "Resolve term conflicts", List("package", "object", "error"), "error")
351353
val Ylog: Setting[List[String]] = PhasesSetting("-Ylog", "Log operations during")
352354
val YlogClasspath: Setting[Boolean] = BooleanSetting("-Ylog-classpath", "Output information about what classpath is being applied.")

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

+17-7
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,17 @@ object SymDenotations {
166166
println(i"${" " * indent}completed $name in $owner")
167167
}
168168
}
169-
else {
170-
if (myFlags.is(Touched))
171-
throw CyclicReference(this)(using ctx.withOwner(symbol))
172-
myFlags |= Touched
173-
atPhase(validFor.firstPhaseId)(completer.complete(this))
174-
}
169+
else
170+
val traceCycles = CyclicReference.isTraced
171+
try
172+
if traceCycles then
173+
CyclicReference.pushTrace("compute the signature of ", symbol, "")
174+
if myFlags.is(Touched) then
175+
throw CyclicReference(this)(using ctx.withOwner(symbol))
176+
myFlags |= Touched
177+
atPhase(validFor.firstPhaseId)(completer.complete(this))
178+
finally
179+
if traceCycles then CyclicReference.popTrace()
175180

176181
protected[dotc] def info_=(tp: Type): Unit = {
177182
/* // DEBUG
@@ -2965,7 +2970,10 @@ object SymDenotations {
29652970
def apply(clsd: ClassDenotation)(implicit onBehalf: BaseData, ctx: Context)
29662971
: (List[ClassSymbol], BaseClassSet) = {
29672972
assert(isValid)
2973+
val traceCycles = CyclicReference.isTraced
29682974
try
2975+
if traceCycles then
2976+
CyclicReference.pushTrace("compute the base classes of ", clsd.symbol, "")
29692977
if (cache != null) cache.uncheckedNN
29702978
else {
29712979
if (locked) throw CyclicReference(clsd)
@@ -2978,7 +2986,9 @@ object SymDenotations {
29782986
else onBehalf.signalProvisional()
29792987
computed
29802988
}
2981-
finally addDependent(onBehalf)
2989+
finally
2990+
if traceCycles then CyclicReference.popTrace()
2991+
addDependent(onBehalf)
29822992
}
29832993

29842994
def sameGroup(p1: Phase, p2: Phase) = p1.sameParentsStartId == p2.sameParentsStartId

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ object Symbols extends SymUtils {
129129
final def lastKnownDenotation: SymDenotation =
130130
lastDenot
131131

132-
private[core] def defRunId: RunId =
132+
private[dotc] def defRunId: RunId =
133133
lastDenot.validFor.runId
134134

135135
private inline def associatedFileMatches(inline filter: AbstractFile => Boolean)(using Context): Boolean =

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

+30-9
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ import Denotations.*
1212
import Decorators.*
1313
import reporting.*
1414
import ast.untpd
15+
import util.Property
1516
import config.Printers.{cyclicErrors, noPrinter}
17+
import collection.mutable
1618

1719
import scala.annotation.constructorOnly
1820

@@ -27,6 +29,7 @@ abstract class TypeError(using creationContext: Context) extends Exception(""):
2729
|| ctx.settings.YdebugTypeError.value
2830
|| ctx.settings.YdebugError.value
2931
|| ctx.settings.YdebugUnpickling.value
32+
|| ctx.settings.YdebugCyclic.value
3033

3134
override def fillInStackTrace(): Throwable =
3235
if computeStackTrace then super.fillInStackTrace().nn
@@ -72,8 +75,7 @@ extends TypeError:
7275
def explanation: String = s"$op $details"
7376

7477
private def recursions: List[RecursionOverflow] = {
75-
import scala.collection.mutable.ListBuffer
76-
val result = ListBuffer.empty[RecursionOverflow]
78+
val result = mutable.ListBuffer.empty[RecursionOverflow]
7779
@annotation.tailrec def loop(throwable: Throwable): List[RecursionOverflow] = throwable match {
7880
case ro: RecursionOverflow =>
7981
result += ro
@@ -135,7 +137,10 @@ end handleRecursive
135137
* so it requires knowing denot already.
136138
* @param denot
137139
*/
138-
class CyclicReference(val denot: SymDenotation)(using Context) extends TypeError:
140+
class CyclicReference(
141+
val denot: SymDenotation,
142+
val optTrace: Option[Array[CyclicReference.TraceElement]])(using Context)
143+
extends TypeError:
139144
var inImplicitSearch: Boolean = false
140145

141146
val cycleSym = denot.symbol
@@ -161,11 +166,11 @@ class CyclicReference(val denot: SymDenotation)(using Context) extends TypeError
161166
cx.tree match {
162167
case tree: untpd.ValOrDefDef if !tree.tpt.typeOpt.exists =>
163168
if (inImplicitSearch)
164-
TermMemberNeedsResultTypeForImplicitSearch(cycleSym)
169+
TermMemberNeedsResultTypeForImplicitSearch(this)
165170
else if (isMethod)
166-
OverloadedOrRecursiveMethodNeedsResultType(cycleSym)
171+
OverloadedOrRecursiveMethodNeedsResultType(this)
167172
else if (isVal)
168-
RecursiveValueNeedsResultType(cycleSym)
173+
RecursiveValueNeedsResultType(this)
169174
else
170175
errorMsg(cx.outer)
171176
case _ =>
@@ -174,22 +179,38 @@ class CyclicReference(val denot: SymDenotation)(using Context) extends TypeError
174179

175180
// Give up and give generic errors.
176181
else if (cycleSym.isOneOf(GivenOrImplicitVal, butNot = Method) && cycleSym.owner.isTerm)
177-
CyclicReferenceInvolvingImplicit(cycleSym)
182+
CyclicReferenceInvolvingImplicit(this)
178183
else
179-
CyclicReferenceInvolving(denot)
184+
CyclicReferenceInvolving(this)
180185

181186
errorMsg(ctx)
182187
end toMessage
183188

184189
object CyclicReference:
190+
185191
def apply(denot: SymDenotation)(using Context): CyclicReference =
186-
val ex = new CyclicReference(denot)
192+
val ex = new CyclicReference(denot, ctx.property(Trace).map(_.toArray))
187193
if ex.computeStackTrace then
188194
cyclicErrors.println(s"Cyclic reference involving! $denot")
189195
val sts = ex.getStackTrace.asInstanceOf[Array[StackTraceElement]]
190196
for (elem <- sts take 200)
191197
cyclicErrors.println(elem.toString)
192198
ex
199+
200+
type TraceElement = (/*prefix:*/ String, Symbol, /*suffix:*/ String)
201+
type Trace = mutable.ArrayBuffer[TraceElement]
202+
val Trace = Property.Key[Trace]
203+
204+
def isTraced(using Context) =
205+
ctx.property(CyclicReference.Trace).isDefined
206+
207+
def pushTrace(info: TraceElement)(using Context): Unit =
208+
for buf <- ctx.property(CyclicReference.Trace) do
209+
buf += info
210+
211+
def popTrace()(using Context): Unit =
212+
for buf <- ctx.property(CyclicReference.Trace) do
213+
buf.dropRightInPlace(1)
193214
end CyclicReference
194215

195216
class UnpicklingError(denot: Denotation, where: String, cause: Throwable)(using Context) extends TypeError:

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

+2
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,8 @@ object Types extends TypeUtils {
640640
tp.superType.baseClasses
641641
case tp: ClassInfo =>
642642
tp.cls.classDenot.baseClasses
643+
case tp: WildcardType =>
644+
tp.effectiveBounds.hi.baseClasses
643645
case _ => Nil
644646
catch case ex: Throwable =>
645647
handleRecursive("base classes of", this.show, ex)

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

+10-5
Original file line numberDiff line numberDiff line change
@@ -124,20 +124,25 @@ class TreeUnpickler(reader: TastyReader,
124124
val mode = ctx.mode
125125
val source = ctx.source
126126
def complete(denot: SymDenotation)(using Context): Unit =
127-
def fail(ex: Throwable) =
128-
def where =
129-
val f = denot.symbol.associatedFile
130-
if f == null then "" else s" in $f"
131-
throw UnpicklingError(denot, where, ex)
127+
def where =
128+
val f = denot.symbol.associatedFile
129+
if f == null then "" else s" in $f"
130+
def fail(ex: Throwable) = throw UnpicklingError(denot, where, ex)
132131
treeAtAddr(currentAddr) =
132+
val traceCycles = CyclicReference.isTraced
133133
try
134+
if traceCycles then
135+
CyclicReference.pushTrace("read the definition of ", denot.symbol, where)
134136
atPhaseBeforeTransforms {
135137
new TreeReader(reader).readIndexedDef()(
136138
using ctx.withOwner(owner).withModeBits(mode).withSource(source))
137139
}
138140
catch
141+
case ex: CyclicReference => throw ex
139142
case ex: AssertionError => fail(ex)
140143
case ex: Exception => fail(ex)
144+
finally
145+
if traceCycles then CyclicReference.popTrace()
141146
}
142147

143148
class TreeReader(val reader: TastyReader) {

compiler/src/dotty/tools/dotc/interactive/Completion.scala

+26-22
Original file line numberDiff line numberDiff line change
@@ -184,12 +184,12 @@ object Completion:
184184
val completions = adjustedPath match
185185
// Ignore synthetic select from `This` because in code it was `Ident`
186186
// See example in dotty.tools.languageserver.CompletionTest.syntheticThis
187-
case Select(qual @ This(_), _) :: _ if qual.span.isSynthetic => completer.scopeCompletions
188-
case Select(qual, _) :: _ if qual.tpe.hasSimpleKind => completer.selectionCompletions(qual)
189-
case Select(qual, _) :: _ => Map.empty
190-
case (tree: ImportOrExport) :: _ => completer.directMemberCompletions(tree.expr)
191-
case (_: untpd.ImportSelector) :: Import(expr, _) :: _ => completer.directMemberCompletions(expr)
192-
case _ => completer.scopeCompletions
187+
case Select(qual @ This(_), _) :: _ if qual.span.isSynthetic => completer.scopeCompletions
188+
case Select(qual, _) :: _ if qual.typeOpt.hasSimpleKind => completer.selectionCompletions(qual)
189+
case Select(qual, _) :: _ => Map.empty
190+
case (tree: ImportOrExport) :: _ => completer.directMemberCompletions(tree.expr)
191+
case (_: untpd.ImportSelector) :: Import(expr, _) :: _ => completer.directMemberCompletions(expr)
192+
case _ => completer.scopeCompletions
193193

194194
val describedCompletions = describeCompletions(completions)
195195
val backtickedCompletions =
@@ -348,7 +348,7 @@ object Completion:
348348
/** Widen only those types which are applied or are exactly nothing
349349
*/
350350
def widenQualifier(qual: Tree)(using Context): Tree =
351-
qual.tpe.widenDealias match
351+
qual.typeOpt.widenDealias match
352352
case widenedType if widenedType.isExactlyNothing => qual.withType(widenedType)
353353
case appliedType: AppliedType => qual.withType(appliedType)
354354
case _ => qual
@@ -368,10 +368,10 @@ object Completion:
368368
* These include inherited definitions but not members added by extensions or implicit conversions
369369
*/
370370
def directMemberCompletions(qual: Tree)(using Context): CompletionMap =
371-
if qual.tpe.isExactlyNothing then
371+
if qual.typeOpt.isExactlyNothing then
372372
Map.empty
373373
else
374-
accessibleMembers(qual.tpe).groupByName
374+
accessibleMembers(qual.typeOpt).groupByName
375375

376376
/** Completions introduced by imports directly in this context.
377377
* Completions from outer contexts are not included.
@@ -415,7 +415,7 @@ object Completion:
415415

416416
/** Completions from implicit conversions including old style extensions using implicit classes */
417417
private def implicitConversionMemberCompletions(qual: Tree)(using Context): CompletionMap =
418-
if qual.tpe.isExactlyNothing || qual.tpe.isNullType then
418+
if qual.typeOpt.isExactlyNothing || qual.typeOpt.isNullType then
419419
Map.empty
420420
else
421421
implicitConversionTargets(qual)(using ctx.fresh.setExploreTyperState())
@@ -432,7 +432,7 @@ object Completion:
432432
def tryApplyingReceiverToExtension(termRef: TermRef): Option[SingleDenotation] =
433433
ctx.typer.tryApplyingExtensionMethod(termRef, qual)
434434
.map { tree =>
435-
val tpe = asDefLikeType(tree.tpe.dealias)
435+
val tpe = asDefLikeType(tree.typeOpt.dealias)
436436
termRef.denot.asSingleDenotation.mapInfo(_ => tpe)
437437
}
438438

@@ -453,16 +453,16 @@ object Completion:
453453

454454
// 1. The extension method is visible under a simple name, by being defined or inherited or imported in a scope enclosing the reference.
455455
val termCompleter = new Completer(Mode.Term, prefix, pos)
456-
val extMethodsInScope = termCompleter.scopeCompletions.toList.flatMap {
457-
case (name, denots) => denots.collect { case d: SymDenotation if d.isTerm => (d.termRef, name.asTermName) }
458-
}
456+
val extMethodsInScope = termCompleter.scopeCompletions.toList.flatMap:
457+
case (name, denots) => denots.collect:
458+
case d: SymDenotation if d.isTerm && d.termRef.symbol.is(Extension) => (d.termRef, name.asTermName)
459459

460460
// 2. The extension method is a member of some given instance that is visible at the point of the reference.
461461
val givensInScope = ctx.implicits.eligible(defn.AnyType).map(_.implicitRef.underlyingRef)
462462
val extMethodsFromGivensInScope = extractMemberExtensionMethods(givensInScope)
463463

464464
// 3. The reference is of the form r.m and the extension method is defined in the implicit scope of the type of r.
465-
val implicitScopeCompanions = ctx.run.nn.implicitScope(qual.tpe).companionRefs.showAsList
465+
val implicitScopeCompanions = ctx.run.nn.implicitScope(qual.typeOpt).companionRefs.showAsList
466466
val extMethodsFromImplicitScope = extractMemberExtensionMethods(implicitScopeCompanions)
467467

468468
// 4. The reference is of the form r.m and the extension method is defined in some given instance in the implicit scope of the type of r.
@@ -472,7 +472,7 @@ object Completion:
472472
val availableExtMethods = extMethodsFromGivensInImplicitScope ++ extMethodsFromImplicitScope ++ extMethodsFromGivensInScope ++ extMethodsInScope
473473
val extMethodsWithAppliedReceiver = availableExtMethods.flatMap {
474474
case (termRef, termName) =>
475-
if termRef.symbol.is(ExtensionMethod) && !qual.tpe.isBottomType then
475+
if termRef.symbol.is(ExtensionMethod) && !qual.typeOpt.isBottomType then
476476
tryApplyingReceiverToExtension(termRef)
477477
.map(denot => termName -> denot)
478478
else None
@@ -551,21 +551,25 @@ object Completion:
551551
* @param qual The argument to which the implicit conversion should be applied.
552552
* @return The set of types after `qual` implicit conversion.
553553
*/
554-
private def implicitConversionTargets(qual: Tree)(using Context): Set[Type] = {
554+
private def implicitConversionTargets(qual: Tree)(using Context): Set[Type] =
555555
val typer = ctx.typer
556-
val conversions = new typer.ImplicitSearch(defn.AnyType, qual, pos.span).allImplicits
557-
val targets = conversions.map(_.tree.tpe)
556+
val targets = try {
557+
val conversions = new typer.ImplicitSearch(defn.AnyType, qual, pos.span).allImplicits
558+
conversions.map(_.tree.typeOpt)
559+
} catch {
560+
case _ =>
561+
interactiv.println(i"implicit conversion targets failed: ${qual.show}")
562+
Set.empty
563+
}
558564

559565
interactiv.println(i"implicit conversion targets considered: ${targets.toList}%, %")
560566
targets
561-
}
562567

563568
/** Filter for names that should appear when looking for completions. */
564-
private object completionsFilter extends NameFilter {
569+
private object completionsFilter extends NameFilter:
565570
def apply(pre: Type, name: Name)(using Context): Boolean =
566571
!name.isConstructorName && name.toTermName.info.kind == SimpleNameKind
567572
def isStable = true
568-
}
569573

570574
extension (denotations: Seq[SingleDenotation])
571575
def groupByName(using Context): CompletionMap = denotations.groupBy(_.name)

compiler/src/dotty/tools/dotc/interactive/Interactive.scala

+2-4
Original file line numberDiff line numberDiff line change
@@ -282,12 +282,10 @@ object Interactive {
282282
case nested :: encl :: rest =>
283283
val outer = contextOfPath(encl :: rest)
284284
try encl match {
285-
case tree @ PackageDef(pkg, stats) =>
286-
assert(tree.symbol.exists)
285+
case tree @ PackageDef(pkg, stats) if tree.symbol.exists =>
287286
if (nested `eq` pkg) outer
288287
else contextOfStat(stats, nested, pkg.symbol.moduleClass, outer.packageContext(tree, tree.symbol))
289-
case tree: DefDef =>
290-
assert(tree.symbol.exists)
288+
case tree: DefDef if tree.symbol.exists =>
291289
val localCtx = outer.localContext(tree, tree.symbol).setNewScope
292290
for params <- tree.paramss; param <- params do localCtx.enter(param.symbol)
293291
// Note: this overapproximates visibility a bit, since value parameters are only visible

compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ class InteractiveDriver(val settings: List[String]) extends Driver {
277277
if (t.symbol.exists && t.hasType) {
278278
if (!t.symbol.isCompleted) t.symbol.info = UnspecifiedErrorType
279279
t.symbol.annotations.foreach { annot =>
280-
/* In some cases annotations are are used on themself (possibly larger cycles).
280+
/* In some cases annotations are used on themself (possibly larger cycles).
281281
* This is the case with the java.lang.annotation.Target annotation, would end
282282
* in an infinite loop while cleaning. The `seen` is added to ensure that those
283283
* trees are not cleand twice.

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -3270,7 +3270,7 @@ object Parsers {
32703270
/** ContextTypes ::= FunArgType {‘,’ FunArgType}
32713271
*/
32723272
def contextTypes(paramOwner: ParamOwner, numLeadParams: Int, impliedMods: Modifiers): List[ValDef] =
3273-
val tps = commaSeparated(funArgType)
3273+
val tps = commaSeparated(() => paramTypeOf(toplevelTyp))
32743274
var counter = numLeadParams
32753275
def nextIdx = { counter += 1; counter }
32763276
val paramFlags = if paramOwner.isClass then LocalParamAccessor else Param

0 commit comments

Comments
 (0)