Skip to content

Commit bf24325

Browse files
committed
Make various methods that check if a class is a Function return true for FunctionXXL
This only makes a difference after erasure, and I believe this is less surprising than the previous behavior. This necessitated a slight refactoring in GenericSignature to avoid an infinite loop now that `isXXLFunctionClass` returns true for scala.FunctionXXL and not just for the classes that erase to scala.FunctionXXL.
1 parent cb528b9 commit bf24325

File tree

4 files changed

+70
-59
lines changed

4 files changed

+70
-59
lines changed

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,7 @@ class Definitions {
10011001
tp.derivesFrom(NothingClass) || tp.derivesFrom(NullClass)
10021002

10031003
/** Is a function class.
1004+
* - FunctionXXL
10041005
* - FunctionN for N >= 0
10051006
* - ImplicitFunctionN for N >= 0
10061007
* - ErasedFunctionN for N > 0
@@ -1020,15 +1021,21 @@ class Definitions {
10201021
*/
10211022
def isErasedFunctionClass(cls: Symbol): Boolean = scalaClassName(cls).isErasedFunction
10221023

1023-
/** Is a class that will be erased to FunctionXXL
1024+
/** Is either FunctionXXL or a class that will be erased to FunctionXXL
1025+
* - FunctionXXL
10241026
* - FunctionN for N >= 22
10251027
* - ImplicitFunctionN for N >= 22
10261028
*/
1027-
def isXXLFunctionClass(cls: Symbol): Boolean = scalaClassName(cls).functionArity > MaxImplementedFunctionArity
1029+
def isXXLFunctionClass(cls: Symbol): Boolean = {
1030+
val name = scalaClassName(cls)
1031+
(name eq tpnme.FunctionXXL) || name.functionArity > MaxImplementedFunctionArity
1032+
}
10281033

10291034
/** Is a synthetic function class
10301035
* - FunctionN for N > 22
1031-
* - ImplicitFunctionN for N > 0
1036+
* - ImplicitFunctionN for N >= 0
1037+
* - ErasedFunctionN for N > 0
1038+
* - ErasedImplicitFunctionN for N > 0
10321039
*/
10331040
def isSyntheticFunctionClass(cls: Symbol): Boolean = scalaClassName(cls).isSyntheticFunction
10341041

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,9 @@ object NameOps {
173173
if (n == 0) -1 else n
174174
}
175175

176-
/** Is a function name, i.e one of FunctionN, ImplicitFunctionN for N >= 0 or ErasedFunctionN, ErasedImplicitFunctionN for N > 0
176+
/** Is a function name, i.e one of FunctionXXL, FunctionN, ImplicitFunctionN for N >= 0 or ErasedFunctionN, ErasedImplicitFunctionN for N > 0
177177
*/
178-
def isFunction: Boolean = functionArity >= 0
178+
def isFunction: Boolean = (name eq tpnme.FunctionXXL) || functionArity >= 0
179179

180180
/** Is an implicit function name, i.e one of ImplicitFunctionN for N >= 0 or ErasedImplicitFunctionN for N > 0
181181
*/

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ object StdNames {
204204
final val Singleton: N = "Singleton"
205205
final val Throwable: N = "Throwable"
206206
final val IOOBException: N = "IndexOutOfBoundsException"
207+
final val FunctionXXL: N = "FunctionXXL"
207208

208209
final val ClassfileAnnotation: N = "ClassfileAnnotation"
209210
final val ClassManifest: N = "ClassManifest"

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

Lines changed: 57 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,60 @@ object GenericSignatures {
123123
builder.append('L').append(name)
124124
}
125125

126+
def classSig(sym: Symbol, pre: Type = NoType, args: List[Type] = Nil): Unit = {
127+
def argSig(tp: Type): Unit =
128+
tp match {
129+
case bounds: TypeBounds =>
130+
if (!(defn.AnyType <:< bounds.hi)) {
131+
builder.append('+')
132+
boxedSig(bounds.hi)
133+
}
134+
else if (!(bounds.lo <:< defn.NothingType)) {
135+
builder.append('-')
136+
boxedSig(bounds.lo)
137+
}
138+
else builder.append('*')
139+
case PolyType(_, res) =>
140+
builder.append('*') // scala/bug#7932
141+
case _: HKTypeLambda =>
142+
fullNameInSig(tp.typeSymbol)
143+
builder.append(';')
144+
case _ =>
145+
boxedSig(tp)
146+
}
147+
148+
if (pre.exists) {
149+
val preRebound = pre.baseType(sym.owner) // #2585
150+
if (needsJavaSig(preRebound, Nil)) {
151+
val i = builder.length()
152+
jsig(preRebound)
153+
if (builder.charAt(i) == 'L') {
154+
builder.delete(builder.length() - 1, builder.length())// delete ';'
155+
// If the prefix is a module, drop the '$'. Classes (or modules) nested in modules
156+
// are separated by a single '$' in the filename: `object o { object i }` is o$i$.
157+
if (preRebound.typeSymbol.is(ModuleClass))
158+
builder.delete(builder.length() - 1, builder.length())
159+
160+
// Ensure every '.' in the generated signature immediately follows
161+
// a close angle bracket '>'. Any which do not are replaced with '$'.
162+
// This arises due to multiply nested classes in the face of the
163+
// rewriting explained at rebindInnerClass.
164+
165+
// TODO revisit this. Does it align with javac for code that can be expressed in both languages?
166+
val delimiter = if (builder.charAt(builder.length() - 1) == '>') '.' else '$'
167+
builder.append(delimiter).append(sanitizeName(sym.name.asSimpleName))
168+
} else fullNameInSig(sym)
169+
} else fullNameInSig(sym)
170+
} else fullNameInSig(sym)
171+
172+
if (args.nonEmpty) {
173+
builder.append('<')
174+
args foreach argSig
175+
builder.append('>')
176+
}
177+
builder.append(';')
178+
}
179+
126180
@noinline
127181
def jsig(tp0: Type, toplevel: Boolean = false, primitiveOK: Boolean = true): Unit = {
128182

@@ -133,57 +187,6 @@ object GenericSignatures {
133187
typeParamSig(ref.paramName.lastPart)
134188

135189
case RefOrAppliedType(sym, pre, args) =>
136-
def argSig(tp: Type): Unit =
137-
tp match {
138-
case bounds: TypeBounds =>
139-
if (!(defn.AnyType <:< bounds.hi)) {
140-
builder.append('+')
141-
boxedSig(bounds.hi)
142-
}
143-
else if (!(bounds.lo <:< defn.NothingType)) {
144-
builder.append('-')
145-
boxedSig(bounds.lo)
146-
}
147-
else builder.append('*')
148-
case PolyType(_, res) =>
149-
builder.append('*') // scala/bug#7932
150-
case _: HKTypeLambda =>
151-
fullNameInSig(tp.typeSymbol)
152-
builder.append(';')
153-
case _ =>
154-
boxedSig(tp)
155-
}
156-
def classSig: Unit = {
157-
val preRebound = pre.baseType(sym.owner) // #2585
158-
if (needsJavaSig(preRebound, Nil)) {
159-
val i = builder.length()
160-
jsig(preRebound)
161-
if (builder.charAt(i) == 'L') {
162-
builder.delete(builder.length() - 1, builder.length())// delete ';'
163-
// If the prefix is a module, drop the '$'. Classes (or modules) nested in modules
164-
// are separated by a single '$' in the filename: `object o { object i }` is o$i$.
165-
if (preRebound.typeSymbol.is(ModuleClass))
166-
builder.delete(builder.length() - 1, builder.length())
167-
168-
// Ensure every '.' in the generated signature immediately follows
169-
// a close angle bracket '>'. Any which do not are replaced with '$'.
170-
// This arises due to multiply nested classes in the face of the
171-
// rewriting explained at rebindInnerClass.
172-
173-
// TODO revisit this. Does it align with javac for code that can be expressed in both languages?
174-
val delimiter = if (builder.charAt(builder.length() - 1) == '>') '.' else '$'
175-
builder.append(delimiter).append(sanitizeName(sym.name.asSimpleName))
176-
} else fullNameInSig(sym)
177-
} else fullNameInSig(sym)
178-
179-
if (args.nonEmpty) {
180-
builder.append('<')
181-
args foreach argSig
182-
builder.append('>')
183-
}
184-
builder.append(';')
185-
}
186-
187190
// If args isEmpty, Array is being used as a type constructor
188191
if (sym == defn.ArrayClass && args.nonEmpty) {
189192
if (unboundedGenericArrayLevel(tp) == 1) jsig(defn.ObjectType)
@@ -215,14 +218,14 @@ object GenericSignatures {
215218
val unboxed = ValueClasses.valueClassUnbox(sym.asClass).info.finalResultType
216219
val unboxedSeen = tp.memberInfo(ValueClasses.valueClassUnbox(sym.asClass)).finalResultType
217220
if (unboxedSeen.isPrimitiveValueType && !primitiveOK)
218-
classSig
221+
classSig(sym, pre, args)
219222
else
220223
jsig(unboxedSeen, toplevel, primitiveOK)
221224
}
222225
else if (defn.isXXLFunctionClass(sym))
223-
jsig(defn.FunctionXXLType, toplevel, primitiveOK)
226+
classSig(defn.FunctionXXLClass)
224227
else if (sym.isClass)
225-
classSig
228+
classSig(sym, pre, args)
226229
else
227230
jsig(erasure(tp), toplevel, primitiveOK)
228231

0 commit comments

Comments
 (0)