Refactoring: extract methods about constructor codegen out
#KT-25614 In Progress
This commit is contained in:
@@ -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<ConstructorDescriptor> 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<ValueParameterDescriptor> 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<ConstructorDescriptor> 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<FieldInfo> 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<ConstructorDescriptor> 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<JvmMethodParameterSignature> delegatingParameters = delegateConstructorCallable.getValueParameters();
|
||||||
|
List<JvmMethodParameterSignature> 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(), "<init>", "(Ljava/lang/String;I)V", false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "()V", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static ArgumentGenerator generateThisCallImplicitArguments(
|
||||||
|
@NotNull InstructionAdapter iv,
|
||||||
|
@NotNull ExpressionCodegen codegen,
|
||||||
|
@NotNull ConstructorDescriptor delegatingConstructor,
|
||||||
|
@NotNull CallableMethod delegatingCallable,
|
||||||
|
@NotNull List<JvmMethodParameterSignature> delegatingParameters,
|
||||||
|
@NotNull List<JvmMethodParameterSignature> 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<ConstructorDescriptor> superConstructorCall,
|
||||||
|
@NotNull CallableMethod superCallable,
|
||||||
|
@NotNull List<JvmMethodParameterSignature> superParameters,
|
||||||
|
@NotNull List<JvmMethodParameterSignature> 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<JvmMethodParameterSignature> 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<KtExpression> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<KtDelegatedSuperTypeEntry, Field> 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<KtSuperTypeListEntry> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
|||||||
import org.jetbrains.kotlin.config.LanguageFeature;
|
import org.jetbrains.kotlin.config.LanguageFeature;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
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.java.descriptors.JavaClassDescriptor;
|
||||||
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode;
|
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode;
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader;
|
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.JvmDeclarationOrigin;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature;
|
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.jvm.jvmSignature.JvmMethodSignature;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter;
|
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
|
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.binding.CodegenBinding.enumEntryNeedSubclass;
|
||||||
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtils2Kt.initDefaultSourceMappingIfNeeded;
|
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtils2Kt.initDefaultSourceMappingIfNeeded;
|
||||||
import static org.jetbrains.kotlin.load.java.JvmAbi.*;
|
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.BindingContextUtils.getNotNull;
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
|
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
||||||
@@ -101,6 +99,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
|
|
||||||
private final DescriptorSerializer serializer;
|
private final DescriptorSerializer serializer;
|
||||||
|
|
||||||
|
private final ConstructorCodegen constructorCodegen;
|
||||||
|
|
||||||
public ImplementationBodyCodegen(
|
public ImplementationBodyCodegen(
|
||||||
@NotNull KtPureClassOrObject aClass,
|
@NotNull KtPureClassOrObject aClass,
|
||||||
@NotNull ClassContext context,
|
@NotNull ClassContext context,
|
||||||
@@ -112,7 +112,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
super(aClass, context, v, state, parentCodegen);
|
super(aClass, context, v, state, parentCodegen);
|
||||||
this.classAsmType = getObjectType(typeMapper.classInternalName(descriptor));
|
this.classAsmType = getObjectType(typeMapper.classInternalName(descriptor));
|
||||||
this.isLocal = isLocal;
|
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);
|
JvmSerializerExtension extension = new JvmSerializerExtension(v.getSerializationBindings(), state);
|
||||||
this.serializer = DescriptorSerializer.create(
|
this.serializer = DescriptorSerializer.create(
|
||||||
@@ -121,6 +124,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
? ((ImplementationBodyCodegen) parentCodegen).serializer
|
? ((ImplementationBodyCodegen) parentCodegen).serializer
|
||||||
: DescriptorSerializer.createTopLevel(extension)
|
: DescriptorSerializer.createTopLevel(extension)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.constructorCodegen = new ConstructorCodegen(
|
||||||
|
descriptor, context, functionCodegen, this,
|
||||||
|
this, state, kind, v, classAsmType, myClass, bindingContext
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -449,9 +457,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
protected void generateConstructors() {
|
protected void generateConstructors() {
|
||||||
try {
|
try {
|
||||||
lookupConstructorExpressionsInClosureIfPresent();
|
lookupConstructorExpressionsInClosureIfPresent();
|
||||||
generatePrimaryConstructor(delegationFieldsInfo);
|
constructorCodegen.generatePrimaryConstructor(delegationFieldsInfo, superClassAsmType);
|
||||||
for (ClassConstructorDescriptor secondaryConstructor : DescriptorUtilsKt.getSecondaryConstructors(descriptor)) {
|
for (ClassConstructorDescriptor secondaryConstructor : DescriptorUtilsKt.getSecondaryConstructors(descriptor)) {
|
||||||
generateSecondaryConstructor(secondaryConstructor);
|
constructorCodegen.generateSecondaryConstructor(secondaryConstructor, superClassAsmType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (CompilationException | ProcessCanceledException e) {
|
catch (CompilationException | ProcessCanceledException e) {
|
||||||
@@ -928,276 +936,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
field.store(property, codegen.v);
|
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<ValueParameterDescriptor> 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<ConstructorDescriptor> 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<KtExpression> 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) {
|
public void generateInitializers(@NotNull ExpressionCodegen codegen) {
|
||||||
generateInitializers(() -> codegen);
|
generateInitializers(() -> codegen);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateClosureInitialization(@NotNull InstructionAdapter iv) {
|
|
||||||
MutableClosure closure = context.closure;
|
|
||||||
if (closure != null) {
|
|
||||||
List<FieldInfo> 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(), "<init>", "(Ljava/lang/String;I)V", false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "()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<KtDelegatedSuperTypeEntry, Field> 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<KtSuperTypeListEntry> 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() {
|
private void lookupConstructorExpressionsInClosureIfPresent() {
|
||||||
if (!state.getClassBuilderMode().generateBodies || descriptor.getConstructors().isEmpty()) return;
|
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<ConstructorDescriptor> 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<ConstructorDescriptor> 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<JvmMethodParameterSignature> delegatingParameters = delegateConstructorCallable.getValueParameters();
|
|
||||||
List<JvmMethodParameterSignature> 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<ConstructorDescriptor> superConstructorCall,
|
|
||||||
@NotNull CallableMethod superCallable,
|
|
||||||
@NotNull List<JvmMethodParameterSignature> superParameters,
|
|
||||||
@NotNull List<JvmMethodParameterSignature> 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<JvmMethodParameterSignature> 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<JvmMethodParameterSignature> delegatingParameters,
|
|
||||||
@NotNull List<JvmMethodParameterSignature> 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() {
|
private void generateEnumEntries() {
|
||||||
if (descriptor.getKind() != ClassKind.ENUM_CLASS) return;
|
if (descriptor.getKind() != ClassKind.ENUM_CLASS) return;
|
||||||
|
|
||||||
@@ -1615,7 +1203,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
generateDelegateField(field);
|
generateDelegateField(field);
|
||||||
KtExpression delegateExpression = ((KtDelegatedSuperTypeEntry) specifier).getDelegateExpression();
|
KtExpression delegateExpression = ((KtDelegatedSuperTypeEntry) specifier).getDelegateExpression();
|
||||||
KotlinType delegateExpressionType = delegateExpression != null ? bindingContext.getType(delegateExpression) : null;
|
KotlinType delegateExpressionType = delegateExpression != null ? bindingContext.getType(delegateExpression) : null;
|
||||||
ClassDescriptor superClass = getSuperClass(specifier);
|
ClassDescriptor superClass = JvmCodegenUtil.getSuperClass(specifier, state, bindingContext);
|
||||||
if (superClass == null) continue;
|
if (superClass == null) continue;
|
||||||
|
|
||||||
generateDelegates(superClass, delegateExpressionType, field);
|
generateDelegates(superClass, delegateExpressionType, field);
|
||||||
|
|||||||
@@ -11,12 +11,14 @@ import kotlin.collections.CollectionsKt;
|
|||||||
import kotlin.text.StringsKt;
|
import kotlin.text.StringsKt;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
||||||
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor;
|
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor;
|
||||||
import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
|
import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
|
||||||
import org.jetbrains.kotlin.codegen.context.CodegenContext;
|
import org.jetbrains.kotlin.codegen.context.CodegenContext;
|
||||||
import org.jetbrains.kotlin.codegen.context.FacadePartWithSourceFile;
|
import org.jetbrains.kotlin.codegen.context.FacadePartWithSourceFile;
|
||||||
import org.jetbrains.kotlin.codegen.context.MethodContext;
|
import org.jetbrains.kotlin.codegen.context.MethodContext;
|
||||||
import org.jetbrains.kotlin.codegen.context.RootContext;
|
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.codegen.state.KotlinTypeMapper;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
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.Call;
|
||||||
import org.jetbrains.kotlin.psi.KtFile;
|
import org.jetbrains.kotlin.psi.KtFile;
|
||||||
import org.jetbrains.kotlin.psi.KtFunction;
|
import org.jetbrains.kotlin.psi.KtFunction;
|
||||||
|
import org.jetbrains.kotlin.psi.KtSuperTypeListEntry;
|
||||||
import org.jetbrains.kotlin.psi.codeFragmentUtil.CodeFragmentUtilKt;
|
import org.jetbrains.kotlin.psi.codeFragmentUtil.CodeFragmentUtilKt;
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||||
@@ -363,4 +366,17 @@ public class JvmCodegenUtil {
|
|||||||
JvmCodegenUtil::isDeclarationOfBigArityFunctionInvoke
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user