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:
Generated
+11
-10
@@ -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" />
|
||||
|
||||
@@ -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
@@ -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.
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user