diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ConstructorCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ConstructorCodegen.java new file mode 100644 index 00000000000..2e53320fa29 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ConstructorCodegen.java @@ -0,0 +1,439 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.codegen; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.codegen.binding.MutableClosure; +import org.jetbrains.kotlin.codegen.context.ConstructorContext; +import org.jetbrains.kotlin.codegen.context.FieldOwnerContext; +import org.jetbrains.kotlin.codegen.context.MethodContext; +import org.jetbrains.kotlin.codegen.state.GenerationState; +import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; +import org.jetbrains.kotlin.descriptors.*; +import org.jetbrains.kotlin.psi.*; +import org.jetbrains.kotlin.resolve.BindingContext; +import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind; +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature; +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; +import org.jetbrains.org.objectweb.asm.Type; +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; + +import java.util.Collections; +import java.util.List; + +import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface; +import static org.jetbrains.kotlin.codegen.MemberCodegen.markLineNumberForDescriptor; +import static org.jetbrains.kotlin.resolve.BindingContextUtils.getDelegationConstructorCall; +import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration; +import static org.jetbrains.kotlin.resolve.DescriptorUtils.*; +import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_STRING_TYPE; +import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE; +import static org.jetbrains.org.objectweb.asm.Opcodes.RETURN; + +public class ConstructorCodegen { + private final ClassDescriptor descriptor; + private final FieldOwnerContext context; + private final FunctionCodegen functionCodegen; + private final MemberCodegen memberCodegen; + private final ClassBodyCodegen classBodyCodegen; + private final GenerationState state; + private final OwnerKind kind; + private final ClassBuilder v; + private final Type classAsmType; + private final KtPureClassOrObject myClass; + private final BindingContext bindingContext; + private final KotlinTypeMapper typeMapper; + + public ConstructorCodegen( + @NotNull ClassDescriptor descriptor, + @NotNull FieldOwnerContext context, + @NotNull FunctionCodegen codegen, + @NotNull MemberCodegen memberCodegen, + @NotNull ClassBodyCodegen classBodyCodegen, + @NotNull GenerationState state, + @NotNull OwnerKind kind, + @NotNull ClassBuilder v, + @NotNull Type type, + @NotNull KtPureClassOrObject myClass, + @NotNull BindingContext bindingContext + ) { + this.descriptor = descriptor; + this.context = context; + functionCodegen = codegen; + this.memberCodegen = memberCodegen; + this.classBodyCodegen = classBodyCodegen; + this.state = state; + this.kind = kind; + this.v = v; + this.classAsmType = type; + this.myClass = myClass; + this.bindingContext = bindingContext; + this.typeMapper = state.getTypeMapper(); + } + + public void generatePrimaryConstructor(DelegationFieldsInfo delegationFieldsInfo, Type superClassAsmType) { + if (isJvmInterface(descriptor)) return; + + ClassConstructorDescriptor constructorDescriptor = descriptor.getUnsubstitutedPrimaryConstructor(); + if (constructorDescriptor == null) return; + + ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor); + + KtPrimaryConstructor primaryConstructor = myClass.getPrimaryConstructor(); + JvmDeclarationOrigin origin = JvmDeclarationOriginKt + .OtherOrigin(primaryConstructor != null ? primaryConstructor : myClass.getPsiOrParent(), constructorDescriptor); + functionCodegen.generateMethod(origin, constructorDescriptor, constructorContext, + new FunctionGenerationStrategy.CodegenBased(state) { + @Override + public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { + generatePrimaryConstructorImpl( + constructorDescriptor, + codegen, + delegationFieldsInfo, + primaryConstructor, + superClassAsmType + ); + } + } + ); + + functionCodegen.generateDefaultIfNeeded(constructorContext, constructorDescriptor, OwnerKind.IMPLEMENTATION, + DefaultParameterValueLoader.DEFAULT, null); + + new DefaultParameterValueSubstitutor(state).generatePrimaryConstructorOverloadsIfNeeded(constructorDescriptor, v, memberCodegen, kind, myClass); + } + + public void generateSecondaryConstructor( + @NotNull ClassConstructorDescriptor constructorDescriptor, + @NotNull Type superClassAsmType + ) { + if (!canHaveDeclaredConstructors(descriptor)) return; + + ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor); + + KtSecondaryConstructor constructor = (KtSecondaryConstructor) descriptorToDeclaration(constructorDescriptor); + + functionCodegen.generateMethod( + JvmDeclarationOriginKt.OtherOrigin(constructor, constructorDescriptor), + constructorDescriptor, constructorContext, + new FunctionGenerationStrategy.CodegenBased(state) { + @Override + public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { + generateSecondaryConstructorImpl(constructorDescriptor, codegen, superClassAsmType); + } + } + ); + + functionCodegen.generateDefaultIfNeeded(constructorContext, constructorDescriptor, OwnerKind.IMPLEMENTATION, + DefaultParameterValueLoader.DEFAULT, null); + + new DefaultParameterValueSubstitutor(state).generateOverloadsIfNeeded( + constructor, constructorDescriptor, constructorDescriptor, kind, v, memberCodegen + ); + } + + private void generateDelegatorToConstructorCall( + @NotNull InstructionAdapter iv, + @NotNull ExpressionCodegen codegen, + @NotNull ClassConstructorDescriptor constructorDescriptor, + @Nullable ResolvedCall delegationConstructorCall, + @NotNull Type superClassAsmType + ) { + MethodContext codegenContext = codegen.context; + assert codegenContext instanceof ConstructorContext : + "Constructor context expected: " + codegenContext; + assert !((ConstructorContext) codegenContext).isThisInitialized() : + "Delegating constructor call is already generated for " + ((ConstructorContext) codegenContext).getConstructorDescriptor(); + + if (delegationConstructorCall == null) { + genSimpleSuperCall(iv, superClassAsmType); + } + else { + generateDelegationConstructorCall(iv, codegen, constructorDescriptor, delegationConstructorCall); + } + + ((ConstructorContext) codegenContext).setThisInitialized(true); + } + + private void generatePrimaryConstructorImpl( + @NotNull ClassConstructorDescriptor constructorDescriptor, + @NotNull ExpressionCodegen codegen, + @NotNull DelegationFieldsInfo fieldsInfo, + @Nullable KtPrimaryConstructor primaryConstructor, + @NotNull Type superClassAsmType + ) { + InstructionAdapter iv = codegen.v; + + markLineNumberForConstructor(constructorDescriptor, primaryConstructor, codegen); + + generateClosureInitialization(iv); + + generateDelegatorToConstructorCall( + iv, codegen, constructorDescriptor, getDelegationConstructorCall(bindingContext, constructorDescriptor), superClassAsmType + ); + + for (KtSuperTypeListEntry specifier : myClass.getSuperTypeListEntries()) { + if (specifier instanceof KtDelegatedSuperTypeEntry) { + genCallToDelegatorByExpressionSpecifier(iv, codegen, (KtDelegatedSuperTypeEntry) specifier, fieldsInfo); + } + } + + int curParam = 0; + List parameters = constructorDescriptor.getValueParameters(); + for (KtParameter parameter : classBodyCodegen.getPrimaryConstructorParameters()) { + if (parameter.hasValOrVar()) { + VariableDescriptor descriptor = parameters.get(curParam); + Type type = typeMapper.mapType(descriptor); + iv.load(0, classAsmType); + iv.load(codegen.myFrameMap.getIndex(descriptor), type); + PropertyDescriptor propertyDescriptor = bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter); + assert propertyDescriptor != null : "Property descriptor is not found for primary constructor parameter: " + parameter; + iv.putfield(classAsmType.getInternalName(), context.getFieldName(propertyDescriptor, false), type.getDescriptor()); + } + curParam++; + } + + //object initialization was moved to initializeObjects() + if (!isObject(descriptor)) { + memberCodegen.generateInitializers(() -> codegen); + } + iv.visitInsn(RETURN); + } + + private void generateSecondaryConstructorImpl( + @NotNull ClassConstructorDescriptor constructorDescriptor, + @NotNull ExpressionCodegen codegen, + @NotNull Type superClassAsmType + ) { + InstructionAdapter iv = codegen.v; + + KtSecondaryConstructor constructor = + (KtSecondaryConstructor) DescriptorToSourceUtils.descriptorToDeclaration(constructorDescriptor); + + markLineNumberForConstructor(constructorDescriptor, constructor, codegen); + + ResolvedCall constructorDelegationCall = + getDelegationConstructorCall(bindingContext, constructorDescriptor); + ConstructorDescriptor delegateConstructor = constructorDelegationCall == null ? null : + constructorDelegationCall.getResultingDescriptor(); + + generateDelegatorToConstructorCall(iv, codegen, constructorDescriptor, constructorDelegationCall, superClassAsmType); + if (!isSameClassConstructor(delegateConstructor)) { + // Initialization happens only for constructors delegating to super + generateClosureInitialization(iv); + memberCodegen.generateInitializers(() -> codegen); + } + + assert constructor != null; + if (constructor.hasBody()) { + codegen.gen(constructor.getBodyExpression(), Type.VOID_TYPE); + } + + iv.visitInsn(RETURN); + } + + private void genCallToDelegatorByExpressionSpecifier( + InstructionAdapter iv, + ExpressionCodegen codegen, + KtDelegatedSuperTypeEntry specifier, + DelegationFieldsInfo fieldsInfo + ) { + 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); + } + } + + private boolean isSameClassConstructor(@Nullable ConstructorDescriptor delegatingConstructor) { + return delegatingConstructor != null && delegatingConstructor.getContainingDeclaration() == descriptor; + } + + private void generateClosureInitialization(@NotNull InstructionAdapter iv) { + MutableClosure closure = context.closure; + if (closure != null) { + List argsFromClosure = ClosureCodegen.calculateConstructorParameters(typeMapper, closure, classAsmType); + int k = 1; + for (FieldInfo info : argsFromClosure) { + k = AsmUtil.genAssignInstanceFieldFromParam(info, k, iv); + } + } + } + + private void generateDelegationConstructorCall( + @NotNull InstructionAdapter iv, + @NotNull ExpressionCodegen codegen, + @NotNull ClassConstructorDescriptor constructorDescriptor, + @NotNull ResolvedCall delegationConstructorCall + ) { + iv.load(0, OBJECT_TYPE); + ConstructorDescriptor delegateConstructor = SamCodegenUtil.resolveSamAdapter(codegen.getConstructorDescriptor(delegationConstructorCall)); + + KotlinTypeMapper typeMapper = state.getTypeMapper(); + + CallableMethod delegateConstructorCallable = typeMapper.mapToCallableMethod(delegateConstructor, false); + CallableMethod callable = typeMapper.mapToCallableMethod(constructorDescriptor, false); + + List delegatingParameters = delegateConstructorCallable.getValueParameters(); + List parameters = callable.getValueParameters(); + + ArgumentGenerator argumentGenerator; + if (isSameClassConstructor(delegateConstructor)) { + // if it's the same class constructor we should just pass all synthetic parameters + argumentGenerator = + generateThisCallImplicitArguments(iv, codegen, delegateConstructor, delegateConstructorCallable, delegatingParameters, + parameters); + } + else { + argumentGenerator = + generateSuperCallImplicitArguments(iv, codegen, constructorDescriptor, delegateConstructor, delegationConstructorCall, + delegateConstructorCallable, + delegatingParameters, + parameters); + } + + codegen.invokeMethodWithArguments( + delegateConstructorCallable, delegationConstructorCall, StackValue.none(), codegen.defaultCallGenerator, argumentGenerator); + } + + private void genSimpleSuperCall(InstructionAdapter iv, Type superClassAsmType) { + iv.load(0, superClassAsmType); + if (descriptor.getKind() == ClassKind.ENUM_CLASS || descriptor.getKind() == ClassKind.ENUM_ENTRY) { + iv.load(1, JAVA_STRING_TYPE); + iv.load(2, Type.INT_TYPE); + iv.invokespecial(superClassAsmType.getInternalName(), "", "(Ljava/lang/String;I)V", false); + } + else { + iv.invokespecial(superClassAsmType.getInternalName(), "", "()V", false); + } + } + + @NotNull + private static ArgumentGenerator generateThisCallImplicitArguments( + @NotNull InstructionAdapter iv, + @NotNull ExpressionCodegen codegen, + @NotNull ConstructorDescriptor delegatingConstructor, + @NotNull CallableMethod delegatingCallable, + @NotNull List delegatingParameters, + @NotNull List parameters + ) { + int offset = 1; + int index = 0; + for (; index < delegatingParameters.size(); index++) { + JvmMethodParameterKind delegatingKind = delegatingParameters.get(index).getKind(); + if (delegatingKind == JvmMethodParameterKind.VALUE) { + assert index == parameters.size() || parameters.get(index).getKind() == JvmMethodParameterKind.VALUE: + "Delegating constructor has not enough implicit parameters"; + break; + } + assert index < parameters.size() && parameters.get(index).getKind() == delegatingKind : + "Constructors of the same class should have the same set of implicit arguments"; + JvmMethodParameterSignature parameter = parameters.get(index); + + iv.load(offset, parameter.getAsmType()); + offset += parameter.getAsmType().getSize(); + } + + assert index == parameters.size() || parameters.get(index).getKind() == JvmMethodParameterKind.VALUE : + "Delegating constructor has not enough parameters"; + + return new CallBasedArgumentGenerator(codegen, codegen.defaultCallGenerator, delegatingConstructor.getValueParameters(), + delegatingCallable.getValueParameterTypes()); + } + + @NotNull + private ArgumentGenerator generateSuperCallImplicitArguments( + @NotNull InstructionAdapter iv, + @NotNull ExpressionCodegen codegen, + @NotNull ConstructorDescriptor constructorDescriptor, + @NotNull ConstructorDescriptor superConstructor, + @NotNull ResolvedCall superConstructorCall, + @NotNull CallableMethod superCallable, + @NotNull List superParameters, + @NotNull List parameters + ) { + int offset = 1; + int superIndex = 0; + + // Here we match all the super constructor parameters except those with kind VALUE to the derived constructor parameters, push + // them all onto the stack and update "offset" variable so that in the end it points to the slot of the first VALUE argument + for (JvmMethodParameterSignature parameter : parameters) { + if (superIndex >= superParameters.size()) break; + + JvmMethodParameterKind superKind = superParameters.get(superIndex).getKind(); + JvmMethodParameterKind kind = parameter.getKind(); + Type type = parameter.getAsmType(); + + if (superKind == JvmMethodParameterKind.VALUE && kind == JvmMethodParameterKind.SUPER_CALL_PARAM) { + // Stop when we reach the actual value parameters present in the code; they will be generated via ResolvedCall below + break; + } + + if (superKind == JvmMethodParameterKind.OUTER) { + assert kind == JvmMethodParameterKind.OUTER || kind == JvmMethodParameterKind.SUPER_CALL_PARAM : + String.format("Non-outer parameter incorrectly mapped to outer for %s: %s vs %s", + constructorDescriptor, parameters, superParameters); + // Super constructor requires OUTER parameter, but our OUTER instance may be different from what is expected by the super + // constructor. We need to traverse our outer classes from the bottom up, to find the needed class. See innerExtendsOuter.kt + ClassDescriptor outerForSuper = (ClassDescriptor) superConstructor.getContainingDeclaration().getContainingDeclaration(); + StackValue outer = codegen.generateThisOrOuter(outerForSuper, true, true); + outer.put(outer.type, codegen.v); + superIndex++; + } + else if (kind == JvmMethodParameterKind.SUPER_CALL_PARAM || kind == JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL) { + iv.load(offset, type); + superIndex++; + } + + offset += type.getSize(); + } + + if (isAnonymousObject(descriptor)) { + List superValues = superParameters.subList(superIndex, superParameters.size()); + return new ObjectSuperCallArgumentGenerator( + superValues, iv, + superConstructor.getValueParameters(), codegen.typeMapper, + offset, superConstructorCall + ); + } + else { + return new CallBasedArgumentGenerator(codegen, codegen.defaultCallGenerator, superConstructor.getValueParameters(), + superCallable.getValueParameterTypes()); + } + } + + private static void markLineNumberForConstructor( + @NotNull ClassConstructorDescriptor descriptor, + @Nullable KtConstructor constructor, + @NotNull ExpressionCodegen codegen + ) { + if (constructor == null) { + markLineNumberForDescriptor(descriptor.getContainingDeclaration(), codegen.v); + } + else if (constructor.hasBody() && !(constructor instanceof KtSecondaryConstructor && !((KtSecondaryConstructor) constructor).hasImplicitDelegationCall())) { + KtBlockExpression bodyExpression = constructor.getBodyExpression(); + List statements = bodyExpression != null ? bodyExpression.getStatements() : Collections.emptyList(); + if (!statements.isEmpty()) { + codegen.markStartLineNumber(statements.iterator().next()); + } + else { + codegen.markStartLineNumber(bodyExpression != null ? bodyExpression : constructor); + } + } + else { + codegen.markStartLineNumber(constructor); + } + } +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/DelegationFieldsInfo.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/DelegationFieldsInfo.java new file mode 100644 index 00000000000..5a5f2d8498f --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/DelegationFieldsInfo.java @@ -0,0 +1,113 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.codegen; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.backend.common.CodegenUtil; +import org.jetbrains.kotlin.codegen.state.GenerationState; +import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; +import org.jetbrains.kotlin.descriptors.ClassDescriptor; +import org.jetbrains.kotlin.descriptors.PropertyDescriptor; +import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry; +import org.jetbrains.kotlin.psi.KtExpression; +import org.jetbrains.kotlin.psi.KtSuperTypeListEntry; +import org.jetbrains.kotlin.resolve.BindingContext; +import org.jetbrains.kotlin.types.KotlinType; +import org.jetbrains.org.objectweb.asm.Type; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.jetbrains.kotlin.load.java.JvmAbi.DELEGATE_SUPER_FIELD_PREFIX; + +public class DelegationFieldsInfo { + private final Type classAsmType; + private final ClassDescriptor classDescriptor; + private final GenerationState state; + private final KotlinTypeMapper typeMapper; + private final BindingContext bindingContext; + + public DelegationFieldsInfo( + @NotNull Type type, + @NotNull ClassDescriptor descriptor, + @NotNull GenerationState state, + @NotNull BindingContext context + ) { + this.classAsmType = type; + this.classDescriptor = descriptor; + this.state = state; + this.typeMapper = state.getTypeMapper(); + this.bindingContext = context; + } + + public class Field { + public final Type type; + public final String name; + public final boolean generateField; + + private Field(Type type, String name, boolean generateField) { + this.type = type; + this.name = name; + this.generateField = generateField; + } + + @NotNull + public StackValue getStackValue() { + return StackValue.field(type, classAsmType, name, false, StackValue.none()); + } + } + private final Map fields = new HashMap<>(); + + @Nullable + public DelegationFieldsInfo.Field getInfo(KtDelegatedSuperTypeEntry specifier) { + DelegationFieldsInfo.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) { + fields.put(specifier, + new DelegationFieldsInfo.Field(typeMapper.mapType(propertyDescriptor), propertyDescriptor.getName().asString(), false)); + } + + private void addField(KtDelegatedSuperTypeEntry specifier, Type type, String name) { + fields.put(specifier, new DelegationFieldsInfo.Field(type, name, true)); + } + + @NotNull + public DelegationFieldsInfo getDelegationFieldsInfo(@NotNull List delegationSpecifiers) { + DelegationFieldsInfo result = new DelegationFieldsInfo(classAsmType, classDescriptor, state, bindingContext); + int n = 0; + for (KtSuperTypeListEntry specifier : delegationSpecifiers) { + if (specifier instanceof KtDelegatedSuperTypeEntry) { + KtExpression expression = ((KtDelegatedSuperTypeEntry) specifier).getDelegateExpression(); + if (expression == null) continue; + + PropertyDescriptor propertyDescriptor = CodegenUtil.getDelegatePropertyIfAny(expression, classDescriptor, bindingContext); + + + if (CodegenUtil.isFinalPropertyWithBackingField(propertyDescriptor, bindingContext)) { + result.addField((KtDelegatedSuperTypeEntry) specifier, propertyDescriptor); + } + else { + KotlinType expressionType = bindingContext.getType(expression); + ClassDescriptor superClass = JvmCodegenUtil.getSuperClass(specifier, state, bindingContext); + Type asmType = + expressionType != null ? typeMapper.mapType(expressionType) : + superClass != null ? typeMapper.mapType(superClass) : null; + + if (asmType == null) continue; + + result.addField((KtDelegatedSuperTypeEntry) specifier, asmType, DELEGATE_SUPER_FIELD_PREFIX + n); + } + n++; + } + } + return result; + } +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index d1b86024da7..168e443f535 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.config.LanguageFeature; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.incremental.components.NoLookupLocation; +import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor; import org.jetbrains.kotlin.load.kotlin.TypeMappingMode; import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader; @@ -46,8 +47,6 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature; -import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind; -import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter; import org.jetbrains.kotlin.resolve.scopes.MemberScope; @@ -71,7 +70,6 @@ import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*; import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.enumEntryNeedSubclass; import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtils2Kt.initDefaultSourceMappingIfNeeded; import static org.jetbrains.kotlin.load.java.JvmAbi.*; -import static org.jetbrains.kotlin.resolve.BindingContextUtils.getDelegationConstructorCall; import static org.jetbrains.kotlin.resolve.BindingContextUtils.getNotNull; import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration; import static org.jetbrains.kotlin.resolve.DescriptorUtils.*; @@ -101,6 +99,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { private final DescriptorSerializer serializer; + private final ConstructorCodegen constructorCodegen; + public ImplementationBodyCodegen( @NotNull KtPureClassOrObject aClass, @NotNull ClassContext context, @@ -112,7 +112,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { super(aClass, context, v, state, parentCodegen); this.classAsmType = getObjectType(typeMapper.classInternalName(descriptor)); this.isLocal = isLocal; - this.delegationFieldsInfo = getDelegationFieldsInfo(myClass.getSuperTypeListEntries()); + + this.delegationFieldsInfo = + new DelegationFieldsInfo(classAsmType, descriptor, state, bindingContext) + .getDelegationFieldsInfo(myClass.getSuperTypeListEntries()); JvmSerializerExtension extension = new JvmSerializerExtension(v.getSerializationBindings(), state); this.serializer = DescriptorSerializer.create( @@ -121,6 +124,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { ? ((ImplementationBodyCodegen) parentCodegen).serializer : DescriptorSerializer.createTopLevel(extension) ); + + this.constructorCodegen = new ConstructorCodegen( + descriptor, context, functionCodegen, this, + this, state, kind, v, classAsmType, myClass, bindingContext + ); } @Override @@ -449,9 +457,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { protected void generateConstructors() { try { lookupConstructorExpressionsInClosureIfPresent(); - generatePrimaryConstructor(delegationFieldsInfo); + constructorCodegen.generatePrimaryConstructor(delegationFieldsInfo, superClassAsmType); for (ClassConstructorDescriptor secondaryConstructor : DescriptorUtilsKt.getSecondaryConstructors(descriptor)) { - generateSecondaryConstructor(secondaryConstructor); + constructorCodegen.generateSecondaryConstructor(secondaryConstructor, superClassAsmType); } } catch (CompilationException | ProcessCanceledException e) { @@ -928,276 +936,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { field.store(property, codegen.v); } - private void generatePrimaryConstructor(DelegationFieldsInfo delegationFieldsInfo) { - if (isJvmInterface(descriptor)) return; - - ClassConstructorDescriptor constructorDescriptor = descriptor.getUnsubstitutedPrimaryConstructor(); - if (constructorDescriptor == null) return; - - ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor); - - KtPrimaryConstructor primaryConstructor = myClass.getPrimaryConstructor(); - JvmDeclarationOrigin origin = JvmDeclarationOriginKt - .OtherOrigin(primaryConstructor != null ? primaryConstructor : myClass.getPsiOrParent(), constructorDescriptor); - functionCodegen.generateMethod(origin, constructorDescriptor, constructorContext, - new FunctionGenerationStrategy.CodegenBased(state) { - @Override - public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { - generatePrimaryConstructorImpl(constructorDescriptor, codegen, delegationFieldsInfo, primaryConstructor); - } - } - ); - - functionCodegen.generateDefaultIfNeeded(constructorContext, constructorDescriptor, OwnerKind.IMPLEMENTATION, - DefaultParameterValueLoader.DEFAULT, null); - - new DefaultParameterValueSubstitutor(state).generatePrimaryConstructorOverloadsIfNeeded(constructorDescriptor, v, this, kind, myClass); - } - - private void generateSecondaryConstructor(@NotNull ClassConstructorDescriptor constructorDescriptor) { - if (!canHaveDeclaredConstructors(descriptor)) return; - - ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor); - - KtSecondaryConstructor constructor = (KtSecondaryConstructor) descriptorToDeclaration(constructorDescriptor); - - functionCodegen.generateMethod( - JvmDeclarationOriginKt.OtherOrigin(constructor, constructorDescriptor), - constructorDescriptor, constructorContext, - new FunctionGenerationStrategy.CodegenBased(state) { - @Override - public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { - generateSecondaryConstructorImpl(constructorDescriptor, codegen); - } - } - ); - - functionCodegen.generateDefaultIfNeeded(constructorContext, constructorDescriptor, OwnerKind.IMPLEMENTATION, - DefaultParameterValueLoader.DEFAULT, null); - - new DefaultParameterValueSubstitutor(state).generateOverloadsIfNeeded( - constructor, constructorDescriptor, constructorDescriptor, kind, v, this - ); - } - - private void generatePrimaryConstructorImpl( - @NotNull ClassConstructorDescriptor constructorDescriptor, - @NotNull ExpressionCodegen codegen, - @NotNull DelegationFieldsInfo fieldsInfo, - @Nullable KtPrimaryConstructor primaryConstructor - ) { - InstructionAdapter iv = codegen.v; - - markLineNumberForConstructor(constructorDescriptor, primaryConstructor, codegen); - - generateClosureInitialization(iv); - - generateDelegatorToConstructorCall(iv, codegen, constructorDescriptor, - getDelegationConstructorCall(bindingContext, constructorDescriptor)); - - for (KtSuperTypeListEntry specifier : myClass.getSuperTypeListEntries()) { - if (specifier instanceof KtDelegatedSuperTypeEntry) { - genCallToDelegatorByExpressionSpecifier(iv, codegen, (KtDelegatedSuperTypeEntry) specifier, fieldsInfo); - } - } - - int curParam = 0; - List parameters = constructorDescriptor.getValueParameters(); - for (KtParameter parameter : getPrimaryConstructorParameters()) { - if (parameter.hasValOrVar()) { - VariableDescriptor descriptor = parameters.get(curParam); - Type type = typeMapper.mapType(descriptor); - iv.load(0, classAsmType); - iv.load(codegen.myFrameMap.getIndex(descriptor), type); - PropertyDescriptor propertyDescriptor = bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter); - assert propertyDescriptor != null : "Property descriptor is not found for primary constructor parameter: " + parameter; - iv.putfield(classAsmType.getInternalName(), context.getFieldName(propertyDescriptor, false), type.getDescriptor()); - } - curParam++; - } - - //object initialization was moved to initializeObjects() - if (!isObject(descriptor)) { - generateInitializers(codegen); - } - iv.visitInsn(RETURN); - } - - private void generateSecondaryConstructorImpl( - @NotNull ClassConstructorDescriptor constructorDescriptor, - @NotNull ExpressionCodegen codegen - ) { - InstructionAdapter iv = codegen.v; - - KtSecondaryConstructor constructor = - (KtSecondaryConstructor) DescriptorToSourceUtils.descriptorToDeclaration(constructorDescriptor); - - markLineNumberForConstructor(constructorDescriptor, constructor, codegen); - - ResolvedCall constructorDelegationCall = - getDelegationConstructorCall(bindingContext, constructorDescriptor); - ConstructorDescriptor delegateConstructor = constructorDelegationCall == null ? null : - constructorDelegationCall.getResultingDescriptor(); - - generateDelegatorToConstructorCall(iv, codegen, constructorDescriptor, constructorDelegationCall); - if (!isSameClassConstructor(delegateConstructor)) { - // Initialization happens only for constructors delegating to super - generateClosureInitialization(iv); - generateInitializers(codegen); - } - - assert constructor != null; - if (constructor.hasBody()) { - codegen.gen(constructor.getBodyExpression(), Type.VOID_TYPE); - } - - iv.visitInsn(RETURN); - } - - private static void markLineNumberForConstructor( - @NotNull ClassConstructorDescriptor descriptor, - @Nullable KtConstructor constructor, - @NotNull ExpressionCodegen codegen - ) { - if (constructor == null) { - markLineNumberForDescriptor(descriptor.getContainingDeclaration(), codegen.v); - } - else if (constructor.hasBody() && !(constructor instanceof KtSecondaryConstructor && !((KtSecondaryConstructor) constructor).hasImplicitDelegationCall())) { - KtBlockExpression bodyExpression = constructor.getBodyExpression(); - List statements = bodyExpression != null ? bodyExpression.getStatements() : Collections.emptyList(); - if (!statements.isEmpty()) { - codegen.markStartLineNumber(statements.iterator().next()); - } - else { - codegen.markStartLineNumber(bodyExpression != null ? bodyExpression : constructor); - } - } - else { - codegen.markStartLineNumber(constructor); - } - } - public void generateInitializers(@NotNull ExpressionCodegen codegen) { generateInitializers(() -> codegen); } - private void generateClosureInitialization(@NotNull InstructionAdapter iv) { - MutableClosure closure = context.closure; - if (closure != null) { - List argsFromClosure = ClosureCodegen.calculateConstructorParameters(typeMapper, closure, classAsmType); - int k = 1; - for (FieldInfo info : argsFromClosure) { - k = AsmUtil.genAssignInstanceFieldFromParam(info, k, iv); - } - } - } - - private void genSimpleSuperCall(InstructionAdapter iv) { - iv.load(0, superClassAsmType); - if (descriptor.getKind() == ClassKind.ENUM_CLASS || descriptor.getKind() == ClassKind.ENUM_ENTRY) { - iv.load(1, JAVA_STRING_TYPE); - iv.load(2, Type.INT_TYPE); - iv.invokespecial(superClassAsmType.getInternalName(), "", "(Ljava/lang/String;I)V", false); - } - else { - iv.invokespecial(superClassAsmType.getInternalName(), "", "()V", false); - } - } - - private class DelegationFieldsInfo { - private class Field { - public final Type type; - public final String name; - public final boolean generateField; - - private Field(Type type, String name, boolean generateField) { - this.type = type; - this.name = name; - this.generateField = generateField; - } - - @NotNull - public StackValue getStackValue() { - return StackValue.field(type, classAsmType, name, false, StackValue.none()); - } - } - private final Map fields = new HashMap<>(); - - @Nullable - public Field getInfo(KtDelegatedSuperTypeEntry 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) { - fields.put(specifier, - new Field(typeMapper.mapType(propertyDescriptor), propertyDescriptor.getName().asString(), false)); - } - - private void addField(KtDelegatedSuperTypeEntry specifier, Type type, String name) { - fields.put(specifier, new Field(type, name, true)); - } - } - - @NotNull - private DelegationFieldsInfo getDelegationFieldsInfo(@NotNull List delegationSpecifiers) { - DelegationFieldsInfo result = new DelegationFieldsInfo(); - int n = 0; - for (KtSuperTypeListEntry specifier : delegationSpecifiers) { - if (specifier instanceof KtDelegatedSuperTypeEntry) { - KtExpression expression = ((KtDelegatedSuperTypeEntry) specifier).getDelegateExpression(); - if (expression == null) continue; - - PropertyDescriptor propertyDescriptor = CodegenUtil.getDelegatePropertyIfAny(expression, descriptor, bindingContext); - - - if (CodegenUtil.isFinalPropertyWithBackingField(propertyDescriptor, bindingContext)) { - result.addField((KtDelegatedSuperTypeEntry) specifier, propertyDescriptor); - } - else { - KotlinType expressionType = bindingContext.getType(expression); - ClassDescriptor superClass = getSuperClass(specifier); - Type asmType = - expressionType != null ? typeMapper.mapType(expressionType) : - superClass != null ? typeMapper.mapType(superClass) : null; - - if (asmType == null) continue; - - result.addField((KtDelegatedSuperTypeEntry) specifier, asmType, DELEGATE_SUPER_FIELD_PREFIX + n); - } - n++; - } - } - return result; - } - - @Nullable - private ClassDescriptor getSuperClass(@NotNull KtSuperTypeListEntry specifier) { - 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( - InstructionAdapter iv, - ExpressionCodegen codegen, - KtDelegatedSuperTypeEntry specifier, - DelegationFieldsInfo fieldsInfo - ) { - 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); - } - } - private void lookupConstructorExpressionsInClosureIfPresent() { if (!state.getClassBuilderMode().generateBodies || descriptor.getConstructors().isEmpty()) return; @@ -1374,160 +1116,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { ); } - private void generateDelegatorToConstructorCall( - @NotNull InstructionAdapter iv, - @NotNull ExpressionCodegen codegen, - @NotNull ClassConstructorDescriptor constructorDescriptor, - @Nullable ResolvedCall delegationConstructorCall - ) { - MethodContext codegenContext = codegen.context; - assert codegenContext instanceof ConstructorContext : - "Constructor context expected: " + codegenContext; - assert !((ConstructorContext) codegenContext).isThisInitialized() : - "Delegating constructor call is already generated for " + ((ConstructorContext) codegenContext).getConstructorDescriptor(); - - if (delegationConstructorCall == null) { - genSimpleSuperCall(iv); - } - else { - generateDelegationConstructorCall(iv, codegen, constructorDescriptor, delegationConstructorCall); - } - - ((ConstructorContext) codegenContext).setThisInitialized(true); - } - - private void generateDelegationConstructorCall( - @NotNull InstructionAdapter iv, - @NotNull ExpressionCodegen codegen, - @NotNull ClassConstructorDescriptor constructorDescriptor, - @NotNull ResolvedCall delegationConstructorCall - ) { - iv.load(0, OBJECT_TYPE); - ConstructorDescriptor delegateConstructor = SamCodegenUtil.resolveSamAdapter(codegen.getConstructorDescriptor(delegationConstructorCall)); - - CallableMethod delegateConstructorCallable = typeMapper.mapToCallableMethod(delegateConstructor, false); - CallableMethod callable = typeMapper.mapToCallableMethod(constructorDescriptor, false); - - List delegatingParameters = delegateConstructorCallable.getValueParameters(); - List parameters = callable.getValueParameters(); - - ArgumentGenerator argumentGenerator; - if (isSameClassConstructor(delegateConstructor)) { - // if it's the same class constructor we should just pass all synthetic parameters - argumentGenerator = - generateThisCallImplicitArguments(iv, codegen, delegateConstructor, delegateConstructorCallable, delegatingParameters, - parameters); - } - else { - argumentGenerator = - generateSuperCallImplicitArguments(iv, codegen, constructorDescriptor, delegateConstructor, delegationConstructorCall, - delegateConstructorCallable, - delegatingParameters, - parameters); - } - - codegen.invokeMethodWithArguments( - delegateConstructorCallable, delegationConstructorCall, StackValue.none(), codegen.defaultCallGenerator, argumentGenerator); - } - - private boolean isSameClassConstructor(@Nullable ConstructorDescriptor delegatingConstructor) { - return delegatingConstructor != null && delegatingConstructor.getContainingDeclaration() == descriptor; - } - - @NotNull - private ArgumentGenerator generateSuperCallImplicitArguments( - @NotNull InstructionAdapter iv, - @NotNull ExpressionCodegen codegen, - @NotNull ConstructorDescriptor constructorDescriptor, - @NotNull ConstructorDescriptor superConstructor, - @NotNull ResolvedCall superConstructorCall, - @NotNull CallableMethod superCallable, - @NotNull List superParameters, - @NotNull List parameters - ) { - int offset = 1; - int superIndex = 0; - - // Here we match all the super constructor parameters except those with kind VALUE to the derived constructor parameters, push - // them all onto the stack and update "offset" variable so that in the end it points to the slot of the first VALUE argument - for (JvmMethodParameterSignature parameter : parameters) { - if (superIndex >= superParameters.size()) break; - - JvmMethodParameterKind superKind = superParameters.get(superIndex).getKind(); - JvmMethodParameterKind kind = parameter.getKind(); - Type type = parameter.getAsmType(); - - if (superKind == JvmMethodParameterKind.VALUE && kind == JvmMethodParameterKind.SUPER_CALL_PARAM) { - // Stop when we reach the actual value parameters present in the code; they will be generated via ResolvedCall below - break; - } - - if (superKind == JvmMethodParameterKind.OUTER) { - assert kind == JvmMethodParameterKind.OUTER || kind == JvmMethodParameterKind.SUPER_CALL_PARAM : - String.format("Non-outer parameter incorrectly mapped to outer for %s: %s vs %s", - constructorDescriptor, parameters, superParameters); - // Super constructor requires OUTER parameter, but our OUTER instance may be different from what is expected by the super - // constructor. We need to traverse our outer classes from the bottom up, to find the needed class. See innerExtendsOuter.kt - ClassDescriptor outerForSuper = (ClassDescriptor) superConstructor.getContainingDeclaration().getContainingDeclaration(); - StackValue outer = codegen.generateThisOrOuter(outerForSuper, true, true); - outer.put(outer.type, codegen.v); - superIndex++; - } - else if (kind == JvmMethodParameterKind.SUPER_CALL_PARAM || kind == JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL) { - iv.load(offset, type); - superIndex++; - } - - offset += type.getSize(); - } - - if (isAnonymousObject(descriptor)) { - List superValues = superParameters.subList(superIndex, superParameters.size()); - return new ObjectSuperCallArgumentGenerator( - superValues, iv, - superConstructor.getValueParameters(), codegen.typeMapper, - offset, superConstructorCall - ); - } - else { - return new CallBasedArgumentGenerator(codegen, codegen.defaultCallGenerator, superConstructor.getValueParameters(), - superCallable.getValueParameterTypes()); - } - } - - @NotNull - private static ArgumentGenerator generateThisCallImplicitArguments( - @NotNull InstructionAdapter iv, - @NotNull ExpressionCodegen codegen, - @NotNull ConstructorDescriptor delegatingConstructor, - @NotNull CallableMethod delegatingCallable, - @NotNull List delegatingParameters, - @NotNull List parameters - ) { - int offset = 1; - int index = 0; - for (; index < delegatingParameters.size(); index++) { - JvmMethodParameterKind delegatingKind = delegatingParameters.get(index).getKind(); - if (delegatingKind == JvmMethodParameterKind.VALUE) { - assert index == parameters.size() || parameters.get(index).getKind() == JvmMethodParameterKind.VALUE: - "Delegating constructor has not enough implicit parameters"; - break; - } - assert index < parameters.size() && parameters.get(index).getKind() == delegatingKind : - "Constructors of the same class should have the same set of implicit arguments"; - JvmMethodParameterSignature parameter = parameters.get(index); - - iv.load(offset, parameter.getAsmType()); - offset += parameter.getAsmType().getSize(); - } - - assert index == parameters.size() || parameters.get(index).getKind() == JvmMethodParameterKind.VALUE : - "Delegating constructor has not enough parameters"; - - return new CallBasedArgumentGenerator(codegen, codegen.defaultCallGenerator, delegatingConstructor.getValueParameters(), - delegatingCallable.getValueParameterTypes()); - } - private void generateEnumEntries() { if (descriptor.getKind() != ClassKind.ENUM_CLASS) return; @@ -1615,7 +1203,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { generateDelegateField(field); KtExpression delegateExpression = ((KtDelegatedSuperTypeEntry) specifier).getDelegateExpression(); KotlinType delegateExpressionType = delegateExpression != null ? bindingContext.getType(delegateExpression) : null; - ClassDescriptor superClass = getSuperClass(specifier); + ClassDescriptor superClass = JvmCodegenUtil.getSuperClass(specifier, state, bindingContext); if (superClass == null) continue; generateDelegates(superClass, delegateExpressionType, field); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java index 4ed072098f5..0676dd8cade 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java @@ -11,12 +11,14 @@ import kotlin.collections.CollectionsKt; import kotlin.text.StringsKt; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.backend.common.CodegenUtil; import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor; import org.jetbrains.kotlin.codegen.binding.CalculatedClosure; import org.jetbrains.kotlin.codegen.context.CodegenContext; import org.jetbrains.kotlin.codegen.context.FacadePartWithSourceFile; import org.jetbrains.kotlin.codegen.context.MethodContext; import org.jetbrains.kotlin.codegen.context.RootContext; +import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor; @@ -29,6 +31,7 @@ import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.Call; import org.jetbrains.kotlin.psi.KtFile; import org.jetbrains.kotlin.psi.KtFunction; +import org.jetbrains.kotlin.psi.KtSuperTypeListEntry; import org.jetbrains.kotlin.psi.codeFragmentUtil.CodeFragmentUtilKt; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; @@ -363,4 +366,17 @@ public class JvmCodegenUtil { JvmCodegenUtil::isDeclarationOfBigArityFunctionInvoke ); } + + @Nullable + public static ClassDescriptor getSuperClass( + @NotNull KtSuperTypeListEntry specifier, + @NotNull GenerationState state, + @NotNull BindingContext bindingContext + ) { + ClassDescriptor superClass = CodegenUtil.getSuperClassBySuperTypeListEntry(specifier, bindingContext); + + assert superClass != null || state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES + : "ClassDescriptor should not be null:" + specifier.getText(); + return superClass; + } }