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
|
@NotNull
|
||||||
public ClassDescriptor classDescriptorForScrpitDescriptor(@NotNull ScriptDescriptor scriptDescriptor) {
|
public ClassDescriptor classDescriptorForScriptDescriptor(@NotNull ScriptDescriptor scriptDescriptor) {
|
||||||
ClassDescriptorImpl classDescriptor = classesForFunctions.get(scriptDescriptor);
|
ClassDescriptorImpl classDescriptor = classesForFunctions.get(scriptDescriptor);
|
||||||
if (classDescriptor == null) {
|
if (classDescriptor == null) {
|
||||||
throw new IllegalStateException("Class for script is not registered: " + scriptDescriptor);
|
throw new IllegalStateException("Class for script is not registered: " + scriptDescriptor);
|
||||||
@@ -146,7 +146,7 @@ public class ClosureAnnotator {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public JvmClassName classNameForScriptDescriptor(@NotNull ScriptDescriptor scriptDescriptor) {
|
public JvmClassName classNameForScriptDescriptor(@NotNull ScriptDescriptor scriptDescriptor) {
|
||||||
return classNameForClassDescriptor(classDescriptorForScrpitDescriptor(scriptDescriptor));
|
return classNameForClassDescriptor(classDescriptorForScriptDescriptor(scriptDescriptor));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mapFilesToNamespaces(Collection<JetFile> files) {
|
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.calls.*;
|
||||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||||
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
|
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.*;
|
||||||
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.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
|
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
|
||||||
import org.jetbrains.jet.lang.types.lang.JetStandardLibraryNames;
|
import org.jetbrains.jet.lang.types.lang.JetStandardLibraryNames;
|
||||||
@@ -136,7 +132,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
assert provided instanceof ClassDescriptor;
|
assert provided instanceof ClassDescriptor;
|
||||||
|
|
||||||
if (!CodegenUtil.isInterface(provided) && CodegenUtil.isInterface(required)) {
|
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;
|
return inner;
|
||||||
@@ -199,7 +198,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
public StackValue visitSuperExpression(JetSuperExpression expression, StackValue data) {
|
public StackValue visitSuperExpression(JetSuperExpression expression, StackValue data) {
|
||||||
final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference());
|
final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference());
|
||||||
if (descriptor instanceof ClassDescriptor) {
|
if (descriptor instanceof ClassDescriptor) {
|
||||||
return generateThisOrOuter((ClassDescriptor) descriptor);
|
return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
JetType type = context.getThisDescriptor().getDefaultType();
|
JetType type = context.getThisDescriptor().getDefaultType();
|
||||||
@@ -1161,9 +1160,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
|
|
||||||
if (descriptor instanceof ValueParameterDescriptor && descriptor.getContainingDeclaration() instanceof ScriptDescriptor) {
|
if (descriptor instanceof ValueParameterDescriptor && descriptor.getContainingDeclaration() instanceof ScriptDescriptor) {
|
||||||
ScriptDescriptor scriptDescriptor = (ScriptDescriptor) descriptor.getContainingDeclaration();
|
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;
|
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);
|
Type fieldType = typeMapper.mapType(valueParameterDescriptor.getType(), MapTypeMode.VALUE);
|
||||||
return StackValue.field(fieldType, scriptClassName, valueParameterDescriptor.getName().getIdentifier(), false);
|
return StackValue.field(fieldType, scriptClassName, valueParameterDescriptor.getName().getIdentifier(), false);
|
||||||
}
|
}
|
||||||
@@ -1513,27 +1515,23 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
} else {
|
} else {
|
||||||
v.getstatic(classObjType.getInternalName(), "$classobj", exprType.getDescriptor());
|
v.getstatic(classObjType.getInternalName(), "$classobj", exprType.getDescriptor());
|
||||||
}
|
}
|
||||||
|
StackValue.onStack(exprType).put(type, v);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
generateThisOrOuter(classReceiverDeclarationDescriptor).put(exprType, v);
|
StackValue.thisOrOuter(this, classReceiverDeclarationDescriptor).put(type, v);
|
||||||
}
|
}
|
||||||
StackValue.onStack(exprType).put(type, v);
|
|
||||||
}
|
}
|
||||||
else if (descriptor instanceof ScriptReceiver) {
|
else if (descriptor instanceof ScriptReceiver) {
|
||||||
generateScript((ScriptReceiver) descriptor);
|
generateScript((ScriptReceiver) descriptor);
|
||||||
}
|
}
|
||||||
else if (descriptor instanceof ExtensionReceiver) {
|
else if (descriptor instanceof ExtensionReceiver) {
|
||||||
Type exprType = asmType(descriptor.getType());
|
|
||||||
ExtensionReceiver extensionReceiver = (ExtensionReceiver) descriptor;
|
ExtensionReceiver extensionReceiver = (ExtensionReceiver) descriptor;
|
||||||
generateReceiver(extensionReceiver.getDeclarationDescriptor()).put(exprType, v);
|
generateReceiver(extensionReceiver.getDeclarationDescriptor()).put(type, v);
|
||||||
StackValue.onStack(exprType).put(type, v);
|
|
||||||
}
|
}
|
||||||
else if (descriptor instanceof ExpressionReceiver) {
|
else if (descriptor instanceof ExpressionReceiver) {
|
||||||
ExpressionReceiver expressionReceiver = (ExpressionReceiver) descriptor;
|
ExpressionReceiver expressionReceiver = (ExpressionReceiver) descriptor;
|
||||||
JetExpression expr = expressionReceiver.getExpression();
|
JetExpression expr = expressionReceiver.getExpression();
|
||||||
Type exprType = asmType(expressionReceiver.getType());
|
gen(expr, type);
|
||||||
gen(expr, exprType);
|
|
||||||
StackValue.onStack(exprType).put(type, v);
|
|
||||||
}
|
}
|
||||||
else if (descriptor instanceof AutoCastReceiver) {
|
else if (descriptor instanceof AutoCastReceiver) {
|
||||||
AutoCastReceiver autoCastReceiver = (AutoCastReceiver) descriptor;
|
AutoCastReceiver autoCastReceiver = (AutoCastReceiver) descriptor;
|
||||||
@@ -1602,25 +1600,23 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
cur = cur.getParentContext();
|
cur = cur.getParentContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new UnsupportedOperationException(); }
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass) {
|
|
||||||
CodegenContext cur = context;
|
|
||||||
|
|
||||||
|
public StackValue generateThisOrOuter(@NotNull final ClassDescriptor calleeContainingClass) {
|
||||||
PsiElement psiElement = BindingContextUtils.classDescriptorToDeclaration(bindingContext, calleeContainingClass);
|
PsiElement psiElement = BindingContextUtils.classDescriptorToDeclaration(bindingContext, calleeContainingClass);
|
||||||
boolean isObject = psiElement instanceof JetClassOrObject && CodegenUtil.isNonLiteralObject((JetClassOrObject) psiElement);
|
boolean isObject = psiElement instanceof JetClassOrObject && CodegenUtil.isNonLiteralObject((JetClassOrObject) psiElement);
|
||||||
|
|
||||||
cur = context;
|
CodegenContext cur = context;
|
||||||
StackValue result = StackValue.local(0, TYPE_OBJECT);
|
Type type = asmType(calleeContainingClass.getDefaultType());
|
||||||
|
StackValue result = StackValue.local(0, type);
|
||||||
while (cur != null) {
|
while (cur != null) {
|
||||||
if (cur instanceof CodegenContexts.MethodContext && !(cur instanceof CodegenContexts.ConstructorContext))
|
if (cur instanceof CodegenContexts.MethodContext && !(cur instanceof CodegenContexts.ConstructorContext))
|
||||||
cur = cur.getParentContext();
|
cur = cur.getParentContext();
|
||||||
|
|
||||||
if (DescriptorUtils.isSubclass(cur.getThisDescriptor(), calleeContainingClass)) {
|
if (DescriptorUtils.isSubclass(cur.getThisDescriptor(), calleeContainingClass)) {
|
||||||
Type type = asmType(calleeContainingClass.getDefaultType());
|
|
||||||
if (!isObject || (cur.getThisDescriptor() == calleeContainingClass)) {
|
if (!isObject || (cur.getThisDescriptor() == calleeContainingClass)) {
|
||||||
result.put(TYPE_OBJECT, v);
|
return castToRequiredTypeOfInterfaceIfNeeded(result, cur.getThisDescriptor(), calleeContainingClass);
|
||||||
return castToRequiredTypeOfInterfaceIfNeeded(StackValue.onStack(type), cur.getThisDescriptor(), calleeContainingClass);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
v.getstatic(type.getInternalName(), "$instance", type.getDescriptor());
|
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) {
|
public StackValue visitThisExpression(JetThisExpression expression, StackValue receiver) {
|
||||||
final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference());
|
final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference());
|
||||||
if (descriptor instanceof ClassDescriptor) {
|
if (descriptor instanceof ClassDescriptor) {
|
||||||
return generateThisOrOuter((ClassDescriptor) descriptor);
|
return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (descriptor instanceof FunctionDescriptor || descriptor instanceof PropertyDescriptor) {
|
if (descriptor instanceof FunctionDescriptor || descriptor instanceof PropertyDescriptor) {
|
||||||
|
|||||||
@@ -953,7 +953,7 @@ public class JetTypeMapper {
|
|||||||
|
|
||||||
for (ScriptDescriptor importedScript : importedScripts) {
|
for (ScriptDescriptor importedScript : importedScripts) {
|
||||||
signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE);
|
signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE);
|
||||||
mapType(closureAnnotator.classDescriptorForScrpitDescriptor(importedScript).getDefaultType(), signatureWriter, MapTypeMode.VALUE);
|
mapType(closureAnnotator.classDescriptorForScriptDescriptor(importedScript).getDefaultType(), signatureWriter, MapTypeMode.VALUE);
|
||||||
signatureWriter.writeParameterTypeEnd();
|
signatureWriter.writeParameterTypeEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ import org.objectweb.asm.Type;
|
|||||||
import org.objectweb.asm.commons.InstructionAdapter;
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -99,7 +98,7 @@ public class ScriptCodegen {
|
|||||||
|
|
||||||
ScriptDescriptor scriptDescriptor = (ScriptDescriptor) state.getBindingContext().get(BindingContext.SCRIPT, scriptDeclaration);
|
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);
|
CodegenContexts.ScriptContext context = (CodegenContexts.ScriptContext) CodegenContexts.STATIC.intoScript(scriptDescriptor, classDescriptorForScript);
|
||||||
|
|
||||||
|
|||||||
@@ -1087,7 +1087,8 @@ public abstract class StackValue {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void put(Type type, InstructionAdapter v) {
|
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);
|
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY);
|
||||||
blackBoxMultiFile("regressions/kt2060_1.kt", "regressions/kt2060.kt");
|
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