Merge remote branch 'origin/master'
Conflicts: idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java
This commit is contained in:
@@ -42,7 +42,7 @@ fun Any?.toString() : String// = this === other
|
||||
|
||||
class Iterator<out T> {
|
||||
fun next() : T
|
||||
abstract val hasNext : Boolean
|
||||
abstract fun hasNext() : Boolean
|
||||
}
|
||||
|
||||
class Iterable<out T> {
|
||||
|
||||
@@ -59,7 +59,7 @@ public class ClassCodegen {
|
||||
v.anew(JetTypeMapper.TYPE_TYPEINFO);
|
||||
v.dup();
|
||||
v.aconst(asmType);
|
||||
v.aconst(isNullable);
|
||||
v.iconst(isNullable?1:0);
|
||||
v.invokespecial("jet/typeinfo/TypeInfo", "<init>", "(Ljava/lang/Class;Z)V");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.ProjectScope;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import gnu.trove.THashSet;
|
||||
import jet.Range;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethod;
|
||||
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods;
|
||||
import org.jetbrains.jet.lang.ErrorHandler;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor;
|
||||
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.TypeProjection;
|
||||
@@ -32,31 +31,21 @@ import java.util.*;
|
||||
/**
|
||||
* @author max
|
||||
* @author yole
|
||||
* @author alex.tkachman
|
||||
*/
|
||||
public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
private static final String CLASS_OBJECT = "java/lang/Object";
|
||||
private static final String CLASS_STRING = "java/lang/String";
|
||||
public static final String CLASS_STRING_BUILDER = "java/lang/StringBuilder";
|
||||
private static final String CLASS_COMPARABLE = "java/lang/Comparable";
|
||||
private static final String CLASS_ITERABLE = "java/lang/Iterable";
|
||||
private static final String CLASS_ITERATOR = "java/util/Iterator";
|
||||
|
||||
private static final String CLASS_RANGE = "jet/Range";
|
||||
private static final String CLASS_NO_PATTERN_MATCHED_EXCEPTION = "jet/NoPatternMatchedException";
|
||||
private static final String CLASS_TYPE_CAST_EXCEPTION = "jet/TypeCastException";
|
||||
|
||||
private static final String ITERABLE_ITERATOR_DESCRIPTOR = "()Ljava/util/Iterator;";
|
||||
private static final String ITERATOR_HASNEXT_DESCRIPTOR = "()Z";
|
||||
private static final String ITERATOR_NEXT_DESCRIPTOR = "()Ljava/lang/Object;";
|
||||
|
||||
private static final Type OBJECT_TYPE = Type.getType(Object.class);
|
||||
private static final Type INTEGER_TYPE = Type.getType(Integer.class);
|
||||
private static final Type ITERATOR_TYPE = Type.getType(Iterator.class);
|
||||
private static final Type THROWABLE_TYPE = Type.getType(Throwable.class);
|
||||
private static final Type STRING_TYPE = Type.getObjectType(CLASS_STRING);
|
||||
|
||||
private static final Type RANGE_TYPE = Type.getType(Range.class);
|
||||
|
||||
private final Stack<Label> myContinueTargets = new Stack<Label>();
|
||||
private final Stack<Label> myBreakTargets = new Stack<Label>();
|
||||
|
||||
@@ -242,33 +231,43 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
}
|
||||
else {
|
||||
final DeclarationDescriptor descriptor = expressionType.getConstructor().getDeclarationDescriptor();
|
||||
final PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor);
|
||||
if (declaration instanceof PsiClass) {
|
||||
final Project project = declaration.getProject();
|
||||
final PsiClass iterable = JavaPsiFacade.getInstance(project).findClass("java.lang.Iterable", ProjectScope.getAllScope(project));
|
||||
if (((PsiClass) declaration).isInheritor(iterable, true)) {
|
||||
generateForInIterable(expression, loopRangeType);
|
||||
return StackValue.none();
|
||||
}
|
||||
}
|
||||
if (isClass(descriptor, "IntRange")) { // TODO IntRange subclasses
|
||||
new ForInRangeLoopGenerator(expression, loopRangeType).invoke();
|
||||
return StackValue.none();
|
||||
}
|
||||
throw new UnsupportedOperationException("for/in loop currently only supported for arrays and Iterable instances");
|
||||
|
||||
generateForInIterable(expression, loopRangeType);
|
||||
return StackValue.none();
|
||||
}
|
||||
}
|
||||
|
||||
private void generateForInIterable(JetForExpression expression, Type loopRangeType) {
|
||||
final JetExpression loopRange = expression.getLoopRange();
|
||||
|
||||
FunctionDescriptor iteratorDescriptor = bindingContext.get(BindingContext.LOOP_RANGE_ITERATOR, loopRange);
|
||||
FunctionDescriptor nextDescriptor = bindingContext.get(BindingContext.LOOP_RANGE_NEXT, loopRange);
|
||||
DeclarationDescriptor hasNextDescriptor = bindingContext.get(BindingContext.LOOP_RANGE_HAS_NEXT, loopRange);
|
||||
|
||||
if(iteratorDescriptor == null)
|
||||
throw new IllegalStateException("No iterator() method " + ErrorHandler.atLocation(loopRange));
|
||||
if(nextDescriptor == null)
|
||||
throw new IllegalStateException("No next() method " + ErrorHandler.atLocation(loopRange));
|
||||
if(hasNextDescriptor == null)
|
||||
throw new IllegalStateException("No iterator() method " + ErrorHandler.atLocation(loopRange));
|
||||
|
||||
final JetParameter loopParameter = expression.getLoopParameter();
|
||||
final VariableDescriptor parameterDescriptor = bindingContext.get(BindingContext.VALUE_PARAMETER, loopParameter);
|
||||
|
||||
JetType iteratorType = parameterDescriptor.getOutType();
|
||||
Type asmIterType = typeMapper.boxType(typeMapper.mapType(iteratorType));
|
||||
|
||||
JetType paramType = parameterDescriptor.getOutType();
|
||||
Type asmParamType = typeMapper.boxType(typeMapper.mapType(paramType));
|
||||
Type asmParamType = typeMapper.mapType(paramType);
|
||||
|
||||
int iteratorVar = myMap.enterTemp();
|
||||
gen(expression.getLoopRange(), loopRangeType);
|
||||
v.invokeinterface(CLASS_ITERABLE, "iterator", ITERABLE_ITERATOR_DESCRIPTOR);
|
||||
v.store(iteratorVar, ITERATOR_TYPE);
|
||||
invokeFunctionNoParams(iteratorDescriptor, asmIterType, v);
|
||||
v.store(iteratorVar, asmIterType);
|
||||
|
||||
Label begin = new Label();
|
||||
Label end = new Label();
|
||||
@@ -276,13 +275,21 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
myBreakTargets.push(end);
|
||||
|
||||
v.mark(begin);
|
||||
v.load(iteratorVar, ITERATOR_TYPE);
|
||||
v.invokeinterface(CLASS_ITERATOR, "hasNext", ITERATOR_HASNEXT_DESCRIPTOR);
|
||||
v.load(iteratorVar, asmIterType);
|
||||
FunctionDescriptor hND;
|
||||
if(hasNextDescriptor instanceof FunctionDescriptor) {
|
||||
hND = (FunctionDescriptor) hasNextDescriptor;
|
||||
}
|
||||
else {
|
||||
hND = ((PropertyDescriptor) hasNextDescriptor).getGetter();
|
||||
}
|
||||
invokeFunctionNoParams(hND, Type.BOOLEAN_TYPE, v);
|
||||
v.ifeq(end);
|
||||
|
||||
myMap.enter(parameterDescriptor, asmParamType.getSize());
|
||||
v.load(iteratorVar, ITERATOR_TYPE);
|
||||
v.invokeinterface(CLASS_ITERATOR, "next", ITERATOR_NEXT_DESCRIPTOR);
|
||||
v.load(iteratorVar, asmIterType);
|
||||
invokeFunctionNoParams(nextDescriptor, asmParamType, v);
|
||||
|
||||
// TODO checkcast should be generated via StackValue
|
||||
if (asmParamType.getSort() == Type.OBJECT && !"java.lang.Object".equals(asmParamType.getClassName())) {
|
||||
v.checkcast(asmParamType);
|
||||
@@ -295,6 +302,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
v.mark(end);
|
||||
|
||||
int paramIndex = myMap.leave(parameterDescriptor);
|
||||
//noinspection ConstantConditions
|
||||
v.visitLocalVariable(loopParameter.getName(), asmParamType.getDescriptor(), null, begin, end, paramIndex);
|
||||
myMap.leaveTemp();
|
||||
myBreakTargets.pop();
|
||||
@@ -350,6 +358,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
|
||||
cleanupTemp();
|
||||
final int paramIndex = myMap.leave(parameterDescriptor);
|
||||
//noinspection ConstantConditions
|
||||
v.visitLocalVariable(expression.getLoopParameter().getName(), asmParamType.getDescriptor(), null, condition, end, paramIndex);
|
||||
myBreakTargets.pop();
|
||||
myContinueTargets.pop();
|
||||
@@ -381,7 +390,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
v.arraylength();
|
||||
v.store(myLengthVar, Type.INT_TYPE);
|
||||
myIndexVar = myMap.enterTemp();
|
||||
v.aconst(0);
|
||||
v.iconst(0);
|
||||
v.store(myIndexVar, Type.INT_TYPE);
|
||||
}
|
||||
|
||||
@@ -532,6 +541,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
@Override
|
||||
public StackValue visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, StackValue receiver) {
|
||||
if (bindingContext.get(BindingContext.BLOCK, expression)) {
|
||||
//noinspection ConstantConditions
|
||||
return generateBlock(expression.getFunctionLiteral().getBodyExpression().getStatements());
|
||||
}
|
||||
else {
|
||||
@@ -770,12 +780,36 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
return myMap.getIndex(descriptor);
|
||||
}
|
||||
|
||||
public void invokeFunctionNoParams(FunctionDescriptor functionDescriptor, Type type, InstructionAdapterEx v) {
|
||||
DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration();
|
||||
boolean isStatic = containingDeclaration instanceof NamespaceDescriptorImpl;
|
||||
functionDescriptor = functionDescriptor.getOriginal();
|
||||
String owner;
|
||||
|
||||
boolean isInterface;
|
||||
boolean isInsideClass = containingDeclaration == contextType();
|
||||
if (isInsideClass || isStatic) {
|
||||
owner = typeMapper.getOwner(functionDescriptor, contextKind());
|
||||
isInterface = false;
|
||||
}
|
||||
else {
|
||||
owner = typeMapper.getOwner(functionDescriptor, OwnerKind.INTERFACE);
|
||||
if(containingDeclaration instanceof JavaClassDescriptor) {
|
||||
PsiClass psiElement = (PsiClass) bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, containingDeclaration);
|
||||
isInterface = psiElement.isInterface();
|
||||
}
|
||||
else
|
||||
isInterface = !(containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor) containingDeclaration).isObject());
|
||||
}
|
||||
|
||||
v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : isInterface ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL, owner, functionDescriptor.getName(), typeMapper.mapSignature(functionDescriptor.getName(),functionDescriptor).getDescriptor());
|
||||
StackValue.onStack(typeMapper.mapType(functionDescriptor.getReturnType())).coerce(type, v);
|
||||
}
|
||||
|
||||
public StackValue intermediateValueForProperty(PropertyDescriptor propertyDescriptor, final boolean forceField, boolean forceInterface) {
|
||||
DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
|
||||
boolean isStatic = containingDeclaration instanceof NamespaceDescriptorImpl;
|
||||
while(propertyDescriptor != propertyDescriptor.getOriginal())
|
||||
propertyDescriptor = propertyDescriptor.getOriginal();
|
||||
final JetType outType = propertyDescriptor.getOutType();
|
||||
propertyDescriptor = propertyDescriptor.getOriginal();
|
||||
boolean isInsideClass = !forceInterface && containingDeclaration == contextType();
|
||||
Method getter;
|
||||
Method setter;
|
||||
@@ -784,8 +818,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
setter = null;
|
||||
}
|
||||
else {
|
||||
getter = isInsideClass && propertyDescriptor.getGetter() == null ? null : typeMapper.mapGetterSignature(propertyDescriptor);
|
||||
setter = isInsideClass && propertyDescriptor.getSetter() == null ? null : typeMapper.mapSetterSignature(propertyDescriptor);
|
||||
//noinspection ConstantConditions
|
||||
getter = isInsideClass && (propertyDescriptor.getGetter() == null || propertyDescriptor.getGetter().isDefault())
|
||||
? null : typeMapper.mapGetterSignature(propertyDescriptor);
|
||||
//noinspection ConstantConditions
|
||||
setter = isInsideClass && (propertyDescriptor.getSetter() == null || propertyDescriptor.getSetter().isDefault())
|
||||
? null : typeMapper.mapSetterSignature(propertyDescriptor);
|
||||
}
|
||||
|
||||
String owner;
|
||||
@@ -808,7 +846,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
DeclarationDescriptor funDescriptor = resolveCalleeDescriptor(expression);
|
||||
|
||||
if (funDescriptor instanceof ConstructorDescriptor) {
|
||||
return generateConstructorCall(expression, (JetSimpleNameExpression) callee);
|
||||
return generateConstructorCall(expression, (JetSimpleNameExpression) callee, receiver);
|
||||
}
|
||||
else if (funDescriptor instanceof FunctionDescriptor) {
|
||||
final FunctionDescriptor fd = (FunctionDescriptor) funDescriptor;
|
||||
@@ -1069,11 +1107,14 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
|
||||
@Override
|
||||
public StackValue visitPredicateExpression(JetPredicateExpression expression, StackValue receiver) {
|
||||
genToJVMStack(expression.getReceiverExpression());
|
||||
JetExpression expr = expression.getReceiverExpression();
|
||||
StackValue value = gen(expr);
|
||||
Type receiverType = expressionType(expr);
|
||||
value.put(receiverType, v);
|
||||
Label ifFalse = new Label();
|
||||
Label end = new Label();
|
||||
v.dup();
|
||||
StackValue result = gen(expression.getSelectorExpression());
|
||||
StackValue result = genQualified(StackValue.onStack(receiverType), expression.getSelectorExpression());
|
||||
result.condJump(ifFalse, true, v);
|
||||
v.goTo(end);
|
||||
v.mark(ifFalse);
|
||||
@@ -1109,6 +1150,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
else if (opToken == JetTokens.ELVIS) {
|
||||
return generateElvis(expression);
|
||||
}
|
||||
else if(opToken == JetTokens.IN_KEYWORD || opToken == JetTokens.NOT_IN) {
|
||||
return generateIn (expression);
|
||||
}
|
||||
else {
|
||||
DeclarationDescriptor op = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference());
|
||||
final Callable callable = resolveToCallable(op);
|
||||
@@ -1127,6 +1171,64 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
}
|
||||
}
|
||||
|
||||
private StackValue generateIn(JetBinaryExpression expression) {
|
||||
JetExpression expr = expression.getLeft();
|
||||
StackValue leftValue = gen(expr);
|
||||
if(isIntRangeExpr(expression.getRight())) {
|
||||
JetBinaryExpression rangeExpression = (JetBinaryExpression) expression.getRight();
|
||||
boolean inverted = expression.getOperationReference().getReferencedNameElementType() == JetTokens.NOT_IN;
|
||||
getInIntTest(leftValue, rangeExpression, inverted);
|
||||
}
|
||||
else {
|
||||
leftValue.put(JetTypeMapper.TYPE_OBJECT, v);
|
||||
genToJVMStack(expression.getRight());
|
||||
v.swap();
|
||||
FunctionDescriptor op = (FunctionDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference());
|
||||
invokeFunctionNoParams(op, Type.BOOLEAN_TYPE, v);
|
||||
}
|
||||
return StackValue.onStack(Type.BOOLEAN_TYPE);
|
||||
}
|
||||
|
||||
private void getInIntTest(StackValue leftValue, JetBinaryExpression rangeExpression, boolean inverted) {
|
||||
v.iconst(1);
|
||||
// 1
|
||||
leftValue.put(Type.INT_TYPE, v);
|
||||
// 1 l
|
||||
v.dup2();
|
||||
// 1 l 1 l
|
||||
|
||||
//noinspection ConstantConditions
|
||||
gen(rangeExpression.getLeft(), Type.INT_TYPE);
|
||||
// 1 l 1 l r
|
||||
Label lok = new Label();
|
||||
v.ificmpge(lok);
|
||||
// 1 l 1
|
||||
v.pop();
|
||||
v.iconst(0);
|
||||
v.mark(lok);
|
||||
// 1 l c
|
||||
v.dupX2();
|
||||
// c 1 l c
|
||||
v.pop();
|
||||
// c 1 l
|
||||
|
||||
gen(rangeExpression.getRight(), Type.INT_TYPE);
|
||||
// c 1 l r
|
||||
Label rok = new Label();
|
||||
v.ificmple(rok);
|
||||
// c 1
|
||||
v.pop();
|
||||
v.iconst(0);
|
||||
v.mark(rok);
|
||||
// c c
|
||||
|
||||
v.and(Type.INT_TYPE);
|
||||
if(inverted) {
|
||||
v.iconst(1);
|
||||
v.xor(Type.INT_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
private StackValue generateBooleanAnd(JetBinaryExpression expression) {
|
||||
gen(expression.getLeft(), Type.BOOLEAN_TYPE);
|
||||
Label ifFalse = new Label();
|
||||
@@ -1135,7 +1237,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
Label end = new Label();
|
||||
v.goTo(end);
|
||||
v.mark(ifFalse);
|
||||
v.aconst(false);
|
||||
v.iconst(0);
|
||||
v.mark(end);
|
||||
return StackValue.onStack(Type.BOOLEAN_TYPE);
|
||||
}
|
||||
@@ -1148,14 +1250,24 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
Label end = new Label();
|
||||
v.goTo(end);
|
||||
v.mark(ifTrue);
|
||||
v.aconst(true);
|
||||
v.iconst(1);
|
||||
v.mark(end);
|
||||
return StackValue.onStack(Type.BOOLEAN_TYPE);
|
||||
}
|
||||
|
||||
private StackValue generateEquals(JetExpression left, JetExpression right, IElementType opToken) {
|
||||
Type leftType = expressionType(left);
|
||||
Type rightType = expressionType(right);
|
||||
JetType leftJetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, left);
|
||||
Type leftType = typeMapper.mapType(leftJetType);
|
||||
JetType rightJetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, right);
|
||||
Type rightType = typeMapper.mapType(rightJetType);
|
||||
if(leftType == JetTypeMapper.TYPE_NOTHING) {
|
||||
return genCmpWithNull(right, rightType, opToken);
|
||||
}
|
||||
|
||||
if(rightType == JetTypeMapper.TYPE_NOTHING) {
|
||||
return genCmpWithNull(left, leftType, opToken);
|
||||
}
|
||||
|
||||
if(JetTypeMapper.isPrimitive(leftType) != JetTypeMapper.isPrimitive(rightType)) {
|
||||
gen(left, leftType);
|
||||
v.valueOf(leftType);
|
||||
@@ -1168,10 +1280,30 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
gen(left, leftType);
|
||||
gen(right, rightType);
|
||||
}
|
||||
return generateEqualsForExpressionsOnStack(opToken, leftType, rightType);
|
||||
|
||||
if(JetTypeMapper.isPrimitive(leftType)) // both are primitive
|
||||
return generateEqualsForExpressionsOnStack(opToken, leftType, rightType, false, false);
|
||||
|
||||
return generateEqualsForExpressionsOnStack(opToken, leftType, rightType, leftJetType.isNullable(), rightJetType.isNullable());
|
||||
}
|
||||
|
||||
private StackValue generateEqualsForExpressionsOnStack(IElementType opToken, Type leftType, Type rightType) {
|
||||
private StackValue genCmpWithNull(JetExpression exp, Type expType, IElementType opToken) {
|
||||
v.iconst(1);
|
||||
gen(exp, typeMapper.boxType(expType));
|
||||
Label ok = new Label();
|
||||
if(JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) {
|
||||
v.ifnull(ok);
|
||||
}
|
||||
else {
|
||||
v.ifnonnull(ok);
|
||||
}
|
||||
v.pop();
|
||||
v.iconst(0);
|
||||
v.mark(ok);
|
||||
return StackValue.onStack(Type.BOOLEAN_TYPE);
|
||||
}
|
||||
|
||||
private StackValue generateEqualsForExpressionsOnStack(IElementType opToken, Type leftType, Type rightType, boolean leftNullable, boolean rightNullable) {
|
||||
if (isNumberPrimitive(leftType) && leftType == rightType) {
|
||||
return compareExpressionsOnStack(opToken, leftType);
|
||||
}
|
||||
@@ -1180,38 +1312,67 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
return StackValue.cmp(opToken, leftType);
|
||||
}
|
||||
else {
|
||||
return generateNullSafeEquals(opToken);
|
||||
return generateNullSafeEquals(opToken, leftNullable, rightNullable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private StackValue generateNullSafeEquals(IElementType opToken) {
|
||||
v.dup2(); // left right left right
|
||||
Label rightNull = new Label();
|
||||
v.ifnull(rightNull);
|
||||
Label leftNull = new Label();
|
||||
v.ifnull(leftNull);
|
||||
v.invokevirtual(CLASS_OBJECT, "equals", "(Ljava/lang/Object;)Z");
|
||||
Label end = new Label();
|
||||
v.goTo(end);
|
||||
v.mark(rightNull);
|
||||
// left right left
|
||||
Label bothNull = new Label();
|
||||
v.ifnull(bothNull);
|
||||
v.mark(leftNull);
|
||||
v.pop2();
|
||||
v.aconst(Boolean.FALSE);
|
||||
v.goTo(end);
|
||||
v.mark(bothNull);
|
||||
v.pop2();
|
||||
v.aconst(Boolean.TRUE);
|
||||
v.mark(end);
|
||||
|
||||
final StackValue onStack = StackValue.onStack(Type.BOOLEAN_TYPE);
|
||||
if (opToken == JetTokens.EXCLEQ) {
|
||||
return StackValue.not(onStack);
|
||||
private StackValue generateNullSafeEquals(IElementType opToken, boolean leftNullable, boolean rightNullable) {
|
||||
if(!leftNullable) {
|
||||
v.invokevirtual(CLASS_OBJECT, "equals", "(Ljava/lang/Object;)Z");
|
||||
if (opToken == JetTokens.EXCLEQ) {
|
||||
v.iconst(1);
|
||||
v.xor(Type.INT_TYPE);
|
||||
}
|
||||
}
|
||||
return onStack;
|
||||
else {
|
||||
if(rightNullable) {
|
||||
v.dup2(); // left right left right
|
||||
Label rightNull = new Label();
|
||||
v.ifnull(rightNull);
|
||||
Label leftNull = new Label();
|
||||
v.ifnull(leftNull);
|
||||
v.invokevirtual(CLASS_OBJECT, "equals", "(Ljava/lang/Object;)Z");
|
||||
if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) {
|
||||
v.iconst(1);
|
||||
v.xor(Type.INT_TYPE);
|
||||
}
|
||||
Label end = new Label();
|
||||
v.goTo(end);
|
||||
v.mark(rightNull);
|
||||
// left right left
|
||||
Label bothNull = new Label();
|
||||
v.ifnull(bothNull);
|
||||
v.mark(leftNull);
|
||||
v.pop2();
|
||||
v.iconst(opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ ? 1 : 0);
|
||||
v.goTo(end);
|
||||
v.mark(bothNull);
|
||||
v.pop2();
|
||||
v.iconst(opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ ? 0 : 1);
|
||||
v.mark(end);
|
||||
}
|
||||
else {
|
||||
v.dup2(); // left right left right
|
||||
v.pop();
|
||||
Label leftNull = new Label();
|
||||
v.ifnull(leftNull);
|
||||
v.invokevirtual(CLASS_OBJECT, "equals", "(Ljava/lang/Object;)Z");
|
||||
if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) {
|
||||
v.iconst(1);
|
||||
v.xor(Type.INT_TYPE);
|
||||
}
|
||||
Label end = new Label();
|
||||
v.goTo(end);
|
||||
// left right
|
||||
v.mark(leftNull);
|
||||
v.pop2();
|
||||
v.iconst(opToken == JetTokens.EXCLEQ ? 1 : 0);
|
||||
v.mark(end);
|
||||
}
|
||||
}
|
||||
|
||||
return StackValue.onStack(Type.BOOLEAN_TYPE);
|
||||
}
|
||||
|
||||
private StackValue generateElvis(JetBinaryExpression expression) {
|
||||
@@ -1262,7 +1423,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
private StackValue compareExpressionsOnStack(IElementType opToken, Type operandType) {
|
||||
if (operandType.getSort() == Type.OBJECT) {
|
||||
v.invokeinterface(CLASS_COMPARABLE, "compareTo", "(Ljava/lang/Object;)I");
|
||||
v.aconst(0);
|
||||
v.iconst(0);
|
||||
operandType = Type.INT_TYPE;
|
||||
}
|
||||
return StackValue.cmp(opToken, operandType);
|
||||
@@ -1286,6 +1447,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
value.dupReceiver(v, 0); // receiver receiver
|
||||
value.put(lhsType, v); // receiver lhs
|
||||
final IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
|
||||
//noinspection NullableProblems
|
||||
intrinsic.generate(this, v, lhsType, expression, Arrays.asList(expression.getRight()), null);
|
||||
value.store(v);
|
||||
}
|
||||
@@ -1394,16 +1556,19 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
value.dupReceiver(v, 0);
|
||||
value.put(asmType, v);
|
||||
if (asmType == Type.LONG_TYPE) {
|
||||
v.aconst(Long.valueOf(increment));
|
||||
//noinspection UnnecessaryBoxing
|
||||
v.lconst(increment);
|
||||
}
|
||||
else if (asmType == Type.FLOAT_TYPE) {
|
||||
v.aconst(Float.valueOf(increment));
|
||||
//noinspection UnnecessaryBoxing
|
||||
v.fconst(increment);
|
||||
}
|
||||
else if (asmType == Type.DOUBLE_TYPE) {
|
||||
v.aconst(Double.valueOf(increment));
|
||||
//noinspection UnnecessaryBoxing
|
||||
v.dconst(increment);
|
||||
}
|
||||
else {
|
||||
v.aconst(increment);
|
||||
v.iconst(increment);
|
||||
}
|
||||
v.add(asmType);
|
||||
value.store(v);
|
||||
@@ -1425,7 +1590,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
return StackValue.none();
|
||||
}
|
||||
|
||||
private StackValue generateConstructorCall(JetCallExpression expression, JetSimpleNameExpression constructorReference) {
|
||||
private StackValue generateConstructorCall(JetCallExpression expression, JetSimpleNameExpression constructorReference, StackValue receiver) {
|
||||
DeclarationDescriptor constructorDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, constructorReference);
|
||||
final PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, constructorDescriptor);
|
||||
Type type;
|
||||
@@ -1440,11 +1605,27 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
else {
|
||||
ClassDescriptor classDecl = (ClassDescriptor) constructorDescriptor.getContainingDeclaration();
|
||||
|
||||
receiver.put(receiver.type, v);
|
||||
v.anew(type);
|
||||
v.dup();
|
||||
|
||||
// TODO typechecker must verify that we're the outer class of the instance being created
|
||||
pushOuterClassArguments(classDecl);
|
||||
//noinspection ConstantConditions
|
||||
if (classDecl.getContainingDeclaration() instanceof ClassDescriptor) {
|
||||
if(!receiver.type.equals(Type.VOID_TYPE)) {
|
||||
// class object is in receiver
|
||||
v.dupX1();
|
||||
v.swap();
|
||||
}
|
||||
else {
|
||||
// this$0 need to be put on stack
|
||||
v.dup();
|
||||
v.load(0, JetTypeMapper.jetImplementationType(classDecl));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// regular case
|
||||
v.dup();
|
||||
}
|
||||
|
||||
CallableMethod method = typeMapper.mapToCallableMethod((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION);
|
||||
invokeMethodWithArguments(method, expression);
|
||||
@@ -1467,12 +1648,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
generateTypeInfo(typeArgument);
|
||||
}
|
||||
|
||||
private void pushOuterClassArguments(ClassDescriptor classDecl) {
|
||||
if (classDecl.getContainingDeclaration() instanceof ClassDescriptor) {
|
||||
v.load(0, JetTypeMapper.jetImplementationType(classDecl));
|
||||
}
|
||||
}
|
||||
|
||||
private Type generateJavaConstructorCall(JetCallExpression expression, PsiMethod constructor) {
|
||||
PsiClass javaClass = constructor.getContainingClass();
|
||||
Type type = JetTypeMapper.psiClassType(javaClass);
|
||||
@@ -1660,7 +1835,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
JetExpression condExpression = ((JetExpressionPattern) pattern).getExpression();
|
||||
Type condType = isNumberPrimitive(subjectType) ? expressionType(condExpression) : OBJECT_TYPE;
|
||||
gen(condExpression, condType);
|
||||
return generateEqualsForExpressionsOnStack(JetTokens.EQEQ, subjectType, condType);
|
||||
return generateEqualsForExpressionsOnStack(JetTokens.EQEQ, subjectType, condType, false, false);
|
||||
}
|
||||
else if (pattern instanceof JetWildcardPattern) {
|
||||
return StackValue.constant(!negated, Type.BOOLEAN_TYPE);
|
||||
@@ -1702,7 +1877,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
|
||||
v.mark(lblCheck);
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
final boolean isLast = i == entries.size() - 1;
|
||||
final StackValue tupleField = StackValue.field(OBJECT_TYPE, tupleClassName, "_" + (i + 1), false);
|
||||
final StackValue stackValue = generatePatternMatch(entries.get(i).getPattern(), false, tupleField, nextEntry);
|
||||
stackValue.condJump(lblPopAndFail, true, v);
|
||||
@@ -1713,7 +1887,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
v.goTo(nextEntry);
|
||||
}
|
||||
else {
|
||||
v.aconst(!negated);
|
||||
v.iconst(!negated?1:0);
|
||||
}
|
||||
v.goTo(lblDone);
|
||||
v.mark(lblFail);
|
||||
@@ -1721,7 +1895,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
v.goTo(nextEntry);
|
||||
}
|
||||
else {
|
||||
v.aconst(negated);
|
||||
v.iconst(negated?1:0);
|
||||
}
|
||||
v.mark(lblDone);
|
||||
return StackValue.onStack(Type.BOOLEAN_TYPE);
|
||||
@@ -1753,7 +1927,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
v.goTo(end);
|
||||
v.mark(nope);
|
||||
v.pop();
|
||||
v.aconst(1);
|
||||
v.iconst(1);
|
||||
v.mark(end);
|
||||
}
|
||||
else {
|
||||
@@ -1778,7 +1952,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
v.anew(JetTypeMapper.TYPE_TYPEINFO);
|
||||
v.dup();
|
||||
v.aconst(jvmType);
|
||||
v.aconst(jetType.isNullable());
|
||||
v.iconst(jetType.isNullable()?1:0);
|
||||
List<TypeProjection> arguments = jetType.getArguments();
|
||||
if (arguments.size() > 0) {
|
||||
v.iconst(arguments.size());
|
||||
@@ -1862,15 +2036,21 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
return StackValue.onStack(expressionType(expression));
|
||||
}
|
||||
|
||||
private StackValue generateWhenCondition(Type subjectType, int subjectLocal, JetWhenCondition condition,
|
||||
@Nullable Label nextEntry) {
|
||||
private StackValue generateWhenCondition(Type subjectType, int subjectLocal, JetWhenCondition condition, @Nullable Label nextEntry) {
|
||||
StackValue conditionValue;
|
||||
if (condition instanceof JetWhenConditionInRange) {
|
||||
JetExpression range = ((JetWhenConditionInRange) condition).getRangeExpression();
|
||||
gen(range, RANGE_TYPE);
|
||||
new StackValue.Local(subjectLocal, subjectType).put(INTEGER_TYPE, v);
|
||||
v.invokeinterface(CLASS_RANGE, "contains", "(Ljava/lang/Comparable;)Z");
|
||||
conditionValue = new StackValue.OnStack(Type.BOOLEAN_TYPE);
|
||||
JetWhenConditionInRange conditionInRange = (JetWhenConditionInRange) condition;
|
||||
JetExpression rangeExpression = conditionInRange.getRangeExpression();
|
||||
if(isIntRangeExpr(rangeExpression)) {
|
||||
getInIntTest(new StackValue.Local(subjectLocal, subjectType), (JetBinaryExpression) rangeExpression, conditionInRange.getOperationReference().getReferencedNameElementType() == JetTokens.NOT_IN);
|
||||
}
|
||||
else {
|
||||
FunctionDescriptor op = (FunctionDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, conditionInRange.getOperationReference());
|
||||
genToJVMStack(rangeExpression);
|
||||
new StackValue.Local(subjectLocal, subjectType).put(JetTypeMapper.TYPE_OBJECT, v);
|
||||
invokeFunctionNoParams(op, Type.BOOLEAN_TYPE, v);
|
||||
}
|
||||
return StackValue.onStack(Type.BOOLEAN_TYPE);
|
||||
}
|
||||
else if (condition instanceof JetWhenConditionIsPattern) {
|
||||
JetWhenConditionIsPattern patternCondition = (JetWhenConditionIsPattern) condition;
|
||||
@@ -1886,7 +2066,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
if (!(declarationDescriptor instanceof FunctionDescriptor)) {
|
||||
throw new UnsupportedOperationException("expected function descriptor in when condition with call, found " + declarationDescriptor);
|
||||
}
|
||||
conditionValue = invokeFunction((JetCallExpression) call, declarationDescriptor, StackValue.none());
|
||||
conditionValue = invokeFunction((JetCallExpression) call, declarationDescriptor, StackValue.onStack(subjectType));
|
||||
}
|
||||
else if (call instanceof JetSimpleNameExpression) {
|
||||
final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) call);
|
||||
@@ -1908,16 +2088,35 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
return conditionValue;
|
||||
}
|
||||
|
||||
private boolean isIntRangeExpr(JetExpression rangeExpression) {
|
||||
if(rangeExpression instanceof JetBinaryExpression) {
|
||||
JetBinaryExpression binaryExpression = (JetBinaryExpression) rangeExpression;
|
||||
if (binaryExpression.getOperationReference().getReferencedNameElementType() == JetTokens.RANGE) {
|
||||
JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, rangeExpression);
|
||||
final DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
|
||||
if (isClass(descriptor, "IntRange")) { // TODO IntRange subclasses
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StackValue visitTupleExpression(JetTupleExpression expression, StackValue receiver) {
|
||||
final List<JetExpression> entries = expression.getEntries();
|
||||
if (entries.size() > 22) {
|
||||
throw new UnsupportedOperationException("tuple too large");
|
||||
}
|
||||
if(entries.size() == 0) {
|
||||
v.visitFieldInsn(Opcodes.GETSTATIC, "jet/Tuple0", "INSTANCE", "Ljet/Tuple0;");
|
||||
return StackValue.onStack(Type.getObjectType("jet/Tuple0"));
|
||||
}
|
||||
|
||||
final String className = "jet/Tuple" + entries.size();
|
||||
Type tupleType = Type.getObjectType(className);
|
||||
StringBuilder signature = new StringBuilder("(");
|
||||
for (JetExpression entry : entries) {
|
||||
for (int i = 0; i != entries.size(); ++i) {
|
||||
signature.append("Ljava/lang/Object;");
|
||||
}
|
||||
signature.append(")V");
|
||||
|
||||
@@ -8,7 +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.jetbrains.jet.lang.types.TypeUtils;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
@@ -66,6 +66,8 @@ public class FunctionCodegen {
|
||||
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());
|
||||
if(function.getReturnType() == Type.VOID_TYPE)
|
||||
iv.aconst(null);
|
||||
iv.areturn(overriden.getReturnType());
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
@@ -133,8 +135,8 @@ public class FunctionCodegen {
|
||||
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));
|
||||
if(!TypeUtils.equalClasses(overriddenFunction.getOriginal().getReturnType(), functionDescriptor.getReturnType())) {
|
||||
generateBridgeMethod(jvmSignature, state.getTypeMapper().mapSignature(overriddenFunction.getName(), overriddenFunction.getOriginal()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
@@ -147,7 +148,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
}
|
||||
|
||||
protected void generatePrimaryConstructor() {
|
||||
ConstructorDescriptor constructorDescriptor = state.getBindingContext().get(BindingContext.CONSTRUCTOR, (JetElement) myClass);
|
||||
ConstructorDescriptor constructorDescriptor = state.getBindingContext().get(BindingContext.CONSTRUCTOR, myClass);
|
||||
if (constructorDescriptor == null && !(myClass instanceof JetObjectDeclaration) && !isEnum(myClass)) return;
|
||||
|
||||
Method method;
|
||||
@@ -193,10 +194,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
iv.invokespecial(superClass, "<init>", /* TODO super constructor descriptor */"()V");
|
||||
}
|
||||
|
||||
final DeclarationDescriptor outerDescriptor = getOuterClassDescriptor();
|
||||
if (outerDescriptor instanceof ClassDescriptor) {
|
||||
final ClassDescriptor outerClassDescriptor = (ClassDescriptor) outerDescriptor;
|
||||
final Type type = JetTypeMapper.jetImplementationType(outerClassDescriptor);
|
||||
final ClassDescriptor outerDescriptor = getOuterClassDescriptor();
|
||||
if (outerDescriptor != null && !outerDescriptor.isObject()) {
|
||||
final Type type = JetTypeMapper.jetImplementationType(outerDescriptor);
|
||||
String interfaceDesc = type.getDescriptor();
|
||||
final String fieldName = "this$0";
|
||||
v.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, fieldName, interfaceDesc, null, null);
|
||||
@@ -393,7 +393,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
iv.dup();
|
||||
|
||||
iv.aconst(state.getTypeMapper().jvmType(descriptor, OwnerKind.INTERFACE));
|
||||
iv.aconst(false);
|
||||
iv.iconst(0);
|
||||
iv.iconst(typeParamCount);
|
||||
iv.newarray(JetTypeMapper.TYPE_TYPEINFO);
|
||||
|
||||
@@ -410,12 +410,45 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
protected void generateInitializers(ExpressionCodegen codegen, InstructionAdapter iv) {
|
||||
for (JetDeclaration declaration : myClass.getDeclarations()) {
|
||||
if (declaration instanceof JetProperty) {
|
||||
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, (JetProperty) declaration);
|
||||
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, declaration);
|
||||
if (state.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) {
|
||||
final JetExpression initializer = ((JetProperty) declaration).getInitializer();
|
||||
if (initializer != null) {
|
||||
CompileTimeConstant<?> compileTimeValue = state.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, initializer);
|
||||
if(compileTimeValue != null) {
|
||||
assert compileTimeValue != null;
|
||||
Object value = compileTimeValue.getValue();
|
||||
Type type = state.getTypeMapper().mapType(propertyDescriptor.getOutType());
|
||||
if(JetTypeMapper.isPrimitive(type)) {
|
||||
if( !propertyDescriptor.getOutType().isNullable() && value instanceof Number) {
|
||||
if(type == Type.INT_TYPE && ((Number)value).intValue() == 0)
|
||||
continue;
|
||||
if(type == Type.BYTE_TYPE && ((Number)value).byteValue() == 0)
|
||||
continue;
|
||||
if(type == Type.LONG_TYPE && ((Number)value).longValue() == 0L)
|
||||
continue;
|
||||
if(type == Type.SHORT_TYPE && ((Number)value).shortValue() == 0)
|
||||
continue;
|
||||
if(type == Type.DOUBLE_TYPE && ((Number)value).doubleValue() == 0d)
|
||||
continue;
|
||||
if(type == Type.FLOAT_TYPE && ((Number)value).byteValue() == 0f)
|
||||
continue;
|
||||
}
|
||||
if(type == Type.BOOLEAN_TYPE && value instanceof Boolean && !((Boolean)value))
|
||||
continue;
|
||||
if(type == Type.CHAR_TYPE && value instanceof Character && ((Character)value) == 0)
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
if(value == null)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
iv.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
codegen.genToJVMStack(initializer);
|
||||
Type type = codegen.expressionType(initializer);
|
||||
if(propertyDescriptor.getOutType().isNullable())
|
||||
type = state.getTypeMapper().boxType(type);
|
||||
codegen.gen(initializer, type);
|
||||
codegen.intermediateValueForProperty(propertyDescriptor, false, false).store(iv);
|
||||
}
|
||||
|
||||
@@ -436,7 +469,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
propertyCodegen.gen((JetProperty) declaration);
|
||||
}
|
||||
else if (declaration instanceof JetFunction) {
|
||||
if (!overriden.contains(state.getBindingContext().get(BindingContext.FUNCTION, (JetNamedFunction) declaration))) {
|
||||
if (!overriden.contains(state.getBindingContext().get(BindingContext.FUNCTION, declaration))) {
|
||||
functionCodegen.gen((JetNamedFunction) declaration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ public class JetTypeMapper {
|
||||
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);
|
||||
public static final Type TYPE_NOTHING = Type.getObjectType("jet/Nothing");
|
||||
|
||||
private final JetStandardLibrary standardLibrary;
|
||||
private final BindingContext bindingContext;
|
||||
@@ -273,13 +274,24 @@ public class JetTypeMapper {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public Type mapType(final JetType jetType) {
|
||||
@NotNull public Type mapReturnType(@NotNull final JetType jetType, OwnerKind kind) {
|
||||
if (jetType.equals(JetStandardClasses.getUnitType()) || jetType.equals(JetStandardClasses.getNothingType())) {
|
||||
return Type.VOID_TYPE;
|
||||
}
|
||||
return mapType(jetType, kind);
|
||||
}
|
||||
|
||||
@NotNull public Type mapReturnType(final JetType jetType) {
|
||||
return mapReturnType(jetType, OwnerKind.INTERFACE);
|
||||
}
|
||||
|
||||
@NotNull public Type mapType(final JetType jetType) {
|
||||
return mapType(jetType, OwnerKind.INTERFACE);
|
||||
}
|
||||
|
||||
public Type mapType(@NotNull final JetType jetType, OwnerKind kind) {
|
||||
if (jetType.equals(JetStandardClasses.getUnitType()) || jetType.equals(JetStandardClasses.getNothingType())) {
|
||||
return Type.VOID_TYPE;
|
||||
@NotNull public Type mapType(@NotNull final JetType jetType, OwnerKind kind) {
|
||||
if (jetType.equals(JetStandardClasses.getNothingType()) || jetType.equals(JetStandardClasses.getNullableNothingType())) {
|
||||
return TYPE_NOTHING;
|
||||
}
|
||||
if (jetType.equals(standardLibrary.getIntType())) {
|
||||
return Type.INT_TYPE;
|
||||
@@ -410,10 +422,10 @@ public class JetTypeMapper {
|
||||
if (returnTypeRef == null) {
|
||||
final FunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, f);
|
||||
final JetType type = functionDescriptor.getReturnType();
|
||||
returnType = mapType(type);
|
||||
returnType = mapReturnType(type);
|
||||
}
|
||||
else {
|
||||
returnType = mapType(bindingContext.get(BindingContext.TYPE, returnTypeRef));
|
||||
returnType = mapReturnType(bindingContext.get(BindingContext.TYPE, returnTypeRef));
|
||||
}
|
||||
return new Method(f.getName(), returnType, parameterTypes.toArray(new Type[parameterTypes.size()]));
|
||||
}
|
||||
@@ -470,7 +482,7 @@ public class JetTypeMapper {
|
||||
for (ValueParameterDescriptor parameter : parameters) {
|
||||
parameterTypes.add(mapType(parameter.getOutType()));
|
||||
}
|
||||
Type returnType = mapType(f.getReturnType());
|
||||
Type returnType = mapReturnType(f.getReturnType());
|
||||
return new Method(name, returnType, parameterTypes.toArray(new Type[parameterTypes.size()]));
|
||||
}
|
||||
|
||||
|
||||
@@ -156,8 +156,26 @@ public abstract class StackValue {
|
||||
protected void coerce(Type type, InstructionAdapter v) {
|
||||
if (type.equals(this.type)) return;
|
||||
|
||||
if (type.getSort() == Type.OBJECT && this.type.getSort() == Type.OBJECT) {
|
||||
// v.checkcast(type);
|
||||
if (type.getSort() == Type.VOID && this.type.getSort() != Type.VOID) {
|
||||
if(this.type.getSize() == 1)
|
||||
v.pop();
|
||||
else
|
||||
v.pop2();
|
||||
}
|
||||
else if (type.getSort() != Type.VOID && this.type.getSort() == Type.VOID) {
|
||||
if(type.getSort() == Type.OBJECT)
|
||||
v.visitFieldInsn(Opcodes.GETSTATIC, "jet/Tuple0", "INSTANCE", "Ljet/Tuple0;");
|
||||
else if(type == Type.LONG_TYPE)
|
||||
v.lconst(0);
|
||||
else if(type == Type.FLOAT_TYPE)
|
||||
v.fconst(0);
|
||||
else if(type == Type.DOUBLE_TYPE)
|
||||
v.dconst(0);
|
||||
else
|
||||
v.iconst(0);
|
||||
}
|
||||
else if (type.getSort() == Type.OBJECT && this.type.getSort() == Type.OBJECT) {
|
||||
// v.checkcast(type);
|
||||
}
|
||||
else if (type.getSort() == Type.OBJECT) {
|
||||
box(this.type, type, v);
|
||||
@@ -201,6 +219,7 @@ public abstract class StackValue {
|
||||
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
coerce(type, v);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,14 +275,26 @@ public abstract class StackValue {
|
||||
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
v.aconst(value);
|
||||
if(value instanceof Integer)
|
||||
v.iconst((Integer) value);
|
||||
else
|
||||
if(value instanceof Long)
|
||||
v.lconst((Long) value);
|
||||
else
|
||||
if(value instanceof Float)
|
||||
v.fconst((Float) value);
|
||||
else
|
||||
if(value instanceof Double)
|
||||
v.dconst((Double) value);
|
||||
else
|
||||
v.aconst(value);
|
||||
coerce(type, v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
|
||||
if (value instanceof Boolean) {
|
||||
boolean boolValue = ((Boolean) value).booleanValue();
|
||||
boolean boolValue = (Boolean) value;
|
||||
if (boolValue ^ jumpIfFalse) {
|
||||
v.goTo(label);
|
||||
}
|
||||
|
||||
@@ -35,13 +35,13 @@ public class Increment implements IntrinsicMethod {
|
||||
value.dupReceiver(v, 0);
|
||||
value.put(expectedType, v);
|
||||
if (expectedType == Type.LONG_TYPE) {
|
||||
v.aconst(Long.valueOf(myDelta));
|
||||
v.lconst(myDelta);
|
||||
}
|
||||
else if (expectedType == Type.FLOAT_TYPE) {
|
||||
v.aconst(Float.valueOf(myDelta));
|
||||
v.fconst(myDelta);
|
||||
}
|
||||
else if (expectedType == Type.DOUBLE_TYPE) {
|
||||
v.aconst(Double.valueOf(myDelta));
|
||||
v.dconst(myDelta);
|
||||
}
|
||||
else {
|
||||
v.aconst(myDelta);
|
||||
|
||||
@@ -16,7 +16,7 @@ public class Inv implements IntrinsicMethod {
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
|
||||
receiver.put(expectedType, v);
|
||||
v.aconst(-1);
|
||||
v.iconst(-1);
|
||||
v.xor(expectedType);
|
||||
return StackValue.onStack(expectedType);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import java.util.List;
|
||||
public abstract class PropertyAccessorDescriptor extends DeclarationDescriptorImpl implements FunctionDescriptor, MemberDescriptor {
|
||||
|
||||
private final boolean hasBody;
|
||||
private final boolean isDefault;
|
||||
private final MemberModifiers modifiers;
|
||||
|
||||
protected PropertyAccessorDescriptor(
|
||||
@@ -20,16 +21,22 @@ public abstract class PropertyAccessorDescriptor extends DeclarationDescriptorIm
|
||||
@NotNull PropertyDescriptor correspondingProperty,
|
||||
@NotNull List<AnnotationDescriptor> annotations,
|
||||
@NotNull String name,
|
||||
boolean hasBody) {
|
||||
boolean hasBody,
|
||||
boolean isDefault) {
|
||||
super(correspondingProperty.getContainingDeclaration(), annotations, name);
|
||||
this.modifiers = modifiers;
|
||||
this.hasBody = hasBody;
|
||||
this.isDefault = isDefault;
|
||||
}
|
||||
|
||||
public boolean hasBody() {
|
||||
return hasBody;
|
||||
}
|
||||
|
||||
public boolean isDefault() {
|
||||
return isDefault;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PropertyAccessorDescriptor getOriginal() {
|
||||
|
||||
@@ -39,7 +39,7 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Member
|
||||
this.isVar = isVar;
|
||||
this.memberModifiers = memberModifiers;
|
||||
this.receiverType = receiverType;
|
||||
this.original = original == null ? this : original;
|
||||
this.original = original == null ? this : original.getOriginal();
|
||||
}
|
||||
|
||||
public PropertyDescriptor(
|
||||
|
||||
@@ -17,8 +17,8 @@ public class PropertyGetterDescriptor extends PropertyAccessorDescriptor {
|
||||
private final Set<PropertyGetterDescriptor> overriddenGetters = Sets.newHashSet();
|
||||
private JetType returnType;
|
||||
|
||||
public PropertyGetterDescriptor(@NotNull MemberModifiers modifiers, @NotNull PropertyDescriptor correspondingProperty, @NotNull List<AnnotationDescriptor> annotations, @Nullable JetType returnType, boolean hasBody) {
|
||||
super(modifiers, correspondingProperty, annotations, "get-" + correspondingProperty.getName(), hasBody);
|
||||
public PropertyGetterDescriptor(@NotNull MemberModifiers modifiers, @NotNull PropertyDescriptor correspondingProperty, @NotNull List<AnnotationDescriptor> annotations, @Nullable JetType returnType, boolean hasBody, boolean isDefault) {
|
||||
super(modifiers, correspondingProperty, annotations, "get-" + correspondingProperty.getName(), hasBody, isDefault);
|
||||
this.returnType = returnType == null ? correspondingProperty.getOutType() : returnType;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ public class PropertySetterDescriptor extends PropertyAccessorDescriptor {
|
||||
private MutableValueParameterDescriptor parameter;
|
||||
private final Set<PropertySetterDescriptor> overriddenSetters = Sets.newHashSet();
|
||||
|
||||
public PropertySetterDescriptor(@NotNull MemberModifiers modifiers, @NotNull PropertyDescriptor correspondingProperty, @NotNull List<AnnotationDescriptor> annotations, boolean hasBody) {
|
||||
super(modifiers, correspondingProperty, annotations, "set-" + correspondingProperty.getName(), hasBody);
|
||||
public PropertySetterDescriptor(@NotNull MemberModifiers modifiers, @NotNull PropertyDescriptor correspondingProperty, @NotNull List<AnnotationDescriptor> annotations, boolean hasBody, boolean isDefault) {
|
||||
super(modifiers, correspondingProperty, annotations, "set-" + correspondingProperty.getName(), hasBody, isDefault);
|
||||
}
|
||||
|
||||
public void initialize(@NotNull MutableValueParameterDescriptor parameter) {
|
||||
|
||||
@@ -19,6 +19,8 @@ public interface AnnotationArgumentVisitor<R, D> {
|
||||
|
||||
R visitDoubleValue(DoubleValue value, D data);
|
||||
|
||||
R visitFloatValue(FloatValue value, D data);
|
||||
|
||||
R visitBooleanValue(BooleanValue value, D data);
|
||||
|
||||
R visitCharValue(CharValue value, D data);
|
||||
|
||||
@@ -22,7 +22,7 @@ public class JetObjectDeclaration extends JetNamedDeclaration implements JetClas
|
||||
@Override
|
||||
public String getName() {
|
||||
JetObjectDeclarationName nameAsDeclaration = getNameAsDeclaration();
|
||||
return nameAsDeclaration == null ? "<Anonymous>" : nameAsDeclaration.getName();
|
||||
return nameAsDeclaration == null ? "ClassObj" : nameAsDeclaration.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -568,18 +568,20 @@ public class ClassDescriptorResolver {
|
||||
@Nullable
|
||||
private PropertySetterDescriptor resolvePropertySetterDescriptor(@NotNull JetScope scope, @NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
|
||||
JetPropertyAccessor setter = property.getSetter();
|
||||
if (setter != null && !property.isVar()) {
|
||||
trace.getErrorHandler().genericError(setter.asElement().getNode(), "A 'val'-property cannot have a setter");
|
||||
if (! property.isVar()) {
|
||||
if (setter != null) {
|
||||
trace.getErrorHandler().genericError(setter.asElement().getNode(), "A 'val'-property cannot have a setter");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
PropertySetterDescriptor setterDescriptor = null;
|
||||
PropertySetterDescriptor setterDescriptor;
|
||||
if (setter != null) {
|
||||
List<AnnotationDescriptor> annotations = annotationResolver.resolveAnnotations(scope, setter.getModifierList());
|
||||
JetParameter parameter = setter.getParameter();
|
||||
|
||||
setterDescriptor = new PropertySetterDescriptor(
|
||||
resolveModifiers(setter.getModifierList(), DEFAULT_MODIFIERS), // TODO : default modifiers differ in different contexts
|
||||
propertyDescriptor, annotations, setter.getBodyExpression() != null);
|
||||
propertyDescriptor, annotations, setter.getBodyExpression() != null, false);
|
||||
if (parameter != null) {
|
||||
if (parameter.isRef()) {
|
||||
trace.getErrorHandler().genericError(parameter.getRefNode(), "Setter parameters can not be 'ref'");
|
||||
@@ -614,12 +616,17 @@ public class ClassDescriptorResolver {
|
||||
}
|
||||
trace.record(BindingContext.PROPERTY_ACCESSOR, setter, setterDescriptor);
|
||||
}
|
||||
else {
|
||||
setterDescriptor = new PropertySetterDescriptor(
|
||||
propertyDescriptor.getModifiers(),
|
||||
propertyDescriptor, Collections.<AnnotationDescriptor>emptyList(), false, true);
|
||||
}
|
||||
return setterDescriptor;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PropertyGetterDescriptor resolvePropertyGetterDescriptor(@NotNull JetScope scope, @NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) {
|
||||
PropertyGetterDescriptor getterDescriptor = null;
|
||||
PropertyGetterDescriptor getterDescriptor;
|
||||
JetPropertyAccessor getter = property.getGetter();
|
||||
if (getter != null) {
|
||||
List<AnnotationDescriptor> annotations = annotationResolver.resolveAnnotations(scope, getter.getModifierList());
|
||||
@@ -632,9 +639,14 @@ public class ClassDescriptorResolver {
|
||||
|
||||
getterDescriptor = new PropertyGetterDescriptor(
|
||||
resolveModifiers(getter.getModifierList(), DEFAULT_MODIFIERS), // TODO : default modifiers differ in different contexts
|
||||
propertyDescriptor, annotations, returnType, getter.getBodyExpression() != null);
|
||||
propertyDescriptor, annotations, returnType, getter.getBodyExpression() != null, false);
|
||||
trace.record(BindingContext.PROPERTY_ACCESSOR, getter, getterDescriptor);
|
||||
}
|
||||
else {
|
||||
getterDescriptor = new PropertyGetterDescriptor(
|
||||
propertyDescriptor.getModifiers(),
|
||||
propertyDescriptor, Collections.<AnnotationDescriptor>emptyList(), propertyDescriptor.getOutType(), false, true);
|
||||
}
|
||||
return getterDescriptor;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.jetbrains.jet.lang.resolve.constants;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationArgumentVisitor;
|
||||
import org.jetbrains.jet.lang.types.JetStandardLibrary;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
|
||||
/**
|
||||
* @author alex.tkachman
|
||||
*/
|
||||
public class FloatValue implements CompileTimeConstant<Float> {
|
||||
private final float value;
|
||||
|
||||
public FloatValue(float value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JetType getType(@NotNull JetStandardLibrary standardLibrary) {
|
||||
return standardLibrary.getFloatType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, D> R accept(AnnotationArgumentVisitor<R, D> visitor, D data) {
|
||||
return visitor.visitFloatValue(this, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value + ".flt";
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,9 @@ package org.jetbrains.jet.lang.types;
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotatedImpl;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.JetScope;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -113,7 +113,6 @@ public final class JetTypeImpl extends AnnotatedImpl implements JetType {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static boolean equalTypes(@NotNull JetType type1, @NotNull JetType type2, @NotNull BiMap<TypeConstructor, TypeConstructor> equalityAxioms) {
|
||||
if (type1.isNullable() != type2.isNullable()) {
|
||||
return false;
|
||||
|
||||
@@ -37,6 +37,17 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.*;
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JetTypeInferrer {
|
||||
|
||||
private static final Set<String> numberConversions = new HashSet();
|
||||
|
||||
static {
|
||||
numberConversions.add("dbl");
|
||||
numberConversions.add("flt");
|
||||
numberConversions.add("lng");
|
||||
numberConversions.add("sht");
|
||||
numberConversions.add("byt");
|
||||
numberConversions.add("int");
|
||||
}
|
||||
|
||||
private static final JetType FORBIDDEN = new JetType() {
|
||||
@NotNull
|
||||
@@ -1456,7 +1467,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 + " " + ErrorHandler.atLocation(reportErrorOn));
|
||||
context.trace.getErrorHandler().genericError(reportErrorOn.getNode(), "Incompatible types: " + type + " and " + subjectType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1825,7 +1836,7 @@ public class JetTypeInferrer {
|
||||
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");
|
||||
context.trace.getErrorHandler().genericError(reportErrorsOn, "An ambiguity between 'iterator().hasNext()' function and 'iterator().hasNext' property");
|
||||
}
|
||||
else if (!hasNextFunctionSupported && !hasNextPropertySupported) {
|
||||
context.trace.getErrorHandler().genericError(reportErrorsOn, "Loop range must have an 'iterator().hasNext()' function or an 'iterator().hasNext' property");
|
||||
@@ -1907,6 +1918,10 @@ public class JetTypeInferrer {
|
||||
if (selectorExpression == null) return null;
|
||||
if (receiverType == null) receiverType = ErrorUtils.createErrorType("Type for " + expression.getText());
|
||||
|
||||
if (selectorExpression instanceof JetSimpleNameExpression) {
|
||||
propagateConstantValues(expression, context, (JetSimpleNameExpression) selectorExpression);
|
||||
}
|
||||
|
||||
// Clean resolution: no autocasts
|
||||
TemporaryBindingTrace cleanResolutionTrace = TemporaryBindingTrace.create(context.trace);
|
||||
TypeInferenceContext cleanResolutionContext = context.replaceBindingTrace(cleanResolutionTrace);
|
||||
@@ -1974,6 +1989,36 @@ public class JetTypeInferrer {
|
||||
return context.services.checkType(result, expression, contextWithExpectedType);
|
||||
}
|
||||
|
||||
private void propagateConstantValues(JetQualifiedExpression expression, TypeInferenceContext context, JetSimpleNameExpression selectorExpression) {
|
||||
JetExpression receiverExpression = expression.getReceiverExpression();
|
||||
CompileTimeConstant<?> receiverValue = context.trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, receiverExpression);
|
||||
CompileTimeConstant<?> wholeExpressionValue = context.trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, expression);
|
||||
if (wholeExpressionValue == null && receiverValue != null && !(receiverValue instanceof ErrorValue) && receiverValue.getValue() instanceof Number) {
|
||||
Number value = (Number) receiverValue.getValue();
|
||||
String referencedName = selectorExpression.getReferencedName();
|
||||
if (numberConversions.contains(referencedName)) {
|
||||
if ("dbl".equals(referencedName)) {
|
||||
context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new DoubleValue(value.doubleValue()));
|
||||
}
|
||||
else if ("flt".equals(referencedName)) {
|
||||
context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new FloatValue(value.floatValue()));
|
||||
}
|
||||
else if ("lng".equals(referencedName)) {
|
||||
context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new LongValue(value.longValue()));
|
||||
}
|
||||
else if ("sht".equals(referencedName)) {
|
||||
context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new ShortValue(value.shortValue()));
|
||||
}
|
||||
else if ("byt".equals(referencedName)) {
|
||||
context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new ByteValue(value.byteValue()));
|
||||
}
|
||||
else if ("int".equals(referencedName)) {
|
||||
context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new IntValue(value.intValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private FunctionDescriptor getCalleeFunctionDescriptor(@NotNull JetExpression selectorExpression, final TypeInferenceContext context) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||
@@ -311,4 +312,12 @@ public class TypeUtils {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean equalClasses(@NotNull JetType type1, @NotNull JetType type2) {
|
||||
DeclarationDescriptor declarationDescriptor1 = type1.getConstructor().getDeclarationDescriptor();
|
||||
if (declarationDescriptor1 == null) return false; // No class, classes are not equal
|
||||
DeclarationDescriptor declarationDescriptor2 = type2.getConstructor().getDeclarationDescriptor();
|
||||
if (declarationDescriptor2 == null) return false; // Class of type1 is not null
|
||||
return declarationDescriptor1.getOriginal().equals(declarationDescriptor2.getOriginal());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
fun box() : String {
|
||||
var sum : Int = 0
|
||||
var i = 0
|
||||
|
||||
val c6 = MyCollection4()
|
||||
sum = 0
|
||||
for (el in c6) {
|
||||
sum = sum + el
|
||||
}
|
||||
if(sum != 15) return "c6 failed"
|
||||
|
||||
val c5 = MyCollection3()
|
||||
sum = 0
|
||||
for (el in c5) {
|
||||
sum = sum + (el ?: 0)
|
||||
}
|
||||
if(sum != 15) return "c5 failed"
|
||||
|
||||
val c1: java.lang.Iterable<Int> = MyCollection1()
|
||||
sum = 0
|
||||
for (el in c1) {
|
||||
sum = sum + el
|
||||
}
|
||||
if(sum != 15) return "c1 failed"
|
||||
|
||||
val c2 = MyCollection1()
|
||||
sum = 0
|
||||
for (el in c2) {
|
||||
sum = sum + el
|
||||
}
|
||||
if(sum != 15) return "c2 failed"
|
||||
|
||||
val c3: Iterable<Int> = MyCollection2()
|
||||
sum = 0
|
||||
for (el in c3) {
|
||||
sum = sum + el
|
||||
}
|
||||
if(sum != 15) return "c3 failed"
|
||||
|
||||
val c4 = MyCollection2()
|
||||
sum = 0
|
||||
for (el in c4) {
|
||||
sum = sum + el
|
||||
}
|
||||
if(sum != 15) return "c4 failed"
|
||||
|
||||
val a : Array<Int> = Array<Int> (5)
|
||||
for(el in 0..4) {
|
||||
a[i] = i++
|
||||
}
|
||||
sum = 0
|
||||
for (el in a) {
|
||||
sum = sum + el
|
||||
}
|
||||
if(sum != 10) return "a failed"
|
||||
|
||||
val b : Array<Int?> = Array<Int?> (5)
|
||||
i = 0
|
||||
while(i < 5) {
|
||||
b[i] = i++
|
||||
}
|
||||
sum = 0
|
||||
for (el in b) {
|
||||
sum = sum + (el ?: 0)
|
||||
}
|
||||
System.out?.println(sum)
|
||||
if(sum != 10) return "b failed"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
class MyCollection1(): java.lang.Iterable<Int> {
|
||||
fun iterator(): java.util.Iterator<Int> = MyIterator()
|
||||
|
||||
class MyIterator(): java.util.Iterator<Int> {
|
||||
var k : Int = 5
|
||||
|
||||
fun next() : Int = k--
|
||||
fun hasNext() = k > 0
|
||||
}
|
||||
}
|
||||
|
||||
class MyCollection2(): Iterable<Int> {
|
||||
fun iterator(): Iterator<Int> = MyIterator()
|
||||
|
||||
class MyIterator(): Iterator<Int> {
|
||||
var k : Int = 5
|
||||
|
||||
fun next() : Int = k--
|
||||
fun hasNext() = k > 0
|
||||
}
|
||||
}
|
||||
|
||||
class MyCollection3() {
|
||||
fun iterator() = MyIterator()
|
||||
|
||||
class MyIterator() {
|
||||
var k : Int = 5
|
||||
|
||||
fun next() : Int? = k--
|
||||
fun hasNext() = k > 0
|
||||
}
|
||||
}
|
||||
|
||||
class MyCollection4() {
|
||||
fun iterator() = MyIterator()
|
||||
|
||||
class MyIterator() {
|
||||
var k : Int = 5
|
||||
|
||||
fun next() : Int = k--
|
||||
fun hasNext() = k > 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fun isDigit(a: Int) : String {
|
||||
val aa = java.util.ArrayList<Int> ()
|
||||
aa.add(239)
|
||||
|
||||
if(a in aa) return "array list"
|
||||
if(a in 0..9) return "digit"
|
||||
if(a !in 0..100) return "not small"
|
||||
return "something"
|
||||
}
|
||||
@@ -1,4 +1,11 @@
|
||||
fun isDigit(a: Int) = when(a) {
|
||||
in 0..9 => "digit"
|
||||
else => "something"
|
||||
fun isDigit(a: Int) : String {
|
||||
val aa = java.util.ArrayList<Int> ()
|
||||
aa.add(239)
|
||||
|
||||
return when(a) {
|
||||
in aa => "array list"
|
||||
in 0..9 => "digit"
|
||||
!in 0..100 => "not small"
|
||||
else => "something"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
fun main(args: Array<String>?) {
|
||||
val y: Unit = () //do not compile
|
||||
A<Unit>() //do not compile
|
||||
C<Unit>(()) //do not compile
|
||||
//do not compile
|
||||
System.out?.println(fff<Unit>(())) //do not compile
|
||||
System.out?.println(id<Unit>(y)) //do not compile
|
||||
System.out?.println(fff<Unit>(id<Unit>(y)) == id<Unit>(foreach(Array<Int>(0),{(e : Int) : Unit => }))) //do not compile
|
||||
}
|
||||
class A<T>()
|
||||
|
||||
class C<T>(val value: T) {
|
||||
fun foo(): T = value
|
||||
}
|
||||
|
||||
fun <T> fff(x: T) : T { return x }
|
||||
|
||||
fun <T> id(value: T): T = value
|
||||
|
||||
fun foreach(array: Array<Int>?, action: fun(Int): Unit) {
|
||||
for (el in array) {
|
||||
action(el) //exception through compilation (see below)
|
||||
}
|
||||
}
|
||||
|
||||
fun almostFilter(array: Array<Int>, action: fun(Int): Int) {
|
||||
for (el in array) {
|
||||
action(el)
|
||||
}
|
||||
}
|
||||
|
||||
fun box() : String {
|
||||
val a = Array<Int> (3)
|
||||
a[0] = 0
|
||||
a[1] = 1
|
||||
a[2] = 2
|
||||
foreach(a, { (el : Int) : Unit => System.out?.println(el) })
|
||||
almostFilter(a, { (el : Int) : Int => el })
|
||||
main(null)
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
namespace x
|
||||
|
||||
class Outer(val name: String) {
|
||||
class Inner() {
|
||||
val me = name
|
||||
|
||||
class object {
|
||||
fun bar() = "bar"
|
||||
}
|
||||
}
|
||||
|
||||
class object {
|
||||
class StaticInner() {
|
||||
class object {
|
||||
fun f() = "oo"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun box (): String {
|
||||
val inner = Outer("mama").Inner() //verify error
|
||||
if(inner.me != "mama")
|
||||
return "fail"
|
||||
|
||||
val outer = Outer ("papa")
|
||||
val inner2 = outer.Inner ()
|
||||
if(inner2.me != "papa")
|
||||
return "fail"
|
||||
|
||||
if(Outer.StaticInner.f() != "oo" )
|
||||
return "fail"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -39,6 +39,11 @@ fun t3 () : Boolean {
|
||||
if(d.isT(10)) return false
|
||||
if(!d.isT(null)) return false
|
||||
|
||||
val f = B<java.lang.String?>()
|
||||
if(!f.isT("aaa")) return false
|
||||
if(f.isT(10)) return false
|
||||
if(!f.isT(null)) return false
|
||||
|
||||
val c = B<Int>()
|
||||
if(c.isT("aaa")) return false
|
||||
if(!c.isT(10)) return false
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
class A() {
|
||||
var xi = 0
|
||||
var xin : Int? = 0
|
||||
var xinn : Int? = null
|
||||
|
||||
var xl = 0.lng
|
||||
var xln : Long? = 0.lng
|
||||
var xlnn : Long? = null
|
||||
|
||||
var xb = 0.byt
|
||||
var xbn : Long? = 0.byt
|
||||
var xbnn : Long? = null
|
||||
|
||||
var xf = 0.flt
|
||||
var xfn : Float? = 0.flt
|
||||
var xfnn : Float? = null
|
||||
|
||||
var xd = 0.dbl
|
||||
var xdn : Double? = 0.dbl
|
||||
var xdnn : Double? = null
|
||||
|
||||
var xs = 0.sht
|
||||
var xsn : Short? = 0.sht
|
||||
var xsnn : Short? = null
|
||||
}
|
||||
|
||||
fun box() : String {
|
||||
return "OK"
|
||||
}
|
||||
@@ -168,4 +168,13 @@ public class ClassGenTest extends CodegenTestCase {
|
||||
final Method rgbMethod = colorClass.getMethod("getRgb");
|
||||
assertEquals(0xFF0000, rgbMethod.invoke(redValue));
|
||||
}
|
||||
|
||||
public void testKt249() throws Exception {
|
||||
blackBoxFile("regressions/kt249.jet");
|
||||
}
|
||||
|
||||
public void testKt48 () throws Exception {
|
||||
blackBoxFile("regressions/kt48.jet");
|
||||
System.out.println(generateToText());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,4 +140,41 @@ public class ControlStructuresTest extends CodegenTestCase {
|
||||
assertTrue(caught);
|
||||
assertEquals("foobar", sb.toString());
|
||||
}
|
||||
|
||||
public void testForUserType() throws Exception {
|
||||
blackBoxFile("controlStructures/forUserType.jet");
|
||||
}
|
||||
|
||||
public void testKt237() throws Exception {
|
||||
blackBoxFile("regressions/kt237.jet");
|
||||
}
|
||||
|
||||
public void testCompareToNull() throws Exception {
|
||||
loadText("fun foo(a: String?, b: String?): Boolean = a == null && b !== null && null == a && null !== b");
|
||||
String text = generateToText();
|
||||
assertTrue(!text.contains("java/lang/Object.equals"));
|
||||
System.out.println(text);
|
||||
final Method main = generateFunction();
|
||||
assertEquals(true, main.invoke(null, null, "lala"));
|
||||
assertEquals(false, main.invoke(null, null, null));
|
||||
}
|
||||
|
||||
public void testCompareToNonnullableEq() throws Exception {
|
||||
loadText("fun foo(a: String?, b: String): Boolean = a == b || b == a");
|
||||
String text = generateToText();
|
||||
System.out.println(text);
|
||||
final Method main = generateFunction();
|
||||
assertEquals(false, main.invoke(null, null, "lala"));
|
||||
assertEquals(true, main.invoke(null, "papa", "papa"));
|
||||
}
|
||||
|
||||
public void testCompareToNonnullableNotEq() throws Exception {
|
||||
loadText("fun foo(a: String?, b: String): Boolean = a != b");
|
||||
String text = generateToText();
|
||||
System.out.println(text);
|
||||
assertTrue(text.contains("IXOR"));
|
||||
final Method main = generateFunction();
|
||||
assertEquals(true, main.invoke(null, null, "lala"));
|
||||
assertEquals(false, main.invoke(null, "papa", "papa"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,6 +209,7 @@ public class NamespaceGenTest extends CodegenTestCase {
|
||||
public void testJavaEqualsNull() throws Exception {
|
||||
loadText("fun foo(s1: String?, s2: String?) = s1 == s2");
|
||||
final Method main = generateFunction();
|
||||
System.out.println(generateToText());
|
||||
assertEquals(Boolean.TRUE, main.invoke(null, null, null));
|
||||
assertEquals(Boolean.FALSE, main.invoke(null, "jet", null));
|
||||
assertEquals(Boolean.FALSE, main.invoke(null, null, "jet"));
|
||||
@@ -217,6 +218,7 @@ public class NamespaceGenTest extends CodegenTestCase {
|
||||
public void testEqualsNullLiteral() throws Exception {
|
||||
loadText("fun foo(s: String?) = s == null");
|
||||
final Method main = generateFunction();
|
||||
System.out.println(generateToText());
|
||||
assertEquals(Boolean.TRUE, main.invoke(null, new Object[] { null }));
|
||||
assertEquals(Boolean.FALSE, main.invoke(null, "jet"));
|
||||
}
|
||||
@@ -448,8 +450,14 @@ public class NamespaceGenTest extends CodegenTestCase {
|
||||
public void testPredicateOperator() throws Exception {
|
||||
loadText("fun foo(s: String) = s?startsWith(\"J\")");
|
||||
final Method main = generateFunction();
|
||||
try {
|
||||
assertEquals("JetBrains", main.invoke(null, "JetBrains"));
|
||||
assertNull(main.invoke(null, "IntelliJ"));
|
||||
}
|
||||
catch (Throwable t) {
|
||||
System.out.println(generateToText());
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void testEscapeSequence() throws Exception {
|
||||
|
||||
@@ -35,12 +35,28 @@ public class PatternMatchingTest extends CodegenTestCase {
|
||||
assertEquals("something", foo.invoke(null, new Object()));
|
||||
}
|
||||
|
||||
public void testInrange() throws Exception {
|
||||
loadFile();
|
||||
System.out.println(generateToText());
|
||||
Method foo = generateFunction();
|
||||
assertEquals("array list", foo.invoke(null, 239));
|
||||
assertEquals("digit", foo.invoke(null, 0));
|
||||
assertEquals("digit", foo.invoke(null, 9));
|
||||
assertEquals("digit", foo.invoke(null, 5));
|
||||
assertEquals("not small", foo.invoke(null, 190));
|
||||
assertEquals("something", foo.invoke(null, 19));
|
||||
}
|
||||
|
||||
public void testRange() throws Exception {
|
||||
loadFile();
|
||||
System.out.println(generateToText());
|
||||
Method foo = generateFunction();
|
||||
assertEquals("array list", foo.invoke(null, 239));
|
||||
assertEquals("digit", foo.invoke(null, 0));
|
||||
assertEquals("digit", foo.invoke(null, 9));
|
||||
assertEquals("digit", foo.invoke(null, 5));
|
||||
assertEquals("something", foo.invoke(null, 19));
|
||||
assertEquals("not small", foo.invoke(null, 190));
|
||||
}
|
||||
|
||||
public void testRangeChar() throws Exception {
|
||||
@@ -80,8 +96,14 @@ public class PatternMatchingTest extends CodegenTestCase {
|
||||
public void testCall() throws Exception {
|
||||
loadText("fun foo(s: String) = when(s) { .startsWith(\"J\") => \"JetBrains\"; else => \"something\" }");
|
||||
Method foo = generateFunction();
|
||||
assertEquals("JetBrains", foo.invoke(null, "Java"));
|
||||
assertEquals("something", foo.invoke(null, "C#"));
|
||||
try {
|
||||
assertEquals("JetBrains", foo.invoke(null, "Java"));
|
||||
assertEquals("something", foo.invoke(null, "C#"));
|
||||
}
|
||||
catch (Throwable t) {
|
||||
System.out.println(generateToText());
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void testCallProperty() throws Exception {
|
||||
|
||||
@@ -134,4 +134,10 @@ public class PropertyGenTest extends CodegenTestCase {
|
||||
public void testKt257 () throws Exception {
|
||||
blackBoxFile("regressions/kt257.jet");
|
||||
}
|
||||
|
||||
public void testKt160() throws Exception {
|
||||
loadText("public val s = java.lang.Double.toString(1.0)");
|
||||
final Method method = generateFunction("getS");
|
||||
assertEquals(method.invoke(null), "1.0");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
package jet;
|
||||
|
||||
public abstract class Iterable$$Impl implements Iterable {
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package jet;
|
||||
|
||||
public interface Iterable<T> extends JetObject {
|
||||
Iterator<T> iterator ();
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package jet;
|
||||
|
||||
public abstract class Iterator$$Impl implements Iterator {
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package jet;
|
||||
|
||||
public interface Iterator<T> extends JetObject {
|
||||
boolean hasNext();
|
||||
T next ();
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package jet;
|
||||
|
||||
/**
|
||||
* @author alex.tkachman
|
||||
*/
|
||||
public class Tuple0 {
|
||||
public static final Tuple0 INSTANCE = new Tuple0();
|
||||
|
||||
private Tuple0() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "()";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o == INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 239;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user