Skip to content

Commit ac390f3

Browse files
author
gorilskij
committed
Merge remote-tracking branch 'origin/main'
2 parents 11a3f9f + 3f5c7cf commit ac390f3

File tree

69 files changed

+2419
-1420
lines changed

Some content is hidden

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

69 files changed

+2419
-1420
lines changed

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

Lines changed: 156 additions & 98 deletions
Large diffs are not rendered by default.

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

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,18 @@ trait BCodeSkelBuilder extends BCodeHelpers {
4040

4141
lazy val NativeAttr: Symbol = requiredClass[scala.native]
4242

43+
/** The destination of a value generated by `genLoadTo`. */
44+
enum LoadDestination:
45+
/** The value is put on the stack, and control flows through to the next opcode. */
46+
case FallThrough
47+
/** The value is put on the stack, and control flow is transferred to the given `label`. */
48+
case Jump(label: asm.Label)
49+
/** The value is RETURN'ed from the enclosing method. */
50+
case Return
51+
/** The value is ATHROW'n. */
52+
case Throw
53+
end LoadDestination
54+
4355
/*
4456
* There's a dedicated PlainClassBuilder for each CompilationUnit,
4557
* which simplifies the initialization of per-class data structures in `genPlainClass()` which in turn delegates to `initJClass()`
@@ -379,21 +391,21 @@ trait BCodeSkelBuilder extends BCodeHelpers {
379391
/* ---------------- Part 1 of program points, ie Labels in the ASM world ---------------- */
380392

381393
/*
382-
* A jump is represented as an Apply node whose symbol denotes a LabelDef, the target of the jump.
383-
* The `jumpDest` map is used to:
384-
* (a) find the asm.Label for the target, given an Apply node's symbol;
385-
* (b) anchor an asm.Label in the instruction stream, given a LabelDef node.
386-
* In other words, (a) is necessary when visiting a jump-source, and (b) when visiting a jump-target.
387-
* A related map is `labelDef`: it has the same keys as `jumpDest` but its values are LabelDef nodes not asm.Labels.
388-
*
394+
* A jump is represented as a Return node whose `from` symbol denotes a Labeled's Bind node, the target of the jump.
395+
* The `jumpDest` map is used to find the `LoadDestination` at the end of the `Labeled` block, as well as the
396+
* corresponding expected type. The `LoadDestination` can never be `FallThrough` here.
389397
*/
390-
var jumpDest: immutable.Map[ /* Labeled or LabelDef */ Symbol, asm.Label ] = null
391-
def programPoint(labelSym: Symbol): asm.Label = {
398+
var jumpDest: immutable.Map[ /* Labeled */ Symbol, (BType, LoadDestination) ] = null
399+
def registerJumpDest(labelSym: Symbol, expectedType: BType, dest: LoadDestination): Unit = {
400+
assert(labelSym.is(Label), s"trying to register a jump-dest for a non-label symbol, at: ${labelSym.span}")
401+
assert(dest != LoadDestination.FallThrough, s"trying to register a FallThrough dest for label, at: ${labelSym.span}")
402+
assert(!jumpDest.contains(labelSym), s"trying to register a second jump-dest for label, at: ${labelSym.span}")
403+
jumpDest += (labelSym -> (expectedType, dest))
404+
}
405+
def findJumpDest(labelSym: Symbol): (BType, LoadDestination) = {
392406
assert(labelSym.is(Label), s"trying to map a non-label symbol to an asm.Label, at: ${labelSym.span}")
393407
jumpDest.getOrElse(labelSym, {
394-
val pp = new asm.Label
395-
jumpDest += (labelSym -> pp)
396-
pp
408+
abort(s"unknown label symbol, for label at: ${labelSym.span}")
397409
})
398410
}
399411

@@ -566,7 +578,7 @@ trait BCodeSkelBuilder extends BCodeHelpers {
566578
def resetMethodBookkeeping(dd: DefDef) = {
567579
val rhs = dd.rhs
568580
locals.reset(isStaticMethod = methSymbol.isStaticMember)
569-
jumpDest = immutable.Map.empty[ /* LabelDef */ Symbol, asm.Label ]
581+
jumpDest = immutable.Map.empty
570582

571583
// check previous invocation of genDefDef exited as many varsInScope as it entered.
572584
assert(varsInScope == null, "Unbalanced entering/exiting of GenBCode's genBlock().")
@@ -799,20 +811,16 @@ trait BCodeSkelBuilder extends BCodeHelpers {
799811

800812
def emitNormalMethodBody(): Unit = {
801813
val veryFirstProgramPoint = currProgramPoint()
802-
genLoad(trimmedRhs, returnType)
803-
804-
trimmedRhs match {
805-
case (_: Return) | Block(_, (_: Return)) => ()
806-
case (_: Apply) | Block(_, (_: Apply)) if trimmedRhs.symbol eq defn.throwMethod => ()
807-
case tpd.EmptyTree =>
808-
report.error("Concrete method has no definition: " + dd + (
809-
if (ctx.settings.Ydebug.value) "(found: " + methSymbol.owner.info.decls.toList.mkString(", ") + ")"
810-
else ""),
811-
ctx.source.atSpan(NoSpan)
812-
)
813-
case _ =>
814-
bc emitRETURN returnType
815-
}
814+
815+
if trimmedRhs == tpd.EmptyTree then
816+
report.error("Concrete method has no definition: " + dd + (
817+
if (ctx.settings.Ydebug.value) "(found: " + methSymbol.owner.info.decls.toList.mkString(", ") + ")"
818+
else ""),
819+
ctx.source.atSpan(NoSpan)
820+
)
821+
else
822+
genLoadTo(trimmedRhs, returnType, LoadDestination.Return)
823+
816824
if (emitVars) {
817825
// add entries to LocalVariableTable JVM attribute
818826
val onePastLastProgramPoint = currProgramPoint()
@@ -905,7 +913,7 @@ trait BCodeSkelBuilder extends BCodeHelpers {
905913
}
906914
}
907915

908-
def genLoad(tree: Tree, expectedType: BType): Unit
916+
def genLoadTo(tree: Tree, expectedType: BType, dest: LoadDestination): Unit
909917

910918
} // end of class PlainSkelBuilder
911919

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ trait BCodeSyncAndTry extends BCodeBodyBuilder {
397397

398398
/* `tmp` (if non-null) is the symbol of the local-var used to preserve the result of the try-body, see `guardResult` */
399399
def emitFinalizer(finalizer: Tree, tmp: Symbol, isDuplicate: Boolean): Unit = {
400-
var saved: immutable.Map[ /* LabelDef */ Symbol, asm.Label ] = null
400+
var saved: immutable.Map[ /* Labeled */ Symbol, (BType, LoadDestination) ] = null
401401
if (isDuplicate) {
402402
saved = jumpDest
403403
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class GenBCode extends Phase {
6161

6262
private var myPrimitives: DottyPrimitives = null
6363

64-
def run(using Context): Unit =
64+
override def run(using Context): Unit =
6565
if myPrimitives == null then myPrimitives = new DottyPrimitives(ctx)
6666
new GenBCodePipeline(
6767
DottyBackendInterface(outputDir, superCallsMap),

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import Denotations.Denotation
1111
import typer.Typer
1212
import typer.ImportInfo.withRootImports
1313
import Decorators._
14-
import io.{AbstractFile, VirtualFile}
14+
import io.AbstractFile
1515
import Phases.unfusedPhases
1616

1717
import util._

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

Lines changed: 52 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,16 @@ object desugar {
393393
vparam.withMods(mods & (GivenOrImplicit | Erased | hasDefault) | Param)
394394
}
395395

396+
def mkApply(fn: Tree, paramss: List[ParamClause])(using Context): Tree =
397+
paramss.foldLeft(fn) { (fn, params) => params match
398+
case TypeDefs(params) =>
399+
TypeApply(fn, params.map(refOfDef))
400+
case (vparam: ValDef) :: _ if vparam.mods.is(Given) =>
401+
Apply(fn, params.map(refOfDef)).setApplyKind(ApplyKind.Using)
402+
case _ =>
403+
Apply(fn, params.map(refOfDef))
404+
}
405+
396406
/** The expansion of a class definition. See inline comments for what is involved */
397407
def classDef(cdef: TypeDef)(using Context): Tree = {
398408
val impl @ Template(constr0, _, self, _) = cdef.rhs
@@ -588,7 +598,7 @@ object desugar {
588598
}
589599

590600
// new C[Ts](paramss)
591-
lazy val creatorExpr = {
601+
lazy val creatorExpr =
592602
val vparamss = constrVparamss match
593603
case (vparam :: _) :: _ if vparam.mods.is(Implicit) => // add a leading () to match class parameters
594604
Nil :: constrVparamss
@@ -607,7 +617,6 @@ object desugar {
607617
}
608618
}
609619
ensureApplied(nu)
610-
}
611620

612621
val copiedAccessFlags = if migrateTo3 then EmptyFlags else AccessFlags
613622

@@ -892,48 +901,50 @@ object desugar {
892901
}
893902
}
894903

904+
def extMethod(mdef: DefDef, extParamss: List[ParamClause])(using Context): DefDef =
905+
cpy.DefDef(mdef)(
906+
name = normalizeName(mdef, mdef.tpt).asTermName,
907+
paramss =
908+
if mdef.name.isRightAssocOperatorName then
909+
val (typaramss, paramss) = mdef.paramss.span(isTypeParamClause) // first extract type parameters
910+
911+
paramss match
912+
case params :: paramss1 => // `params` must have a single parameter and without `given` flag
913+
914+
def badRightAssoc(problem: String) =
915+
report.error(i"right-associative extension method $problem", mdef.srcPos)
916+
extParamss ++ mdef.paramss
917+
918+
params match
919+
case ValDefs(vparam :: Nil) =>
920+
if !vparam.mods.is(Given) then
921+
// we merge the extension parameters with the method parameters,
922+
// swapping the operator arguments:
923+
// e.g.
924+
// extension [A](using B)(c: C)(using D)
925+
// def %:[E](f: F)(g: G)(using H): Res = ???
926+
// will be encoded as
927+
// def %:[A](using B)[E](f: F)(c: C)(using D)(g: G)(using H): Res = ???
928+
val (leadingUsing, otherExtParamss) = extParamss.span(isUsingOrTypeParamClause)
929+
leadingUsing ::: typaramss ::: params :: otherExtParamss ::: paramss1
930+
else
931+
badRightAssoc("cannot start with using clause")
932+
case _ =>
933+
badRightAssoc("must start with a single parameter")
934+
case _ =>
935+
// no value parameters, so not an infix operator.
936+
extParamss ++ mdef.paramss
937+
else
938+
extParamss ++ mdef.paramss
939+
).withMods(mdef.mods | ExtensionMethod)
940+
895941
/** Transform extension construct to list of extension methods */
896942
def extMethods(ext: ExtMethods)(using Context): Tree = flatTree {
897-
for mdef <- ext.methods yield
898-
defDef(
899-
cpy.DefDef(mdef)(
900-
name = normalizeName(mdef, ext).asTermName,
901-
paramss =
902-
if mdef.name.isRightAssocOperatorName then
903-
val (typaramss, paramss) = mdef.paramss.span(isTypeParamClause) // first extract type parameters
904-
905-
paramss match
906-
case params :: paramss1 => // `params` must have a single parameter and without `given` flag
907-
908-
def badRightAssoc(problem: String) =
909-
report.error(i"right-associative extension method $problem", mdef.srcPos)
910-
ext.paramss ++ mdef.paramss
911-
912-
params match
913-
case ValDefs(vparam :: Nil) =>
914-
if !vparam.mods.is(Given) then
915-
// we merge the extension parameters with the method parameters,
916-
// swapping the operator arguments:
917-
// e.g.
918-
// extension [A](using B)(c: C)(using D)
919-
// def %:[E](f: F)(g: G)(using H): Res = ???
920-
// will be encoded as
921-
// def %:[A](using B)[E](f: F)(c: C)(using D)(g: G)(using H): Res = ???
922-
val (leadingUsing, otherExtParamss) = ext.paramss.span(isUsingOrTypeParamClause)
923-
leadingUsing ::: typaramss ::: params :: otherExtParamss ::: paramss1
924-
else
925-
badRightAssoc("cannot start with using clause")
926-
case _ =>
927-
badRightAssoc("must start with a single parameter")
928-
case _ =>
929-
// no value parameters, so not an infix operator.
930-
ext.paramss ++ mdef.paramss
931-
else
932-
ext.paramss ++ mdef.paramss
933-
).withMods(mdef.mods | ExtensionMethod)
934-
)
943+
ext.methods map {
944+
case exp: Export => exp
945+
case mdef: DefDef => defDef(extMethod(mdef, ext.paramss))
946+
}
935947
}
936-
937948
/** Transforms
938949
*
939950
* <mods> type t >: Low <: Hi

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
117117
case class GenAlias(pat: Tree, expr: Tree)(implicit @constructorOnly src: SourceFile) extends Tree
118118
case class ContextBounds(bounds: TypeBoundsTree, cxBounds: List[Tree])(implicit @constructorOnly src: SourceFile) extends TypTree
119119
case class PatDef(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree)(implicit @constructorOnly src: SourceFile) extends DefTree
120-
case class ExtMethods(paramss: List[ParamClause], methods: List[DefDef])(implicit @constructorOnly src: SourceFile) extends Tree
120+
case class ExtMethods(paramss: List[ParamClause], methods: List[Tree])(implicit @constructorOnly src: SourceFile) extends Tree
121121
case class MacroTree(expr: Tree)(implicit @constructorOnly src: SourceFile) extends Tree
122122

123123
case class ImportSelector(imported: Ident, renamed: Tree = EmptyTree, bound: Tree = EmptyTree)(implicit @constructorOnly src: SourceFile) extends Tree {
@@ -640,7 +640,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
640640
case tree: PatDef if (mods eq tree.mods) && (pats eq tree.pats) && (tpt eq tree.tpt) && (rhs eq tree.rhs) => tree
641641
case _ => finalize(tree, untpd.PatDef(mods, pats, tpt, rhs)(tree.source))
642642
}
643-
def ExtMethods(tree: Tree)(paramss: List[ParamClause], methods: List[DefDef])(using Context): Tree = tree match
643+
def ExtMethods(tree: Tree)(paramss: List[ParamClause], methods: List[Tree])(using Context): Tree = tree match
644644
case tree: ExtMethods if (paramss eq tree.paramss) && (methods == tree.methods) => tree
645645
case _ => finalize(tree, untpd.ExtMethods(paramss, methods)(tree.source))
646646
def ImportSelector(tree: Tree)(imported: Ident, renamed: Tree, bound: Tree)(using Context): Tree = tree match {

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

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -81,16 +81,28 @@ trait ConstraintHandling {
8181
assert(homogenizeArgs == false)
8282
assert(comparedTypeLambdas == Set.empty)
8383

84-
def nestingLevel(param: TypeParamRef) = constraint.typeVarOfParam(param) match
84+
def nestingLevel(param: TypeParamRef)(using Context) = constraint.typeVarOfParam(param) match
8585
case tv: TypeVar => tv.nestingLevel
86-
case _ => Int.MaxValue
86+
case _ =>
87+
// This should only happen when reducing match types (in
88+
// TrackingTypeComparer#matchCases) or in uncommitable TyperStates (as
89+
// asserted in ProtoTypes.constrained) and is special-cased in `levelOK`
90+
// below.
91+
Int.MaxValue
92+
93+
/** Is `level` <= `maxLevel` or legal in the current context? */
94+
def levelOK(level: Int, maxLevel: Int)(using Context): Boolean =
95+
level <= maxLevel ||
96+
ctx.isAfterTyper || !ctx.typerState.isCommittable || // Leaks in these cases shouldn't break soundness
97+
level == Int.MaxValue // See `nestingLevel` above.
8798

8899
/** If `param` is nested deeper than `maxLevel`, try to instantiate it to a
89100
* fresh type variable of level `maxLevel` and return the new variable.
90101
* If this isn't possible, throw a TypeError.
91102
*/
92103
def atLevel(maxLevel: Int, param: TypeParamRef)(using Context): TypeParamRef =
93-
if nestingLevel(param) <= maxLevel then return param
104+
if levelOK(nestingLevel(param), maxLevel) then
105+
return param
94106
LevelAvoidMap(0, maxLevel)(param) match
95107
case freshVar: TypeVar => freshVar.origin
96108
case _ => throw new TypeError(
@@ -129,18 +141,12 @@ trait ConstraintHandling {
129141

130142
/** An approximating map that prevents types nested deeper than maxLevel as
131143
* well as WildcardTypes from leaking into the constraint.
132-
* Note that level-checking is turned off after typer and in uncommitable
133-
* TyperState since these leaks should be safe.
134144
*/
135145
class LevelAvoidMap(topLevelVariance: Int, maxLevel: Int)(using Context) extends TypeOps.AvoidMap:
136146
variance = topLevelVariance
137147

138-
/** Are we allowed to refer to types of the given `level`? */
139-
private def levelOK(level: Int): Boolean =
140-
level <= maxLevel || ctx.isAfterTyper || !ctx.typerState.isCommittable
141-
142148
def toAvoid(tp: NamedType): Boolean =
143-
tp.prefix == NoPrefix && !tp.symbol.isStatic && !levelOK(tp.symbol.nestingLevel)
149+
tp.prefix == NoPrefix && !tp.symbol.isStatic && !levelOK(tp.symbol.nestingLevel, maxLevel)
144150

145151
/** Return a (possibly fresh) type variable of a level no greater than `maxLevel` which is:
146152
* - lower-bounded by `tp` if variance >= 0
@@ -185,7 +191,7 @@ trait ConstraintHandling {
185191
end legalVar
186192

187193
override def apply(tp: Type): Type = tp match
188-
case tp: TypeVar if !tp.isInstantiated && !levelOK(tp.nestingLevel) =>
194+
case tp: TypeVar if !tp.isInstantiated && !levelOK(tp.nestingLevel, maxLevel) =>
189195
legalVar(tp)
190196
// TypeParamRef can occur in tl bounds
191197
case tp: TypeParamRef =>
@@ -431,7 +437,6 @@ trait ConstraintHandling {
431437
final def approximation(param: TypeParamRef, fromBelow: Boolean)(using Context): Type =
432438
constraint.entry(param) match
433439
case entry: TypeBounds =>
434-
val maxLevel = nestingLevel(param)
435440
val useLowerBound = fromBelow || param.occursIn(entry.hi)
436441
val inst = if useLowerBound then fullLowerBound(param) else fullUpperBound(param)
437442
typr.println(s"approx ${param.show}, from below = $fromBelow, inst = ${inst.show}")
@@ -627,11 +632,7 @@ trait ConstraintHandling {
627632
case x =>
628633
// Happens if param was already solved while processing earlier params of the same TypeLambda.
629634
// See #4720.
630-
631-
// Should propagate bounds even when param has been solved.
632-
// See #11682.
633-
lower.forall(addOneBound(_, x, isUpper = true)) &&
634-
upper.forall(addOneBound(_, x, isUpper = false))
635+
true
635636
}
636637
}
637638
}
@@ -677,6 +678,11 @@ trait ConstraintHandling {
677678
case t @ TypeParamRef(tl: TypeLambda, n) if comparedTypeLambdas contains tl =>
678679
val bounds = tl.paramInfos(n)
679680
range(bounds.lo, bounds.hi)
681+
case tl: TypeLambda =>
682+
val saved = comparedTypeLambdas
683+
comparedTypeLambdas -= tl
684+
try mapOver(tl)
685+
finally comparedTypeLambdas = saved
680686
case _ =>
681687
mapOver(t)
682688
}

0 commit comments

Comments
 (0)