From bdf76f23c495f33454f7407e5e26442eb5323442 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Mon, 5 Jun 2017 14:58:50 +0300 Subject: [PATCH] Jvm Codegen: do not throw on malformed delegation to a type parameter Fix exception on light class building See KT-15931 --- .../codegen/ImplementationBodyCodegen.java | 43 +++++++++++++------ .../regression/IncompleteClassDelegation.kt | 15 +++++++ .../checkers/PsiCheckerTestGenerated.java | 6 +++ .../declaration/DelegationTranslator.kt | 1 + 4 files changed, 51 insertions(+), 14 deletions(-) create mode 100644 idea/testData/checker/regression/IncompleteClassDelegation.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index 61474fc69a0..59094b20909 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -1105,9 +1105,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } private final Map fields = new HashMap<>(); - @NotNull + @Nullable public Field getInfo(KtDelegatedSuperTypeEntry specifier) { - return fields.get(specifier); + Field field = fields.get(specifier); + assert field != null || state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES : "No field for " + specifier.getText(); + return field; } private void addField(KtDelegatedSuperTypeEntry specifier, PropertyDescriptor propertyDescriptor) { @@ -1127,22 +1129,24 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { for (KtSuperTypeListEntry specifier : delegationSpecifiers) { if (specifier instanceof KtDelegatedSuperTypeEntry) { KtExpression expression = ((KtDelegatedSuperTypeEntry) specifier).getDelegateExpression(); - PropertyDescriptor propertyDescriptor = expression != null - ? CodegenUtil.getDelegatePropertyIfAny(expression, descriptor, bindingContext) - : null; + if (expression == null) continue; + + PropertyDescriptor propertyDescriptor = CodegenUtil.getDelegatePropertyIfAny(expression, descriptor, bindingContext); + if (CodegenUtil.isFinalPropertyWithBackingField(propertyDescriptor, bindingContext)) { result.addField((KtDelegatedSuperTypeEntry) specifier, propertyDescriptor); } else { - KotlinType expressionType = expression != null - ? bindingContext.getType(expression) - : null; + KotlinType expressionType = bindingContext.getType(expression); ClassDescriptor superClass = getSuperClass(specifier); - if (superClass != null) { - Type asmType = expressionType != null ? typeMapper.mapType(expressionType) : typeMapper.mapType(superClass); - result.addField((KtDelegatedSuperTypeEntry) specifier, asmType, JvmAbi.DELEGATE_SUPER_FIELD_PREFIX + n); - } + Type asmType = + expressionType != null ? typeMapper.mapType(expressionType) : + superClass != null ? typeMapper.mapType(superClass) : null; + + if (asmType == null) continue; + + result.addField((KtDelegatedSuperTypeEntry) specifier, asmType, JvmAbi.DELEGATE_SUPER_FIELD_PREFIX + n); } n++; } @@ -1152,7 +1156,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { @Nullable private ClassDescriptor getSuperClass(@NotNull KtSuperTypeListEntry specifier) { - return CodegenUtil.getSuperClassBySuperTypeListEntry(specifier, bindingContext); + ClassDescriptor superClass = CodegenUtil.getSuperClassBySuperTypeListEntry(specifier, bindingContext); + + assert superClass != null || state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES + : "ClassDescriptor should not be null:" + specifier.getText(); + return superClass; } private void genCallToDelegatorByExpressionSpecifier( @@ -1164,6 +1172,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { KtExpression expression = specifier.getDelegateExpression(); DelegationFieldsInfo.Field fieldInfo = fieldsInfo.getInfo(specifier); + if (fieldInfo == null) return; + if (fieldInfo.generateField) { iv.load(0, classAsmType); fieldInfo.getStackValue().store(codegen.gen(expression), iv); @@ -1609,10 +1619,15 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { for (KtSuperTypeListEntry specifier : myClass.getSuperTypeListEntries()) { if (specifier instanceof KtDelegatedSuperTypeEntry) { DelegationFieldsInfo.Field field = delegationFieldsInfo.getInfo((KtDelegatedSuperTypeEntry) specifier); + if (field == null) continue; + generateDelegateField(field); KtExpression delegateExpression = ((KtDelegatedSuperTypeEntry) specifier).getDelegateExpression(); KotlinType delegateExpressionType = delegateExpression != null ? bindingContext.getType(delegateExpression) : null; - generateDelegates(getSuperClass(specifier), delegateExpressionType, field); + ClassDescriptor superClass = getSuperClass(specifier); + if (superClass == null) continue; + + generateDelegates(superClass, delegateExpressionType, field); } } } diff --git a/idea/testData/checker/regression/IncompleteClassDelegation.kt b/idea/testData/checker/regression/IncompleteClassDelegation.kt new file mode 100644 index 00000000000..778afefdf70 --- /dev/null +++ b/idea/testData/checker/regression/IncompleteClassDelegation.kt @@ -0,0 +1,15 @@ +package c + +class C: T by { +} + +class D: T by + +class G : T by { + + val c = 3 +} + +interface I + +class A(a: T) : T by a \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerTestGenerated.java b/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerTestGenerated.java index 758dc525d3e..409e4ddbf6d 100644 --- a/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerTestGenerated.java @@ -551,6 +551,12 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { doTest(fileName); } + @TestMetadata("IncompleteClassDelegation.kt") + public void testIncompleteClassDelegation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/regression/IncompleteClassDelegation.kt"); + doTest(fileName); + } + @TestMetadata("InitializerInInterface.kt") public void testInitializerInInterface() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/regression/InitializerInInterface.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DelegationTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DelegationTranslator.kt index 6fa767504d9..14b27859ec5 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DelegationTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DelegationTranslator.kt @@ -94,6 +94,7 @@ class DelegationTranslator( private fun getSuperClass(specifier: KtSuperTypeListEntry): ClassDescriptor? = CodegenUtil.getSuperClassBySuperTypeListEntry(specifier, bindingContext()) + ?: error("ClassDescriptor of superType should not be null: ${specifier.text}") private fun generateDelegates(specifier: KtSuperTypeListEntry, toClass: ClassDescriptor, field: Field) { for ((descriptor, overriddenDescriptor) in DelegationResolver.getDelegates(classDescriptor, toClass)) {