Skip to content

Commit 964b9d7

Browse files
committed
Merge remote-tracking branch 'dotty/master' into wip_separate_parser_phase
2 parents a810991 + 9e8d5c5 commit 964b9d7

File tree

88 files changed

+912
-175
lines changed

Some content is hidden

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

88 files changed

+912
-175
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ final case class SbtCommunityProject(
140140
case Some(ivyHome) => List(s"-Dsbt.ivy.home=$ivyHome")
141141
case _ => Nil
142142
extraSbtArgs ++ sbtProps ++ List(
143-
"-sbt-version", "1.5.0",
143+
"-sbt-version", "1.5.5",
144144
"-Dsbt.supershell=false",
145145
s"-Ddotty.communitybuild.dir=$communitybuildDir",
146146
s"--addPluginSbtFile=$sbtPluginFilePath"

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

Lines changed: 88 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,30 +1063,109 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
10631063
}
10641064
}
10651065

1066+
/* Generate string concatenation
1067+
*
1068+
* On JDK 8: create and append using `StringBuilder`
1069+
* On JDK 9+: use `invokedynamic` with `StringConcatFactory`
1070+
*/
10661071
def genStringConcat(tree: Tree): BType = {
10671072
lineNumber(tree)
10681073
liftStringConcat(tree) match {
1069-
// Optimization for expressions of the form "" + x. We can avoid the StringBuilder.
1074+
// Optimization for expressions of the form "" + x
10701075
case List(Literal(Constant("")), arg) =>
10711076
genLoad(arg, ObjectReference)
10721077
genCallMethod(defn.String_valueOf_Object, InvokeStyle.Static)
10731078

10741079
case concatenations =>
1075-
bc.genStartConcat
1076-
for (elem <- concatenations) {
1077-
val loadedElem = elem match {
1080+
val concatArguments = concatenations.view
1081+
.filter {
1082+
case Literal(Constant("")) => false // empty strings are no-ops in concatenation
1083+
case _ => true
1084+
}
1085+
.map {
10781086
case Apply(boxOp, value :: Nil) if Erasure.Boxing.isBox(boxOp.symbol) && boxOp.symbol.denot.owner != defn.UnitModuleClass =>
10791087
// Eliminate boxing of primitive values. Boxing is introduced by erasure because
10801088
// there's only a single synthetic `+` method "added" to the string class.
10811089
value
1090+
case other => other
1091+
}
1092+
.toList
1093+
1094+
// `StringConcatFactory` only got added in JDK 9, so use `StringBuilder` for lower
1095+
if (classfileVersion < asm.Opcodes.V9) {
1096+
1097+
// Estimate capacity needed for the string builder
1098+
val approxBuilderSize = concatArguments.view.map {
1099+
case Literal(Constant(s: String)) => s.length
1100+
case Literal(c @ Constant(_)) if c.isNonUnitAnyVal => String.valueOf(c).length
1101+
case _ => 0
1102+
}.sum
1103+
bc.genNewStringBuilder(approxBuilderSize)
1104+
1105+
for (elem <- concatArguments) {
1106+
val elemType = tpeTK(elem)
1107+
genLoad(elem, elemType)
1108+
bc.genStringBuilderAppend(elemType)
1109+
}
1110+
bc.genStringBuilderEnd
1111+
} else {
1112+
1113+
/* `StringConcatFactory#makeConcatWithConstants` accepts max 200 argument slots. If
1114+
* the string concatenation is longer (unlikely), we spill into multiple calls
1115+
*/
1116+
val MaxIndySlots = 200
1117+
val TagArg = '\u0001' // indicates a hole (in the recipe string) for an argument
1118+
val TagConst = '\u0002' // indicates a hole (in the recipe string) for a constant
1119+
1120+
val recipe = new StringBuilder()
1121+
val argTypes = Seq.newBuilder[asm.Type]
1122+
val constVals = Seq.newBuilder[String]
1123+
var totalArgSlots = 0
1124+
var countConcats = 1 // ie. 1 + how many times we spilled
1125+
1126+
for (elem <- concatArguments) {
1127+
val tpe = tpeTK(elem)
1128+
val elemSlots = tpe.size
1129+
1130+
// Unlikely spill case
1131+
if (totalArgSlots + elemSlots >= MaxIndySlots) {
1132+
bc.genIndyStringConcat(recipe.toString, argTypes.result(), constVals.result())
1133+
countConcats += 1
1134+
totalArgSlots = 0
1135+
recipe.setLength(0)
1136+
argTypes.clear()
1137+
constVals.clear()
1138+
}
10821139

1083-
case _ => elem
1140+
elem match {
1141+
case Literal(Constant(s: String)) =>
1142+
if (s.contains(TagArg) || s.contains(TagConst)) {
1143+
totalArgSlots += elemSlots
1144+
recipe.append(TagConst)
1145+
constVals += s
1146+
} else {
1147+
recipe.append(s)
1148+
}
1149+
1150+
case other =>
1151+
totalArgSlots += elemSlots
1152+
recipe.append(TagArg)
1153+
val tpe = tpeTK(elem)
1154+
argTypes += tpe.toASMType
1155+
genLoad(elem, tpe)
1156+
}
1157+
}
1158+
bc.genIndyStringConcat(recipe.toString, argTypes.result(), constVals.result())
1159+
1160+
// If we spilled, generate one final concat
1161+
if (countConcats > 1) {
1162+
bc.genIndyStringConcat(
1163+
TagArg.toString * countConcats,
1164+
Seq.fill(countConcats)(StringRef.toASMType),
1165+
Seq.empty
1166+
)
10841167
}
1085-
val elemType = tpeTK(loadedElem)
1086-
genLoad(loadedElem, elemType)
1087-
bc.genConcat(elemType)
10881168
}
1089-
bc.genEndConcat
10901169
}
10911170
StringRef
10921171
}

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

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -224,24 +224,27 @@ trait BCodeIdiomatic {
224224

225225
} // end of method genPrimitiveShift()
226226

227-
/*
227+
/* Creates a new `StringBuilder` instance with the requested capacity
228+
*
228229
* can-multi-thread
229230
*/
230-
final def genStartConcat: Unit = {
231+
final def genNewStringBuilder(size: Int): Unit = {
231232
jmethod.visitTypeInsn(Opcodes.NEW, JavaStringBuilderClassName)
232233
jmethod.visitInsn(Opcodes.DUP)
234+
jmethod.visitLdcInsn(Integer.valueOf(size))
233235
invokespecial(
234236
JavaStringBuilderClassName,
235237
INSTANCE_CONSTRUCTOR_NAME,
236-
"()V",
238+
"(I)V",
237239
itf = false
238240
)
239241
}
240242

241-
/*
243+
/* Issue a call to `StringBuilder#append` for the right element type
244+
*
242245
* can-multi-thread
243246
*/
244-
def genConcat(elemType: BType): Unit = {
247+
final def genStringBuilderAppend(elemType: BType): Unit = {
245248
val paramType = elemType match {
246249
case ct: ClassBType if ct.isSubtypeOf(StringRef) => StringRef
247250
case ct: ClassBType if ct.isSubtypeOf(jlStringBufferRef) => jlStringBufferRef
@@ -257,13 +260,38 @@ trait BCodeIdiomatic {
257260
invokevirtual(JavaStringBuilderClassName, "append", bt.descriptor)
258261
}
259262

260-
/*
263+
/* Extract the built `String` from the `StringBuilder`
264+
*
261265
* can-multi-thread
262266
*/
263-
final def genEndConcat: Unit = {
267+
final def genStringBuilderEnd: Unit = {
264268
invokevirtual(JavaStringBuilderClassName, "toString", "()Ljava/lang/String;")
265269
}
266270

271+
/* Concatenate top N arguments on the stack with `StringConcatFactory#makeConcatWithConstants`
272+
* (only works for JDK 9+)
273+
*
274+
* can-multi-thread
275+
*/
276+
final def genIndyStringConcat(
277+
recipe: String,
278+
argTypes: Seq[asm.Type],
279+
constants: Seq[String]
280+
): Unit = {
281+
jmethod.visitInvokeDynamicInsn(
282+
"makeConcatWithConstants",
283+
asm.Type.getMethodDescriptor(StringRef.toASMType, argTypes:_*),
284+
new asm.Handle(
285+
asm.Opcodes.H_INVOKESTATIC,
286+
"java/lang/invoke/StringConcatFactory",
287+
"makeConcatWithConstants",
288+
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;",
289+
false
290+
),
291+
(recipe +: constants):_*
292+
)
293+
}
294+
267295
/*
268296
* Emits one or more conversion instructions based on the types given as arguments.
269297
*

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,19 @@ class Compiler {
6666
new CheckStatic, // Check restrictions that apply to @static members
6767
new BetaReduce, // Reduce closure applications
6868
new InlineVals, // Check right hand-sides of an `inline val`s
69-
new ExpandSAMs, // Expand single abstract method closures to anonymous classes
70-
new init.Checker) :: // Check initialization of objects
69+
new ExpandSAMs) :: // Expand single abstract method closures to anonymous classes
70+
List(new init.Checker) :: // Check initialization of objects
7171
List(new ElimRepeated, // Rewrite vararg parameters and arguments
7272
new ProtectedAccessors, // Add accessors for protected members
7373
new ExtensionMethods, // Expand methods of value classes with extension methods
7474
new UncacheGivenAliases, // Avoid caching RHS of simple parameterless given aliases
7575
new ByNameClosures, // Expand arguments to by-name parameters to closures
7676
new HoistSuperArgs, // Hoist complex arguments of supercalls to enclosing scope
7777
new SpecializeApplyMethods, // Adds specialized methods to FunctionN
78-
new RefChecks) :: // Various checks mostly related to abstract members and overriding
79-
List(new ElimOpaque, // Turn opaque into normal aliases
78+
new RefChecks, // Various checks mostly related to abstract members and overriding
8079
new TryCatchPatterns, // Compile cases in try/catch
81-
new PatternMatcher, // Compile pattern matches
80+
new PatternMatcher) :: // Compile pattern matches
81+
List(new ElimOpaque, // Turn opaque into normal aliases
8282
new sjs.ExplicitJSClasses, // Make all JS classes explicit (Scala.js only)
8383
new ExplicitOuter, // Add accessors to outer classes from nested ones.
8484
new ExplicitSelf, // Make references to non-trivial self types explicit as casts

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ package dotty.tools
22
package dotc
33
package config
44

5-
import java.security.AccessControlException
6-
75
/** For placing a wrapper function around property functions.
86
* Motivated by places like google app engine throwing exceptions
97
* on property lookups.
@@ -29,6 +27,14 @@ trait WrappedProperties extends PropertiesTrait {
2927

3028
object WrappedProperties {
3129
object AccessControl extends WrappedProperties {
32-
def wrap[T](body: => T): Option[T] = try Some(body) catch { case _: AccessControlException => None }
30+
def wrap[T](body: => T): Option[T] =
31+
try Some(body)
32+
catch {
33+
// the actual exception we are concerned with is AccessControlException,
34+
// but that's deprecated on JDK 17, so catching its superclass is a convenient
35+
// way to avoid a deprecation warning
36+
case _: SecurityException =>
37+
None
38+
}
3339
}
3440
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ object Phases {
295295
/** If set, implicit search is enabled */
296296
def allowsImplicitSearch: Boolean = false
297297

298-
/** List of names of phases that should precede this phase */
298+
/** List of names of phases that should precede this phase */
299299
def runsAfter: Set[String] = Set.empty
300300

301301
/** @pre `isRunnable` returns true */

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ object SymDenotations {
407407
* @param tparams The type parameters with which the right-hand side bounds should be abstracted
408408
*
409409
*/
410-
def opaqueToBounds(info: Type, rhs: tpd.Tree, tparams: List[TypeParamInfo])(using Context): Type =
410+
def opaqueToBounds(info: Type, rhs: tpd.Tree, tparams: List[TypeSymbol])(using Context): Type =
411411

412412
def setAlias(tp: Type) =
413413
def recur(self: Type): Unit = self match

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4039,7 +4039,7 @@ object Types {
40394039
// ----- Type application: LambdaParam, AppliedType ---------------------
40404040

40414041
/** The parameter of a type lambda */
4042-
case class LambdaParam(tl: TypeLambda, n: Int) extends ParamInfo {
4042+
case class LambdaParam(tl: TypeLambda, n: Int) extends ParamInfo, printing.Showable {
40434043
type ThisName = TypeName
40444044

40454045
def isTypeParam(using Context): Boolean = tl.paramNames.head.isTypeName
@@ -4084,6 +4084,8 @@ object Types {
40844084
case _ =>
40854085
myVariance = Invariant
40864086
myVariance
4087+
4088+
def toText(printer: Printer): Text = printer.toText(this)
40874089
}
40884090

40894091
/** A type application `C[T_1, ..., T_n]` */

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

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -860,14 +860,24 @@ class TreeUnpickler(reader: TastyReader,
860860
sym.info = TypeBounds.empty // needed to avoid cyclic references when unpickling rhs, see i3816.scala
861861
sym.setFlag(Provisional)
862862
val rhs = readTpt()(using localCtx)
863-
sym.info = new NoCompleter {
863+
864+
sym.info = new NoCompleter:
864865
override def completerTypeParams(sym: Symbol)(using Context) =
865866
rhs.tpe.typeParams
866-
}
867-
sym.info = sym.opaqueToBounds(
868-
checkNonCyclic(sym, rhs.tpe.toBounds, reportErrors = false),
869-
rhs, rhs.tpe.typeParams)
870-
if sym.isOpaqueAlias then sym.typeRef.recomputeDenot() // make sure we see the new bounds from now on
867+
868+
def opaqueToBounds(info: Type): Type =
869+
val tparamSyms = rhs match
870+
case LambdaTypeTree(tparams, body) => tparams.map(_.symbol.asType)
871+
case _ => Nil
872+
sym.opaqueToBounds(info, rhs, tparamSyms)
873+
874+
val info = checkNonCyclic(sym, rhs.tpe.toBounds, reportErrors = false)
875+
if sym.isOpaqueAlias then
876+
sym.info = opaqueToBounds(info)
877+
sym.typeRef.recomputeDenot() // make sure we see the new bounds from now on
878+
else
879+
sym.info = info
880+
871881
sym.resetFlag(Provisional)
872882
TypeDef(rhs)
873883
}
@@ -1399,7 +1409,7 @@ class TreeUnpickler(reader: TastyReader,
13991409
if (path.nonEmpty) {
14001410
val sourceFile = ctx.getSource(path)
14011411
posUnpicklerOpt match
1402-
case Some(posUnpickler) =>
1412+
case Some(posUnpickler) if !sourceFile.initizlized =>
14031413
sourceFile.setLineIndicesFromLineSizes(posUnpickler.lineSizes)
14041414
case _ =>
14051415
pickling.println(i"source change at $addr: $path")

compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,12 @@ class PlainPrinter(_ctx: Context) extends Printer {
540540

541541
def toText(annot: Annotation): Text = s"@${annot.symbol.name}" // for now
542542

543+
def toText(param: LambdaParam): Text =
544+
varianceSign(param.paramVariance)
545+
~ toText(param.paramName)
546+
~ (if param.isTypeParam then "" else ": ")
547+
~ toText(param.paramInfo)
548+
543549
protected def escapedString(str: String): String = str flatMap escapedChar
544550

545551
def dclsText(syms: List[Symbol], sep: String): Text = Text(syms map dclText, sep)

compiler/src/dotty/tools/dotc/printing/Printer.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ package printing
44

55
import core._
66
import Texts._, ast.Trees._
7-
import Types.{Type, SingletonType}, Symbols.Symbol, Scopes.Scope, Constants.Constant,
7+
import Types.{Type, SingletonType, LambdaParam},
8+
Symbols.Symbol, Scopes.Scope, Constants.Constant,
89
Names.Name, Denotations._, Annotations.Annotation
910
import typer.Implicits.SearchResult
1011
import util.SourcePosition
@@ -130,6 +131,9 @@ abstract class Printer {
130131
/** Textual representation of type */
131132
def toText(tp: Type): Text
132133

134+
/** Textual representation of lambda param */
135+
def toText(tree: LambdaParam): Text
136+
133137
/** Textual representation of all symbols in given list,
134138
* using `dclText` for displaying each.
135139
*/

compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,8 @@ class ExplicitOuter extends MiniPhase with InfoTransformer { thisPhase =>
4040

4141
override def phaseName: String = ExplicitOuter.name
4242

43-
/** List of names of phases that should have finished their processing of all compilation units
44-
* before this phase starts
45-
*/
46-
override def runsAfter: Set[String] = Set(PatternMatcher.name, HoistSuperArgs.name)
43+
override def runsAfter: Set[String] = Set(HoistSuperArgs.name)
44+
override def runsAfterGroupsOf: Set[String] = Set(PatternMatcher.name)
4745

4846
override def changesMembers: Boolean = true // the phase adds outer accessors
4947

0 commit comments

Comments
 (0)