Skip to content

Commit 5756a33

Browse files
authored
Merge pull request github#10737 from smowton/smowton/fix/type-instance-within-default-value-erasure
Kotlin: fix type variable erasure inside default function values
2 parents 70b8224 + 5dcb70e commit 5756a33

File tree

5 files changed

+95
-14
lines changed

5 files changed

+95
-14
lines changed

java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,23 @@ open class KotlinFileExtractor(
254254
}
255255
}
256256

257+
fun extractClassInstance(classLabel: Label<out DbClassorinterface>, c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>?, shouldExtractOutline: Boolean, shouldExtractDetails: Boolean) {
258+
DeclarationStackAdjuster(c).use {
259+
if (shouldExtractOutline) {
260+
extractClassWithoutMembers(c, argsIncludingOuterClasses)
261+
}
262+
263+
if (shouldExtractDetails) {
264+
val supertypeMode = if (argsIncludingOuterClasses == null) ExtractSupertypesMode.Raw else ExtractSupertypesMode.Specialised(argsIncludingOuterClasses)
265+
extractClassSupertypes(c, classLabel, supertypeMode, true)
266+
extractNonPrivateMemberPrototypes(c, argsIncludingOuterClasses, classLabel)
267+
}
268+
}
269+
}
270+
257271
// `argsIncludingOuterClasses` can be null to describe a raw generic type.
258272
// For non-generic types it will be zero-length list.
259-
fun extractClassInstance(c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>?): Label<out DbClassorinterface> {
273+
private fun extractClassWithoutMembers(c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>?): Label<out DbClassorinterface> {
260274
with("class instance", c) {
261275
if (argsIncludingOuterClasses?.isEmpty() == true) {
262276
logger.error("Instance without type arguments: " + c.name.asString())
@@ -342,7 +356,7 @@ open class KotlinFileExtractor(
342356

343357
// `argsIncludingOuterClasses` can be null to describe a raw generic type.
344358
// For non-generic types it will be zero-length list.
345-
fun extractNonPrivateMemberPrototypes(c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>?, id: Label<out DbClassorinterface>) {
359+
private fun extractNonPrivateMemberPrototypes(c: IrClass, argsIncludingOuterClasses: List<IrTypeArgument>?, id: Label<out DbClassorinterface>) {
346360
with("member prototypes", c) {
347361
val typeParamSubstitution =
348362
when (argsIncludingOuterClasses) {

java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -411,16 +411,9 @@ open class KotlinUsesExtractor(
411411
if (replacedArgsIncludingOuterClasses == null || replacedArgsIncludingOuterClasses.isNotEmpty()) {
412412
// If this is a generic type instantiation or a raw type then it has no
413413
// source entity, so we need to extract it here
414-
val extractorWithCSource by lazy { this.withFileOfClass(replacedClass) }
415-
416-
if (!instanceSeenBefore) {
417-
extractorWithCSource.extractClassInstance(replacedClass, replacedArgsIncludingOuterClasses)
418-
}
419-
420-
if (inReceiverContext && tw.lm.genericSpecialisationsExtracted.add(classLabelResult.classLabel)) {
421-
val supertypeMode = if (replacedArgsIncludingOuterClasses == null) ExtractSupertypesMode.Raw else ExtractSupertypesMode.Specialised(replacedArgsIncludingOuterClasses)
422-
extractorWithCSource.extractClassSupertypes(replacedClass, classLabel, supertypeMode, true)
423-
extractorWithCSource.extractNonPrivateMemberPrototypes(replacedClass, replacedArgsIncludingOuterClasses, classLabel)
414+
val shouldExtractClassDetails = inReceiverContext && tw.lm.genericSpecialisationsExtracted.add(classLabelResult.classLabel)
415+
if (!instanceSeenBefore || shouldExtractClassDetails) {
416+
this.withFileOfClass(replacedClass).extractClassInstance(classLabel, replacedClass, replacedArgsIncludingOuterClasses, !instanceSeenBefore, shouldExtractClassDetails)
424417
}
425418
}
426419

java/ql/test/kotlin/library-tests/parameter-defaults/PrintAst.expected

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,3 +1165,59 @@ test.kt:
11651165
# 161| -1: [VarAccess] p0
11661166
# 161| 0: [VarAccess] p1
11671167
# 161| 1: [VarAccess] p2
1168+
# 165| 15: [Class,GenericType,ParameterizedType] TestGenericUsedWithinDefaultValue
1169+
#-----| -2: (Generic Parameters)
1170+
# 165| 0: [TypeVariable] T
1171+
# 165| 1: [Constructor] TestGenericUsedWithinDefaultValue
1172+
# 165| 5: [BlockStmt] { ... }
1173+
# 165| 0: [SuperConstructorInvocationStmt] super(...)
1174+
# 165| 1: [BlockStmt] { ... }
1175+
# 171| 2: [Method] f
1176+
# 171| 3: [TypeAccess] Unit
1177+
#-----| 4: (Parameters)
1178+
# 171| 0: [Parameter] x
1179+
# 171| 0: [TypeAccess] int
1180+
# 171| 1: [Parameter] y
1181+
# 171| 0: [TypeAccess] String
1182+
# 171| 5: [BlockStmt] { ... }
1183+
# 171| 3: [Method] f$default
1184+
# 171| 3: [TypeAccess] Unit
1185+
#-----| 4: (Parameters)
1186+
# 171| 0: [Parameter] p0
1187+
# 171| 0: [TypeAccess] TestGenericUsedWithinDefaultValue<>
1188+
# 171| 1: [Parameter] p1
1189+
# 171| 0: [TypeAccess] int
1190+
# 171| 2: [Parameter] p2
1191+
# 171| 0: [TypeAccess] String
1192+
# 171| 3: [Parameter] p3
1193+
# 171| 0: [TypeAccess] int
1194+
# 171| 4: [Parameter] p4
1195+
# 171| 0: [TypeAccess] Object
1196+
# 171| 5: [BlockStmt] { ... }
1197+
# 171| 0: [IfStmt] if (...)
1198+
# 171| 0: [EQExpr] ... == ...
1199+
# 171| 0: [AndBitwiseExpr] ... & ...
1200+
# 171| 0: [IntegerLiteral] 2
1201+
# 171| 1: [VarAccess] p3
1202+
# 171| 1: [IntegerLiteral] 0
1203+
# 171| 1: [ExprStmt] <Expr>;
1204+
# 171| 0: [AssignExpr] ...=...
1205+
# 171| 0: [VarAccess] p2
1206+
# 171| 1: [MethodAccess] ident(...)
1207+
# 171| -1: [ClassInstanceExpr] new TestGenericUsedWithinDefaultValue<String>(...)
1208+
# 171| -3: [TypeAccess] TestGenericUsedWithinDefaultValue<String>
1209+
# 171| 0: [TypeAccess] String
1210+
# 171| 0: [StringLiteral] Hello world
1211+
# 171| 1: [ReturnStmt] return ...
1212+
# 171| 0: [MethodAccess] f(...)
1213+
# 171| -1: [VarAccess] p0
1214+
# 171| 0: [VarAccess] p1
1215+
# 171| 1: [VarAccess] p2
1216+
# 173| 4: [Method] ident
1217+
# 173| 3: [TypeAccess] T
1218+
#-----| 4: (Parameters)
1219+
# 173| 0: [Parameter] t
1220+
# 173| 0: [TypeAccess] T
1221+
# 173| 5: [BlockStmt] { ... }
1222+
# 173| 0: [ReturnStmt] return ...
1223+
# 173| 0: [VarAccess] t

java/ql/test/kotlin/library-tests/parameter-defaults/erasure.ql

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
import java
22

3+
class InstantiatedType extends ParameterizedType {
4+
InstantiatedType() { typeArgs(_, _, this) }
5+
}
6+
37
// This checks that all type parameter references are erased in the context of a $default function.
48
predicate containsTypeVariables(Type t) {
5-
t != t.getErasure() and
6-
not t.getErasure().(GenericType).getRawType() = t
9+
t instanceof TypeVariable or
10+
containsTypeVariables(t.(InstantiatedType).getATypeArgument()) or
11+
containsTypeVariables(t.(NestedType).getEnclosingType()) or
12+
containsTypeVariables(t.(Wildcard).getATypeBound().getType())
713
}
814

915
from Expr e

java/ql/test/kotlin/library-tests/parameter-defaults/test.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,15 @@ class VisibilityTests {
161161
private fun i(x: Int, y: Int = 0) = x + y
162162

163163
}
164+
165+
class TestGenericUsedWithinDefaultValue<T> {
166+
167+
// This tests parameter erasure works properly: we should notice that here the type variable T
168+
// isn't used in the specialisation TestGenericUsedWithinDefaultValue<String>, but it can be
169+
// cited in contexts like "the signature of the source declaration of 'TestGenericUsedWithinDefaultValue<String>.f(String)' is 'f(T)'",
170+
// not 'f(Object)' as we might mistakenly conclude if we're inappropriately erasing 'T'.
171+
fun f(x: Int, y: String = TestGenericUsedWithinDefaultValue<String>().ident("Hello world")) { }
172+
173+
fun ident(t: T) = t
174+
175+
}

0 commit comments

Comments
 (0)