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:
Andrey Breslav
2011-09-05 18:15:43 +04:00
37 changed files with 909 additions and 153 deletions
+1 -1
View File
@@ -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");
}
}
+4
View File
@@ -0,0 +1,4 @@
package jet;
public abstract class Iterable$$Impl implements Iterable {
}
+5
View File
@@ -0,0 +1,5 @@
package jet;
public interface Iterable<T> extends JetObject {
Iterator<T> iterator ();
}
+4
View File
@@ -0,0 +1,4 @@
package jet;
public abstract class Iterator$$Impl implements Iterator {
}
+6
View File
@@ -0,0 +1,6 @@
package jet;
public interface Iterator<T> extends JetObject {
boolean hasNext();
T next ();
}
+26
View File
@@ -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;
}
}