Merge remote branch 'origin/master'

Conflicts:
	idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java
	idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java
This commit is contained in:
Andrey Breslav
2011-09-02 13:26:38 +04:00
37 changed files with 855 additions and 109 deletions
+11 -10
View File
@@ -51,16 +51,6 @@
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
<option name="USE_RELATIVE_INDENTS" value="false" />
</ADDITIONAL_INDENT_OPTIONS>
<ADDITIONAL_INDENT_OPTIONS fileType="java">
<option name="INDENT_SIZE" value="4" />
<option name="CONTINUATION_INDENT_SIZE" value="8" />
<option name="TAB_SIZE" value="4" />
<option name="USE_TAB_CHARACTER" value="false" />
<option name="SMART_TABS" value="false" />
<option name="LABEL_INDENT_SIZE" value="0" />
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
<option name="USE_RELATIVE_INDENTS" value="false" />
</ADDITIONAL_INDENT_OPTIONS>
<ADDITIONAL_INDENT_OPTIONS fileType="js">
<option name="INDENT_SIZE" value="4" />
<option name="CONTINUATION_INDENT_SIZE" value="8" />
@@ -151,6 +141,17 @@
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
<option name="USE_RELATIVE_INDENTS" value="false" />
</ADDITIONAL_INDENT_OPTIONS>
<codeStyleSettings language="JAVA">
<option name="ELSE_ON_NEW_LINE" value="true" />
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
<option name="ALIGN_MULTILINE_BINARY_OPERATION" value="true" />
<option name="ALIGN_MULTILINE_TERNARY_OPERATION" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="5" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="IF_BRACE_FORCE" value="1" />
<option name="PARENT_SETTINGS_INSTALLED" value="true" />
<indentOptions />
</codeStyleSettings>
<codeStyleSettings language="JavaScript">
<option name="ELSE_ON_NEW_LINE" value="true" />
<option name="ALIGN_MULTILINE_BINARY_OPERATION" value="true" />
+23
View File
@@ -0,0 +1,23 @@
<idea-plugin version="2">
<name>Plugin name here</name>
<description>short description of the plugin</description>
<version>1.0</version>
<vendor>YourCompany</vendor>
<idea-version since-build="8000"/>
<application-components>
<!-- Add your application components here -->
</application-components>
<project-components>
<!-- Add your project components here -->
</project-components>
<actions>
<!-- Add your actions here -->
</actions>
<extensions defaultExtensionNs="com.intellij">
<!-- Add your extensions here -->
</extensions>
</idea-plugin>
+18 -2
View File
@@ -1,16 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PLUGIN_MODULE" version="4">
<component name="DevKit.ModuleBuildProperties" url="file://$MODULE_DIR$/src/META-INF/plugin.xml" />
<component name="EclipseModuleManager">
<libelement value="jar://$MODULE_DIR$/../lib/asm-util-3.3.1.jar!/" />
<src_description expected_position="1">
<src_folder value="file://$MODULE_DIR$/src" expected_position="1" />
<src_folder value="file://$MODULE_DIR$/tests" expected_position="2" />
</src_description>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
</content>
<orderEntry type="jdk" jdkName="IDEA 10.x" jdkType="IDEA JDK" />
<orderEntry type="jdk" jdkName="IDEA IC-108.1043" jdkType="IDEA JDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="asm" level="project" />
<orderEntry type="module" module-name="stdlib" />
<orderEntry type="module-library">
<library name="asm-util-3.3.1.jar">
<CLASSES>
<root url="jar://$MODULE_DIR$/../lib/asm-util-3.3.1.jar!/" />
<root url="jar://$USER_HOME$/IdeaProjects/untitled/lib/asm-util-3.3.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
</component>
</module>
@@ -74,7 +74,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
"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<StackValue, StackValue> {
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<StackValue, StackValue> {
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<StackValue, StackValue> {
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<StackValue, StackValue> {
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<StackValue, StackValue> {
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<StackValue, StackValue> {
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<StackValue, StackValue> {
}
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<StackValue, StackValue> {
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<StackValue, StackValue> {
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<StackValue, StackValue> {
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<StackValue, StackValue> {
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);
}
}
}
@@ -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<ValueParameterDescriptor> paramDescrs,
List<TypeParameterDescriptor> typeParameters)
FunctionDescriptor functionDescriptor)
{
List<ValueParameterDescriptor> paramDescrs = functionDescriptor.getValueParameters();
List<TypeParameterDescriptor> 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));
}
}
}
}
}
@@ -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());
}
}
@@ -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;
@@ -422,6 +422,7 @@ public abstract class StackValue {
throw new UnsupportedOperationException("no getter specified");
}
getter.invoke(v);
coerce(type, v);
}
@Override
@@ -72,6 +72,7 @@ public class IntrinsicMethods {
declareIntrinsicFunction("String", "plus", 1, new Concat());
declareIntrinsicStringMethods();
declareIntrinsicProperty("String", "length", new StringLength());
}
private void declareIntrinsicStringMethods() {
@@ -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<JetExpression> arguments, StackValue receiver) {
receiver.put(JetTypeMapper.TYPE_OBJECT, v);
v.invokevirtual("java/lang/String", "length", "()I");
return StackValue.onStack(Type.INT_TYPE);
}
}
@@ -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;
}
}
@@ -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));
}
});
}
}
}
@@ -17,7 +17,7 @@ import java.util.List;
*/
public final class JetTypeImpl extends AnnotatedImpl implements JetType {
private static final HashBiMap<TypeConstructor,TypeConstructor> EMPTY_AXIOMS = HashBiMap.<TypeConstructor, TypeConstructor>create();
public static final HashBiMap<TypeConstructor,TypeConstructor> EMPTY_AXIOMS = HashBiMap.<TypeConstructor, TypeConstructor>create();
private final TypeConstructor constructor;
private final List<TypeProjection> arguments;
@@ -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<FunctionDescriptor> iteratorResolutionResult = context.services.callResolver.resolveExactSignature(context.scope, type, "iterator", Collections.<JetType>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<FunctionDescriptor> nextResolutionResult = context.services.callResolver.resolveExactSignature(context.scope, iteratorType, "next", Collections.<JetType>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<FunctionDescriptor> hasNextResolutionResult = context.services.callResolver.resolveExactSignature(context.scope, iteratorType, "hasNext", Collections.<JetType>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
@@ -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.
}
};
}
+8
View File
@@ -0,0 +1,8 @@
fun test() {
1 : Byte
1 : Int
<error>1</error> : Double
1 <warning>as</warning> Byte
1 <warning>as</warning> Int
1 <warning>as</warning> Double
}
+40
View File
@@ -0,0 +1,40 @@
package variance
abstract class Consumer<in T> {}
abstract class Producer<out T> {}
abstract class Usual<T> {}
fun foo(c: Consumer<Int>, p: Producer<Int>, u: Usual<Int>) {
val c1: Consumer<Any> = <error>c</error>
val c2: Consumer<Int> = c1
val p1: Producer<Any> = p
val p2: Producer<Int> = <error>p1</error>
val u1: Usual<Any> = <error>u</error>
val u2: Usual<Int> = <error>u1</error>
}
//Arrays copy example
class Array<T>(val length : Int) {
fun get(index : Int) : T { return null }
fun set(index : Int, value : T) { /* ... */ }
}
fun copy1(from : Array<Any>, to : Array<Any>) {}
fun copy2(from : Array<out Any>, to : Array<in Any>) {}
fun <T> copy3(from : Array<out T>, to : Array<in T>) {}
fun copy4(from : Array<out Number>, to : Array<in Int>) {}
fun f(ints: Array<Int>, any: Array<Any>, numbers: Array<Number>) {
copy1<error>(ints, any)</error>
copy2(ints, any) //ok
copy2<error>(ints, numbers)</error>
copy3<Int>(ints, numbers)
copy4(ints, numbers) //ok
}
@@ -231,6 +231,8 @@ fun mergeAutocasts(a: Any?) {
if (a is String && a is Any) {
val i: Int = <info descr="Automatically cast to String">a</info>.compareTo("")
}
if (a is String && <info descr="Automatically cast to String">a</info>.compareTo("") == 0) {}
if (a is String || a.<error>compareTo</error>("") == 0) {}
}
//mutability
+15
View File
@@ -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"
}
@@ -0,0 +1,10 @@
class A() {
fun foo() {
System.out?.println(1)
}
}
fun box() : String {
val a : A = A()
return "OK"
}
@@ -0,0 +1,58 @@
fun t1 () {
val a1 = Array<String?>(1)
a1[0] = "0" //ok
val s = a1[0] //ok
}
fun t2 () {
val a2 = Array<Int>(1)
a2[0] = 0 //ok
var i = a2[0] //ok
}
fun t3 () {
val a3 = Array<Int?>(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<Int>(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<Int?>(10, 0)
b3.set(5, 6) //ok
b3[4] = 5 //verify error
val v = b3[1] //ok
}
fun box() : String {
return "OK"
}
class StrangeArray<T>(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
}
}
@@ -0,0 +1,3 @@
fun box(i: Int?) {
val j = i?.plus(3) //verify error
}
@@ -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"
}
@@ -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<Int>()
return "OK"
}
@@ -0,0 +1,32 @@
fun foo() {
val l = java.util.ArrayList<Int>(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"
}
@@ -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
}
@@ -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"
}
@@ -0,0 +1,20 @@
class A<T>(var t: T) {}
class B<R>(val r: R) {}
fun box() : String {
val ai = A<Int>(1)
val aai = A<A<Int>>(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<Int>>(B<Int>(1))
if(abi.t.r != 1) return "fail"
return "OK"
}
@@ -0,0 +1,66 @@
class A() {}
class B<T>() {
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<String>()
if(b !is B<String>) return false
if(b !is B<String>?) return false
if(null !is B<String>?) return false
val v = b as B<String> //ok
val u = b as B<String>? //TypeCastException
val w : B<String>? = b as B<String> //ok
val x = w as B<String>? //TypeCastException
return true
}
fun t3 () : Boolean {
val b = B<String>()
if(!b.isT("aaa")) return false
if(b.isT(10)) return false
if(b.isT(null)) return false
val d = B<String?>()
if(!d.isT("aaa")) return false
if(d.isT(10)) return false
if(!d.isT(null)) return false
val c = B<Int>()
if(c.isT("aaa")) return false
if(!c.isT(10)) return false
if(c.isT(null)) return false
val e = B<Int?>()
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"
}
@@ -0,0 +1,7 @@
package org.jetbrains.jet.codegen;
public class ArrayGenTestCase extends CodegenTestCase {
public void testKt238 () throws Exception {
blackBoxFile("regressions/kt238.jet");
}
}
@@ -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");
}
}
@@ -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);
@@ -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");
}
}
@@ -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");
}
}
@@ -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");
}
}
@@ -128,5 +128,10 @@ public class TypeInfoTest extends CodegenTestCase {
}
};
}
public void testKt259() throws Exception {
blackBoxFile("regressions/kt259.jet");
}
}
+26 -10
View File
@@ -40,25 +40,28 @@ public class TypeInfo<T> 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<T> 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> BYTE_TYPE_INFO = new TypeInfo<Byte>(Byte.class, false);