Skip to content

Commit d8e58ad

Browse files
authored
Merge pull request #420 from scala/backport-lts-3.3-23178
Backport "Avoid creating constructors where not warranted" to 3.3 LTS
2 parents 1e07f07 + ac34982 commit d8e58ad

File tree

6 files changed

+45
-31
lines changed

6 files changed

+45
-31
lines changed

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,12 @@ object Primitives {
150150
case object XOR extends LogicalOp
151151

152152
/** Signals the beginning of a series of concatenations.
153-
* On the JVM platform, it should create a new StringBuffer
154-
*/
153+
* On the JVM platform, it should create a new StringBuilder.
154+
*/
155155
case object StartConcat extends Primitive
156156

157-
/**
158-
* type: (buf) => STR
159-
* jvm : It should turn the StringBuffer into a String.
157+
/** type: (buf) => STR
158+
* jvm : It should turn the StringBuilder into a String.
160159
*/
161160
case object EndConcat extends Primitive
162161

compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -194,27 +194,21 @@ class ClassfileParser(
194194
* Updates the read pointer of 'in'. */
195195
def parseParents: List[Type] = {
196196
val superType =
197-
if (classRoot.symbol == defn.ComparableClass ||
198-
classRoot.symbol == defn.JavaCloneableClass ||
199-
classRoot.symbol == defn.JavaSerializableClass) {
200-
// Treat these interfaces as universal traits
201-
in.nextChar
197+
val superClass = in.nextChar
198+
// Treat these interfaces as universal traits
199+
if classRoot.symbol == defn.ComparableClass
200+
|| classRoot.symbol == defn.JavaCloneableClass
201+
|| classRoot.symbol == defn.JavaSerializableClass
202+
then
202203
defn.AnyType
203-
}
204204
else
205-
pool.getSuperClass(in.nextChar).typeRef
205+
pool.getSuperClass(superClass).typeRef
206206
val ifaceCount = in.nextChar
207-
var ifaces = for (i <- (0 until ifaceCount).toList) yield pool.getSuperClass(in.nextChar).typeRef
208-
// Dotty deviation: was
209-
// var ifaces = for (i <- List.range(0, ifaceCount)) ...
210-
// This does not typecheck because the type parameter of List is now lower-bounded by Int | Char.
211-
// Consequently, no best implicit for the "Integral" evidence parameter of "range"
212-
// is found. Previously, this worked because of weak conformance, which has been dropped.
213-
207+
val ifaces = List.fill(ifaceCount.toInt):
208+
pool.getSuperClass(in.nextChar).typeRef
214209
superType :: ifaces
215210
}
216211

217-
218212
val result = unpickleOrParseInnerClasses()
219213
if (!result.isDefined) {
220214
var classInfo: Type = TempClassInfoType(parseParents, instanceScope, classRoot.symbol)
@@ -233,8 +227,8 @@ class ClassfileParser(
233227
moduleRoot.setPrivateWithin(privateWithin)
234228
moduleRoot.sourceModule.setPrivateWithin(privateWithin)
235229

236-
for (i <- 0 until in.nextChar) parseMember(method = false)
237-
for (i <- 0 until in.nextChar) parseMember(method = true)
230+
for (_ <- 0 until in.nextChar) parseMember(method = false)
231+
for (_ <- 0 until in.nextChar) parseMember(method = true)
238232

239233
classRoot.registerCompanion(moduleRoot.symbol)
240234
moduleRoot.registerCompanion(classRoot.symbol)

compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,18 +64,22 @@ object Scala2Unpickler {
6464
denot.info = PolyType.fromParams(denot.owner.typeParams, denot.info)
6565
}
6666

67-
def ensureConstructor(cls: ClassSymbol, clsDenot: ClassDenotation, scope: Scope)(using Context): Unit = {
68-
if (scope.lookup(nme.CONSTRUCTOR) == NoSymbol) {
69-
val constr = newDefaultConstructor(cls)
67+
def ensureConstructor(cls: ClassSymbol, clsDenot: ClassDenotation, scope: Scope)(using Context): Unit =
68+
doEnsureConstructor(cls, clsDenot, scope, fromScala2 = true)
69+
70+
private def doEnsureConstructor(cls: ClassSymbol, clsDenot: ClassDenotation, scope: Scope, fromScala2: Boolean)
71+
(using Context): Unit =
72+
if scope.lookup(nme.CONSTRUCTOR) == NoSymbol then
73+
val constr =
74+
if fromScala2 || cls.isAllOf(Trait | JavaDefined) then newDefaultConstructor(cls)
75+
else newConstructor(cls, Private, paramNames = Nil, paramTypes = Nil)
7076
// Scala 2 traits have a constructor iff they have initialization code
7177
// In dotc we represent that as !StableRealizable, which is also owner.is(NoInits)
7278
if clsDenot.flagsUNSAFE.is(Trait) then
7379
constr.setFlag(StableRealizable)
7480
clsDenot.setFlag(NoInits)
7581
addConstructorTypeParams(constr)
7682
cls.enter(constr, scope)
77-
}
78-
}
7983

8084
def setClassInfo(denot: ClassDenotation, info: Type, fromScala2: Boolean, selfInfo: Type = NoType)(using Context): Unit = {
8185
val cls = denot.classSymbol
@@ -109,7 +113,7 @@ object Scala2Unpickler {
109113
if (tsym.exists) tsym.setFlag(TypeParam)
110114
else denot.enter(tparam, decls)
111115
}
112-
if (!denot.flagsUNSAFE.isAllOf(JavaModule)) ensureConstructor(cls, denot, decls)
116+
if (!denot.flagsUNSAFE.isAllOf(JavaModule)) doEnsureConstructor(cls, denot, decls, fromScala2)
113117

114118
val scalacCompanion = denot.classSymbol.scalacLinkedClass
115119

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ object Formatting {
129129
given Show[Class[?]] = ShowAny
130130
given Show[Throwable] = ShowAny
131131
given Show[StringBuffer] = ShowAny
132+
given Show[StringBuilder] = ShowAny
132133
given Show[CompilationUnit] = ShowAny
133134
given Show[Phases.Phase] = ShowAny
134135
given Show[TyperState] = ShowAny

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3098,18 +3098,18 @@ extends ReferenceMsg(CannotBeAccessedID):
30983098
case _ =>
30993099
i"none of the overloaded alternatives named $name can"
31003100
val where = if (ctx.owner.exists) i" from ${ctx.owner.enclosingClass}" else ""
3101-
val whyNot = new StringBuffer
3101+
val whyNot = new StringBuilder
31023102
for alt <- alts do
31033103
val cls = alt.owner.enclosingSubClass
31043104
val owner = if cls.exists then cls else alt.owner
31053105
val location: String =
31063106
if alt.is(Protected) then
31073107
if alt.privateWithin.exists && alt.privateWithin != owner then
31083108
if owner.is(Final) then alt.privateWithin.showLocated
3109-
else alt.privateWithin.showLocated + ", or " + owner.showLocated + " or one of its subclasses"
3109+
else s"${alt.privateWithin.showLocated}, or ${owner.showLocated} or one of its subclasses"
31103110
else
31113111
if owner.is(Final) then owner.showLocated
3112-
else owner.showLocated + " or one of its subclasses"
3112+
else s"${owner.showLocated} or one of its subclasses"
31133113
else
31143114
alt.privateWithin.orElse(owner).showLocated
31153115
val accessMod = if alt.is(Protected) then "protected" else "private"

tests/neg/i15144.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//> using options --release 11
2+
// test: -jvm 17+
3+
// Must be tested where release target < current JVM.
4+
// Maybe a bug that ct.sym is not used if release == JVM version.
5+
6+
import java.time.Instant
7+
8+
class C:
9+
def f: Instant = new Instant // error
10+
def g: Instant = Instant() // error
11+
def p: P = new P // error
12+
13+
class P private ()
14+
15+
@main def test() = println:
16+
C().f

0 commit comments

Comments
 (0)