From 577fc981387c24a34531539f07484cd254c0fd67 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Tue, 30 Aug 2011 16:27:21 +0200 Subject: [PATCH 01/23] a bit more advanced instruction adapter --- .../jet/codegen/InstructionAdapterEx.java | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 idea/src/org/jetbrains/jet/codegen/InstructionAdapterEx.java diff --git a/idea/src/org/jetbrains/jet/codegen/InstructionAdapterEx.java b/idea/src/org/jetbrains/jet/codegen/InstructionAdapterEx.java new file mode 100644 index 00000000000..66f68991feb --- /dev/null +++ b/idea/src/org/jetbrains/jet/codegen/InstructionAdapterEx.java @@ -0,0 +1,111 @@ +package org.jetbrains.jet.codegen; + +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.InstructionAdapter; +import org.objectweb.asm.commons.Method; + +public class InstructionAdapterEx extends InstructionAdapter { + private static final Type BYTE_TYPE = Type.getObjectType("java/lang/Byte"); + + private static final Type BOOLEAN_TYPE = Type.getObjectType("java/lang/Boolean"); + + private static final Type SHORT_TYPE = Type.getObjectType("java/lang/Short"); + + private static final Type CHARACTER_TYPE = Type.getObjectType("java/lang/Character"); + + private static final Type INTEGER_TYPE = Type.getObjectType("java/lang/Integer"); + + private static final Type FLOAT_TYPE = Type.getObjectType("java/lang/Float"); + + private static final Type LONG_TYPE = Type.getObjectType("java/lang/Long"); + + private static final Type DOUBLE_TYPE = Type.getObjectType("java/lang/Double"); + + private static final Type NUMBER_TYPE = Type.getObjectType("java/lang/Number"); + + private static final Type OBJECT_TYPE = Type.getObjectType("java/lang/Object"); + + private static final Method BOOLEAN_VALUE = Method.getMethod("boolean booleanValue()"); + + private static final Method CHAR_VALUE = Method.getMethod("char charValue()"); + + private static final Method INT_VALUE = Method.getMethod("int intValue()"); + + private static final Method FLOAT_VALUE = Method.getMethod("float floatValue()"); + + private static final Method LONG_VALUE = Method.getMethod("long longValue()"); + + private static final Method DOUBLE_VALUE = Method.getMethod("double doubleValue()"); + + public InstructionAdapterEx(MethodVisitor methodVisitor) { + super(methodVisitor); + } + + private static Type getBoxedType(final Type type) { + switch (type.getSort()) { + case Type.BYTE: + return BYTE_TYPE; + case Type.BOOLEAN: + return BOOLEAN_TYPE; + case Type.SHORT: + return SHORT_TYPE; + case Type.CHAR: + return CHARACTER_TYPE; + case Type.INT: + return INTEGER_TYPE; + case Type.FLOAT: + return FLOAT_TYPE; + case Type.LONG: + return LONG_TYPE; + case Type.DOUBLE: + return DOUBLE_TYPE; + } + return type; + } + + public void valueOf(final Type type) { + if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { + return; + } + if (type == Type.VOID_TYPE) { + aconst(null); + } else { + Type boxed = getBoxedType(type); + invokestatic(boxed.getInternalName(), "valueOf", "(" + type.getDescriptor() + ")" + boxed.getDescriptor()); + } + } + + public void unbox(final Type type) { + Type t = NUMBER_TYPE; + Method sig = null; + switch (type.getSort()) { + case Type.VOID: + return; + case Type.CHAR: + t = CHARACTER_TYPE; + sig = CHAR_VALUE; + break; + case Type.BOOLEAN: + t = BOOLEAN_TYPE; + sig = BOOLEAN_VALUE; + break; + case Type.DOUBLE: + sig = DOUBLE_VALUE; + break; + case Type.FLOAT: + sig = FLOAT_VALUE; + break; + case Type.LONG: + sig = LONG_VALUE; + break; + case Type.INT: + case Type.SHORT: + case Type.BYTE: + sig = INT_VALUE; + } + + checkcast(t); + invokevirtual(t.getInternalName(), sig.getName(), sig.getDescriptor()); + } +} From 4f64a6c7e2d83ef6018e2a8f556c6ba093b08ee8 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Tue, 30 Aug 2011 16:28:49 +0200 Subject: [PATCH 02/23] isPrimitive method added --- .../org/jetbrains/jet/codegen/JetTypeMapper.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index ce26f8dc6dc..ddb3a463377 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -47,6 +47,19 @@ public class JetTypeMapper { return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE; } + public static boolean isPrimitive(Type type) { + return type == Type.INT_TYPE + || type == Type.SHORT_TYPE + || type == Type.BYTE_TYPE + || type == Type.CHAR_TYPE + || type == Type.SHORT_TYPE + || type == Type.FLOAT_TYPE + || type == Type.DOUBLE_TYPE + || type == Type.LONG_TYPE + || type == Type.BOOLEAN_TYPE + || type == Type.VOID_TYPE; + } + static Type psiTypeToAsm(PsiType type) { if (type instanceof PsiPrimitiveType) { if (type == PsiType.VOID) { From efba6c4cb04a9d847ce0c24667606e14034111b6 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Tue, 30 Aug 2011 16:29:35 +0200 Subject: [PATCH 03/23] workaroound for broken API between builds --- .../jet/plugin/structureView/JetStructureViewElement.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewElement.java b/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewElement.java index e398c7d605a..cba16e62868 100644 --- a/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewElement.java +++ b/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewElement.java @@ -3,6 +3,7 @@ package org.jetbrains.jet.plugin.structureView; import com.intellij.ide.structureView.StructureViewTreeElement; import com.intellij.ide.util.treeView.smartTree.TreeElement; import com.intellij.navigation.ItemPresentation; +import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.openapi.util.Iconable; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.NavigatablePsiElement; @@ -68,6 +69,11 @@ public class JetStructureViewElement implements StructureViewTreeElement { ? PsiIconUtil.getProvidersIcon(myElement, open ? Iconable.ICON_FLAG_OPEN : Iconable.ICON_FLAG_CLOSED) : null; } + + @Override + public TextAttributesKey getTextAttributesKey() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } }; } From 1b8f96e53c176dbfdc73e7fb60abf32f1c680ea5 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Tue, 30 Aug 2011 16:32:41 +0200 Subject: [PATCH 04/23] fix for KT-261 --- idea/META-INF/plugin.xml | 23 ++++++++++ idea/idea.iml | 20 ++++++++- .../jet/codegen/FunctionCodegen.java | 45 +++++++++++++++++-- .../jetbrains/jet/lang/types/JetTypeImpl.java | 2 +- idea/testData/codegen/bridge.jet | 15 +++++++ .../jet/codegen/BridgeMethodGenTest.java | 9 ++++ 6 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 idea/META-INF/plugin.xml create mode 100644 idea/testData/codegen/bridge.jet create mode 100644 idea/tests/org/jetbrains/jet/codegen/BridgeMethodGenTest.java diff --git a/idea/META-INF/plugin.xml b/idea/META-INF/plugin.xml new file mode 100644 index 00000000000..09db9b20e72 --- /dev/null +++ b/idea/META-INF/plugin.xml @@ -0,0 +1,23 @@ + + Plugin name here + short description of the plugin + 1.0 + YourCompany + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/idea/idea.iml b/idea/idea.iml index d01e54ca4d0..4c1ad0fba3d 100644 --- a/idea/idea.iml +++ b/idea/idea.iml @@ -1,16 +1,32 @@ + + + + + + + - + - + + + + + + + + + + diff --git a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 7c453ba3d0d..072be3d077a 100644 --- a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.codegen; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; @@ -7,6 +8,7 @@ import org.jetbrains.jet.lang.psi.JetDeclarationWithBody; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetNamedFunction; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.types.JetTypeImpl; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -15,6 +17,7 @@ import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.Method; import java.util.List; +import java.util.Set; /** * @author max @@ -41,15 +44,41 @@ public class FunctionCodegen { ClassContext funContext = owner.intoFunction(functionDescriptor); final JetExpression bodyExpression = f.getBodyExpression(); - generatedMethod(bodyExpression, jvmMethod, funContext, functionDescriptor.getValueParameters(), functionDescriptor.getTypeParameters()); + generatedMethod(bodyExpression, jvmMethod, funContext, functionDescriptor); + } + + private void generateBridgeMethod(Method function, Method overriden) + { + int flags = Opcodes.ACC_PUBLIC; // TODO. + + final MethodVisitor mv = v.visitMethod(flags, function.getName(), overriden.getDescriptor(), null, null); + mv.visitCode(); + + Type[] argTypes = function.getArgumentTypes(); + InstructionAdapterEx iv = new InstructionAdapterEx(mv); + iv.load(0, JetTypeMapper.TYPE_OBJECT); + for (int i = 0, reg = 1; i < argTypes.length; i++) { + Type argType = argTypes[i]; + iv.load(reg, argType); + reg += argType.getSize(); + } + + iv.invokevirtual(state.getTypeMapper().jvmName((ClassDescriptor) owner.getContextDescriptor(), OwnerKind.IMPLEMENTATION), function.getName(), function.getDescriptor()); + if(JetTypeMapper.isPrimitive(function.getReturnType()) && !JetTypeMapper.isPrimitive(overriden.getReturnType())) + iv.valueOf(function.getReturnType()); + iv.areturn(overriden.getReturnType()); + mv.visitMaxs(0, 0); + mv.visitEnd(); } private void generatedMethod(JetExpression bodyExpressions, Method jvmSignature, ClassContext context, - List paramDescrs, - List typeParameters) + FunctionDescriptor functionDescriptor) { + List paramDescrs = functionDescriptor.getValueParameters(); + List typeParameters = functionDescriptor.getTypeParameters(); + int flags = Opcodes.ACC_PUBLIC; // TODO. OwnerKind kind = context.getContextKind(); @@ -99,6 +128,16 @@ public class FunctionCodegen { } mv.visitMaxs(0, 0); mv.visitEnd(); + + Set overriddenFunctions = functionDescriptor.getOverriddenFunctions(); + if(overriddenFunctions.size() > 0) { + for (FunctionDescriptor overriddenFunction : overriddenFunctions) { + // TODO should we check params here as well? + if(!JetTypeImpl.equalTypes(overriddenFunction.getReturnType(), functionDescriptor.getReturnType(), JetTypeImpl.EMPTY_AXIOMS)) { + generateBridgeMethod(jvmSignature, state.getTypeMapper().mapSignature(overriddenFunction.getName(), overriddenFunction)); + } + } + } } } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeImpl.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeImpl.java index 202f16c9628..ac57307b37f 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeImpl.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeImpl.java @@ -17,7 +17,7 @@ import java.util.List; */ public final class JetTypeImpl extends AnnotatedImpl implements JetType { - private static final HashBiMap EMPTY_AXIOMS = HashBiMap.create(); + public static final HashBiMap EMPTY_AXIOMS = HashBiMap.create(); private final TypeConstructor constructor; private final List arguments; diff --git a/idea/testData/codegen/bridge.jet b/idea/testData/codegen/bridge.jet new file mode 100644 index 00000000000..22f30c592e1 --- /dev/null +++ b/idea/testData/codegen/bridge.jet @@ -0,0 +1,15 @@ +import java.lang.Integer + +class C { + fun f(): Any = "C f" +} + +class D() : C { + fun f(): String = "D f" +} + +fun box(): String{ + val d : C = D() + if(d.f() != "D f") return "fail f" + return "OK" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/BridgeMethodGenTest.java b/idea/tests/org/jetbrains/jet/codegen/BridgeMethodGenTest.java new file mode 100644 index 00000000000..2f89c65b0e7 --- /dev/null +++ b/idea/tests/org/jetbrains/jet/codegen/BridgeMethodGenTest.java @@ -0,0 +1,9 @@ +package org.jetbrains.jet.codegen; + +import java.util.List; + +public class BridgeMethodGenTest extends CodegenTestCase { + public void testBridgeMethod () throws Exception { + blackBoxFile("bridge.jet"); + } +} From f01c424eb5f91c548970a3af6a24e075c432bc06 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Tue, 30 Aug 2011 16:37:41 +0200 Subject: [PATCH 05/23] making line # consistent with the one showed in editor (1- instread of 0-based) --- idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java b/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java index 9609cac15a9..d8c850c488c 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java @@ -139,7 +139,7 @@ public class AnalyzingUtils { public void visitErrorElement(PsiErrorElement element) { Document document = PsiDocumentManager.getInstance(element.getProject()).getDocument(element.getContainingFile()); int offset = element.getTextRange().getStartOffset(); - int lineNumber = document.getLineNumber(offset); + int lineNumber = document.getLineNumber(offset)+1; int lineStartOffset = document.getLineStartOffset(lineNumber); int column = offset - lineStartOffset; From 1a62b8c0bd01a489916c17fe86ec0c855c79c211 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Wed, 31 Aug 2011 11:01:28 +0200 Subject: [PATCH 06/23] String.length property added --- .../codegen/intrinsics/IntrinsicMethods.java | 1 + .../jet/codegen/intrinsics/StringLength.java | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 idea/src/org/jetbrains/jet/codegen/intrinsics/StringLength.java diff --git a/idea/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java b/idea/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java index 6e4fbff5a21..402a6db487b 100644 --- a/idea/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java +++ b/idea/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java @@ -72,6 +72,7 @@ public class IntrinsicMethods { declareIntrinsicFunction("String", "plus", 1, new Concat()); declareIntrinsicStringMethods(); + declareIntrinsicProperty("String", "length", new StringLength()); } private void declareIntrinsicStringMethods() { diff --git a/idea/src/org/jetbrains/jet/codegen/intrinsics/StringLength.java b/idea/src/org/jetbrains/jet/codegen/intrinsics/StringLength.java new file mode 100644 index 00000000000..04a254df114 --- /dev/null +++ b/idea/src/org/jetbrains/jet/codegen/intrinsics/StringLength.java @@ -0,0 +1,23 @@ +package org.jetbrains.jet.codegen.intrinsics; + +import com.intellij.psi.PsiElement; +import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.JetTypeMapper; +import org.jetbrains.jet.codegen.StackValue; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.InstructionAdapter; + +import java.util.List; + +/** + * @author alex.tkachman + */ +public class StringLength implements IntrinsicMethod { + @Override + public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { + receiver.put(JetTypeMapper.TYPE_OBJECT, v); + v.invokevirtual("java/lang/String", "length", "()I"); + return StackValue.onStack(Type.INT_TYPE); + } +} From b6800059a0796044662399857eaef32f2b04a84a Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Wed, 31 Aug 2011 11:06:51 +0200 Subject: [PATCH 07/23] a bit improved diagnostic --- .../org/jetbrains/jet/lang/ErrorHandler.java | 17 +++++++++++++++-- .../jet/lang/resolve/AnalyzingUtils.java | 10 ++-------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/idea/src/org/jetbrains/jet/lang/ErrorHandler.java b/idea/src/org/jetbrains/jet/lang/ErrorHandler.java index 6bddbc45a4e..b14ce13cc5f 100644 --- a/idea/src/org/jetbrains/jet/lang/ErrorHandler.java +++ b/idea/src/org/jetbrains/jet/lang/ErrorHandler.java @@ -1,6 +1,9 @@ package org.jetbrains.jet.lang; import com.intellij.lang.ASTNode; +import com.intellij.openapi.editor.Document; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.psi.JetExpression; @@ -16,7 +19,7 @@ public class ErrorHandler { @Override public void unresolvedReference(@NotNull JetReferenceExpression referenceExpression) { throw new IllegalStateException("Unresolved reference: " + referenceExpression.getText() + - " at offset " + referenceExpression.getTextRange().getStartOffset()); + atLocation(referenceExpression)); } @Override @@ -26,7 +29,7 @@ public class ErrorHandler { @Override public void typeMismatch(@NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull JetType actualType) { - throw new IllegalStateException("Type mismatch at " + expression.getTextRange().getStartOffset() + ": inferred type is " + actualType + " but " + expectedType + " was expected"); + throw new IllegalStateException("Type mismatch " + atLocation(expression) + ": inferred type is " + actualType + " but " + expectedType + " was expected"); } @Override @@ -49,4 +52,14 @@ public class ErrorHandler { public void genericWarning(@NotNull ASTNode node, @NotNull String message) { } + + public static String atLocation(PsiElement element) { + Document document = PsiDocumentManager.getInstance(element.getProject()).getDocument(element.getContainingFile()); + int offset = element.getTextRange().getStartOffset(); + int lineNumber = document.getLineNumber(offset); + int lineStartOffset = document.getLineStartOffset(lineNumber); + int column = offset - lineStartOffset; + + return "' at line " + (lineNumber+1) + ":" + column; + } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java b/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java index d8c850c488c..81ab818390d 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java @@ -137,14 +137,8 @@ public class AnalyzingUtils { @Override public void visitErrorElement(PsiErrorElement element) { - Document document = PsiDocumentManager.getInstance(element.getProject()).getDocument(element.getContainingFile()); - int offset = element.getTextRange().getStartOffset(); - int lineNumber = document.getLineNumber(offset)+1; - int lineStartOffset = document.getLineStartOffset(lineNumber); - int column = offset - lineStartOffset; - - throw new IllegalArgumentException(element.getErrorDescription() + "; looking at " + element.getNode().getElementType() + " '" + element.getText() + "' at line " + lineNumber + ":" + column); + throw new IllegalArgumentException(element.getErrorDescription() + "; looking at " + element.getNode().getElementType() + " '" + element.getText() + ErrorHandler.atLocation(element)); } }); } -} \ No newline at end of file +} From 960aa5982229b6863dfa9e92f13b76449e9821fe Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Wed, 31 Aug 2011 12:04:07 +0200 Subject: [PATCH 08/23] fix for KT-247 --- .../jet/codegen/ExpressionCodegen.java | 42 +++++++++++++------ .../jet/codegen/InstructionAdapterEx.java | 1 + idea/testData/codegen/regressions/kt247.jet | 38 +++++++++++++++++ .../org/jetbrains/jet/codegen/Kt247Test.java | 7 ++++ 4 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 idea/testData/codegen/regressions/kt247.jet create mode 100644 idea/tests/org/jetbrains/jet/codegen/Kt247Test.java diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index df9e10521d2..7e84d329d07 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -74,7 +74,7 @@ public class ExpressionCodegen extends JetVisitor { "DOUBLE_TYPE_INFO" }; - private final InstructionAdapter v; + private final InstructionAdapterEx v; private final FrameMap myMap; private final JetTypeMapper typeMapper; private final GenerationState state; @@ -93,7 +93,7 @@ public class ExpressionCodegen extends JetVisitor { this.typeMapper = state.getTypeMapper(); this.returnType = returnType; this.state = state; - this.v = new InstructionAdapter(v); + this.v = new InstructionAdapterEx(v); this.bindingContext = state.getBindingContext(); this.context = context; this.intrinsics = state.getIntrinsics(); @@ -1039,16 +1039,24 @@ public class ExpressionCodegen extends JetVisitor { Label end = new Label(); v.dup(); v.ifnull(ifnull); - gen(expression.getSelectorExpression()); + JetType receiverType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression.getReceiverExpression()); + StackValue propValue = genQualified(StackValue.onStack(typeMapper.mapType(receiverType)), expression.getSelectorExpression()); + Type type = propValue.type; + propValue.put(type, v); + if(JetTypeMapper.isPrimitive(type) && !type.equals(Type.VOID_TYPE)) { + v.valueOf(type); + type = typeMapper.boxType(type); + } v.goTo(end); + v.mark(ifnull); - // null is already on stack here after the dup - JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression); - if (expressionType.equals(JetStandardClasses.getUnitType())) { - v.pop(); + v.pop(); + if(!propValue.type.equals(Type.VOID_TYPE)) { + v.aconst(null); } v.mark(end); - return StackValue.onStack(typeMapper.mapType(expressionType)); + + return StackValue.onStack(type); } @Override @@ -1138,10 +1146,20 @@ public class ExpressionCodegen extends JetVisitor { } private StackValue generateEquals(JetExpression left, JetExpression right, IElementType opToken) { - final Type leftType = expressionType(left); - final Type rightType = expressionType(right); - gen(left, leftType); - gen(right, rightType); + Type leftType = expressionType(left); + Type rightType = expressionType(right); + if(JetTypeMapper.isPrimitive(leftType) != JetTypeMapper.isPrimitive(rightType)) { + gen(left, leftType); + v.valueOf(leftType); + leftType = typeMapper.boxType(leftType); + gen(right, rightType); + v.valueOf(rightType); + rightType = typeMapper.boxType(rightType); + } + else { + gen(left, leftType); + gen(right, rightType); + } return generateEqualsForExpressionsOnStack(opToken, leftType, rightType); } diff --git a/idea/src/org/jetbrains/jet/codegen/InstructionAdapterEx.java b/idea/src/org/jetbrains/jet/codegen/InstructionAdapterEx.java index 66f68991feb..48c9c163486 100644 --- a/idea/src/org/jetbrains/jet/codegen/InstructionAdapterEx.java +++ b/idea/src/org/jetbrains/jet/codegen/InstructionAdapterEx.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.codegen; import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.Method; diff --git a/idea/testData/codegen/regressions/kt247.jet b/idea/testData/codegen/regressions/kt247.jet new file mode 100644 index 00000000000..49637518d25 --- /dev/null +++ b/idea/testData/codegen/regressions/kt247.jet @@ -0,0 +1,38 @@ +fun t1() : Boolean { + val s1 : String? = "sff" + val s2 : String? = null + return s1?.length == 3 && s2?.length == null +} + +fun t2() : Boolean { + val c1: C? = C(1) + val c2: C? = null + return c1?.x == 1 && c2?.x == null +} + +fun t3() { + val d: D = D("s") + System.out?.println(d?.s) + System.out?.println(d?.s == "s") //prints true + System.out?.println(d) //ok +} + +fun t4() { + val e: E? = E() + System.out?.println(e?.foo() == e) //verify error + System.out?.println(e?.foo()) //verify error +} + +fun box() : String { + if(!t1 ()) return "fail" + if(!t2 ()) return "fail" + t3() + t4() + return "OK" +} + +class C(val x: Int) +class D(val s: String) +class E() { + fun foo() = 1 +} diff --git a/idea/tests/org/jetbrains/jet/codegen/Kt247Test.java b/idea/tests/org/jetbrains/jet/codegen/Kt247Test.java new file mode 100644 index 00000000000..ba64714ddd2 --- /dev/null +++ b/idea/tests/org/jetbrains/jet/codegen/Kt247Test.java @@ -0,0 +1,7 @@ +package org.jetbrains.jet.codegen; + +public class Kt247Test extends CodegenTestCase { + public void testMe () throws Exception { + blackBoxFile("regressions/kt247.jet"); + } +} From 6bbcc281cecb99e89f5c26505d6c4d624667f382 Mon Sep 17 00:00:00 2001 From: svtk Date: Wed, 31 Aug 2011 14:43:23 +0400 Subject: [PATCH 09/23] tests for variance added; little fixes --- idea/testData/checker/Variance.jet | 40 ++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 idea/testData/checker/Variance.jet diff --git a/idea/testData/checker/Variance.jet b/idea/testData/checker/Variance.jet new file mode 100644 index 00000000000..385dd5579f6 --- /dev/null +++ b/idea/testData/checker/Variance.jet @@ -0,0 +1,40 @@ +package variance + +abstract class Consumer {} + +abstract class Producer {} + +abstract class Usual {} + +fun foo(c: Consumer, p: Producer, u: Usual) { + val c1: Consumer = c + val c2: Consumer = c1 + + val p1: Producer = p + val p2: Producer = p1 + + val u1: Usual = u + val u2: Usual = u1 +} + +//Arrays copy example +class Array(val length : Int) { + fun get(index : Int) : T { return null } + fun set(index : Int, value : T) { /* ... */ } +} + +fun copy1(from : Array, to : Array) {} + +fun copy2(from : Array, to : Array) {} + +fun copy3(from : Array, to : Array) {} + +fun copy4(from : Array, to : Array) {} + +fun f(ints: Array, any: Array, numbers: Array) { + copy1(ints, any) + copy2(ints, any) //ok + copy2(ints, numbers) + copy3(ints, numbers) + copy4(ints, numbers) //ok +} From bda26a18ff4bb8a6bb4450d8b03d2face23d1d26 Mon Sep 17 00:00:00 2001 From: svtk Date: Wed, 31 Aug 2011 14:49:42 +0400 Subject: [PATCH 10/23] little fixes --- .../jet/lang/types/JetTypeInferrer.java | 43 +++++++++---------- idea/testData/checker/infos/Autocasts.jet | 2 + 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 7a040d42388..8038f27210c 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -832,32 +832,31 @@ public class JetTypeInferrer { return expressionType; } VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(expression, context); - if (variableDescriptor == null) return expressionType; - - JetType enrichedType = null; - List possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypes(variableDescriptor)); - Collections.reverse(possibleTypes); - for (JetType possibleType: possibleTypes) { - if (semanticServices.getTypeChecker().isSubtypeOf(possibleType, context.expectedType)) { - enrichedType = possibleType; - break; + boolean appropriateTypeFound = false; + if (variableDescriptor != null) { + List possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypes(variableDescriptor)); + Collections.reverse(possibleTypes); + for (JetType possibleType : possibleTypes) { + if (semanticServices.getTypeChecker().isSubtypeOf(possibleType, context.expectedType)) { + appropriateTypeFound = true; + break; + } + } + if (!appropriateTypeFound) { + JetType notnullType = context.dataFlowInfo.getOutType(variableDescriptor); + if (notnullType != null && semanticServices.getTypeChecker().isSubtypeOf(notnullType, context.expectedType)) { + appropriateTypeFound = true; + } } } - if (enrichedType == null) { - enrichedType = context.dataFlowInfo.getOutType(variableDescriptor); - } - if (enrichedType == null) { - enrichedType = expressionType; - } - - if (!semanticServices.getTypeChecker().isSubtypeOf(enrichedType, context.expectedType)) { + if (!appropriateTypeFound) { context.trace.getErrorHandler().typeMismatch(expression, context.expectedType, expressionType); - } else { - checkAutoCast(expression, context.expectedType, variableDescriptor, context.trace); + return expressionType; } - return enrichedType; + checkAutoCast(expression, context.expectedType, variableDescriptor, context.trace); + return context.expectedType; } - + private void checkAutoCast(JetExpression expression, JetType type, VariableDescriptor variableDescriptor, BindingTrace trace) { if (variableDescriptor.isVar()) { trace.getErrorHandler().genericError(expression.getNode(), "Automatic cast to " + type + " is impossible, because variable " + variableDescriptor.getName() + " is mutable"); @@ -1470,7 +1469,7 @@ public class JetTypeInferrer { @Override public JetType visitBlockExpression(JetBlockExpression expression, TypeInferenceContext context) { - return context.services.checkType(getBlockReturnedType(context.scope, expression, context), expression, context); + return getBlockReturnedType(context.scope, expression, context); } @Override diff --git a/idea/testData/checker/infos/Autocasts.jet b/idea/testData/checker/infos/Autocasts.jet index a984f13d017..4a201ea3397 100644 --- a/idea/testData/checker/infos/Autocasts.jet +++ b/idea/testData/checker/infos/Autocasts.jet @@ -231,6 +231,8 @@ fun mergeAutocasts(a: Any?) { if (a is String && a is Any) { val i: Int = a.compareTo("") } + if (a is String && a.compareTo("") == 0) {} + if (a is String || a.compareTo("") == 0) {} } //mutability From d6a9e89175f4582f8ef96e8488f6e7f94cf6fb68 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Wed, 31 Aug 2011 13:00:03 +0200 Subject: [PATCH 11/23] fix for KT-245 --- .../jet/codegen/ExpressionCodegen.java | 2 +- idea/testData/codegen/regressions/kt245.jet | 32 +++++++++++++++++++ .../org/jetbrains/jet/codegen/Kt247Test.java | 7 ---- .../jetbrains/jet/codegen/SafeRefTest.java | 11 +++++++ 4 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 idea/testData/codegen/regressions/kt245.jet delete mode 100644 idea/tests/org/jetbrains/jet/codegen/Kt247Test.java create mode 100644 idea/tests/org/jetbrains/jet/codegen/SafeRefTest.java diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 7e84d329d07..121099053bd 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -263,7 +263,7 @@ public class ExpressionCodegen extends JetVisitor { final JetParameter loopParameter = expression.getLoopParameter(); final VariableDescriptor parameterDescriptor = bindingContext.get(BindingContext.VALUE_PARAMETER, loopParameter); JetType paramType = parameterDescriptor.getOutType(); - Type asmParamType = typeMapper.mapType(paramType); + Type asmParamType = typeMapper.boxType(typeMapper.mapType(paramType)); int iteratorVar = myMap.enterTemp(); gen(expression.getLoopRange(), loopRangeType); diff --git a/idea/testData/codegen/regressions/kt245.jet b/idea/testData/codegen/regressions/kt245.jet new file mode 100644 index 00000000000..3a40068ec94 --- /dev/null +++ b/idea/testData/codegen/regressions/kt245.jet @@ -0,0 +1,32 @@ +fun foo() { + val l = java.util.ArrayList(2) + l.add(1) + + for (el in l) {} + + //verify error "Expecting to find integer on stack" + val iterator = l.iterator() + + //another verify error "Mismatched stack types" + while (iterator?.hasNext() ?: false) { + val i = iterator?.next() + } + + //the same + if (iterator != null) { + while (iterator.hasNext()) { + val i = iterator?.next() + } + } + + //this way it works + if (iterator != null) { + while (iterator.hasNext()) { + iterator.next() //because of the bug KT-244 i can't write "val i = iterator.next()" + } + } +} + +fun box() : String { + return "OK" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/Kt247Test.java b/idea/tests/org/jetbrains/jet/codegen/Kt247Test.java deleted file mode 100644 index ba64714ddd2..00000000000 --- a/idea/tests/org/jetbrains/jet/codegen/Kt247Test.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.jetbrains.jet.codegen; - -public class Kt247Test extends CodegenTestCase { - public void testMe () throws Exception { - blackBoxFile("regressions/kt247.jet"); - } -} diff --git a/idea/tests/org/jetbrains/jet/codegen/SafeRefTest.java b/idea/tests/org/jetbrains/jet/codegen/SafeRefTest.java new file mode 100644 index 00000000000..69d6dc16648 --- /dev/null +++ b/idea/tests/org/jetbrains/jet/codegen/SafeRefTest.java @@ -0,0 +1,11 @@ +package org.jetbrains.jet.codegen; + +public class SafeRefTest extends CodegenTestCase { + public void test247 () throws Exception { + blackBoxFile("regressions/kt247.jet"); + } + + public void test245 () throws Exception { + blackBoxFile("regressions/kt245.jet"); + } +} From 13ca1ea274141baa95500f3bd4c4be6f6e611ed6 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Wed, 31 Aug 2011 13:58:26 +0200 Subject: [PATCH 12/23] added test for KT-242 --- idea/testData/codegen/regressions/kt242.jet | 19 +++++++++++++++++++ .../jet/codegen/PrimitiveTypesTest.java | 4 +++- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 idea/testData/codegen/regressions/kt242.jet diff --git a/idea/testData/codegen/regressions/kt242.jet b/idea/testData/codegen/regressions/kt242.jet new file mode 100644 index 00000000000..4e2de93cff3 --- /dev/null +++ b/idea/testData/codegen/regressions/kt242.jet @@ -0,0 +1,19 @@ +fun box() : String { + val i: Int? = 7 + val j: Int? = null + val k = 7 + + //verify errors + if (i == 7) {} + if (7 == i) {} + + if (j == 7) {} + if (7 == j) {} + + if (i == k) {} + if (k == i) {} + + if (j == k) {} + if (k == j) {} + return "OK" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java b/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java index 71369d938f8..029166cd9f6 100644 --- a/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java @@ -259,5 +259,7 @@ public class PrimitiveTypesTest extends CodegenTestCase { assertEquals(expected, main.invoke(null, arg1, arg2)); } - + public void testKt242 () throws Exception { + blackBoxFile("regressions/kt242.jet"); + } } From 38146e1600573d2a26abbe560e546b3a92c7fd4e Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Wed, 31 Aug 2011 14:06:53 +0200 Subject: [PATCH 13/23] added test for KT-239 --- idea/testData/codegen/regressions/kt239.jet | 3 +++ idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java | 4 ++++ 2 files changed, 7 insertions(+) create mode 100644 idea/testData/codegen/regressions/kt239.jet diff --git a/idea/testData/codegen/regressions/kt239.jet b/idea/testData/codegen/regressions/kt239.jet new file mode 100644 index 00000000000..ca9e1cc1d5e --- /dev/null +++ b/idea/testData/codegen/regressions/kt239.jet @@ -0,0 +1,3 @@ +fun box(i: Int?) { + val j = i?.plus(3) //verify error +} diff --git a/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java b/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java index 029166cd9f6..adc0bd15095 100644 --- a/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java @@ -262,4 +262,8 @@ public class PrimitiveTypesTest extends CodegenTestCase { public void testKt242 () throws Exception { blackBoxFile("regressions/kt242.jet"); } + + public void testKt239 () throws Exception { + blackBoxFile("regressions/kt242.jet"); + } } From 778ba44c644b95a4e806869f81ffbc63e016f1ac Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Wed, 31 Aug 2011 14:16:09 +0200 Subject: [PATCH 14/23] added test for KT-232 --- idea/testData/codegen/regressions/kt232.jet | 10 ++++++++++ idea/tests/org/jetbrains/jet/codegen/SafeRefTest.java | 4 ++++ 2 files changed, 14 insertions(+) create mode 100644 idea/testData/codegen/regressions/kt232.jet diff --git a/idea/testData/codegen/regressions/kt232.jet b/idea/testData/codegen/regressions/kt232.jet new file mode 100644 index 00000000000..c356e429d72 --- /dev/null +++ b/idea/testData/codegen/regressions/kt232.jet @@ -0,0 +1,10 @@ +class A() { + fun foo() { + System.out?.println(1) + } +} + +fun box() : String { + val a : A = A() + return "OK" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/SafeRefTest.java b/idea/tests/org/jetbrains/jet/codegen/SafeRefTest.java index 69d6dc16648..76c4e191086 100644 --- a/idea/tests/org/jetbrains/jet/codegen/SafeRefTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/SafeRefTest.java @@ -8,4 +8,8 @@ public class SafeRefTest extends CodegenTestCase { public void test245 () throws Exception { blackBoxFile("regressions/kt245.jet"); } + + public void test232 () throws Exception { + blackBoxFile("regressions/kt232.jet"); + } } From 628f5a5232c5eaa96ca3d7bad0dfa918caf35711 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Wed, 31 Aug 2011 15:53:54 +0200 Subject: [PATCH 15/23] added test for KT-238 --- .../jet/codegen/ExpressionCodegen.java | 8 ++- .../org/jetbrains/jet/codegen/StackValue.java | 1 + idea/testData/codegen/regressions/kt238.jet | 58 +++++++++++++++++++ .../jet/codegen/ArrayGetTestCase.java | 7 +++ .../jet/codegen/CodegenTestCase.java | 6 +- 5 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 idea/testData/codegen/regressions/kt238.jet create mode 100644 idea/tests/org/jetbrains/jet/codegen/ArrayGetTestCase.java diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 121099053bd..7217beb58a5 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1262,7 +1262,7 @@ public class ExpressionCodegen extends JetVisitor { private StackValue generateAssignmentExpression(JetBinaryExpression expression) { StackValue stackValue = gen(expression.getLeft()); - genToJVMStack(expression.getRight()); + gen(expression.getRight(), stackValue.type); stackValue.store(v); return StackValue.none(); } @@ -1507,8 +1507,10 @@ public class ExpressionCodegen extends JetVisitor { throw new UnsupportedOperationException("unknown accessor type"); } boolean isGetter = accessor.getSignature().getName().equals("get"); - return StackValue.collectionElement(JetTypeMapper.TYPE_OBJECT, isGetter ? accessor : null, - isGetter ? null : accessor); + return StackValue.collectionElement( + isGetter ? accessor.getSignature().getReturnType() : accessor.getSignature().getArgumentTypes()[1], + isGetter ? accessor : null, + isGetter ? null : accessor); } } diff --git a/idea/src/org/jetbrains/jet/codegen/StackValue.java b/idea/src/org/jetbrains/jet/codegen/StackValue.java index 6ddb6eff631..17248b5c6f0 100644 --- a/idea/src/org/jetbrains/jet/codegen/StackValue.java +++ b/idea/src/org/jetbrains/jet/codegen/StackValue.java @@ -422,6 +422,7 @@ public abstract class StackValue { throw new UnsupportedOperationException("no getter specified"); } getter.invoke(v); + coerce(type, v); } @Override diff --git a/idea/testData/codegen/regressions/kt238.jet b/idea/testData/codegen/regressions/kt238.jet new file mode 100644 index 00000000000..d890c1aea61 --- /dev/null +++ b/idea/testData/codegen/regressions/kt238.jet @@ -0,0 +1,58 @@ +fun t1 () { + val a1 = Array(1) + a1[0] = "0" //ok + val s = a1[0] //ok +} + +fun t2 () { + val a2 = Array(1) + a2[0] = 0 //ok + var i = a2[0] //ok +} + +fun t3 () { + val a3 = Array(1) + a3[0] = 0 //verify error + var j = a3[0] //ok + var k : Int = a3[0] ?: 5 //ok +} + +fun t4 () { + val b1 = StrangeIntArray(10) + b1[4] = 5 //ok + var i = b1[1] //ok +} + +fun t5 () { + val b2 = StrangeArray(10, 0) + b2.set(4, 5) //ok + b2[4] = 5 //verify error + var i = b2.get(2) //ok + i = b2[1] //verify error +} + +fun t6() { + val b3 = StrangeArray(10, 0) + b3.set(5, 6) //ok + b3[4] = 5 //verify error + val v = b3[1] //ok +} + +fun box() : String { + return "OK" +} + +class StrangeArray(size: Int, private var defaultValue: T) { + fun get(index: Int): T = defaultValue + fun set(index: Int, v: T) { + defaultValue = v + } +} + +class StrangeIntArray(size: Int) { + private var defaultValue = 0 + fun get(index: Int): Int = defaultValue + fun set(index: Int, v: Int) { + defaultValue = v + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/ArrayGetTestCase.java b/idea/tests/org/jetbrains/jet/codegen/ArrayGetTestCase.java new file mode 100644 index 00000000000..689dfc6294b --- /dev/null +++ b/idea/tests/org/jetbrains/jet/codegen/ArrayGetTestCase.java @@ -0,0 +1,7 @@ +package org.jetbrains.jet.codegen; + +public class ArrayGetTestCase extends CodegenTestCase { + public void testKt238 () throws Exception { + blackBoxFile("regressions/kt238.jet"); + } +} diff --git a/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java b/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java index 54d0a7947c9..b9ac1380d91 100644 --- a/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java +++ b/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java @@ -89,9 +89,9 @@ public abstract class CodegenTestCase extends LightCodeInsightFixtureTestCase { final JetNamespace namespace = jetFile.getRootNamespace(); String fqName = NamespaceCodegen.getJVMClassName(namespace.getFQName()).replace("/", "."); Class namespaceClass = loader.loadClass(fqName); - Method method = namespaceClass.getMethod("box"); - return (String) method.invoke(null); - } + Method method = namespaceClass.getMethod("box"); + return (String) method.invoke(null); + } protected String generateToText() { GenerationState state = new GenerationState(getProject(), true); From 6fcd36f9bd2a08c55c9f08db673d443c277b5b7f Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Wed, 31 Aug 2011 17:42:12 +0200 Subject: [PATCH 16/23] added test for KT-243 --- .../jet/codegen/ExpressionCodegen.java | 22 ++++++++++++------- .../jetbrains/jet/codegen/JetTypeMapper.java | 6 +++++ idea/testData/codegen/regressions/kt243.jet | 8 +++++++ ...GetTestCase.java => ArrayGenTestCase.java} | 2 +- .../jet/codegen/PrimitiveTypesTest.java | 4 ++++ 5 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 idea/testData/codegen/regressions/kt243.jet rename idea/tests/org/jetbrains/jet/codegen/{ArrayGetTestCase.java => ArrayGenTestCase.java} (71%) diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 7217beb58a5..26b45bb9f5f 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -731,15 +731,21 @@ public class ExpressionCodegen extends JetVisitor { } } else if (descriptor instanceof ClassDescriptor) { - final JetClassObject classObject = ((JetClass) declaration).getClassObject(); - if (classObject == null) { - throw new UnsupportedOperationException("trying to reference a class which doesn't have a class object"); + if(declaration instanceof JetClass) { + final JetClassObject classObject = ((JetClass) declaration).getClassObject(); + if (classObject == null) { + throw new UnsupportedOperationException("trying to reference a class which doesn't have a class object"); + } + final String type = typeMapper.jvmName(classObject); + return StackValue.field(Type.getObjectType(type), + typeMapper.jvmName((ClassDescriptor) descriptor, OwnerKind.IMPLEMENTATION), + "$classobj", + true); + } + else { + // todo ? + return StackValue.none(); } - final String type = typeMapper.jvmName(classObject); - return StackValue.field(Type.getObjectType(type), - typeMapper.jvmName((ClassDescriptor) descriptor, OwnerKind.IMPLEMENTATION), - "$classobj", - true); } else if (descriptor instanceof TypeParameterDescriptor) { loadTypeParameterTypeInfo((TypeParameterDescriptor) descriptor); diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index ddb3a463377..5713d75b728 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -24,6 +24,7 @@ public class JetTypeMapper { public static final Type TYPE_OBJECT = Type.getObjectType("java/lang/Object"); public static final Type TYPE_TYPEINFO = Type.getType(TypeInfo.class); public static final Type TYPE_JET_OBJECT = Type.getType(JetObject.class); + public static final Type TYPE_CLASS = Type.getType(Class.class); private final JetStandardLibrary standardLibrary; private final BindingContext bindingContext; @@ -61,6 +62,11 @@ public class JetTypeMapper { } static Type psiTypeToAsm(PsiType type) { + if(type instanceof PsiArrayType) { + PsiArrayType psiArrayType = (PsiArrayType) type; + return Type.getType("[" + psiTypeToAsm(psiArrayType.getComponentType()).getDescriptor()); + } + if (type instanceof PsiPrimitiveType) { if (type == PsiType.VOID) { return Type.VOID_TYPE; diff --git a/idea/testData/codegen/regressions/kt243.jet b/idea/testData/codegen/regressions/kt243.jet new file mode 100644 index 00000000000..1e96f08fe50 --- /dev/null +++ b/idea/testData/codegen/regressions/kt243.jet @@ -0,0 +1,8 @@ +fun box() : String { + val t = java.lang.String.copyValueOf(java.lang.String("s").toCharArray()) + val i = java.lang.Integer.MAX_VALUE + val j = java.lang.Integer.valueOf(15) + val s = java.lang.String.valueOf(1) + val l = java.util.Collections.emptyList() + return "OK" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/ArrayGetTestCase.java b/idea/tests/org/jetbrains/jet/codegen/ArrayGenTestCase.java similarity index 71% rename from idea/tests/org/jetbrains/jet/codegen/ArrayGetTestCase.java rename to idea/tests/org/jetbrains/jet/codegen/ArrayGenTestCase.java index 689dfc6294b..36153e29568 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ArrayGetTestCase.java +++ b/idea/tests/org/jetbrains/jet/codegen/ArrayGenTestCase.java @@ -1,6 +1,6 @@ package org.jetbrains.jet.codegen; -public class ArrayGetTestCase extends CodegenTestCase { +public class ArrayGenTestCase extends CodegenTestCase { public void testKt238 () throws Exception { blackBoxFile("regressions/kt238.jet"); } diff --git a/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java b/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java index adc0bd15095..41a81f3713e 100644 --- a/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java @@ -266,4 +266,8 @@ public class PrimitiveTypesTest extends CodegenTestCase { public void testKt239 () throws Exception { blackBoxFile("regressions/kt242.jet"); } + + public void testKt243 () throws Exception { + blackBoxFile("regressions/kt243.jet"); + } } From 60d8ada2163563ee9c70b0ad177318892d3bf67c Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Wed, 31 Aug 2011 19:16:07 +0200 Subject: [PATCH 17/23] added test for KT-248 --- idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java | 4 ++-- idea/testData/codegen/regressions/kt248.jet | 7 +++++++ .../org/jetbrains/jet/codegen/PrimitiveTypesTest.java | 4 ++++ 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 idea/testData/codegen/regressions/kt248.jet diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 26b45bb9f5f..b7b1a4a3d9b 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1613,7 +1613,7 @@ public class ExpressionCodegen extends JetVisitor { if (!(descriptor instanceof ClassDescriptor)) { throw new UnsupportedOperationException("don't know how to handle non-class types in as/as?"); } - Type type = typeMapper.mapType(jetType, OwnerKind.INTERFACE); + Type type = typeMapper.boxType(typeMapper.mapType(jetType, OwnerKind.INTERFACE)); generateInstanceOf(StackValue.expression(OBJECT_TYPE, expression.getLeft(), this), jetType, true); Label isInstance = new Label(); v.ifne(isInstance); @@ -1739,7 +1739,7 @@ public class ExpressionCodegen extends JetVisitor { if (leaveExpressionOnStack) { v.dup(); } - Type type = typeMapper.mapType(jetType, OwnerKind.INTERFACE); + Type type = typeMapper.boxType(typeMapper.mapType(jetType, OwnerKind.INTERFACE)); v.instanceOf(type); } } diff --git a/idea/testData/codegen/regressions/kt248.jet b/idea/testData/codegen/regressions/kt248.jet new file mode 100644 index 00000000000..0607b21341f --- /dev/null +++ b/idea/testData/codegen/regressions/kt248.jet @@ -0,0 +1,7 @@ +fun box() : String { + val b = true as? Boolean //exception + val i = 1 as Int //exception + val j = 1 as Int? //ok + val s = "s" as String //ok + return "OK" +} diff --git a/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java b/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java index 41a81f3713e..389d6be3b04 100644 --- a/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java @@ -270,4 +270,8 @@ public class PrimitiveTypesTest extends CodegenTestCase { public void testKt243 () throws Exception { blackBoxFile("regressions/kt243.jet"); } + + public void testKt248 () throws Exception { + blackBoxFile("regressions/kt248.jet"); + } } From ec31f991c004c843411504a6dc2b369dc7104fed Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Wed, 31 Aug 2011 22:02:05 +0400 Subject: [PATCH 18/23] 1 as Byte typechecks fine --- .../jet/lang/types/JetTypeInferrer.java | 79 +++++++++++++++---- idea/testData/checker/Constants.jet | 8 ++ 2 files changed, 70 insertions(+), 17 deletions(-) create mode 100644 idea/testData/checker/Constants.jet diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 8038f27210c..f4a58ef411e 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -7,6 +7,7 @@ import com.google.common.collect.Sets; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; @@ -952,6 +953,11 @@ public class JetTypeInferrer { if (newTrace == trace) return this; return new TypeInferenceContext(newTrace, scope, preferBlock, dataFlowInfo, expectedType, expectedReturnType); } + + public TypeInferenceContext replaceExpectedTypeAndTrace(@NotNull JetType newExpectedType, @NotNull BindingTrace newTrace) { + if (newExpectedType == expectedType && newTrace == trace) return this; + return new TypeInferenceContext(newTrace, scope, preferBlock, dataFlowInfo, newExpectedType, expectedReturnType); + } } private class TypeInferrerVisitor extends JetVisitor { @@ -1301,35 +1307,74 @@ public class JetTypeInferrer { @Override public JetType visitBinaryWithTypeRHSExpression(JetBinaryExpressionWithTypeRHS expression, TypeInferenceContext context) { - IElementType operationType = expression.getOperationSign().getReferencedNameElementType(); - JetType actualType = getType(context.scope, expression.getLeft(), false, context.replaceExpectedType(NO_EXPECTED_TYPE)); JetTypeReference right = expression.getRight(); - JetType result = null; + JetType result = null; if (right != null) { JetType targetType = context.typeResolver.resolveType(context.scope, right); - if (operationType == JetTokens.COLON) { - if (actualType != null && !semanticServices.getTypeChecker().isSubtypeOf(actualType, targetType)) { - context.trace.getErrorHandler().typeMismatch(expression.getLeft(), targetType, actualType); + + if (isTypeFlexible(expression.getLeft())) { + TemporaryBindingTrace temporaryTraceWithExpectedType = new TemporaryBindingTrace(context.trace.getBindingContext()); + boolean success = checkBinaryWithTypeRHS(expression, context, targetType, targetType, temporaryTraceWithExpectedType); + if (success) { + temporaryTraceWithExpectedType.addAllMyDataTo(context.trace); + } + else { + TemporaryBindingTrace temporaryTraceWithoutExpectedType = new TemporaryBindingTrace(context.trace.getBindingContext()); + checkBinaryWithTypeRHS(expression, context, targetType, NO_EXPECTED_TYPE, temporaryTraceWithoutExpectedType); + temporaryTraceWithoutExpectedType.addAllMyDataTo(context.trace); } - result = targetType; - } - else if (operationType == JetTokens.AS_KEYWORD) { - checkForCastImpossibility(expression, actualType, targetType, context); - result = targetType; - } - else if (operationType == JetTokens.AS_SAFE) { - checkForCastImpossibility(expression, actualType, targetType, context); - result = TypeUtils.makeNullable(targetType); } else { - context.trace.getErrorHandler().genericError(expression.getOperationSign().getNode(), "Unsupported binary operation"); + TemporaryBindingTrace temporaryTraceWithoutExpectedType = new TemporaryBindingTrace(context.trace.getBindingContext()); + checkBinaryWithTypeRHS(expression, context, targetType, NO_EXPECTED_TYPE, temporaryTraceWithoutExpectedType); + temporaryTraceWithoutExpectedType.addAllMyDataTo(context.trace); } + + IElementType operationType = expression.getOperationSign().getReferencedNameElementType(); + result = operationType == JetTokens.AS_SAFE ? TypeUtils.makeNullable(targetType) : targetType; + } + else { + getType(context.scope, expression.getLeft(), false, context.replaceExpectedType(NO_EXPECTED_TYPE)); } return context.services.checkType(result, expression, context); } + private boolean isTypeFlexible(@Nullable JetExpression expression) { + if (expression == null) return false; + + return TokenSet.create( + JetNodeTypes.INTEGER_CONSTANT, + JetNodeTypes.FLOAT_CONSTANT + ).contains(expression.getNode().getElementType()); + } + + private boolean checkBinaryWithTypeRHS(JetBinaryExpressionWithTypeRHS expression, TypeInferenceContext context, @NotNull JetType targetType, @NotNull JetType expectedType, TemporaryBindingTrace temporaryTrace) { + TypeInferenceContext newContext = context.replaceExpectedTypeAndTrace(expectedType, temporaryTrace); + + JetType actualType = getType(context.scope, expression.getLeft(), false, newContext); + if (actualType == null) return false; + + JetSimpleNameExpression operationSign = expression.getOperationSign(); + IElementType operationType = operationSign.getReferencedNameElementType(); + if (operationType == JetTokens.COLON) { + if (targetType != NO_EXPECTED_TYPE && !semanticServices.getTypeChecker().isSubtypeOf(actualType, targetType)) { + context.trace.getErrorHandler().typeMismatch(expression.getLeft(), targetType, actualType); + return false; + } + return true; + } + else if (operationType == JetTokens.AS_KEYWORD || operationType == JetTokens.AS_SAFE) { + checkForCastImpossibility(expression, actualType, targetType, context); + return true; + } + else { + context.trace.getErrorHandler().genericError(operationSign.getNode(), "Unsupported binary operation"); + return false; + } + } + private void checkForCastImpossibility(JetBinaryExpressionWithTypeRHS expression, JetType actualType, JetType targetType, TypeInferenceContext context) { - if (actualType == null) return; + if (actualType == null || targetType == NO_EXPECTED_TYPE) return; JetTypeChecker typeChecker = semanticServices.getTypeChecker(); if (!typeChecker.isSubtypeOf(targetType, actualType)) { diff --git a/idea/testData/checker/Constants.jet b/idea/testData/checker/Constants.jet new file mode 100644 index 00000000000..d1b647b8fa3 --- /dev/null +++ b/idea/testData/checker/Constants.jet @@ -0,0 +1,8 @@ +fun test() { + 1 : Byte + 1 : Int + 1 : Double + 1 as Byte + 1 as Int + 1 as Double +} \ No newline at end of file From 9e9959f9530097f542ac3f6e2e9ce247c19942fd Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Wed, 31 Aug 2011 23:15:00 +0200 Subject: [PATCH 19/23] fix for for KT-259 --- idea/testData/codegen/regressions/kt259.jet | 20 +++++++++++++++++++ .../jetbrains/jet/codegen/TypeInfoTest.java | 5 +++++ stdlib/src/jet/typeinfo/TypeInfo.java | 2 +- 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 idea/testData/codegen/regressions/kt259.jet diff --git a/idea/testData/codegen/regressions/kt259.jet b/idea/testData/codegen/regressions/kt259.jet new file mode 100644 index 00000000000..d2ca498a3b9 --- /dev/null +++ b/idea/testData/codegen/regressions/kt259.jet @@ -0,0 +1,20 @@ +class A() {} +class B() {} + +fun box() : String { + val a = A() + System.out?.println(a is A) //true + System.out?.println(a is A?) //true + + val b = B() + System.out?.println(b is B) //true + System.out?.println(b is B?) //false !!! + + val v = b as B //ok + val u = b as B? //TypeCastException + + val w : B? = b as B //ok + val x = w as B? //TypeCastException + + return "OK" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java index d440c3abd22..d4843618aa9 100644 --- a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java @@ -128,5 +128,10 @@ public class TypeInfoTest extends CodegenTestCase { } }; } + + public void testKt259() throws Exception { + blackBoxFile("regressions/kt259.jet"); + } + } diff --git a/stdlib/src/jet/typeinfo/TypeInfo.java b/stdlib/src/jet/typeinfo/TypeInfo.java index 56607c87bbf..ec93f487468 100644 --- a/stdlib/src/jet/typeinfo/TypeInfo.java +++ b/stdlib/src/jet/typeinfo/TypeInfo.java @@ -49,7 +49,7 @@ public class TypeInfo implements JetObject { if (!theClass.isAssignableFrom(other.theClass)) { return false; } - if (nullable && !other.nullable) { + if (!nullable && other.nullable) { return false; } if (typeParameters != null) { From 475b15aacab3533d3f6cda3c1f06c601b837071c Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Thu, 1 Sep 2011 14:01:05 +0200 Subject: [PATCH 20/23] fixes bugs in TypeInfo --- .../jet/codegen/ExpressionCodegen.java | 17 +++++- .../jet/lang/types/JetTypeInferrer.java | 3 +- idea/testData/codegen/regressions/kt259.jet | 58 +++++++++++++++++-- stdlib/src/jet/typeinfo/TypeInfo.java | 36 ++++++++---- 4 files changed, 96 insertions(+), 18 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index b7b1a4a3d9b..d4140c3c47d 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1740,7 +1740,22 @@ public class ExpressionCodegen extends JetVisitor { v.dup(); } Type type = typeMapper.boxType(typeMapper.mapType(jetType, OwnerKind.INTERFACE)); - v.instanceOf(type); + if(jetType.isNullable()) { + Label nope = new Label(); + Label end = new Label(); + + v.dup(); + v.ifnull(nope); + v.instanceOf(type); + v.goTo(end); + v.mark(nope); + v.pop(); + v.aconst(1); + v.mark(end); + } + else { + v.instanceOf(type); + } } } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index f4a58ef411e..cb44761b03e 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -11,6 +11,7 @@ import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; +import org.jetbrains.jet.lang.ErrorHandler; import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; import org.jetbrains.jet.lang.descriptors.*; @@ -1708,7 +1709,7 @@ public class JetTypeInferrer { return; } if (TypeUtils.intersect(semanticServices.getTypeChecker(), Sets.newHashSet(type, subjectType)) == null) { - context.trace.getErrorHandler().genericError(reportErrorOn.getNode(), "Incompatible types: " + type + " and " + subjectType); // TODO : message + context.trace.getErrorHandler().genericError(reportErrorOn.getNode(), "Incompatible types: " + type + " and " + subjectType + " " + ErrorHandler.atLocation(reportErrorOn)); } } diff --git a/idea/testData/codegen/regressions/kt259.jet b/idea/testData/codegen/regressions/kt259.jet index d2ca498a3b9..e4a1b9099d8 100644 --- a/idea/testData/codegen/regressions/kt259.jet +++ b/idea/testData/codegen/regressions/kt259.jet @@ -1,20 +1,66 @@ class A() {} -class B() {} +class B() { + fun isT (a : Any?) : Boolean { + return a is T + } +} -fun box() : String { +fun t1() : Boolean { val a = A() - System.out?.println(a is A) //true - System.out?.println(a is A?) //true + if(a !is A) return false + if(a !is A?) return false + if(null !is A?) return false + return true +} +fun t2 () : Boolean { val b = B() - System.out?.println(b is B) //true - System.out?.println(b is B?) //false !!! + if(b !is B) return false + if(b !is B?) return false + if(null !is B?) return false val v = b as B //ok val u = b as B? //TypeCastException val w : B? = b as B //ok val x = w as B? //TypeCastException + return true +} +fun t3 () : Boolean { + val b = B() + if(!b.isT("aaa")) return false + + if(b.isT(10)) return false + if(b.isT(null)) return false + + val d = B() + if(!d.isT("aaa")) return false + if(d.isT(10)) return false + if(!d.isT(null)) return false + + val c = B() + if(c.isT("aaa")) return false + if(!c.isT(10)) return false + if(c.isT(null)) return false + + val e = B() + if(e.isT("aaa")) return false + if(!e.isT(10)) return false + if(!e.isT(null)) return false + + return true +} + +fun box() : String { + if(!t1()) { + return "t1 failed" + } + if(!t2()) { + return "t2 failed" + } + if(!t3()) { + return "t3 failed" + } return "OK" } \ No newline at end of file diff --git a/stdlib/src/jet/typeinfo/TypeInfo.java b/stdlib/src/jet/typeinfo/TypeInfo.java index ec93f487468..55f848c7b2c 100644 --- a/stdlib/src/jet/typeinfo/TypeInfo.java +++ b/stdlib/src/jet/typeinfo/TypeInfo.java @@ -40,25 +40,28 @@ public class TypeInfo implements JetObject { public boolean isInstance(Object obj) { if (obj instanceof JetObject) { - return isSubtypeOf(((JetObject) obj).getTypeInfo()); + return ((JetObject) obj).getTypeInfo().isSubtypeOf(this); } - throw new UnsupportedOperationException(); // TODO + if(obj == null) + return nullable; + + return theClass.isAssignableFrom(obj.getClass()); // TODO } - public boolean isSubtypeOf(TypeInfo other) { - if (!theClass.isAssignableFrom(other.theClass)) { + public boolean isSubtypeOf(TypeInfo superType) { + if (!superType.theClass.isAssignableFrom(theClass)) { return false; } - if (!nullable && other.nullable) { + if (nullable && !superType.nullable) { return false; } if (typeParameters != null) { - if (other.typeParameters == null || other.typeParameters.length != typeParameters.length) { + if (superType.typeParameters == null || superType.typeParameters.length != typeParameters.length) { throw new IllegalArgumentException("inconsistent type infos for the same class"); } for (int i = 0; i < typeParameters.length; i++) { // TODO handle variance here - if (!typeParameters [i].equals(other.typeParameters [i])) { + if (!typeParameters [i].equals(superType.typeParameters [i])) { return false; } } @@ -95,9 +98,22 @@ public class TypeInfo implements JetObject { @Override public int hashCode() { - int result = theClass.hashCode(); - result = 31 * result + (typeParameters != null ? Arrays.hashCode(typeParameters) : 0); - return result; + return 31 * theClass.hashCode() + (typeParameters != null ? Arrays.hashCode(typeParameters) : 0); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder().append(theClass.getName()); + if(typeParameters != null && typeParameters.length != 0) { + sb.append("<"); + for(int i = 0; i != typeParameters.length-1; ++i) { + sb.append(typeParameters[i].toString()).append(","); + } + sb.append(typeParameters[typeParameters.length - 1].toString()).append(">"); + } + if(nullable) + sb.append("?"); + return sb.toString(); } public static final TypeInfo BYTE_TYPE_INFO = new TypeInfo(Byte.class, false); From 47222c7474e186dc1c05b7f32eea5eb2ab0b76af Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Thu, 1 Sep 2011 16:45:40 +0200 Subject: [PATCH 21/23] fix for KT-257 --- .../jet/codegen/ExpressionCodegen.java | 8 +++++--- idea/testData/codegen/regressions/kt257.jet | 20 +++++++++++++++++++ .../jet/codegen/PropertyGenTest.java | 4 ++++ 3 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 idea/testData/codegen/regressions/kt257.jet diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index d4140c3c47d..f0609efca0f 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -725,7 +725,8 @@ public class ExpressionCodegen extends JetVisitor { if (receiver == StackValue.none()) { receiver = generateThisOrOuter((ClassDescriptor) propertyDescriptor.getContainingDeclaration()); } - receiver.put(JetTypeMapper.TYPE_OBJECT, v); + JetType receiverType = bindingContext.get(BindingContext.EXPRESSION_TYPE, r); + receiver.put(receiverType != null ? typeMapper.mapType(receiverType) : JetTypeMapper.TYPE_OBJECT, v); } return iValue; } @@ -772,7 +773,8 @@ public class ExpressionCodegen extends JetVisitor { public StackValue intermediateValueForProperty(PropertyDescriptor propertyDescriptor, final boolean forceField, boolean forceInterface) { DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); boolean isStatic = containingDeclaration instanceof NamespaceDescriptorImpl; - propertyDescriptor = propertyDescriptor.getOriginal(); + while(propertyDescriptor != propertyDescriptor.getOriginal()) + propertyDescriptor = propertyDescriptor.getOriginal(); final JetType outType = propertyDescriptor.getOutType(); boolean isInsideClass = !forceInterface && containingDeclaration == contextType(); Method getter; @@ -797,7 +799,7 @@ public class ExpressionCodegen extends JetVisitor { isInterface = !(containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor) containingDeclaration).isObject()); } - return StackValue.property(propertyDescriptor.getName(), owner, typeMapper.mapType(outType), isStatic, isInterface, getter, setter); + return StackValue.property(propertyDescriptor.getName(), owner, typeMapper.mapType(propertyDescriptor.getOutType()), isStatic, isInterface, getter, setter); } @Override diff --git a/idea/testData/codegen/regressions/kt257.jet b/idea/testData/codegen/regressions/kt257.jet new file mode 100644 index 00000000000..3a965795a2c --- /dev/null +++ b/idea/testData/codegen/regressions/kt257.jet @@ -0,0 +1,20 @@ +class A(var t: T) {} +class B(val r: R) {} + +fun box() : String { + val ai = A(1) + val aai = A>(ai) + if(aai.t.t != 1) return "fail" + + aai.t.t = 2 + if(aai.t.t != 2) return "fail" + + if(ai.t != 2) return "fail" + if(aai.t != ai) return "fail" + if(aai.t !== ai) return "fail" + + val abi = A>(B(1)) + if(abi.t.r != 1) return "fail" + + return "OK" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java b/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java index 28ab6b95901..f6621b37e98 100644 --- a/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java @@ -130,4 +130,8 @@ public class PropertyGenTest extends CodegenTestCase { final Class aClass = loadClass("Foo", codegens); assertNotNull(aClass.getMethod("getX")); } + + public void testKt257 () throws Exception { + blackBoxFile("regressions/kt257.jet"); + } } From 049c29677f4456eccbc4c6438bcf390ff9248f39 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 2 Sep 2011 12:28:10 +0400 Subject: [PATCH 22/23] For-related descriptors stored --- .../jet/lang/resolve/BindingContext.java | 2 + .../jet/lang/types/JetTypeInferrer.java | 128 ++++-------------- 2 files changed, 32 insertions(+), 98 deletions(-) diff --git a/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java index ef21ee997f0..6991fa672fa 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -20,6 +20,8 @@ public interface BindingContext { WritableSlice TYPE = ManyMapSlices.createSimpleSlice("TYPE"); WritableSlice EXPRESSION_TYPE = new BasicWritableSlice("EXPRESSION_TYPE", RewritePolicy.DO_NOTHING); WritableSlice REFERENCE_TARGET = new BasicWritableSlice("REFERENCE_TARGET", RewritePolicy.DO_NOTHING); + WritableSlice LOOP_RANGE_ITERATOR = ManyMapSlices.createSimpleSlice("LOOP_RANGE_ITERATOR"); + WritableSlice LOOP_RANGE_HAS_NEXT = ManyMapSlices.createSimpleSlice("LOOP_RANGE_HAS_NEXT"); WritableSlice AUTOCAST = ManyMapSlices.createSimpleSlice("AUTOCAST"); WritableSlice RESOLUTION_SCOPE = ManyMapSlices.createSimpleSlice("RESOLUTION_SCOPE"); diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index cb44761b03e..f5f6c5d0dd5 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -29,6 +29,8 @@ import org.jetbrains.jet.util.WritableSlice; import java.util.*; +import static org.jetbrains.jet.lang.resolve.BindingContext.LOOP_RANGE_HAS_NEXT; +import static org.jetbrains.jet.lang.resolve.BindingContext.LOOP_RANGE_ITERATOR; import static org.jetbrains.jet.lang.resolve.BindingContext.STATEMENT; /** @@ -2028,7 +2030,7 @@ public class JetTypeInferrer { } JetType expectedParameterType = null; if (loopRangeType != null) { - expectedParameterType = checkIterableConvention(loopRangeType, loopRange.getNode(), context); + expectedParameterType = checkIterableConvention(loopRangeType, loopRange, context); } WritableScope loopScope = newWritableScopeImpl(context.scope, context.trace).setDebugName("Scope with for-loop index"); @@ -2063,12 +2065,19 @@ public class JetTypeInferrer { } @Nullable - private JetType checkIterableConvention(@NotNull JetType type, @NotNull ASTNode reportErrorsOn, TypeInferenceContext context) { + private JetType checkIterableConvention(@NotNull JetType type, @NotNull JetExpression loopRange, TypeInferenceContext context) { + ASTNode reportErrorsOn = loopRange.getNode(); OverloadResolutionResult iteratorResolutionResult = context.services.resolveNoParametersFunction(type, context.scope, "iterator"); if (iteratorResolutionResult.isSuccess()) { - JetType iteratorType = iteratorResolutionResult.getFunctionDescriptor().getReturnType(); - boolean hasNextFunctionSupported = checkHasNextFunctionSupport(reportErrorsOn, iteratorType, context); - boolean hasNextPropertySupported = checkHasNextPropertySupport(reportErrorsOn, iteratorType, context); + FunctionDescriptor iteratorFunction = iteratorResolutionResult.getFunctionDescriptor(); + + context.trace.record(LOOP_RANGE_ITERATOR, loopRange, iteratorFunction); + + JetType iteratorType = iteratorFunction.getReturnType(); + FunctionDescriptor hasNextFunction = checkHasNextFunctionSupport(loopRange, iteratorType, context); + boolean hasNextFunctionSupported = hasNextFunction != null; + VariableDescriptor hasNextProperty = checkHasNextPropertySupport(loopRange, iteratorType, context); + boolean hasNextPropertySupported = hasNextProperty != null; if (hasNextFunctionSupported && hasNextPropertySupported && !ErrorUtils.isErrorType(iteratorType)) { // TODO : overload resolution rules impose priorities here??? context.trace.getErrorHandler().genericError(reportErrorsOn, "An ambiguity between 'iterator().hasNext()' function and 'iterator().hasNext()' property"); @@ -2076,6 +2085,9 @@ public class JetTypeInferrer { else if (!hasNextFunctionSupported && !hasNextPropertySupported) { context.trace.getErrorHandler().genericError(reportErrorsOn, "Loop range must have an 'iterator().hasNext()' function or an 'iterator().hasNext' property"); } + else { + context.trace.record(LOOP_RANGE_HAS_NEXT, loopRange, hasNextFunctionSupported ? hasNextFunction : hasNextProperty); + } OverloadResolutionResult nextResolutionResult = context.services.resolveNoParametersFunction(iteratorType, context.scope, "next"); if (nextResolutionResult.isAmbiguity()) { @@ -2096,122 +2108,42 @@ public class JetTypeInferrer { return null; } - private boolean checkHasNextFunctionSupport(@NotNull ASTNode reportErrorsOn, @NotNull JetType iteratorType, TypeInferenceContext context) { + @Nullable + private FunctionDescriptor checkHasNextFunctionSupport(@NotNull JetExpression loopRange, @NotNull JetType iteratorType, TypeInferenceContext context) { OverloadResolutionResult hasNextResolutionResult = context.services.resolveNoParametersFunction(iteratorType, context.scope, "hasNext"); if (hasNextResolutionResult.isAmbiguity()) { - context.trace.getErrorHandler().genericError(reportErrorsOn, "Method 'iterator().hasNext()' is ambiguous for this expression"); + context.trace.getErrorHandler().genericError(loopRange.getNode(), "Method 'iterator().hasNext()' is ambiguous for this expression"); } else if (hasNextResolutionResult.isNothing()) { - return false; + return null; } else { + assert hasNextResolutionResult.isSuccess(); JetType hasNextReturnType = hasNextResolutionResult.getFunctionDescriptor().getReturnType(); if (!isBoolean(hasNextReturnType)) { - context.trace.getErrorHandler().genericError(reportErrorsOn, "The 'iterator().hasNext()' method of the loop range must return Boolean, but returns " + hasNextReturnType); + context.trace.getErrorHandler().genericError(loopRange.getNode(), "The 'iterator().hasNext()' method of the loop range must return Boolean, but returns " + hasNextReturnType); } } - return true; + return hasNextResolutionResult.getFunctionDescriptor(); } - private boolean checkHasNextPropertySupport(@NotNull ASTNode reportErrorsOn, @NotNull JetType iteratorType, TypeInferenceContext context) { + @Nullable + private VariableDescriptor checkHasNextPropertySupport(@NotNull JetExpression loopRange, @NotNull JetType iteratorType, TypeInferenceContext context) { VariableDescriptor hasNextProperty = iteratorType.getMemberScope().getVariable("hasNext"); // TODO :extension properties if (hasNextProperty == null) { - return false; + return null; } else { JetType hasNextReturnType = hasNextProperty.getOutType(); if (hasNextReturnType == null) { // TODO : accessibility - context.trace.getErrorHandler().genericError(reportErrorsOn, "The 'iterator().hasNext' property of the loop range must be readable"); + context.trace.getErrorHandler().genericError(loopRange.getNode(), "The 'iterator().hasNext' property of the loop range must be readable"); } else if (!isBoolean(hasNextReturnType)) { - context.trace.getErrorHandler().genericError(reportErrorsOn, "The 'iterator().hasNext' property of the loop range must return Boolean, but returns " + hasNextReturnType); + context.trace.getErrorHandler().genericError(loopRange.getNode(), "The 'iterator().hasNext' property of the loop range must return Boolean, but returns " + hasNextReturnType); } } - return true; + return hasNextProperty; } -// @Override -// public void visitNewExpression(JetNewExpression expression) { -// // TODO : type argument inference -// JetTypeReference typeReference = expression.getTypeReference(); -// if (typeReference != null) { -// result = checkTypeInitializerCall(scope, typeReference, expression); -// } -// } - -// private void resolveCallWithExplicitName(@NotNull JetScope scope, JetExpression receiver, String functionName, List resolvedTypeArguments, List valueArguments) { -// -// boolean someNamed = false; -// boolean allNamed = true; -// for (ValueArgumentPsi valueArgument : valueArguments) { -// if (valueArgument.isNamed()) { -// context.trace.getErrorHandler().genericError(valueArgument.asElement().getNode(), "Named arguments are not supported"); -// someNamed = true; -// } -// else { -// allNamed = false; -// } -// } -// if (someNamed) { -// return; // TODO -// } -// if (someNamed && !allNamed) { -// // TODO function literals outside parentheses -// } -// -// ErrorHandlerWithRegions errorHandler = context.trace.getErrorHandler(); -// -// // 1. resolve 'receiver' in 'scope' with expected type 'NO_EXPECTED_TYPE' -// errorHandler.openRegion(); -// JetType receiverType = JetTypeInferrer.this.getType(scope, receiver, false, NO_EXPECTED_TYPE); -// // for each applicable function in 'receiverType' -// Set allFunctions = receiverType.getMemberScope().getFunctionGroup(functionName).getFunctionDescriptors(); -// Map> applicableFunctions = Maps.newHashMap(); -// int typeArgCount = resolvedTypeArguments.size(); -// int valueArgCount = valueArguments.size(); -// for (FunctionDescriptor functionDescriptor : allFunctions) { -// if (typeArgCount == 0 || functionDescriptor.getTypeParameters().size() == typeArgCount) { -// if (FunctionDescriptorUtil.getMinimumArity(functionDescriptor) <= valueArgCount && -// valueArgCount <= FunctionDescriptorUtil.getMaximumArity(functionDescriptor)) { -// // get expected types for value parameters -// if (typeArgCount > 0) { -// FunctionDescriptor substitutedFunctionDescriptor = FunctionDescriptorUtil.substituteFunctionDescriptor(resolvedTypeArguments, functionDescriptor); -// } -// else { -// FunctionDescriptor substitutedFunctionDescriptor = FunctionDescriptorUtil.substituteFunctionDescriptor(TypeUtils.getDefaultTypes(functionDescriptor.getTypeParameters()), functionDescriptor); -// List valueArgumentTypes = getArgumentTypes(substitutedFunctionDescriptor, valueArguments); -// if (valueArgumentTypes == null) { -// Map noExpectedTypes = Maps.newHashMap(); -// for (TypeParameterDescriptor typeParameterDescriptor : functionDescriptor.getTypeParameters()) { -// noExpectedTypes.put(typeParameterDescriptor.getTypeConstructor(), new TypeProjection(NO_EXPECTED_TYPE)); -// } -// substitutedFunctionDescriptor = functionDescriptor.substitute(TypeSubstitutor.create(noExpectedTypes)); -// valueArgumentTypes = getArgumentTypes(substitutedFunctionDescriptor, valueArguments); -// } -// if (valueArgumentTypes != null) { -// List typeArguments = solveConstraintSystem(functionDescriptor, valueArgumentTypes, expectedReturnType); -// if (typeArguments != null) { -// applicableFunctions.put(functionDescriptor, typeArguments); -// } -// } -// } -// // type-check the parameters -// // if something was found (one or many options -// errorHandler.closeAndCommitCurrentRegion(); -// // otherwise -// errorHandler.closeAndReturnCurrentRegion(); -// -// } -// } -// } -// // get expected types for value parameters -// // type-check the parameters -// // if something was found (one or many options -// errorHandler.closeAndCommitCurrentRegion(); -// // otherwise -// errorHandler.closeAndReturnCurrentRegion(); -// -// } - @Override public JetType visitHashQualifiedExpression(JetHashQualifiedExpression expression, TypeInferenceContext context) { context.trace.getErrorHandler().genericError(expression.getOperationTokenNode(), "Unsupported"); From 496d3e472d255e2422e5bf869866eb13f43621e7 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 2 Sep 2011 12:33:53 +0400 Subject: [PATCH 23/23] LOOP_RANGE_NEXT --- .idea/projectCodeStyle.xml | 21 ++++++++++--------- .../jet/lang/resolve/BindingContext.java | 1 + .../jet/lang/types/JetTypeInferrer.java | 8 +++---- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/.idea/projectCodeStyle.xml b/.idea/projectCodeStyle.xml index 4169b3f2f33..25b91e81484 100644 --- a/.idea/projectCodeStyle.xml +++ b/.idea/projectCodeStyle.xml @@ -51,16 +51,6 @@