avoid coercing 'this' to a supertype; cleaner handling of stackvalues for 'this' and 'super' (KT-2395)
This commit is contained in:
@@ -127,7 +127,7 @@ public class ClosureAnnotator {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ClassDescriptor classDescriptorForScrpitDescriptor(@NotNull ScriptDescriptor scriptDescriptor) {
|
||||
public ClassDescriptor classDescriptorForScriptDescriptor(@NotNull ScriptDescriptor scriptDescriptor) {
|
||||
ClassDescriptorImpl classDescriptor = classesForFunctions.get(scriptDescriptor);
|
||||
if (classDescriptor == null) {
|
||||
throw new IllegalStateException("Class for script is not registered: " + scriptDescriptor);
|
||||
@@ -146,7 +146,7 @@ public class ClosureAnnotator {
|
||||
|
||||
@NotNull
|
||||
public JvmClassName classNameForScriptDescriptor(@NotNull ScriptDescriptor scriptDescriptor) {
|
||||
return classNameForClassDescriptor(classDescriptorForScrpitDescriptor(scriptDescriptor));
|
||||
return classNameForClassDescriptor(classDescriptorForScriptDescriptor(scriptDescriptor));
|
||||
}
|
||||
|
||||
private void mapFilesToNamespaces(Collection<JetFile> files) {
|
||||
|
||||
@@ -35,11 +35,7 @@ import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.calls.*;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ClassReceiver;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ScriptReceiver;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.*;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
|
||||
import org.jetbrains.jet.lang.types.lang.JetStandardLibraryNames;
|
||||
@@ -136,7 +132,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
assert provided instanceof ClassDescriptor;
|
||||
|
||||
if (!CodegenUtil.isInterface(provided) && CodegenUtil.isInterface(required)) {
|
||||
v.checkcast(asmType(required.getDefaultType()));
|
||||
inner.put(TYPE_OBJECT, v);
|
||||
final Type type = asmType(required.getDefaultType());
|
||||
v.checkcast(type);
|
||||
return StackValue.onStack(type);
|
||||
}
|
||||
|
||||
return inner;
|
||||
@@ -199,7 +198,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
public StackValue visitSuperExpression(JetSuperExpression expression, StackValue data) {
|
||||
final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference());
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
return generateThisOrOuter((ClassDescriptor) descriptor);
|
||||
return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor);
|
||||
}
|
||||
else {
|
||||
JetType type = context.getThisDescriptor().getDefaultType();
|
||||
@@ -1161,9 +1160,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
|
||||
if (descriptor instanceof ValueParameterDescriptor && descriptor.getContainingDeclaration() instanceof ScriptDescriptor) {
|
||||
ScriptDescriptor scriptDescriptor = (ScriptDescriptor) descriptor.getContainingDeclaration();
|
||||
JvmClassName scriptClassName = state.getInjector().getClosureAnnotator().classNameForScriptDescriptor(scriptDescriptor);
|
||||
final ClosureAnnotator closureAnnotator = state.getInjector().getClosureAnnotator();
|
||||
JvmClassName scriptClassName = closureAnnotator.classNameForScriptDescriptor(scriptDescriptor);
|
||||
ValueParameterDescriptor valueParameterDescriptor = (ValueParameterDescriptor) descriptor;
|
||||
generateThisOrOuter(state.getInjector().getClosureAnnotator().classDescriptorForScrpitDescriptor(scriptDescriptor));
|
||||
final ClassDescriptor scriptClass = closureAnnotator.classDescriptorForScriptDescriptor(scriptDescriptor);
|
||||
final StackValue script = StackValue.thisOrOuter(this, scriptClass);
|
||||
script.put(script.type, v);
|
||||
Type fieldType = typeMapper.mapType(valueParameterDescriptor.getType(), MapTypeMode.VALUE);
|
||||
return StackValue.field(fieldType, scriptClassName, valueParameterDescriptor.getName().getIdentifier(), false);
|
||||
}
|
||||
@@ -1513,27 +1515,23 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
} else {
|
||||
v.getstatic(classObjType.getInternalName(), "$classobj", exprType.getDescriptor());
|
||||
}
|
||||
StackValue.onStack(exprType).put(type, v);
|
||||
}
|
||||
else {
|
||||
generateThisOrOuter(classReceiverDeclarationDescriptor).put(exprType, v);
|
||||
StackValue.thisOrOuter(this, classReceiverDeclarationDescriptor).put(type, v);
|
||||
}
|
||||
StackValue.onStack(exprType).put(type, v);
|
||||
}
|
||||
else if (descriptor instanceof ScriptReceiver) {
|
||||
generateScript((ScriptReceiver) descriptor);
|
||||
}
|
||||
else if (descriptor instanceof ExtensionReceiver) {
|
||||
Type exprType = asmType(descriptor.getType());
|
||||
ExtensionReceiver extensionReceiver = (ExtensionReceiver) descriptor;
|
||||
generateReceiver(extensionReceiver.getDeclarationDescriptor()).put(exprType, v);
|
||||
StackValue.onStack(exprType).put(type, v);
|
||||
generateReceiver(extensionReceiver.getDeclarationDescriptor()).put(type, v);
|
||||
}
|
||||
else if (descriptor instanceof ExpressionReceiver) {
|
||||
ExpressionReceiver expressionReceiver = (ExpressionReceiver) descriptor;
|
||||
JetExpression expr = expressionReceiver.getExpression();
|
||||
Type exprType = asmType(expressionReceiver.getType());
|
||||
gen(expr, exprType);
|
||||
StackValue.onStack(exprType).put(type, v);
|
||||
gen(expr, type);
|
||||
}
|
||||
else if (descriptor instanceof AutoCastReceiver) {
|
||||
AutoCastReceiver autoCastReceiver = (AutoCastReceiver) descriptor;
|
||||
@@ -1602,25 +1600,23 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
cur = cur.getParentContext();
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException(); }
|
||||
|
||||
public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass) {
|
||||
CodegenContext cur = context;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public StackValue generateThisOrOuter(@NotNull final ClassDescriptor calleeContainingClass) {
|
||||
PsiElement psiElement = BindingContextUtils.classDescriptorToDeclaration(bindingContext, calleeContainingClass);
|
||||
boolean isObject = psiElement instanceof JetClassOrObject && CodegenUtil.isNonLiteralObject((JetClassOrObject) psiElement);
|
||||
|
||||
cur = context;
|
||||
StackValue result = StackValue.local(0, TYPE_OBJECT);
|
||||
CodegenContext cur = context;
|
||||
Type type = asmType(calleeContainingClass.getDefaultType());
|
||||
StackValue result = StackValue.local(0, type);
|
||||
while (cur != null) {
|
||||
if (cur instanceof CodegenContexts.MethodContext && !(cur instanceof CodegenContexts.ConstructorContext))
|
||||
cur = cur.getParentContext();
|
||||
|
||||
if (DescriptorUtils.isSubclass(cur.getThisDescriptor(), calleeContainingClass)) {
|
||||
Type type = asmType(calleeContainingClass.getDefaultType());
|
||||
if (!isObject || (cur.getThisDescriptor() == calleeContainingClass)) {
|
||||
result.put(TYPE_OBJECT, v);
|
||||
return castToRequiredTypeOfInterfaceIfNeeded(StackValue.onStack(type), cur.getThisDescriptor(), calleeContainingClass);
|
||||
return castToRequiredTypeOfInterfaceIfNeeded(result, cur.getThisDescriptor(), calleeContainingClass);
|
||||
}
|
||||
else {
|
||||
v.getstatic(type.getInternalName(), "$instance", type.getDescriptor());
|
||||
@@ -2697,7 +2693,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
public StackValue visitThisExpression(JetThisExpression expression, StackValue receiver) {
|
||||
final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference());
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
return generateThisOrOuter((ClassDescriptor) descriptor);
|
||||
return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor);
|
||||
}
|
||||
else {
|
||||
if (descriptor instanceof FunctionDescriptor || descriptor instanceof PropertyDescriptor) {
|
||||
|
||||
@@ -953,7 +953,7 @@ public class JetTypeMapper {
|
||||
|
||||
for (ScriptDescriptor importedScript : importedScripts) {
|
||||
signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE);
|
||||
mapType(closureAnnotator.classDescriptorForScrpitDescriptor(importedScript).getDefaultType(), signatureWriter, MapTypeMode.VALUE);
|
||||
mapType(closureAnnotator.classDescriptorForScriptDescriptor(importedScript).getDefaultType(), signatureWriter, MapTypeMode.VALUE);
|
||||
signatureWriter.writeParameterTypeEnd();
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -99,7 +98,7 @@ public class ScriptCodegen {
|
||||
|
||||
ScriptDescriptor scriptDescriptor = (ScriptDescriptor) state.getBindingContext().get(BindingContext.SCRIPT, scriptDeclaration);
|
||||
|
||||
ClassDescriptor classDescriptorForScript = closureAnnotator.classDescriptorForScrpitDescriptor(scriptDescriptor);
|
||||
ClassDescriptor classDescriptorForScript = closureAnnotator.classDescriptorForScriptDescriptor(scriptDescriptor);
|
||||
|
||||
CodegenContexts.ScriptContext context = (CodegenContexts.ScriptContext) CodegenContexts.STATIC.intoScript(scriptDescriptor, classDescriptorForScript);
|
||||
|
||||
|
||||
@@ -1087,7 +1087,8 @@ public abstract class StackValue {
|
||||
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
codegen.generateThisOrOuter(descriptor);
|
||||
final StackValue stackValue = codegen.generateThisOrOuter(descriptor);
|
||||
stackValue.put(stackValue.type, v); // no coercion here
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import java.util.AbstractList
|
||||
|
||||
class MyList(): AbstractList<String>() {
|
||||
public fun getModificationCount(): Int = modCount
|
||||
public override fun get(index: Int): String? = ""
|
||||
public override fun size(): Int = 0
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return if (MyList().getModificationCount() == 0) "OK" else "fail"
|
||||
}
|
||||
@@ -471,4 +471,9 @@ public class ClassGenTest extends CodegenTestCase {
|
||||
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY);
|
||||
blackBoxMultiFile("regressions/kt2060_1.kt", "regressions/kt2060.kt");
|
||||
}
|
||||
|
||||
public void testKt2395() {
|
||||
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY);
|
||||
blackBoxMultiFile("regressions/kt2395.kt");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user