Skip to content

Commit dd86f7a

Browse files
committed
Kotlin: Revert type erasure within $default functions
This imprecise implementation turned out to cause linkage errors, e.g. when type variables in the signatures of member methods were inappropriately erased. For the time being we accept that $default methods despite having erased signatures in keeping with their JVM representation can contain expressions whose types make reference to their surrounding function or class' type variables, even though they should be out of scope since $default methods are static and don't have type parameters, and need to cope with the inconsistency in QL.
1 parent 636d5e3 commit dd86f7a

File tree

5 files changed

+48
-28
lines changed

5 files changed

+48
-28
lines changed

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,8 +1194,6 @@ open class KotlinFileExtractor(
11941194
// n + o'th parameter, where `o` is the parameter offset caused by adding any dispatch receiver to the parameter list.
11951195
// Note we don't need to add the extension receiver here because `useValueParameter` always assumes an extension receiver
11961196
// will be prepended if one exists.
1197-
// Note we have to get the real function ID here before entering this block, because otherwise we'll misrepresent the signature of a generic
1198-
// function without its type variables -- for example, trying to address `f(T, List<T>)` as `f(Object, List)`.
11991197
val realFunctionId = useFunction<DbCallable>(f)
12001198
DeclarationStackAdjuster(f, OverriddenFunctionAttributes(id, id, locId, nonSyntheticParams, typeParameters = listOf(), isStatic = true)).use {
12011199
val realParamsVarId = getValueParameterLabel(id, parameterTypes.size - 2)

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

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -643,26 +643,6 @@ open class KotlinUsesExtractor(
643643
RETURN, GENERIC_ARGUMENT, OTHER
644644
}
645645

646-
private fun isOnDeclarationStackWithoutTypeParameters(f: IrFunction) =
647-
this is KotlinFileExtractor && this.declarationStack.findOverriddenAttributes(f)?.typeParameters?.isEmpty() == true
648-
649-
private fun isStaticFunctionOnStackBeforeClass(c: IrClass) =
650-
this is KotlinFileExtractor && (this.declarationStack.findFirst { it.first == c || it.second?.isStatic == true })?.second?.isStatic == true
651-
652-
private fun isUnavailableTypeParameter(t: IrType) =
653-
t is IrSimpleType && t.classifier.owner.let { owner ->
654-
owner is IrTypeParameter && owner.parent.let { parent ->
655-
when (parent) {
656-
is IrFunction -> isOnDeclarationStackWithoutTypeParameters(parent)
657-
is IrClass -> isStaticFunctionOnStackBeforeClass(parent)
658-
else -> false
659-
}
660-
}
661-
}
662-
663-
private fun argIsUnavailableTypeParameter(t: IrTypeArgument) =
664-
t is IrTypeProjection && isUnavailableTypeParameter(t.type)
665-
666646
private fun useSimpleType(s: IrSimpleType, context: TypeContext): TypeResults {
667647
if (s.abbreviation != null) {
668648
// TODO: Extract this information
@@ -735,13 +715,11 @@ open class KotlinUsesExtractor(
735715
}
736716

737717
owner is IrClass -> {
738-
val args = if (s.isRawType() || s.arguments.any { argIsUnavailableTypeParameter(it) }) null else s.arguments
718+
val args = if (s.isRawType()) null else s.arguments
739719

740720
return useSimpleTypeClass(owner, args, s.isNullable())
741721
}
742722
owner is IrTypeParameter -> {
743-
if (isUnavailableTypeParameter(s))
744-
return useType(erase(s), context)
745723
val javaResult = useTypeParameter(owner)
746724
val aClassId = makeClass("kotlin", "TypeParam") // TODO: Wrong
747725
val kotlinResult = if (true) TypeResult(fakeKotlinType(), "TODO", "TODO") else
@@ -1474,7 +1452,13 @@ open class KotlinUsesExtractor(
14741452
param.parent.let {
14751453
(it as? IrFunction)?.let { fn ->
14761454
if (this is KotlinFileExtractor)
1477-
this.declarationStack.findOverriddenAttributes(fn)?.id
1455+
this.declarationStack.findOverriddenAttributes(fn)?.takeUnless {
1456+
// When extracting the `static fun f$default(...)` that accompanies `fun <T> f(val x: T? = defaultExpr, ...)`,
1457+
// `f$default` has no type parameters, and so there is no `f$default::T` to refer to.
1458+
// We have no good way to extract references to `T` in `defaultExpr`, so we just fall back on describing it
1459+
// in terms of `f::T`, even though that type variable ought to be out of scope here.
1460+
attribs -> attribs.typeParameters?.isEmpty() == true
1461+
}?.id
14781462
else
14791463
null
14801464
} ?:

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,7 +1337,7 @@ test.kt:
13371337
# 145| 0: [AssignExpr] ...=...
13381338
# 145| 0: [VarAccess] p4
13391339
# 145| 1: [MethodAccess] listOf(...)
1340-
# 145| -2: [TypeAccess] Object
1340+
# 145| -2: [TypeAccess] T
13411341
# 145| -1: [TypeAccess] CollectionsKt
13421342
# 145| 0: [VarAccess] p2
13431343
# 145| 3: [IfStmt] if (...)
@@ -1360,7 +1360,7 @@ test.kt:
13601360
# 145| 0: [AssignExpr] ...=...
13611361
# 145| 0: [VarAccess] p6
13621362
# 145| 1: [MethodAccess] listOf(...)
1363-
# 145| -2: [TypeAccess] Object
1363+
# 145| -2: [TypeAccess] S
13641364
# 145| -1: [TypeAccess] CollectionsKt
13651365
# 145| 0: [VarAccess] p1
13661366
# 145| 5: [ReturnStmt] return ...
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
| test.kt:124:3:126:3 | ...=... | test.kt:122:19:122:19 | T |
2+
| test.kt:124:3:126:3 | ...=... | test.kt:122:19:122:19 | T |
3+
| test.kt:124:3:126:3 | p1 | test.kt:122:19:122:19 | T |
4+
| test.kt:124:3:126:3 | p2 | test.kt:122:19:122:19 | T |
5+
| test.kt:124:3:126:3 | p2 | test.kt:122:19:122:19 | T |
6+
| test.kt:124:3:126:3 | p3 | test.kt:122:19:122:19 | T |
7+
| test.kt:124:3:126:3 | p3 | test.kt:122:19:122:19 | T |
8+
| test.kt:124:22:124:22 | p1 | test.kt:122:19:122:19 | T |
9+
| test.kt:135:3:135:43 | ...=... | test.kt:122:19:122:19 | T |
10+
| test.kt:135:3:135:43 | p1 | test.kt:122:19:122:19 | T |
11+
| test.kt:135:3:135:43 | p2 | test.kt:122:19:122:19 | T |
12+
| test.kt:135:3:135:43 | p2 | test.kt:122:19:122:19 | T |
13+
| test.kt:135:3:135:43 | testReturn(...) | test.kt:122:19:122:19 | T |
14+
| test.kt:145:3:147:3 | ...=... | file:///modules/java.base/java/util/List.class:0:0:0:0 | List<S> |
15+
| test.kt:145:3:147:3 | ...=... | file:///modules/java.base/java/util/List.class:0:0:0:0 | List<T> |
16+
| test.kt:145:3:147:3 | ...=... | test.kt:143:27:143:27 | T |
17+
| test.kt:145:3:147:3 | ...=... | test.kt:143:27:143:27 | T |
18+
| test.kt:145:3:147:3 | ...=... | test.kt:145:8:145:12 | S |
19+
| test.kt:145:3:147:3 | p1 | test.kt:145:8:145:12 | S |
20+
| test.kt:145:3:147:3 | p2 | test.kt:143:27:143:27 | T |
21+
| test.kt:145:3:147:3 | p2 | test.kt:143:27:143:27 | T |
22+
| test.kt:145:3:147:3 | p3 | test.kt:143:27:143:27 | T |
23+
| test.kt:145:3:147:3 | p3 | test.kt:143:27:143:27 | T |
24+
| test.kt:145:3:147:3 | p4 | file:///modules/java.base/java/util/List.class:0:0:0:0 | List<T> |
25+
| test.kt:145:3:147:3 | p4 | file:///modules/java.base/java/util/List.class:0:0:0:0 | List<T> |
26+
| test.kt:145:3:147:3 | p5 | test.kt:145:8:145:12 | S |
27+
| test.kt:145:3:147:3 | p5 | test.kt:145:8:145:12 | S |
28+
| test.kt:145:3:147:3 | p6 | file:///modules/java.base/java/util/List.class:0:0:0:0 | List<S> |
29+
| test.kt:145:3:147:3 | p6 | file:///modules/java.base/java/util/List.class:0:0:0:0 | List<S> |
30+
| test.kt:145:30:145:30 | p1 | test.kt:145:8:145:12 | S |
31+
| test.kt:145:66:145:74 | T | test.kt:143:27:143:27 | T |
32+
| test.kt:145:66:145:74 | listOf(...) | file:///modules/java.base/java/util/List.class:0:0:0:0 | List<T> |
33+
| test.kt:145:73:145:73 | p2 | test.kt:143:27:143:27 | T |
34+
| test.kt:145:111:145:119 | S | test.kt:145:8:145:12 | S |
35+
| test.kt:145:111:145:119 | listOf(...) | file:///modules/java.base/java/util/List.class:0:0:0:0 | List<S> |
36+
| test.kt:145:118:145:118 | p1 | test.kt:145:8:145:12 | S |

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ class InstantiatedType extends ParameterizedType {
55
}
66

77
// This checks that all type parameter references are erased in the context of a $default function.
8+
// Note this is currently expected to fail since for the time being we extract type variable references
9+
// even where they should be out of scope.
810
predicate containsTypeVariables(Type t) {
911
t instanceof TypeVariable or
1012
containsTypeVariables(t.(InstantiatedType).getATypeArgument()) or

0 commit comments

Comments
 (0)