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 @@
-
-
-
-
-
-
-
-
-
-
@@ -151,6 +141,17 @@
+
+
+
+
+
+
+
+
+
+
+
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/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java
index 9b288b7e33d..3ec9cf112a7 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();
@@ -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);
@@ -725,21 +725,28 @@ 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;
}
}
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);
@@ -766,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;
@@ -791,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
@@ -1039,16 +1047,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 +1154,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);
}
@@ -1244,7 +1270,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();
}
@@ -1490,8 +1516,10 @@ public class ExpressionCodegen extends JetVisitor {
throw new UnsupportedOperationException("unknown accessor type: " + declaration);
}
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);
}
}
@@ -1588,7 +1616,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);
@@ -1714,8 +1742,23 @@ public class ExpressionCodegen extends JetVisitor {
if (leaveExpressionOnStack) {
v.dup();
}
- Type type = typeMapper.mapType(jetType, OwnerKind.INTERFACE);
- v.instanceOf(type);
+ Type type = typeMapper.boxType(typeMapper.mapType(jetType, OwnerKind.INTERFACE));
+ 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/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 extends FunctionDescriptor> 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/codegen/InstructionAdapterEx.java b/idea/src/org/jetbrains/jet/codegen/InstructionAdapterEx.java
new file mode 100644
index 00000000000..48c9c163486
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/codegen/InstructionAdapterEx.java
@@ -0,0 +1,112 @@
+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;
+
+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());
+ }
+}
diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java
index ce26f8dc6dc..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;
@@ -47,7 +48,25 @@ 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 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/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/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);
+ }
+}
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 9609cac15a9..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);
- 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
+}
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/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java
index 50e08f25544..f53eabef481 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.*;
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;
@@ -30,8 +31,7 @@ import org.jetbrains.jet.util.slicedmap.WritableSlice;
import java.util.*;
-import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
-import static org.jetbrains.jet.lang.resolve.BindingContext.STATEMENT;
+import static org.jetbrains.jet.lang.resolve.BindingContext.*;
/**
* @author abreslav
@@ -622,6 +622,11 @@ public class JetTypeInferrer {
return newContext(newTrace, scope, dataFlowInfo, expectedType, expectedReturnType);
}
+ public TypeInferenceContext replaceExpectedTypeAndTrace(@NotNull JetType newExpectedType, @NotNull BindingTrace newTrace) {
+ if (newExpectedType == expectedType && newTrace == trace) return this;
+ return newContext(newTrace, scope, dataFlowInfo, newExpectedType, expectedReturnType);
+ }
+
@NotNull
public TypeInferenceContext replaceScope(@NotNull JetScope newScope) {
if (newScope == scope) return this;
@@ -1046,35 +1051,74 @@ public class JetTypeInferrer {
@Override
public JetType visitBinaryWithTypeRHSExpression(JetBinaryExpressionWithTypeRHS expression, TypeInferenceContext context) {
- IElementType operationType = expression.getOperationSign().getReferencedNameElementType();
- JetType actualType = getType(expression.getLeft(), context.replaceExpectedType(NO_EXPECTED_TYPE).replaceScope(context.scope));
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)) {
@@ -1214,7 +1258,7 @@ public class JetTypeInferrer {
@Override
public JetType visitBlockExpression(JetBlockExpression expression, TypeInferenceContext context) {
- return context.services.checkType(context.services.getBlockReturnedType(context.scope, expression, CoercionStrategy.NO_COERCION, context), expression, context);
+ return context.services.getBlockReturnedType(context.scope, expression, CoercionStrategy.NO_COERCION, context);
}
@Override
@@ -1412,7 +1456,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));
}
}
@@ -1731,7 +1775,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");
@@ -1766,12 +1810,19 @@ public class JetTypeInferrer {
}
@Nullable
- private JetType checkIterableConvention(@NotNull JetType type, @NotNull ASTNode reportErrorsOn, TypeInferenceContext context) {
- OverloadResolutionResult iteratorResolutionResult = context.services.callResolver.resolveExactSignature(context.scope, type, "iterator", Collections.emptyList());
+ 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.getDescriptor().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");
@@ -1779,6 +1830,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.callResolver.resolveExactSignature(context.scope, iteratorType, "next", Collections.emptyList());
if (nextResolutionResult.isAmbiguity()) {
@@ -1786,7 +1840,9 @@ public class JetTypeInferrer {
} else if (nextResolutionResult.isNothing()) {
context.trace.getErrorHandler().genericError(reportErrorsOn, "Loop range must have an 'iterator().next()' method");
} else {
- return nextResolutionResult.getDescriptor().getReturnType();
+ FunctionDescriptor nextFunction = nextResolutionResult.getFunctionDescriptor();
+ context.trace.record(LOOP_RANGE_NEXT, loopRange, nextFunction);
+ return nextFunction.getReturnType();
}
}
else {
@@ -1799,37 +1855,40 @@ public class JetTypeInferrer {
return null;
}
- private boolean checkHasNextFunctionSupport(@NotNull ASTNode reportErrorsOn, @NotNull JetType iteratorType, TypeInferenceContext context) {
- OverloadResolutionResult hasNextResolutionResult = context.services.callResolver.resolveExactSignature(context.scope, iteratorType, "hasNext", Collections.emptyList());
+ @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 {
- JetType hasNextReturnType = hasNextResolutionResult.getDescriptor().getReturnType();
+ 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
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.
+ }
};
}
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
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
+}
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
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/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/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/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/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/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/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/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/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/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/testData/codegen/regressions/kt259.jet b/idea/testData/codegen/regressions/kt259.jet
new file mode 100644
index 00000000000..e4a1b9099d8
--- /dev/null
+++ b/idea/testData/codegen/regressions/kt259.jet
@@ -0,0 +1,66 @@
+class A() {}
+class B() {
+ fun isT (a : Any?) : Boolean {
+ return a is T
+ }
+}
+
+fun t1() : Boolean {
+ val a = A()
+ 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()
+ 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/idea/tests/org/jetbrains/jet/codegen/ArrayGenTestCase.java b/idea/tests/org/jetbrains/jet/codegen/ArrayGenTestCase.java
new file mode 100644
index 00000000000..36153e29568
--- /dev/null
+++ b/idea/tests/org/jetbrains/jet/codegen/ArrayGenTestCase.java
@@ -0,0 +1,7 @@
+package org.jetbrains.jet.codegen;
+
+public class ArrayGenTestCase extends CodegenTestCase {
+ public void testKt238 () throws Exception {
+ blackBoxFile("regressions/kt238.jet");
+ }
+}
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");
+ }
+}
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);
diff --git a/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java b/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java
index 71369d938f8..389d6be3b04 100644
--- a/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java
+++ b/idea/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java
@@ -259,5 +259,19 @@ public class PrimitiveTypesTest extends CodegenTestCase {
assertEquals(expected, main.invoke(null, arg1, arg2));
}
+ public void testKt242 () throws Exception {
+ blackBoxFile("regressions/kt242.jet");
+ }
+ public void testKt239 () throws Exception {
+ blackBoxFile("regressions/kt242.jet");
+ }
+
+ public void testKt243 () throws Exception {
+ blackBoxFile("regressions/kt243.jet");
+ }
+
+ public void testKt248 () throws Exception {
+ blackBoxFile("regressions/kt248.jet");
+ }
}
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");
+ }
}
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..76c4e191086
--- /dev/null
+++ b/idea/tests/org/jetbrains/jet/codegen/SafeRefTest.java
@@ -0,0 +1,15 @@
+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");
+ }
+
+ public void test232 () throws Exception {
+ blackBoxFile("regressions/kt232.jet");
+ }
+}
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..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);