Reflection: create synthetic classes instead of throwing UOE

... for Kotlin-generated classes which do not correspond to a "class"
from the Kotlin language's point of view. For example, Kotlin lambdas,
file facade classes, multifile class facade/part classes, WhenMappings,
DefaultImpls. They can be distinguished from normal classes by the value
of `KotlinClassHeader.Kind` (which is the same as `Metadata.kind`).

Another theoretical option would be to throw exception at the point
where the `::class` expression is used, if the expression's type on the
left-hand side is a synthetic class. But we can't really do that since
it'll affect performance of most `<expression>::class` expressions.

So, construct a fake synthetic class instead, without any members except
equals/hashCode/toString, and without any non-trivial modifiers. It kind
of contradicts the general idea that kotlin-reflect presents anything
exactly the same as the compiler sees it, but arguably it's worth it to
avoid unexpected exceptions like in KT-41373.

In the newly added test, Java lambda check is muted but it should work
exactly the same as for Kotlin lambdas and other synthetic classes. It's
fixed in a subsequent commit.

 #KT-41373 In Progress
This commit is contained in:
Alexander Udalov
2023-01-30 23:04:38 +01:00
committed by Space Team
parent d833b732c9
commit 5dc882abf5
17 changed files with 356 additions and 17 deletions
@@ -32779,6 +32779,16 @@ public class FirJsCodegenBoxTestGenerated extends AbstractFirJsCodegenBoxTest {
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/syntheticClasses")
@TestDataPath("$PROJECT_ROOT")
public class SyntheticClasses {
@Test
public void testAllFilesPresentInSyntheticClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/syntheticClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf")
@TestDataPath("$PROJECT_ROOT")
@@ -32779,6 +32779,16 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/syntheticClasses")
@TestDataPath("$PROJECT_ROOT")
public class SyntheticClasses {
@Test
public void testAllFilesPresentInSyntheticClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/syntheticClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf")
@TestDataPath("$PROJECT_ROOT")
@@ -32779,6 +32779,16 @@ public class IrJsES6CodegenBoxTestGenerated extends AbstractIrJsES6CodegenBoxTes
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/syntheticClasses")
@TestDataPath("$PROJECT_ROOT")
public class SyntheticClasses {
@Test
public void testAllFilesPresentInSyntheticClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/syntheticClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf")
@TestDataPath("$PROJECT_ROOT")