Merge remote branch 'origin/master'

Conflicts:
	compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java
This commit is contained in:
Andrey Breslav
2011-10-13 17:55:59 +04:00
79 changed files with 2607 additions and 505 deletions
@@ -13,6 +13,7 @@ import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.ProjectionErasingJetType;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -117,7 +118,7 @@ public class ClosureCodegen {
final Type enclosingType = context.enclosingClassType(state.getTypeMapper());
if (enclosingType == null) captureThis = false;
final Method constructor = generateConstructor(funClass, captureThis);
final Method constructor = generateConstructor(funClass, captureThis, funDescriptor.getReturnType());
if (captureThis) {
cv.visitField(Opcodes.ACC_PRIVATE, "this$0", enclosingType.getDescriptor(), null, null);
@@ -175,7 +176,7 @@ public class ClosureCodegen {
mv.visitEnd();
}
private Method generateConstructor(String funClass, boolean captureThis) {
private Method generateConstructor(String funClass, boolean captureThis, JetType returnType) {
int argCount = closure.size();
if (captureThis) {
@@ -199,9 +200,11 @@ public class ClosureCodegen {
final MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "<init>", constructor.getDescriptor(), null, new String[0]);
mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv);
ExpressionCodegen expressionCodegen = new ExpressionCodegen(mv, null, Type.VOID_TYPE, context, state);
iv.load(0, Type.getObjectType(funClass));
iv.invokespecial(funClass, "<init>", "()V");
expressionCodegen.generateTypeInfo(new ProjectionErasingJetType(returnType));
iv.invokespecial(funClass, "<init>", "(Ljet/typeinfo/TypeInfo;)V");
i = 1;
for (Type type : argTypes) {
@@ -52,8 +52,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
private final InstructionAdapter v;
private final FrameMap myMap;
private final JetTypeMapper typeMapper;
private final GenerationState state;
private final Type returnType;
private final BindingContext bindingContext;
private final Map<TypeParameterDescriptor, StackValue> typeParameterExpressions = new HashMap<TypeParameterDescriptor, StackValue>();
private final ClassContext context;
@@ -74,6 +76,14 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
this.intrinsics = state.getIntrinsics();
}
public GenerationState getState() {
return state;
}
public BindingContext getBindingContext() {
return bindingContext;
}
public JetTypeMapper getTypeMapper() {
return state.getTypeMapper();
}
@@ -207,7 +217,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
else {
assert expressionType != null;
final DeclarationDescriptor descriptor = expressionType.getConstructor().getDeclarationDescriptor();
if (isClass(descriptor, "IntRange")) { // TODO IntRange subclasses
if (isClass(descriptor, "IntRange")) { // TODO IntRange subclasses (now IntRange is final)
new ForInRangeLoopGenerator(expression, loopRangeType).invoke();
return StackValue.none();
}
@@ -921,7 +931,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
callableMethod = ClosureCodegen.asCallableMethod((FunctionDescriptor) fd);
}
else if (fd instanceof FunctionDescriptor) {
callableMethod = ClosureCodegen.asCallableMethod((FunctionDescriptor) fd);
callableMethod = typeMapper.mapToCallableMethod((FunctionDescriptor) fd, null);
}
else {
throw new UnsupportedOperationException("can't resolve declaration to callable: " + fd);
@@ -2076,7 +2086,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
}
}
void generateTypeInfo(JetType jetType) {
public void generateTypeInfo(JetType jetType) {
String knownTypeInfo = typeMapper.isKnownTypeInfo(jetType);
if(knownTypeInfo != null) {
v.getstatic("jet/typeinfo/TypeInfo", knownTypeInfo, "Ljet/typeinfo/TypeInfo;");
@@ -2287,7 +2297,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, rangeExpression);
assert jetType != null;
final DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
if (isClass(descriptor, "IntRange")) { // TODO IntRange subclasses
if (isClass(descriptor, "IntRange")) {
return true;
}
}
@@ -2308,7 +2318,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
final String className = "jet/Tuple" + entries.size();
Type tupleType = Type.getObjectType(className);
StringBuilder signature = new StringBuilder("(");
StringBuilder signature = new StringBuilder("(Ljet/typeinfo/TypeInfo;");
for (int i = 0; i != entries.size(); ++i) {
signature.append("Ljava/lang/Object;");
}
@@ -2316,6 +2326,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
v.anew(tupleType);
v.dup();
generateTypeInfo(new ProjectionErasingJetType(bindingContext.get(BindingContext.EXPRESSION_TYPE, expression)));
for (JetExpression entry : entries) {
gen(entry, OBJECT_TYPE);
}
@@ -57,6 +57,8 @@ public class JetTypeMapper {
private final HashMap<JetType,String> knowTypes = new HashMap<JetType, String>();
public static final Type TYPE_FUNCTION1 = Type.getObjectType("jet/Function1");
public static final Type TYPE_ITERATOR = Type.getObjectType("jet/Iterator");
public static final Type TYPE_INT_RANGE = Type.getObjectType("jet/IntRange");
public JetTypeMapper(JetStandardLibrary standardLibrary, BindingContext bindingContext) {
this.standardLibrary = standardLibrary;
@@ -316,6 +318,9 @@ public class JetTypeMapper {
if (jetType.equals(JetStandardClasses.getUnitType()) || jetType.equals(JetStandardClasses.getNothingType())) {
return Type.VOID_TYPE;
}
if (jetType.equals(JetStandardClasses.getNullableNothingType())) {
return TYPE_OBJECT;
}
return mapType(jetType, kind);
}
@@ -460,17 +465,16 @@ public class JetTypeMapper {
}
private Method mapSignature(JetNamedFunction f, List<Type> valueParameterTypes, OwnerKind kind) {
final JetTypeReference receiverTypeRef = f.getReceiverTypeRef();
final JetType receiverType = receiverTypeRef == null ? null : bindingContext.get(BindingContext.TYPE, receiverTypeRef);
final List<JetParameter> parameters = f.getValueParameters();
private Method mapSignature(FunctionDescriptor f, List<Type> valueParameterTypes, OwnerKind kind) {
final ReceiverDescriptor receiverTypeRef = f.getReceiver();
final JetType receiverType = receiverTypeRef == ReceiverDescriptor.NO_RECEIVER ? null : receiverTypeRef.getType();
final List<ValueParameterDescriptor> parameters = f.getValueParameters();
List<Type> parameterTypes = new ArrayList<Type>();
if (receiverType != null) {
parameterTypes.add(mapType(receiverType));
}
FunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, f);
if(kind == OwnerKind.TRAIT_IMPL) {
ClassDescriptor containingDeclaration = (ClassDescriptor) functionDescriptor.getContainingDeclaration();
ClassDescriptor containingDeclaration = (ClassDescriptor) f.getContainingDeclaration();
JetType jetType = TraitImplBodyCodegen.getSuperClass(containingDeclaration, bindingContext);
Type type = mapType(jetType);
if(type.getInternalName().equals("java/lang/Object")) {
@@ -480,24 +484,15 @@ public class JetTypeMapper {
valueParameterTypes.add(type);
parameterTypes.add(type);
}
for (JetParameter parameter : parameters) {
final Type type = mapType(bindingContext.get(BindingContext.TYPE, parameter.getTypeReference()));
for (ValueParameterDescriptor parameter : parameters) {
final Type type = mapType(parameter.getOutType());
valueParameterTypes.add(type);
parameterTypes.add(type);
}
for (int n = f.getTypeParameters().size(); n > 0; n--) {
parameterTypes.add(TYPE_TYPEINFO);
}
final JetTypeReference returnTypeRef = f.getReturnTypeRef();
Type returnType;
if (returnTypeRef == null) {
assert functionDescriptor != null;
final JetType type = functionDescriptor.getReturnType();
returnType = mapReturnType(type);
}
else {
returnType = mapReturnType(bindingContext.get(BindingContext.TYPE, returnTypeRef));
}
Type returnType = mapReturnType(f.getReturnType());
return new Method(f.getName(), returnType, parameterTypes.toArray(new Type[parameterTypes.size()]));
}
@@ -511,9 +506,13 @@ public class JetTypeMapper {
JetNamedFunction f = (JetNamedFunction) declaration;
final FunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, f);
assert functionDescriptor != null;
return mapToCallableMethod(functionDescriptor, kind);
}
public CallableMethod mapToCallableMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) {
final DeclarationDescriptor functionParent = functionDescriptor.getContainingDeclaration();
final List<Type> valueParameterTypes = new ArrayList<Type>();
Method descriptor = mapSignature(f, valueParameterTypes, kind);
Method descriptor = mapSignature(functionDescriptor.getOriginal(), valueParameterTypes, kind);
String owner;
int invokeOpcode;
boolean needsReceiver;
@@ -521,7 +520,7 @@ public class JetTypeMapper {
if (functionParent instanceof NamespaceDescriptor) {
owner = NamespaceCodegen.getJVMClassName(DescriptorRenderer.getFQName(functionParent));
invokeOpcode = Opcodes.INVOKESTATIC;
needsReceiver = f.getReceiverTypeRef() != null;
needsReceiver = functionDescriptor.getReceiver() != ReceiverDescriptor.NO_RECEIVER;
}
else if (functionParent instanceof ClassDescriptor) {
ClassDescriptor containingClass = (ClassDescriptor) functionParent;
@@ -197,6 +197,9 @@ public abstract class StackValue {
if (type.getSort() == Type.BOOLEAN) {
v.checkcast(JetTypeMapper.JL_BOOLEAN_TYPE);
}
else if (type.getSort() == Type.CHAR) {
v.checkcast(JetTypeMapper.JL_CHAR_TYPE);
}
else {
v.checkcast(JetTypeMapper.JL_NUMBER_TYPE);
}
@@ -0,0 +1,21 @@
package org.jetbrains.jet.codegen.intrinsics;
import com.intellij.psi.PsiElement;
import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.JetTypeMapper;
import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
import java.util.List;
public class ArrayIndices implements IntrinsicMethod {
@Override
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
receiver.put(JetTypeMapper.TYPE_OBJECT, v);
v.arraylength();
v.invokestatic("jet/IntRange", "count", "(I)Ljet/IntRange;");
return StackValue.onStack(JetTypeMapper.TYPE_INT_RANGE);
}
}
@@ -0,0 +1,65 @@
package org.jetbrains.jet.codegen.intrinsics;
import com.intellij.psi.PsiElement;
import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.JetTypeMapper;
import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetCallExpression;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.jetbrains.jet.lang.types.JetType;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
import java.util.List;
/**
* @author alex.tkachman
*/
public class ArrayIterator implements IntrinsicMethod {
@Override
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
receiver.put(JetTypeMapper.TYPE_OBJECT, v);
JetCallExpression call = (JetCallExpression) element;
FunctionDescriptor funDescriptor = (FunctionDescriptor) codegen.getBindingContext().get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) call.getCalleeExpression());
ClassDescriptor containingDeclaration = (ClassDescriptor) funDescriptor.getContainingDeclaration().getOriginal();
JetStandardLibrary standardLibrary = codegen.getState().getStandardLibrary();
if(containingDeclaration.equals(standardLibrary.getArray())) {
codegen.generateTypeInfo(funDescriptor.getReturnType().getArguments().get(0).getType());
v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([Ljava/lang/Object;Ljet/typeinfo/TypeInfo;)Ljet/Iterator;");
}
else if(containingDeclaration.equals(standardLibrary.getByteArrayClass())) {
v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([B)Ljet/Iterator;");
}
else if(containingDeclaration.equals(standardLibrary.getShortArrayClass())) {
v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([S)Ljet/Iterator;");
}
else if(containingDeclaration.equals(standardLibrary.getIntArrayClass())) {
v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([I)Ljet/Iterator;");
}
else if(containingDeclaration.equals(standardLibrary.getLongArrayClass())) {
v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([J)Ljet/Iterator;");
}
else if(containingDeclaration.equals(standardLibrary.getFloatArrayClass())) {
v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([F)Ljet/Iterator;");
}
else if(containingDeclaration.equals(standardLibrary.getDoubleArrayClass())) {
v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([D)Ljet/Iterator;");
}
else if(containingDeclaration.equals(standardLibrary.getCharArrayClass())) {
v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([C)Ljet/Iterator;");
}
else if(containingDeclaration.equals(standardLibrary.getBooleanArrayClass())) {
v.invokestatic("jet/arrays/ArrayIterator", "iterator", "([Z)Ljet/Iterator;");
}
else {
throw new UnsupportedOperationException(containingDeclaration.toString());
}
return StackValue.onStack(JetTypeMapper.TYPE_ITERATOR);
}
}
@@ -29,11 +29,13 @@ public class IntrinsicMethods {
private static final IntrinsicMethod DEC = new Increment(-1);
private static final List<String> PRIMITIVE_NUMBER_TYPES = ImmutableList.of("Boolean", "Byte", "Char", "Short", "Int", "Float", "Long", "Double");
public static final ArraySize ARRAY_SIZE = new ArraySize();
public static final IntrinsicMethod ARRAY_SIZE = new ArraySize();
public static final IntrinsicMethod ARRAY_INDICES = new ArrayIndices();
private final Project myProject;
private final JetStandardLibrary myStdLib;
private final Map<DeclarationDescriptor, IntrinsicMethod> myMethods = new HashMap<DeclarationDescriptor, IntrinsicMethod>();
private static final IntrinsicMethod ARRAY_ITERATOR = new ArrayIterator();
public IntrinsicMethods(Project project, JetStandardLibrary stdlib) {
myProject = project;
@@ -87,6 +89,30 @@ public class IntrinsicMethods {
declareIntrinsicProperty("DoubleArray", "size", ARRAY_SIZE);
declareIntrinsicProperty("CharArray", "size", ARRAY_SIZE);
declareIntrinsicProperty("BooleanArray", "size", ARRAY_SIZE);
declareIntrinsicProperty("Array", "indices", ARRAY_INDICES);
declareIntrinsicProperty("ByteArray", "indices", ARRAY_INDICES);
declareIntrinsicProperty("ShortArray", "indices", ARRAY_INDICES);
declareIntrinsicProperty("IntArray", "indices", ARRAY_INDICES);
declareIntrinsicProperty("LongArray", "indices", ARRAY_INDICES);
declareIntrinsicProperty("FloatArray", "indices", ARRAY_INDICES);
declareIntrinsicProperty("DoubleArray", "indices", ARRAY_INDICES);
declareIntrinsicProperty("CharArray", "indices", ARRAY_INDICES);
declareIntrinsicProperty("BooleanArray", "indices", ARRAY_INDICES);
declareIterator(myStdLib.getArray());
declareIterator(myStdLib.getByteArrayClass());
declareIterator(myStdLib.getShortArrayClass());
declareIterator(myStdLib.getIntArrayClass());
declareIterator(myStdLib.getLongArrayClass());
declareIterator(myStdLib.getFloatArrayClass());
declareIterator(myStdLib.getDoubleArrayClass());
declareIterator(myStdLib.getCharArrayClass());
declareIterator(myStdLib.getBooleanArrayClass());
}
private void declareIterator(ClassDescriptor classDescriptor) {
declareOverload(classDescriptor.getDefaultType().getMemberScope().getFunctions("iterator"), 0, ARRAY_ITERATOR);
}
private void declareIntrinsicStringMethods() {
@@ -16,21 +16,15 @@ import java.util.List;
* @author yole
*/
public class RangeTo implements IntrinsicMethod {
private static final String INT_RANGE_CONSTRUCTOR_DESCRIPTOR = "(II)V";
private static final Type INT_RANGE_TYPE = Type.getType(IntRange.class);
private static final String CLASS_INT_RANGE = "jet/IntRange";
@Override
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
JetBinaryExpression expression = (JetBinaryExpression) element;
final Type leftType = codegen.expressionType(expression.getLeft());
if (JetTypeMapper.isIntPrimitive(leftType)) {
v.anew(INT_RANGE_TYPE);
v.dup();
codegen.gen(expression.getLeft(), Type.INT_TYPE);
codegen.gen(expression.getRight(), Type.INT_TYPE);
v.invokespecial(CLASS_INT_RANGE, "<init>", INT_RANGE_CONSTRUCTOR_DESCRIPTOR);
return StackValue.onStack(INT_RANGE_TYPE);
v.invokestatic("jet/IntRange", "rangeTo", "(II)Ljet/IntRange;");
return StackValue.onStack(JetTypeMapper.TYPE_INT_RANGE);
}
else {
throw new UnsupportedOperationException("ranges are only supported for int objects");
+65 -27
View File
@@ -42,7 +42,7 @@ fun Any?.toString() : String// = this === other
trait Iterator<out T> {
fun next() : T
abstract fun hasNext() : Boolean
fun hasNext() : Boolean
}
trait Iterable<out T> {
@@ -54,6 +54,8 @@ class Array<T>(val size : Int, init : fun(Int) : T = null ) {
fun set(index : Int, value : T) : Unit
fun iterator() : Iterator<T>
val indices : IntRange
}
class ByteArray(val size : Int) {
@@ -61,6 +63,8 @@ class ByteArray(val size : Int) {
fun set(index : Int, value : Byte) : Unit
fun iterator() : Iterator<Byte>
val indices : IntRange
}
class ShortArray(val size : Int) {
@@ -68,6 +72,8 @@ class ShortArray(val size : Int) {
fun set(index : Int, value : Short) : Unit
fun iterator() : Iterator<Short>
val indices : IntRange
}
class IntArray(val size : Int) {
@@ -75,6 +81,8 @@ class IntArray(val size : Int) {
fun set(index : Int, value : Int) : Unit
fun iterator() : Iterator<Int>
val indices : IntRange
}
class LongArray(val size : Int) {
@@ -82,6 +90,8 @@ class LongArray(val size : Int) {
fun set(index : Int, value : Long) : Unit
fun iterator() : Iterator<Long>
val indices : IntRange
}
class FloatArray(val size : Int) {
@@ -89,6 +99,8 @@ class FloatArray(val size : Int) {
fun set(index : Int, value : Float) : Unit
fun iterator() : Iterator<Float>
val indices : IntRange
}
class DoubleArray(val size : Int) {
@@ -96,6 +108,8 @@ class DoubleArray(val size : Int) {
fun set(index : Int, value : Double) : Unit
fun iterator() : Iterator<Double>
val indices : IntRange
}
class CharArray(val size : Int) {
@@ -103,6 +117,8 @@ class CharArray(val size : Int) {
fun set(index : Int, value : Char) : Unit
fun iterator() : Iterator<Char>
val indices : IntRange
}
class BooleanArray(val size : Int) {
@@ -110,6 +126,8 @@ class BooleanArray(val size : Int) {
fun set(index : Int, value : Boolean) : Unit
fun iterator() : Iterator<Boolean>
val indices : IntRange
}
trait Comparable<in T> {
@@ -152,8 +170,28 @@ trait Range<in T : Comparable<T>> {
fun contains(item : T) : Boolean
}
class IntRange<T : Comparable<T>>(val start : Int, val end : Int) : Range<T>, Iterable<T> {
class IntRange(val start : Int, size : Int, reversed : Boolean = false) : Range<Int>, Iterable<Int> {
fun iterator () : Iterator<Int>
fun contains (elem: Int) : Boolean
val size : Int
val end : Int
val reversed : Boolean
}
class LongRange(val start : Long, size : Long, reversed : Boolean = false) : Range<Long>, Iterable<Long> {
fun iterator () : Iterator<Long>
fun contains (elem: Long) : Boolean
val size : Long
val end : Long
val reversed : Boolean
}
abstract class Number : Hashable {
@@ -349,11 +387,11 @@ class Long : Number, Comparable<Long> {
fun rangeTo(other : Double) : Range<Double>
fun rangeTo(other : Float) : Range<Double>
fun rangeTo(other : Long) : IntRange<Long>
fun rangeTo(other : Int) : IntRange<Long>
fun rangeTo(other : Short) : IntRange<Long>
fun rangeTo(other : Byte) : IntRange<Long>
fun rangeTo(other : Char) : IntRange<Long>
fun rangeTo(other : Long) : LongRange
fun rangeTo(other : Int) : LongRange
fun rangeTo(other : Short) : LongRange
fun rangeTo(other : Byte) : LongRange
fun rangeTo(other : Char) : LongRange
fun inc() : Long
fun dec() : Long
@@ -420,11 +458,11 @@ class Int : Number, Comparable<Int> {
fun rangeTo(other : Double) : Range<Double>
fun rangeTo(other : Float) : Range<Double>
fun rangeTo(other : Long) : IntRange<Long>
fun rangeTo(other : Int) : IntRange<Int>
fun rangeTo(other : Short) : IntRange<Int>
fun rangeTo(other : Byte) : IntRange<Int>
fun rangeTo(other : Char) : IntRange<Int>
fun rangeTo(other : Long) : LongRange
fun rangeTo(other : Int) : IntRange
fun rangeTo(other : Short) : IntRange
fun rangeTo(other : Byte) : IntRange
fun rangeTo(other : Char) : IntRange
fun inc() : Int
fun dec() : Int
@@ -491,11 +529,11 @@ class Char : Number, Comparable<Char> {
fun rangeTo(other : Double) : Range<Double>
fun rangeTo(other : Float) : Range<Float>
fun rangeTo(other : Long) : IntRange<Long>
fun rangeTo(other : Int) : IntRange<Int>
fun rangeTo(other : Short) : IntRange<Short>
fun rangeTo(other : Byte) : IntRange<Byte>
fun rangeTo(other : Char) : IntRange<Char>
fun rangeTo(other : Long) : LongRange
fun rangeTo(other : Int) : IntRange
fun rangeTo(other : Short) : IntRange
fun rangeTo(other : Byte) : IntRange
fun rangeTo(other : Char) : IntRange
fun inc() : Char
fun dec() : Char
@@ -554,11 +592,11 @@ class Short : Number, Comparable<Short> {
fun rangeTo(other : Double) : Range<Double>
fun rangeTo(other : Float) : Range<Float>
fun rangeTo(other : Long) : IntRange<Long>
fun rangeTo(other : Int) : IntRange<Int>
fun rangeTo(other : Short) : IntRange<Short>
fun rangeTo(other : Byte) : IntRange<Short>
fun rangeTo(other : Char) : IntRange<Int>
fun rangeTo(other : Long) : LongRange
fun rangeTo(other : Int) : IntRange
fun rangeTo(other : Short) : IntRange
fun rangeTo(other : Byte) : IntRange
fun rangeTo(other : Char) : IntRange
fun inc() : Short
fun dec() : Short
@@ -617,11 +655,11 @@ class Byte : Number, Comparable<Byte> {
fun rangeTo(other : Double) : Range<Double>
fun rangeTo(other : Float) : Range<Float>
fun rangeTo(other : Long) : IntRange<Long>
fun rangeTo(other : Int) : IntRange<Int>
fun rangeTo(other : Short) : IntRange<Short>
fun rangeTo(other : Byte) : IntRange<Byte>
fun rangeTo(other : Char) : IntRange<Int>
fun rangeTo(other : Long) : LongRange
fun rangeTo(other : Int) : IntRange
fun rangeTo(other : Short) : IntRange
fun rangeTo(other : Byte) : IntRange
fun rangeTo(other : Char) : IntRange
fun inc() : Byte
fun dec() : Byte
@@ -44,8 +44,8 @@ public class JetSemanticServices {
}
@NotNull
public JetTypeInferrer.Services getTypeInferrerServices(@NotNull BindingTrace trace, @NotNull JetFlowInformationProvider flowInformationProvider) {
return new JetTypeInferrer(flowInformationProvider, this).getServices(trace);
public JetTypeInferrer.Services getTypeInferrerServices(@NotNull BindingTrace trace) {
return new JetTypeInferrer(this).getServices(trace);
}
@NotNull
@@ -25,6 +25,7 @@ public interface JetControlFlowBuilder {
void jumpOnTrue(@NotNull Label label);
void nondeterministicJump(Label label); // Maybe, jump to label
void jumpToError(JetThrowExpression expression);
void jumpToError(JetExpression nothingExpression);
// Entry/exit points
Label getEntryPoint(@NotNull JetElement labelElement);
@@ -62,6 +62,11 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder {
builder.jumpToError(expression);
}
@Override
public void jumpToError(JetExpression nothingExpression) {
builder.jumpToError(nothingExpression);
}
@Override
public Label getEntryPoint(@NotNull JetElement labelElement) {
return builder.getEntryPoint(labelElement);
@@ -1,11 +1,15 @@
package org.jetbrains.jet.lang.cfg;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
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.BindingTrace;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeInferrer;
import org.jetbrains.jet.lexer.JetTokens;
@@ -18,7 +22,7 @@ import static org.jetbrains.jet.lang.diagnostics.Errors.*;
*/
public class JetControlFlowProcessor {
private final Map<String, Stack<JetElement>> labeledElements = new HashMap<String, Stack<JetElement>>();
// private final Map<String, Stack<JetElement>> labeledElements = new HashMap<String, Stack<JetElement>>();
private final JetControlFlowBuilder builder;
private final BindingTrace trace;
@@ -33,10 +37,10 @@ public class JetControlFlowProcessor {
}
public void generateSubroutineControlFlow(@NotNull JetElement subroutineElement, @NotNull List<? extends JetElement> body) {
if (subroutineElement instanceof JetNamedDeclaration) {
JetNamedDeclaration namedDeclaration = (JetNamedDeclaration) subroutineElement;
enterLabeledElement(JetPsiUtil.safeName(namedDeclaration.getName()), namedDeclaration);
}
// if (subroutineElement instanceof JetNamedDeclaration) {
// JetNamedDeclaration namedDeclaration = (JetNamedDeclaration) subroutineElement;
// enterLabeledElement(JetPsiUtil.safeName(namedDeclaration.getName()), namedDeclaration);
// }
boolean functionLiteral = subroutineElement instanceof JetFunctionLiteralExpression;
builder.enterSubroutine(subroutineElement, functionLiteral);
for (JetElement statement : body) {
@@ -45,57 +49,55 @@ public class JetControlFlowProcessor {
builder.exitSubroutine(subroutineElement, functionLiteral);
}
private void enterLabeledElement(@NotNull String labelName, @NotNull JetElement labeledElement) {
Stack<JetElement> stack = labeledElements.get(labelName);
if (stack == null) {
stack = new Stack<JetElement>();
labeledElements.put(labelName, stack);
}
stack.push(labeledElement);
}
// private void enterLabeledElement(@NotNull String labelName, @NotNull JetElement labeledElement) {
// Stack<JetElement> stack = labeledElements.get(labelName);
// if (stack == null) {
// stack = new Stack<JetElement>();
// labeledElements.put(labelName, stack);
// }
// stack.push(labeledElement);
// }
//
// private void exitElement(JetElement element) {
// // TODO : really suboptimal
// for (Iterator<Map.Entry<String, Stack<JetElement>>> mapIter = labeledElements.entrySet().iterator(); mapIter.hasNext(); ) {
// Map.Entry<String, Stack<JetElement>> entry = mapIter.next();
// Stack<JetElement> stack = entry.getValue();
// for (Iterator<JetElement> stackIter = stack.iterator(); stackIter.hasNext(); ) {
// JetElement recorded = stackIter.next();
// if (recorded == element) {
// stackIter.remove();
// }
// }
// if (stack.isEmpty()) {
// mapIter.remove();
// }
// }
// }
private void exitElement(JetElement element) {
// TODO : really suboptimal
for (Iterator<Map.Entry<String, Stack<JetElement>>> mapIter = labeledElements.entrySet().iterator(); mapIter.hasNext(); ) {
Map.Entry<String, Stack<JetElement>> entry = mapIter.next();
Stack<JetElement> stack = entry.getValue();
for (Iterator<JetElement> stackIter = stack.iterator(); stackIter.hasNext(); ) {
JetElement recorded = stackIter.next();
if (recorded == element) {
stackIter.remove();
}
}
if (stack.isEmpty()) {
mapIter.remove();
}
}
}
@Nullable
private JetElement resolveLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved) {
Stack<JetElement> stack = labeledElements.get(labelName);
if (stack == null || stack.isEmpty()) {
if (reportUnresolved) {
trace.report(UNRESOLVED_REFERENCE.on(labelExpression));
}
return null;
}
else if (stack.size() > 1) {
// trace.getErrorHandler().genericWarning(labelExpression.getNode(), "There is more than one label with such a name in this scope");
trace.report(LABEL_NAME_CLASH.on(labelExpression));
}
JetElement result = stack.peek();
trace.record(BindingContext.LABEL_TARGET, labelExpression, result);
return result;
}
// @Nullable
// private JetElement resolveLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved) {
// Stack<JetElement> stack = labeledElements.get(labelName);
// if (stack == null || stack.isEmpty()) {
// if (reportUnresolved) {
//// trace.report(UNRESOLVED_REFERENCE.on(labelExpression));
// }
// return null;
// }
// else if (stack.size() > 1) {
//// trace.getErrorHandler().genericWarning(labelExpression.getNode(), "There is more than one label with such a name in this scope");
//// trace.report(LABEL_NAME_CLASH.on(labelExpression));
// }
//
// JetElement result = stack.peek();
//// trace.record(BindingContext.LABEL_TARGET, labelExpression, result);
// return result;
// }
private class CFPVisitor extends JetVisitorVoid {
// private final boolean preferBlock;
private final boolean inCondition;
private CFPVisitor(boolean inCondition) {
// this.preferBlock = preferBlock;
this.inCondition = inCondition;
}
@@ -109,7 +111,7 @@ public class JetControlFlowProcessor {
visitor = new CFPVisitor(inCondition);
}
element.accept(visitor);
exitElement(element);
// exitElement(element);
}
@Override
@@ -122,12 +124,12 @@ public class JetControlFlowProcessor {
@Override
public void visitThisExpression(JetThisExpression expression) {
JetSimpleNameExpression targetLabel = expression.getTargetLabel();
if (targetLabel != null) {
String labelName = expression.getLabelName();
assert labelName != null;
resolveLabel(labelName, targetLabel, false);
}
// JetSimpleNameExpression targetLabel = expression.getTargetLabel();
// if (targetLabel != null) {
// String labelName = expression.getLabelName();
// assert labelName != null;
// resolveLabel(labelName, targetLabel, false);
// }
builder.read(expression);
}
@@ -139,6 +141,12 @@ public class JetControlFlowProcessor {
@Override
public void visitSimpleNameExpression(JetSimpleNameExpression expression) {
builder.read(expression);
if (trace.get(BindingContext.PROCESSED, expression)) {
JetType type = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression);
if (type != null && JetStandardClasses.isNothing(type)) {
builder.jumpToError(expression);
}
}
}
@Override
@@ -153,7 +161,7 @@ public class JetControlFlowProcessor {
private void visitLabeledExpression(@NotNull String labelName, @NotNull JetExpression labeledExpression) {
JetExpression deparenthesized = JetPsiUtil.deparenthesize(labeledExpression);
if (deparenthesized != null) {
enterLabeledElement(labelName, deparenthesized);
// enterLabeledElement(labelName, deparenthesized);
value(labeledExpression, inCondition);
}
}
@@ -437,12 +445,20 @@ public class JetControlFlowProcessor {
if (labelName != null) {
JetSimpleNameExpression targetLabel = expression.getTargetLabel();
assert targetLabel != null;
loop = resolveLabel(labelName, targetLabel, true);
if (!isLoop(loop)) {
// trace.getErrorHandler().genericError(expression.getNode(), "The label '" + targetLabel.getText() + "' does not denote a loop");
PsiElement labeledElement = BindingContextUtils.resolveToDeclarationPsiElement(trace.getBindingContext(), targetLabel);
if (labeledElement instanceof JetLoopExpression) {
loop = (JetLoopExpression) labeledElement;
}
else {
trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.getText()));
loop = null;
}
// loop = resolveLabel(labelName, targetLabel, true);
// if (!isLoop(loop)) {
//// trace.getErrorHandler().genericError(expression.getNode(), "The label '" + targetLabel.getText() + "' does not denote a loop");
// trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.getText()));
// loop = null;
// }
}
else {
loop = builder.getCurrentLoop();
@@ -454,11 +470,11 @@ public class JetControlFlowProcessor {
return loop;
}
private boolean isLoop(JetElement loop) {
return loop instanceof JetWhileExpression ||
loop instanceof JetDoWhileExpression ||
loop instanceof JetForExpression;
}
// private boolean isLoop(JetElement loop) {
// return loop instanceof JetWhileExpression ||
// loop instanceof JetDoWhileExpression ||
// loop instanceof JetForExpression;
// }
@Override
public void visitReturnExpression(JetReturnExpression expression) {
@@ -471,13 +487,21 @@ public class JetControlFlowProcessor {
if (labelElement != null) {
String labelName = expression.getLabelName();
assert labelName != null;
subroutine = resolveLabel(labelName, labelElement, true);
PsiElement labeledElement = BindingContextUtils.resolveToDeclarationPsiElement(trace.getBindingContext(), labelElement);
if (labeledElement != null) {
assert labeledElement instanceof JetElement;
subroutine = (JetElement) labeledElement;
}
else {
subroutine = null;
}
//subroutine = resolveLabel(labelName, labelElement, true);
}
else {
subroutine = builder.getCurrentSubroutine();
// TODO : a context check
}
if (subroutine != null) {
if (subroutine instanceof JetFunction || subroutine instanceof JetFunctionLiteralExpression) {
if (returnedExpression == null) {
builder.returnNoValue(expression, subroutine);
}
@@ -485,6 +509,11 @@ public class JetControlFlowProcessor {
builder.returnValue(expression, subroutine);
}
}
else {
if (labelElement != null) {
trace.report(NOT_A_RETURN_LABEL.on(expression, expression.getLabelName()));
}
}
}
@Override
@@ -524,6 +553,12 @@ public class JetControlFlowProcessor {
value(selectorExpression, false);
}
builder.read(expression);
if (trace.get(BindingContext.PROCESSED, expression)) {
JetType type = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression);
if (type != null && JetStandardClasses.isNothing(type)) {
builder.jumpToError(expression);
}
}
}
private void visitCall(JetCallElement call) {
@@ -549,6 +584,12 @@ public class JetControlFlowProcessor {
value(expression.getCalleeExpression(), false);
builder.read(expression);
if (trace.get(BindingContext.PROCESSED, expression)) {
JetType type = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression);
if (type != null && JetStandardClasses.isNothing(type)) {
builder.jumpToError(expression);
}
}
}
// @Override
@@ -11,61 +11,61 @@ import java.util.Collection;
* @author abreslav
*/
public interface JetFlowInformationProvider {
JetFlowInformationProvider THROW_EXCEPTION = new JetFlowInformationProvider() {
@Override
public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) {
throw new UnsupportedOperationException();
}
@Override
public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions) {
throw new UnsupportedOperationException();
}
@Override
public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
throw new UnsupportedOperationException();
}
@Override
public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
throw new UnsupportedOperationException();
}
@Override
public boolean isBreakable(JetLoopExpression loop) {
throw new UnsupportedOperationException();
}
};
JetFlowInformationProvider NONE = new JetFlowInformationProvider() {
@Override
public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) {
}
@Override
public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions) {
}
@Override
public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
}
@Override
public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
}
@Override
public boolean isBreakable(JetLoopExpression loop) {
return false;
}
};
// JetFlowInformationProvider THROW_EXCEPTION = new JetFlowInformationProvider() {
// @Override
// public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) {
// throw new UnsupportedOperationException();
// }
//
// @Override
// public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions) {
// throw new UnsupportedOperationException();
// }
//
// @Override
// public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
// throw new UnsupportedOperationException();
// }
//
// @Override
// public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
// throw new UnsupportedOperationException();
// }
//
// @Override
// public boolean isBreakable(JetLoopExpression loop) {
// throw new UnsupportedOperationException();
// }
//
// };
//
// JetFlowInformationProvider NONE = new JetFlowInformationProvider() {
// @Override
// public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) {
//
// }
//
// @Override
// public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions) {
//
// }
//
// @Override
// public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
//
// }
//
// @Override
// public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
//
// }
//
// @Override
// public boolean isBreakable(JetLoopExpression loop) {
// return false;
// }
//
// };
/**
* Collects expressions returned from the given subroutine and 'return;' expressions
@@ -250,6 +250,11 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
public void jumpToError(JetThrowExpression expression) {
add(new UnconditionalJumpInstruction(error));
}
@Override
public void jumpToError(JetExpression nothingExpression) {
add(new UnconditionalJumpInstruction(error));
}
@Override
public void enterTryFinally(@NotNull GenerationTrigger generationTrigger) {
@@ -143,7 +143,6 @@ public interface Errors {
PsiElementOnlyDiagnosticFactory3<JetModifierListOwner, CallableMemberDescriptor, CallableMemberDescriptor, DeclarationDescriptor> VIRTUAL_MEMBER_HIDDEN = PsiElementOnlyDiagnosticFactory3.create(ERROR, "''{0}'' hides ''{1}'' in class {2} and needs 'override' modifier", DescriptorRenderer.TEXT);
SimpleDiagnosticFactory UNREACHABLE_CODE = SimpleDiagnosticFactory.create(ERROR, "Unreachable code");
ParameterizedDiagnosticFactory1<String> UNREACHABLE_BECAUSE_OF_NOTHING = ParameterizedDiagnosticFactory1.create(ERROR, "This code is unreachable, because ''{0}'' never terminates normally");
SimpleDiagnosticFactory MANY_CLASS_OBJECTS = SimpleDiagnosticFactory.create(ERROR, "Only one class object is allowed per class");
SimpleDiagnosticFactory CLASS_OBJECT_NOT_ALLOWED = SimpleDiagnosticFactory.create(ERROR, "A class object is not allowed here");
@@ -191,6 +190,7 @@ public interface Errors {
SimpleDiagnosticFactory RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY = SimpleDiagnosticFactory.create(ERROR, "Returns are not allowed for functions with expression body. Use block body in '{...}'");
SimpleDiagnosticFactory NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY = SimpleDiagnosticFactory.create(ERROR, "A 'return' expression required in a function with a block body ('{...}')");
ParameterizedDiagnosticFactory1<JetType> RETURN_TYPE_MISMATCH = ParameterizedDiagnosticFactory1.create(ERROR, "This function must return a value of type {0}");
ParameterizedDiagnosticFactory1<JetType> EXPECTED_TYPE_MISMATCH = ParameterizedDiagnosticFactory1.create(ERROR, "Expected a value of type {0}");
ParameterizedDiagnosticFactory1<JetType> UPPER_BOUND_VIOLATED = ParameterizedDiagnosticFactory1.create(ERROR, "An upper bound {0} is violated"); // TODO : Message
ParameterizedDiagnosticFactory1<JetType> FINAL_CLASS_OBJECT_UPPER_BOUND = ParameterizedDiagnosticFactory1.create(ERROR, "{0} is a final type, and thus a class object cannot extend it");
@@ -221,6 +221,7 @@ public interface Errors {
SimpleDiagnosticFactory VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION = SimpleDiagnosticFactory.create(ERROR, "A type annotation is required on a value parameter");
SimpleDiagnosticFactory BREAK_OR_CONTINUE_OUTSIDE_A_LOOP = SimpleDiagnosticFactory.create(ERROR, "'break' and 'continue' are only allowed inside a loop");
ParameterizedDiagnosticFactory1<String> NOT_A_LOOP_LABEL = ParameterizedDiagnosticFactory1.create(ERROR, "The label ''{0}'' does not denote a loop");
ParameterizedDiagnosticFactory1<String> NOT_A_RETURN_LABEL = ParameterizedDiagnosticFactory1.create(ERROR, "The label ''{0}'' does not reference to a context from which we can return");
SimpleDiagnosticFactory ANONYMOUS_INITIALIZER_WITHOUT_CONSTRUCTOR = SimpleDiagnosticFactory.create(ERROR, "Anonymous initializers are only allowed in the presence of a primary constructor");
SimpleDiagnosticFactory NULLABLE_SUPERTYPE = SimpleDiagnosticFactory.create(ERROR, "A supertype cannot be nullable");
@@ -7,7 +7,7 @@ import org.jetbrains.jet.JetNodeType;
/**
* @author max
*/
public class JetExpression extends JetElement {
public abstract class JetExpression extends JetElement {
public JetExpression(@NotNull ASTNode node) {
super(node);
}
@@ -0,0 +1,796 @@
package org.jetbrains.jet.lang.psi;
import java.util.List;
/**
* @author svtk
*/
public class JetTreeVisitor<D> extends JetVisitor<Void, D> {
@Override
public Void visitNamespace(JetNamespace namespace, D data) {
List<JetImportDirective> importDirectives = namespace.getImportDirectives();
for (JetImportDirective directive : importDirectives) {
directive.visit(this, data);
}
List<JetDeclaration> declarations = namespace.getDeclarations();
for (JetDeclaration declaration : declarations) {
declaration.visit(this, data);
}
return null;
}
@Override
public Void visitClass(JetClass klass, D data) {
List<JetDeclaration> declarations = klass.getDeclarations();
for (JetDeclaration declaration : declarations) {
declaration.visit(this, data);
}
return null;
}
@Override
public Void visitClassObject(JetClassObject classObject, D data) {
JetObjectDeclaration objectDeclaration = classObject.getObjectDeclaration();
if (objectDeclaration != null) {
objectDeclaration.visit(this, data);
}
return null;
}
@Override
public Void visitConstructor(JetConstructor constructor, D data) {
visitDeclarationWithBody(constructor, data);
return null;
}
@Override
public Void visitNamedFunction(JetNamedFunction function, D data) {
visitDeclarationWithBody(function, data);
return null;
}
@Override
public Void visitProperty(JetProperty property, D data) {
List<JetPropertyAccessor> accessors = property.getAccessors();
for (JetPropertyAccessor accessor : accessors) {
accessor.visit(this, data);
}
JetExpression initializer = property.getInitializer();
if (initializer != null) {
initializer.visit(this, data);
}
return null;
}
@Override
public Void visitTypedef(JetTypedef typedef, D data) {
return super.visitTypedef(typedef, data);
}
@Override
public Void visitJetFile(JetFile file, D data) {
JetNamespace rootNamespace = file.getRootNamespace();
return rootNamespace.visit(this, data);
}
@Override
public Void visitImportDirective(JetImportDirective importDirective, D data) {
return super.visitImportDirective(importDirective, data);
}
@Override
public Void visitClassBody(JetClassBody classBody, D data) {
List<JetDeclaration> declarations = classBody.getDeclarations();
for (JetDeclaration declaration : declarations) {
declaration.visit(this, data);
}
List<JetConstructor> secondaryConstructors = classBody.getSecondaryConstructors();
for (JetConstructor constructor : secondaryConstructors) {
constructor.visit(this, data);
}
return null;
}
@Override
public Void visitNamespaceBody(JetNamespaceBody body, D data) {
List<JetDeclaration> declarations = body.getDeclarations();
for (JetDeclaration declaration : declarations) {
declaration.visit(this, data);
}
return null;
}
@Override
public Void visitModifierList(JetModifierList list, D data) {
return super.visitModifierList(list, data);
}
@Override
public Void visitAnnotation(JetAnnotation annotation, D data) {
return super.visitAnnotation(annotation, data);
}
@Override
public Void visitAnnotationEntry(JetAnnotationEntry annotationEntry, D data) {
return super.visitAnnotationEntry(annotationEntry, data);
}
@Override
public Void visitTypeParameterList(JetTypeParameterList list, D data) {
List<JetTypeParameter> parameters = list.getParameters();
for (JetTypeParameter parameter : parameters) {
parameter.visit(this, data);
}
return null;
}
@Override
public Void visitTypeParameter(JetTypeParameter parameter, D data) {
return super.visitTypeParameter(parameter, data);
}
@Override
public Void visitEnumEntry(JetEnumEntry enumEntry, D data) {
List<JetDelegationSpecifier> delegationSpecifiers = enumEntry.getDelegationSpecifiers();
for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) {
delegationSpecifier.visit(this, data);
}
JetModifierList modifierList = enumEntry.getModifierList();
if (modifierList != null) {
modifierList.visit(this, data);
}
return null;
}
@Override
public Void visitParameterList(JetParameterList list, D data) {
List<JetParameter> parameters = list.getParameters();
for (JetParameter parameter : parameters) {
parameter.visit(this, data);
}
return null;
}
@Override
public Void visitParameter(JetParameter parameter, D data) {
return super.visitParameter(parameter, data);
}
@Override
public Void visitDelegationSpecifierList(JetDelegationSpecifierList list, D data) {
List<JetDelegationSpecifier> delegationSpecifiers = list.getDelegationSpecifiers();
for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) {
delegationSpecifier.visit(this, data);
}
return null;
}
@Override
public Void visitDelegationSpecifier(JetDelegationSpecifier specifier, D data) {
return super.visitDelegationSpecifier(specifier, data);
}
@Override
public Void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier, D data) {
return super.visitDelegationByExpressionSpecifier(specifier, data);
}
@Override
public Void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call, D data) {
return super.visitDelegationToSuperCallSpecifier(call, data);
}
@Override
public Void visitDelegationToSuperClassSpecifier(JetDelegatorToSuperClass specifier, D data) {
return super.visitDelegationToSuperClassSpecifier(specifier, data);
}
@Override
public Void visitDelegationToThisCall(JetDelegatorToThisCall thisCall, D data) {
return super.visitDelegationToThisCall(thisCall, data);
}
@Override
public Void visitTypeReference(JetTypeReference typeReference, D data) {
return super.visitTypeReference(typeReference, data);
}
@Override
public Void visitValueArgumentList(JetValueArgumentList list, D data) {
List<JetValueArgument> arguments = list.getArguments();
for (JetValueArgument argument : arguments) {
argument.visit(this, data);
}
return null;
}
@Override
public Void visitArgument(JetValueArgument argument, D data) {
return super.visitArgument(argument, data);
}
@Override
public Void visitLoopExpression(JetLoopExpression loopExpression, D data) {
JetExpression body = loopExpression.getBody();
if (body != null) {
body.visit(this, data);
}
return null;
}
@Override
public Void visitConstantExpression(JetConstantExpression expression, D data) {
return super.visitConstantExpression(expression, data);
}
@Override
public Void visitSimpleNameExpression(JetSimpleNameExpression expression, D data) {
return super.visitSimpleNameExpression(expression, data);
}
@Override
public Void visitReferenceExpression(JetReferenceExpression expression, D data) {
return super.visitReferenceExpression(expression, data);
}
@Override
public Void visitTupleExpression(JetTupleExpression expression, D data) {
return super.visitTupleExpression(expression, data);
}
@Override
public Void visitPrefixExpression(JetPrefixExpression expression, D data) {
JetExpression baseExpression = expression.getBaseExpression();
if (baseExpression != null) {
baseExpression.visit(this, data);
}
return null;
}
@Override
public Void visitPostfixExpression(JetPostfixExpression expression, D data) {
JetExpression baseExpression = expression.getBaseExpression();
baseExpression.visit(this, data);
return null;
}
@Override
public Void visitUnaryExpression(JetUnaryExpression expression, D data) {
JetExpression baseExpression = expression.getBaseExpression();
assert baseExpression != null;
baseExpression.visit(this, data);
return null;
}
@Override
public Void visitBinaryExpression(JetBinaryExpression expression, D data) {
JetExpression left = expression.getLeft();
left.visit(this, data);
JetExpression right = expression.getRight();
if (right != null) {
right.visit(this, data);
}
return super.visitBinaryExpression(expression, data);
}
@Override
public Void visitReturnExpression(JetReturnExpression expression, D data) {
JetExpression returnedExpression = expression.getReturnedExpression();
if (returnedExpression != null) {
returnedExpression.visit(this, data);
}
return null;
}
@Override
public Void visitLabelQualifiedExpression(JetLabelQualifiedExpression expression, D data) {
JetExpression labeledExpression = expression.getLabeledExpression();
if (labeledExpression != null) {
labeledExpression.visit(this, data);
}
return null;
}
@Override
public Void visitThrowExpression(JetThrowExpression expression, D data) {
JetExpression thrownExpression = expression.getThrownExpression();
if (thrownExpression != null) {
thrownExpression.visit(this, data);
}
return null;
}
@Override
public Void visitBreakExpression(JetBreakExpression expression, D data) {
return super.visitBreakExpression(expression, data);
}
@Override
public Void visitContinueExpression(JetContinueExpression expression, D data) {
return super.visitContinueExpression(expression, data);
}
@Override
public Void visitIfExpression(JetIfExpression expression, D data) {
JetExpression condition = expression.getCondition();
if (condition != null) {
condition.visit(this, data);
}
JetExpression then = expression.getThen();
if (then != null) {
then.visit(this, data);
}
JetExpression anElse = expression.getElse();
if (anElse != null) {
anElse.visit(this, data);
}
return null;
}
@Override
public Void visitWhenExpression(JetWhenExpression expression, D data) {
List<JetWhenEntry> entries = expression.getEntries();
for (JetWhenEntry entry : entries) {
entry.visit(this, data);
}
JetExpression subjectExpression = expression.getSubjectExpression();
if (subjectExpression != null) {
subjectExpression.visit(this, data);
}
return null;
}
@Override
public Void visitTryExpression(JetTryExpression expression, D data) {
JetBlockExpression tryBlock = expression.getTryBlock();
tryBlock.visit(this, data);
List<JetCatchClause> catchClauses = expression.getCatchClauses();
for (JetCatchClause catchClause : catchClauses) {
catchClause.visit(this, data);
}
JetFinallySection finallyBlock = expression.getFinallyBlock();
if (finallyBlock != null) {
finallyBlock.visit(this, data);
}
return null;
}
@Override
public Void visitForExpression(JetForExpression expression, D data) {
JetParameter loopParameter = expression.getLoopParameter();
if (loopParameter != null) {
loopParameter.visit(this, data);
}
JetExpression loopRange = expression.getLoopRange();
if (loopRange != null) {
loopRange.visit(this, data);
}
visitLoopExpression(expression, data);
return null;
}
@Override
public Void visitWhileExpression(JetWhileExpression expression, D data) {
JetExpression condition = expression.getCondition();
if (condition != null) {
condition.visit(this, data);
}
visitLoopExpression(expression, data);
return null;
}
@Override
public Void visitDoWhileExpression(JetDoWhileExpression expression, D data) {
JetExpression condition = expression.getCondition();
if (condition != null) {
condition.visit(this, data);
}
visitLoopExpression(expression, data);
return null;
}
@Override
public Void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, D data) {
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
functionLiteral.visit(this, data);
visitDeclarationWithBody(expression, data);
return null;
}
@Override
public Void visitAnnotatedExpression(JetAnnotatedExpression expression, D data) {
JetExpression baseExpression = expression.getBaseExpression();
baseExpression.visit(this, data);
return null;
}
@Override
public Void visitCallExpression(JetCallExpression expression, D data) {
JetExpression calleeExpression = expression.getCalleeExpression();
if (calleeExpression != null) {
calleeExpression.visit(this, data);
}
return null;
}
@Override
public Void visitArrayAccessExpression(JetArrayAccessExpression expression, D data) {
JetExpression arrayExpression = expression.getArrayExpression();
arrayExpression.visit(this, data);
List<JetExpression> indexExpressions = expression.getIndexExpressions();
for (JetExpression indexExpression : indexExpressions) {
indexExpression.visit(this, data);
}
return null;
}
@Override
public Void visitQualifiedExpression(JetQualifiedExpression expression, D data) {
JetExpression receiver = expression.getReceiverExpression();
receiver.visit(this, data);
JetExpression selector = expression.getSelectorExpression();
if (selector != null) {
selector.visit(this, data);
}
return null;
}
@Override
public Void visitHashQualifiedExpression(JetHashQualifiedExpression expression, D data) {
visitQualifiedExpression(expression, data);
return null;
}
@Override
public Void visitDotQualifiedExpression(JetDotQualifiedExpression expression, D data) {
visitQualifiedExpression(expression, data);
return null;
}
@Override
public Void visitPredicateExpression(JetPredicateExpression expression, D data) {
visitQualifiedExpression(expression, data);
return null;
}
@Override
public Void visitSafeQualifiedExpression(JetSafeQualifiedExpression expression, D data) {
visitQualifiedExpression(expression, data);
return null;
}
@Override
public Void visitObjectLiteralExpression(JetObjectLiteralExpression expression, D data) {
JetObjectDeclaration objectDeclaration = expression.getObjectDeclaration();
objectDeclaration.visit(this, data);
return null;
}
@Override
public Void visitRootNamespaceExpression(JetRootNamespaceExpression expression, D data) {
return super.visitRootNamespaceExpression(expression, data);
}
@Override
public Void visitBlockExpression(JetBlockExpression expression, D data) {
List<JetElement> statements = expression.getStatements();
for (JetElement statement : statements) {
statement.visit(this, data);
}
return null;
}
@Override
public Void visitCatchSection(JetCatchClause catchClause, D data) {
JetParameter catchParameter = catchClause.getCatchParameter();
if (catchParameter != null) {
catchParameter.visit(this, data);
}
JetExpression catchBody = catchClause.getCatchBody();
if (catchBody != null) {
catchBody.visit(this, data);
}
return null;
}
@Override
public Void visitFinallySection(JetFinallySection finallySection, D data) {
JetBlockExpression finalExpression = finallySection.getFinalExpression();
finalExpression.visit(this, data);
return null;
}
@Override
public Void visitTypeArgumentList(JetTypeArgumentList typeArgumentList, D data) {
List<JetTypeProjection> arguments = typeArgumentList.getArguments();
for (JetTypeProjection argument : arguments) {
argument.visit(this, data);
}
return null;
}
@Override
public Void visitThisExpression(JetThisExpression expression, D data) {
JetReferenceExpression thisReference = expression.getThisReference();
thisReference.visit(this, data);
JetTypeReference superTypeQualifier = expression.getSuperTypeQualifier();
if (superTypeQualifier != null) {
superTypeQualifier.visit(this, data);
}
visitLabelQualifiedExpression(expression, data);
return null;
}
@Override
public Void visitParenthesizedExpression(JetParenthesizedExpression expression, D data) {
JetExpression innerExpression = expression.getExpression();
if (innerExpression != null) {
innerExpression.visit(this, data);
}
return null;
}
@Override
public Void visitInitializerList(JetInitializerList list, D data) {
List<JetDelegationSpecifier> initializers = list.getInitializers();
for (JetDelegationSpecifier initializer : initializers) {
initializer.visit(this, data);
}
return null;
}
@Override
public Void visitAnonymousInitializer(JetClassInitializer initializer, D data) {
JetExpression body = initializer.getBody();
body.visit(this, data);
return null;
}
@Override
public Void visitPropertyAccessor(JetPropertyAccessor accessor, D data) {
visitDeclarationWithBody(accessor, data);
return null;
}
@Override
public Void visitTypeConstraintList(JetTypeConstraintList list, D data) {
List<JetTypeConstraint> constraints = list.getConstraints();
for (JetTypeConstraint constraint : constraints) {
constraint.visit(this, data);
}
return null;
}
@Override
public Void visitTypeConstraint(JetTypeConstraint constraint, D data) {
JetSimpleNameExpression subjectTypeParameterName = constraint.getSubjectTypeParameterName();
if (subjectTypeParameterName != null) {
subjectTypeParameterName.visit(this, data);
}
return null;
}
@Override
public Void visitUserType(JetUserType type, D data) {
return super.visitUserType(type, data);
}
@Override
public Void visitTupleType(JetTupleType type, D data) {
return super.visitTupleType(type, data);
}
@Override
public Void visitFunctionType(JetFunctionType type, D data) {
return super.visitFunctionType(type, data);
}
@Override
public Void visitSelfType(JetSelfType type, D data) {
return super.visitSelfType(type, data);
}
@Override
public Void visitBinaryWithTypeRHSExpression(JetBinaryExpressionWithTypeRHS expression, D data) {
JetExpression left = expression.getLeft();
left.visit(this, data);
JetTypeReference right = expression.getRight();
if (right != null) {
right.visit(this, data);
}
return null;
}
@Override
public Void visitStringTemplateExpression(JetStringTemplateExpression expression, D data) {
JetStringTemplateEntry[] entries = expression.getEntries();
for (JetStringTemplateEntry entry : entries) {
entry.visit(this, data);
}
return null;
}
@Override
public Void visitNamedDeclaration(JetNamedDeclaration declaration, D data) {
return super.visitNamedDeclaration(declaration, data);
}
@Override
public Void visitNullableType(JetNullableType nullableType, D data) {
return super.visitNullableType(nullableType, data);
}
@Override
public Void visitTypeProjection(JetTypeProjection typeProjection, D data) {
return super.visitTypeProjection(typeProjection, data);
}
@Override
public Void visitWhenEntry(JetWhenEntry jetWhenEntry, D data) {
JetExpression expression = jetWhenEntry.getExpression();
if (expression != null) {
expression.visit(this, data);
}
JetWhenCondition[] conditions = jetWhenEntry.getConditions();
for (JetWhenCondition condition : conditions) {
condition.visit(this, data);
}
return null;
}
@Override
public Void visitIsExpression(JetIsExpression expression, D data) {
JetExpression leftHandSide = expression.getLeftHandSide();
leftHandSide.visit(this, data);
JetSimpleNameExpression operationReference = expression.getOperationReference();
operationReference.visit(this, data);
JetPattern pattern = expression.getPattern();
if (pattern != null) {
pattern.visit(this, data);
}
return null;
}
@Override
public Void visitWhenConditionCall(JetWhenConditionCall condition, D data) {
JetExpression callSuffixExpression = condition.getCallSuffixExpression();
if (callSuffixExpression != null) {
callSuffixExpression.visit(this, data);
}
return null;
}
@Override
public Void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition, D data) {
JetPattern pattern = condition.getPattern();
if (pattern != null) {
pattern.visit(this, data);
}
return null;
}
@Override
public Void visitWhenConditionInRange(JetWhenConditionInRange condition, D data) {
JetSimpleNameExpression operationReference = condition.getOperationReference();
operationReference.visit(this, data);
JetExpression rangeExpression = condition.getRangeExpression();
if (rangeExpression != null) {
rangeExpression.visit(this, data);
}
return null;
}
@Override
public Void visitTypePattern(JetTypePattern pattern, D data) {
return super.visitTypePattern(pattern, data);
}
@Override
public Void visitWildcardPattern(JetWildcardPattern pattern, D data) {
return super.visitWildcardPattern(pattern, data);
}
@Override
public Void visitExpressionPattern(JetExpressionPattern pattern, D data) {
JetExpression expression = pattern.getExpression();
if (expression != null) {
expression.visit(this, data);
}
return null;
}
@Override
public Void visitTuplePattern(JetTuplePattern pattern, D data) {
List<JetTuplePatternEntry> entries = pattern.getEntries();
for (JetTuplePatternEntry entry : entries) {
entry.visit(this, data);
}
return null;
}
@Override
public Void visitDecomposerPattern(JetDecomposerPattern pattern, D data) {
JetTuplePattern argumentList = pattern.getArgumentList();
argumentList.visit(this, data);
JetExpression decomposerExpression = pattern.getDecomposerExpression();
if (decomposerExpression != null) {
decomposerExpression.visit(this, data);
}
return null;
}
@Override
public Void visitObjectDeclaration(JetObjectDeclaration objectDeclaration, D data) {
List<JetDeclaration> declarations = objectDeclaration.getDeclarations();
for (JetDeclaration declaration : declarations) {
declaration.visit(this, data);
}
JetDelegationSpecifierList delegationSpecifierList = objectDeclaration.getDelegationSpecifierList();
if (delegationSpecifierList != null) {
delegationSpecifierList.visit(this, data);
}
return null;
}
@Override
public Void visitBindingPattern(JetBindingPattern pattern, D data) {
JetWhenCondition condition = pattern.getCondition();
if (condition != null) {
condition.visit(this, data);
}
JetProperty variableDeclaration = pattern.getVariableDeclaration();
variableDeclaration.visit(this, data);
return null;
}
@Override
public Void visitStringTemplateEntry(JetStringTemplateEntry entry, D data) {
JetExpression expression = entry.getExpression();
if (expression != null) {
expression.visit(this, data);
}
return null;
}
@Override
public Void visitStringTemplateEntryWithExpression(JetStringTemplateEntryWithExpression entry, D data) {
visitStringTemplateEntry(entry, data);
return null;
}
@Override
public Void visitBlockStringTemplateEntry(JetBlockStringTemplateEntry entry, D data) {
visitStringTemplateEntry(entry, data);
return null;
}
@Override
public Void visitSimpleNameStringTemplateEntry(JetSimpleNameStringTemplateEntry entry, D data) {
visitStringTemplateEntry(entry, data);
return null;
}
@Override
public Void visitLiteralStringTemplateEntry(JetLiteralStringTemplateEntry entry, D data) {
visitStringTemplateEntry(entry, data);
return null;
}
@Override
public Void visitEscapeStringTemplateEntry(JetEscapeStringTemplateEntry entry, D data) {
visitStringTemplateEntry(entry, data);
return null;
}
private Void visitDeclarationWithBody(JetDeclarationWithBody declaration, D data) {
JetExpression bodyExpression = declaration.getBodyExpression();
if (bodyExpression != null) {
bodyExpression.visit(this, data);
}
List<JetParameter> valueParameters = declaration.getValueParameters();
for (JetParameter valueParameter : valueParameters) {
valueParameter.visit(this, data);
}
return null;
}
}
@@ -34,7 +34,7 @@ public class AnnotationResolver {
this.trace = trace;
// this.typeInferrer = new JetTypeInferrer(JetFlowInformationProvider.THROW_EXCEPTION, semanticServices);
// this.services = typeInferrer.getServices(this.trace);
this.callResolver = new CallResolver(semanticServices, new JetTypeInferrer(JetFlowInformationProvider.THROW_EXCEPTION, semanticServices), DataFlowInfo.getEmpty());
this.callResolver = new CallResolver(semanticServices, new JetTypeInferrer(semanticServices), DataFlowInfo.getEmpty());
}
@NotNull
@@ -125,7 +125,7 @@ public class BodyResolver {
final JetScope scopeForConstructor = primaryConstructor == null
? null
: getInnerScopeForConstructor(primaryConstructor, descriptor.getScopeForMemberResolution(), true);
final JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors, JetFlowInformationProvider.NONE); // TODO : flow
final JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors); // TODO : flow
final Map<JetTypeReference, JetType> supertypes = Maps.newLinkedHashMap();
JetVisitorVoid visitor = new JetVisitorVoid() {
@@ -292,7 +292,7 @@ public class BodyResolver {
ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
assert primaryConstructor != null;
final JetScope scopeForConstructor = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getScopeForMemberResolution(), true);
JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(createFieldAssignTrackingTrace(), JetFlowInformationProvider.NONE); // TODO : flow
JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(createFieldAssignTrackingTrace()); // TODO : flow
for (JetClassInitializer anonymousInitializer : anonymousInitializers) {
typeInferrer.getType(scopeForConstructor, anonymousInitializer.getBody(), NO_EXPECTED_TYPE);
}
@@ -318,7 +318,7 @@ public class BodyResolver {
private void resolveSecondaryConstructorBody(JetConstructor declaration, final ConstructorDescriptor descriptor, final JetScope declaringScope) {
final JetScope functionInnerScope = getInnerScopeForConstructor(descriptor, declaringScope, false);
final JetTypeInferrer.Services typeInferrerForInitializers = context.getSemanticServices().getTypeInferrerServices(traceForConstructors, JetFlowInformationProvider.NONE);
final JetTypeInferrer.Services typeInferrerForInitializers = context.getSemanticServices().getTypeInferrerServices(traceForConstructors);
JetClass containingClass = PsiTreeUtil.getParentOfType(declaration, JetClass.class);
assert containingClass != null : "This must be guaranteed by the parser";
@@ -380,11 +380,11 @@ public class BodyResolver {
}
JetExpression bodyExpression = declaration.getBodyExpression();
if (bodyExpression != null) {
context.getClassDescriptorResolver().computeFlowData(declaration, bodyExpression);
JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(declaration, bodyExpression);
JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors, flowInformationProvider);
//context.getClassDescriptorResolver().computeFlowData(declaration, bodyExpression);
//JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(declaration, bodyExpression);
JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors);
typeInferrer.checkFunctionReturnType(functionInnerScope, declaration, JetStandardClasses.getUnitType());
typeInferrer.checkFunctionReturnType(functionInnerScope, declaration, descriptor, JetStandardClasses.getUnitType());
}
}
@@ -519,8 +519,8 @@ public class BodyResolver {
}
private void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) {
JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(property, initializer); // TODO : flow JET-15
JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors, flowInformationProvider);
//JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(property, initializer); // TODO : flow JET-15
JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors);
JetType type = typeInferrer.getType(getPropertyDeclarationInnerScope(scope, propertyDescriptor), initializer, NO_EXPECTED_TYPE);
JetType expectedType = propertyDescriptor.getInType();
@@ -555,13 +555,13 @@ public class BodyResolver {
JetExpression bodyExpression = function.getBodyExpression();
if (bodyExpression != null) {
JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(function.asElement(), bodyExpression);
JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace, flowInformationProvider);
//JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(function.asElement(), bodyExpression);
JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace);
typeInferrer.checkFunctionReturnType(declaringScope, function, functionDescriptor);
}
JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace, JetFlowInformationProvider.THROW_EXCEPTION);
JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace);
List<JetParameter> valueParameters = function.getValueParameters();
for (int i = 0; i < valueParameters.size(); i++) {
ValueParameterDescriptor valueParameterDescriptor = functionDescriptor.getValueParameters().get(i);
@@ -178,8 +178,8 @@ public class ClassDescriptorResolver {
returnType = DeferredType.create(trace, new LazyValueWithDefault<JetType>(ErrorUtils.createErrorType("Recursive dependency")) {
@Override
protected JetType compute() {
JetFlowInformationProvider flowInformationProvider = computeFlowData(function, bodyExpression);
return semanticServices.getTypeInferrerServices(trace, flowInformationProvider).inferFunctionReturnType(scope, function, functionDescriptor);
//JetFlowInformationProvider flowInformationProvider = computeFlowData(function, bodyExpression);
return semanticServices.getTypeInferrerServices(trace).inferFunctionReturnType(scope, function, functionDescriptor);
}
});
}
@@ -540,8 +540,8 @@ public class ClassDescriptorResolver {
LazyValue<JetType> lazyValue = new LazyValueWithDefault<JetType>(ErrorUtils.createErrorType("Recursive dependency")) {
@Override
protected JetType compute() {
JetFlowInformationProvider flowInformationProvider = computeFlowData(property, initializer);
return semanticServices.getTypeInferrerServices(trace, flowInformationProvider).safeGetType(scope, initializer, JetTypeInferrer.NO_EXPECTED_TYPE);
//JetFlowInformationProvider flowInformationProvider = computeFlowData(property, initializer);
return semanticServices.getTypeInferrerServices(trace).safeGetType(scope, initializer, JetTypeInferrer.NO_EXPECTED_TYPE);
}
};
if (allowDeferred) {
@@ -0,0 +1,114 @@
package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptorImpl;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeInferrer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE;
/**
* @author svtk
*/
public class ControlFlowAnalyzer {
private TopDownAnalysisContext context;
private JetTypeInferrer.Services typeInferrer;
public ControlFlowAnalyzer(TopDownAnalysisContext context) {
this.context = context;
typeInferrer = context.getSemanticServices().getTypeInferrerServices(context.getTrace());
}
public void process() {
for (Map.Entry<JetNamedFunction, FunctionDescriptorImpl> entry : context.getFunctions().entrySet()) {
JetNamedFunction function = entry.getKey();
FunctionDescriptorImpl functionDescriptor = entry.getValue();
final JetType expectedReturnType = !function.hasBlockBody() && !function.hasDeclaredReturnType() ? NO_EXPECTED_TYPE : functionDescriptor.getReturnType();
checkFunction(function, functionDescriptor, expectedReturnType);
}
for (Map.Entry<JetDeclaration, ConstructorDescriptor> entry : this.context.getConstructors().entrySet()) {
JetDeclaration declaration = entry.getKey();
assert declaration instanceof JetConstructor;
JetConstructor constructor = (JetConstructor) declaration;
ConstructorDescriptor descriptor = entry.getValue();
checkFunction(constructor, descriptor, JetStandardClasses.getUnitType());
}
for (JetProperty property : context.getProperties().keySet()) {
checkProperty(property);
}
}
private void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor, final @NotNull JetType expectedReturnType) {
JetExpression bodyExpression = function.getBodyExpression();
if (bodyExpression == null) return;
JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData((JetElement) function, bodyExpression);
final boolean blockBody = function.hasBlockBody();
List<JetElement> unreachableElements = Lists.newArrayList();
flowInformationProvider.collectUnreachableExpressions(function.asElement(), unreachableElements);
// This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well
final Set<JetElement> rootUnreachableElements = JetPsiUtil.findRootExpressions(unreachableElements);
for (JetElement element : rootUnreachableElements) {
context.getTrace().report(UNREACHABLE_CODE.on(element));
}
List<JetExpression> returnedExpressions = Lists.newArrayList();
flowInformationProvider.collectReturnExpressions(function.asElement(), returnedExpressions);
boolean nothingReturned = returnedExpressions.isEmpty();
returnedExpressions.remove(function); // This will be the only "expression" if the body is empty
final JetScope scope = this.context.getDeclaringScopes().get(function);
if (expectedReturnType != NO_EXPECTED_TYPE && !JetStandardClasses.isUnit(expectedReturnType) && returnedExpressions.isEmpty() && !nothingReturned) {
context.getTrace().report(RETURN_TYPE_MISMATCH.on(bodyExpression, expectedReturnType));
}
for (JetExpression returnedExpression : returnedExpressions) {
returnedExpression.accept(new JetVisitorVoid() {
@Override
public void visitReturnExpression(JetReturnExpression expression) {
if (!blockBody) {
context.getTrace().report(RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY.on(expression));
}
}
@Override
public void visitExpression(JetExpression expression) {
if (blockBody && expectedReturnType != NO_EXPECTED_TYPE && !JetStandardClasses.isUnit(expectedReturnType) && !rootUnreachableElements.contains(expression)) {
JetType type = typeInferrer.getType(scope, expression, expectedReturnType);
if (type == null || !JetStandardClasses.isNothing(type)) {
context.getTrace().report(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY.on(expression));
}
}
}
});
}
}
private void checkProperty(JetProperty property) {
JetExpression initializer = property.getInitializer();
if (initializer == null) return;
context.getClassDescriptorResolver().computeFlowData(property, initializer);
}
}
@@ -69,6 +69,7 @@ public class TopDownAnalyzer {
new OverrideResolver(context).process();
new BodyResolver(context).resolveBehaviorDeclarationBodies();
new DeclarationsChecker(context).process();
new ControlFlowAnalyzer(context).process();
}
public static void processStandardLibraryNamespace(
@@ -218,7 +218,7 @@ public class TypeHierarchyResolver {
if (importDirective.isAllUnder()) {
JetExpression importedReference = importDirective.getImportedReference();
if (importedReference != null) {
JetTypeInferrer.Services typeInferrerServices = context.getSemanticServices().getTypeInferrerServices(context.getTrace(), JetFlowInformationProvider.THROW_EXCEPTION);
JetTypeInferrer.Services typeInferrerServices = context.getSemanticServices().getTypeInferrerServices(context.getTrace());
JetType type = typeInferrerServices.getTypeWithNamespaces(namespaceScope, importedReference);
if (type != null) {
namespaceScope.importScope(type.getMemberScope());
@@ -233,7 +233,7 @@ public class TypeHierarchyResolver {
JetExpression importedReference = importDirective.getImportedReference();
if (importedReference instanceof JetDotQualifiedExpression) {
JetDotQualifiedExpression reference = (JetDotQualifiedExpression) importedReference;
JetType type = context.getSemanticServices().getTypeInferrerServices(context.getTrace(), JetFlowInformationProvider.THROW_EXCEPTION).getTypeWithNamespaces(namespaceScope, reference.getReceiverExpression());
JetType type = context.getSemanticServices().getTypeInferrerServices(context.getTrace()).getTypeWithNamespaces(namespaceScope, reference.getReceiverExpression());
JetExpression selectorExpression = reference.getSelectorExpression();
if (selectorExpression != null) {
referenceExpression = (JetSimpleNameExpression) selectorExpression;
@@ -312,8 +312,7 @@ public class JetStandardLibrary {
@NotNull
public JetType getArrayType(@NotNull JetType argument) {
Variance variance = Variance.INVARIANT;
return getArrayType(variance, argument);
return getArrayType(Variance.INVARIANT, argument);
}
@NotNull
@@ -12,7 +12,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
@@ -175,14 +174,16 @@ public class JetTypeInferrer {
}
private final JetSemanticServices semanticServices;
private final JetFlowInformationProvider flowInformationProvider;
// private final JetFlowInformationProvider flowInformationProvider;
private final Map<JetPattern, DataFlowInfo> patternsToDataFlowInfo = Maps.newHashMap();
private final Map<JetPattern, List<VariableDescriptor>> patternsToBoundVariableLists = Maps.newHashMap();
private final LabelsResolver labelsResolver = new LabelsResolver();
public JetTypeInferrer(@NotNull JetFlowInformationProvider flowInformationProvider, @NotNull JetSemanticServices semanticServices) {
public JetTypeInferrer(@NotNull JetSemanticServices semanticServices) {
this.semanticServices = semanticServices;
this.flowInformationProvider = flowInformationProvider;
// this.flowInformationProvider = flowInformationProvider;
}
public Services getServices(@NotNull BindingTrace trace) {
@@ -269,7 +270,7 @@ public class JetTypeInferrer {
expectedReturnType = NO_EXPECTED_TYPE;
}
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace);
checkFunctionReturnType(functionInnerScope, function, expectedReturnType, dataFlowInfo);
checkFunctionReturnType(functionInnerScope, function, functionDescriptor, expectedReturnType, dataFlowInfo);
// Map<JetElement, JetType> typeMap = collectReturnedExpressionsWithTypes(outerScope, function, functionDescriptor, expectedReturnType);
// if (typeMap.isEmpty()) {
// return; // The function returns Nothing
@@ -303,11 +304,11 @@ public class JetTypeInferrer {
// }
}
public void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, @NotNull final JetType expectedReturnType) {
checkFunctionReturnType(functionInnerScope, function, expectedReturnType, DataFlowInfo.getEmpty());
public void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, FunctionDescriptor functionDescriptor, @NotNull final JetType expectedReturnType) {
checkFunctionReturnType(functionInnerScope, function, functionDescriptor, expectedReturnType, DataFlowInfo.getEmpty());
}
private void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, @NotNull final JetType expectedReturnType, @NotNull DataFlowInfo dataFlowInfo) {
private void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, FunctionDescriptor functionDescriptor, @NotNull final JetType expectedReturnType, @NotNull DataFlowInfo dataFlowInfo) {
JetExpression bodyExpression = function.getBodyExpression();
if (bodyExpression == null) return;
@@ -325,56 +326,62 @@ public class JetTypeInferrer {
typeInferrerVisitor.getType(bodyExpression, context);
}
List<JetElement> unreachableElements = Lists.newArrayList();
flowInformationProvider.collectUnreachableExpressions(function.asElement(), unreachableElements);
// List<JetElement> unreachableElements = Lists.newArrayList();
// flowInformationProvider.collectUnreachableExpressions(function.asElement(), unreachableElements);
// This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well
final Set<JetElement> rootUnreachableElements = JetPsiUtil.findRootExpressions(unreachableElements);
// final Set<JetElement> rootUnreachableElements = JetPsiUtil.findRootExpressions(unreachableElements);
// TODO : (return 1) || (return 2) -- only || and right of it is unreachable
// TODO : try {return 1} finally {return 2}. Currently 'return 1' is reported as unreachable,
// though it'd better be reported more specifically
for (JetElement element : rootUnreachableElements) {
// trace.getErrorHandler().genericError(element.getNode(), "Unreachable code");
trace.report(UNREACHABLE_CODE.on(element));
}
// for (JetElement element : rootUnreachableElements) {
// //trace.report(UNREACHABLE_CODE.on(element));
// }
List<JetExpression> returnedExpressions = Lists.newArrayList();
flowInformationProvider.collectReturnExpressions(function.asElement(), returnedExpressions);
// List<JetExpression> returnedExpressions = Lists.newArrayList();
// flowInformationProvider.collectReturnExpressions(function.asElement(), returnedExpressions);
boolean nothingReturned = returnedExpressions.isEmpty();
// boolean nothingReturned = returnedExpressions.isEmpty();
returnedExpressions.remove(function); // This will be the only "expression" if the body is empty
//returnedExpressions.remove(function); // This will be the only "expression" if the body is empty
// Map<JetExpression, JetType> typeMap = collectReturnedExpressionsWithTypes(trace, functionInnerScope, function, functionDescriptor);
// Set<JetExpression> returnedExpressions = typeMap.keySet();
//
//
// if (expectedReturnType != NO_EXPECTED_TYPE && !JetStandardClasses.isUnit(expectedReturnType) && returnedExpressions.isEmpty()) {
// trace.report(RETURN_TYPE_MISMATCH.on(bodyExpression, expectedReturnType));
// }
if (expectedReturnType != NO_EXPECTED_TYPE && !JetStandardClasses.isUnit(expectedReturnType) && returnedExpressions.isEmpty() && !nothingReturned) {
// trace.getErrorHandler().genericError(bodyExpression.getNode(), "This function must return a value of type " + expectedReturnType);
trace.report(RETURN_TYPE_MISMATCH.on(bodyExpression, expectedReturnType));
}
for (JetExpression returnedExpression : returnedExpressions) {
returnedExpression.accept(new JetVisitorVoid() {
@Override
public void visitReturnExpression(JetReturnExpression expression) {
if (!blockBody) {
// trace.getErrorHandler().genericError(expression.getNode(), "Returns are not allowed for functions with expression body. Use block body in '{...}'");
trace.report(RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY.on(expression));
}
}
@Override
public void visitExpression(JetExpression expression) {
if (blockBody && !JetStandardClasses.isUnit(expectedReturnType) && !rootUnreachableElements.contains(expression)) {
//TODO move to pseudocode
JetType type = typeInferrerVisitor.getType(expression, context.replaceExpectedType(NO_EXPECTED_TYPE));
if (type == null || !JetStandardClasses.isNothing(type)) {
// trace.getErrorHandler().genericError(expression.getNode(), "A 'return' expression required in a function with a block body ('{...}')");
trace.report(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY.on(expression));
}
}
}
});
}
// if (expectedReturnType != NO_EXPECTED_TYPE && !JetStandardClasses.isUnit(expectedReturnType) && returnedExpressions.isEmpty() && !nothingReturned) {
//// trace.getErrorHandler().genericError(bodyExpression.getNode(), "This function must return a value of type " + expectedReturnType);
// trace.report(RETURN_TYPE_MISMATCH.on(bodyExpression, expectedReturnType));
// }
//
// for (JetExpression returnedExpression : returnedExpressions) {
// returnedExpression.accept(new JetVisitorVoid() {
// @Override
// public void visitReturnExpression(JetReturnExpression expression) {
// if (!blockBody) {
//// trace.getErrorHandler().genericError(expression.getNode(), "Returns are not allowed for functions with expression body. Use block body in '{...}'");
// trace.report(RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY.on(expression));
// }
// }
//
// @Override
// public void visitExpression(JetExpression expression) {
// if (blockBody && !JetStandardClasses.isUnit(expectedReturnType) && !rootUnreachableElements.contains(expression)) {
// //TODO move to pseudocode
// JetType type = typeInferrerVisitor.getType(expression, context.replaceExpectedType(NO_EXPECTED_TYPE));
// if (type == null || !JetStandardClasses.isNothing(type)) {
//// trace.getErrorHandler().genericError(expression.getNode(), "A 'return' expression required in a function with a block body ('{...}')");
// trace.report(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY.on(expression));
// }
// }
// }
// });
// }
}
@Nullable
@@ -391,26 +398,52 @@ public class JetTypeInferrer {
@NotNull
public JetType inferFunctionReturnType(@NotNull JetScope outerScope, JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) {
Map<JetElement, JetType> typeMap = collectReturnedExpressionsWithTypes(trace, outerScope, function, functionDescriptor);
Map<JetExpression, JetType> typeMap = collectReturnedExpressionsWithTypes(trace, outerScope, function, functionDescriptor);
Collection<JetType> types = typeMap.values();
return types.isEmpty()
? JetStandardClasses.getNothingType()
: semanticServices.getTypeChecker().commonSupertype(types);
}
private Map<JetElement, JetType> collectReturnedExpressionsWithTypes(
@NotNull BindingTrace trace,
private Map<JetExpression, JetType> collectReturnedExpressionsWithTypes(
final @NotNull BindingTrace trace,
JetScope outerScope,
JetDeclarationWithBody function,
final JetDeclarationWithBody function,
FunctionDescriptor functionDescriptor) {
JetExpression bodyExpression = function.getBodyExpression();
assert bodyExpression != null;
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace);
typeInferrerVisitor.getType(bodyExpression, newContext(trace, functionInnerScope, DataFlowInfo.getEmpty(), NO_EXPECTED_TYPE, FORBIDDEN));
Collection<JetExpression> returnedExpressions = new ArrayList<JetExpression>();
Collection<JetElement> elementsReturningUnit = new ArrayList<JetElement>();
flowInformationProvider.collectReturnedInformation(function.asElement(), returnedExpressions, elementsReturningUnit);
Map<JetElement,JetType> typeMap = new HashMap<JetElement, JetType>();
//todo function literals
final Collection<JetExpression> returnedExpressions = new ArrayList<JetExpression>();
if (function.hasBlockBody()) {
//now this code is never invoked!, it should be invoked for inference of return type of function literal with local returns
bodyExpression.visit(new JetTreeVisitor<JetDeclarationWithBody>() {
@Override
public Void visitReturnExpression(JetReturnExpression expression, JetDeclarationWithBody outerFunction) {
JetSimpleNameExpression targetLabel = expression.getTargetLabel();
PsiElement element = targetLabel != null ? trace.get(LABEL_TARGET, targetLabel) : null;
if (element == function || (targetLabel == null && outerFunction == function)) {
returnedExpressions.add(expression);
}
return null;
}
@Override
public Void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, JetDeclarationWithBody outerFunction) {
return super.visitFunctionLiteralExpression(expression, expression.getFunctionLiteral());
}
@Override
public Void visitNamedFunction(JetNamedFunction function, JetDeclarationWithBody outerFunction) {
return super.visitNamedFunction(function, function);
}
}, function);
}
else {
returnedExpressions.add(bodyExpression);
}
Map<JetExpression, JetType> typeMap = new HashMap<JetExpression, JetType>();
for (JetExpression returnedExpression : returnedExpressions) {
JetType cachedType = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, returnedExpression);
trace.record(STATEMENT, returnedExpression, false);
@@ -418,9 +451,6 @@ public class JetTypeInferrer {
typeMap.put(returnedExpression, cachedType);
}
}
for (JetElement jetElement : elementsReturningUnit) {
typeMap.put(jetElement, JetStandardClasses.getUnitType());
}
return typeMap;
}
@@ -438,35 +468,57 @@ public class JetTypeInferrer {
trace.record(STATEMENT, statement);
final JetExpression statementExpression = (JetExpression) statement;
//TODO constructor assert context.expectedType != FORBIDDEN : ""
if (!iterator.hasNext() && context.expectedType != NO_EXPECTED_TYPE) {
if (coercionStrategyForLastExpression == CoercionStrategy.COERCION_TO_UNIT && JetStandardClasses.isUnit(context.expectedType)) {
// This implements coercion to Unit
TemporaryBindingTrace temporaryTraceExpectingUnit = TemporaryBindingTrace.create(trace);
final boolean[] mismatch = new boolean[1];
ObservableBindingTrace errorInterceptingTrace = makeTraceInterceptingTypeMismatch(temporaryTraceExpectingUnit, statementExpression, mismatch);
newContext = newContext(errorInterceptingTrace, scope, newContext.dataFlowInfo, context.expectedType, context.expectedReturnType);
result = blockLevelVisitor.getType(statementExpression, newContext);
if (mismatch[0]) {
TemporaryBindingTrace temporaryTraceNoExpectedType = TemporaryBindingTrace.create(trace);
mismatch[0] = false;
ObservableBindingTrace interceptingTrace = makeTraceInterceptingTypeMismatch(temporaryTraceNoExpectedType, statementExpression, mismatch);
newContext = newContext(interceptingTrace, scope, newContext.dataFlowInfo, NO_EXPECTED_TYPE, context.expectedReturnType);
if (!iterator.hasNext()) {
if (context.expectedType != NO_EXPECTED_TYPE) {
if (coercionStrategyForLastExpression == CoercionStrategy.COERCION_TO_UNIT && JetStandardClasses.isUnit(context.expectedType)) {
// This implements coercion to Unit
TemporaryBindingTrace temporaryTraceExpectingUnit = TemporaryBindingTrace.create(trace);
final boolean[] mismatch = new boolean[1];
ObservableBindingTrace errorInterceptingTrace = makeTraceInterceptingTypeMismatch(temporaryTraceExpectingUnit, statementExpression, mismatch);
newContext = newContext(errorInterceptingTrace, scope, newContext.dataFlowInfo, context.expectedType, context.expectedReturnType);
result = blockLevelVisitor.getType(statementExpression, newContext);
if (mismatch[0]) {
temporaryTraceExpectingUnit.commit();
TemporaryBindingTrace temporaryTraceNoExpectedType = TemporaryBindingTrace.create(trace);
mismatch[0] = false;
ObservableBindingTrace interceptingTrace = makeTraceInterceptingTypeMismatch(temporaryTraceNoExpectedType, statementExpression, mismatch);
newContext = newContext(interceptingTrace, scope, newContext.dataFlowInfo, NO_EXPECTED_TYPE, context.expectedReturnType);
result = blockLevelVisitor.getType(statementExpression, newContext);
if (mismatch[0]) {
temporaryTraceExpectingUnit.commit();
}
else {
temporaryTraceNoExpectedType.commit();
}
}
else {
temporaryTraceNoExpectedType.commit();
temporaryTraceExpectingUnit.commit();
}
}
else {
temporaryTraceExpectingUnit.commit();
newContext = newContext(trace, scope, newContext.dataFlowInfo, context.expectedType, context.expectedReturnType);
result = blockLevelVisitor.getType(statementExpression, newContext);
}
}
else {
newContext = newContext(trace, scope, newContext.dataFlowInfo, context.expectedType, context.expectedReturnType);
result = blockLevelVisitor.getType(statementExpression, newContext);
if (coercionStrategyForLastExpression == CoercionStrategy.COERCION_TO_UNIT) {
boolean mightBeUnit = false;
if (statementExpression instanceof JetDeclaration) {
mightBeUnit = true;
}
if (statementExpression instanceof JetBinaryExpression) {
JetBinaryExpression binaryExpression = (JetBinaryExpression) statementExpression;
IElementType operationType = binaryExpression.getOperationToken();
if (operationType == JetTokens.EQ || assignmentOperationNames.containsKey(operationType)) {
mightBeUnit = true;
}
}
if (mightBeUnit) {
// TypeInferrerVisitorWithWritableScope should return only null or Unit for declarations and assignments
assert result == null || JetStandardClasses.isUnit(result);
result = JetStandardClasses.getUnitType();
}
}
}
}
else {
@@ -712,7 +764,6 @@ public class JetTypeInferrer {
}
private class TypeInferrerVisitor extends JetVisitor<JetType, TypeInferenceContext> {
protected DataFlowInfo resultDataFlowInfo;
@Nullable
@@ -761,10 +812,11 @@ public class JetTypeInferrer {
}
if (result != null) {
context.trace.record(BindingContext.EXPRESSION_TYPE, expression, result);
if (JetStandardClasses.isNothing(result) && !result.isNullable()) {
markDominatedExpressionsAsUnreachable(expression, context);
}
// if (JetStandardClasses.isNothing(result) && !result.isNullable()) {
// markDominatedExpressionsAsUnreachable(expression, context);
// }
}
// }
}
catch (ReenteringLazyValueComputationException e) {
// context.trace.getErrorHandler().genericError(expression.getNode(), "Type checking has run into a recursive problem"); // TODO : message
@@ -792,16 +844,16 @@ public class JetTypeInferrer {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void markDominatedExpressionsAsUnreachable(JetExpression expression, TypeInferenceContext context) {
List<JetElement> dominated = new ArrayList<JetElement>();
flowInformationProvider.collectDominatedExpressions(expression, dominated);
Set<JetElement> rootExpressions = JetPsiUtil.findRootExpressions(dominated);
for (JetElement rootExpression : rootExpressions) {
// context.trace.getErrorHandler().genericError(rootExpression.getNode(),
// "This code is unreachable, because '" + expression.getText() + "' never terminates normally");
context.trace.report(UNREACHABLE_BECAUSE_OF_NOTHING.on(rootExpression, expression.getText()));
}
}
// private void markDominatedExpressionsAsUnreachable(JetExpression expression, TypeInferenceContext context) {
// List<JetElement> dominated = new ArrayList<JetElement>();
// flowInformationProvider.collectDominatedExpressions(expression, dominated);
// Set<JetElement> rootExpressions = JetPsiUtil.findRootExpressions(dominated);
// for (JetElement rootExpression : rootExpressions) {
//// context.trace.getErrorHandler().genericError(rootExpression.getNode(),
//// "This code is unreachable, because '" + expression.getText() + "' never terminates normally");
// context.trace.report(UNREACHABLE_BECAUSE_OF_NOTHING.on(rootExpression, expression.getText()));
// }
// }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1031,7 +1083,7 @@ public class JetTypeInferrer {
JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef();
if (returnTypeRef != null) {
returnType = context.typeResolver.resolveType(context.scope, returnTypeRef);
context.services.checkFunctionReturnType(functionInnerScope, expression, returnType, context.dataFlowInfo);
context.services.checkFunctionReturnType(functionInnerScope, expression, functionDescriptor, returnType, context.dataFlowInfo);
}
else {
if (functionTypeExpected) {
@@ -1045,6 +1097,7 @@ public class JetTypeInferrer {
if (functionTypeExpected) {
JetType expectedReturnType = JetStandardClasses.getReturnType(expectedType);
if (JetStandardClasses.isUnit(expectedReturnType)) {
functionDescriptor.setReturnType(expectedReturnType);
return context.services.checkType(JetStandardClasses.getFunctionType(Collections.<AnnotationDescriptor>emptyList(), effectiveReceiverType, parameterTypes, expectedReturnType), expression, context);
}
@@ -1140,6 +1193,7 @@ public class JetTypeInferrer {
@Override
public JetType visitReturnExpression(JetReturnExpression expression, TypeInferenceContext context) {
labelsResolver.recordLabel(expression, context);
if (context.expectedReturnType == FORBIDDEN) {
// context.trace.getErrorHandler().genericError(expression.getNode(), "'return' is not allowed here");
context.trace.report(RETURN_NOT_ALLOWED.on(expression));
@@ -1162,11 +1216,13 @@ public class JetTypeInferrer {
@Override
public JetType visitBreakExpression(JetBreakExpression expression, TypeInferenceContext context) {
labelsResolver.recordLabel(expression, context);
return context.services.checkType(JetStandardClasses.getNothingType(), expression, context);
}
@Override
public JetType visitContinueExpression(JetContinueExpression expression, TypeInferenceContext context) {
labelsResolver.recordLabel(expression, context);
return context.services.checkType(JetStandardClasses.getNothingType(), expression, context);
}
@@ -1286,50 +1342,7 @@ public class JetTypeInferrer {
ReceiverDescriptor thisReceiver = null;
String labelName = expression.getLabelName();
if (labelName != null) {
Collection<DeclarationDescriptor> declarationsByLabel = context.scope.getDeclarationsByLabel(labelName);
int size = declarationsByLabel.size();
final JetSimpleNameExpression targetLabel = expression.getTargetLabel();
assert targetLabel != null;
if (size == 1) {
DeclarationDescriptor declarationDescriptor = declarationsByLabel.iterator().next();
if (declarationDescriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
thisReceiver = classDescriptor.getImplicitReceiver();
}
else if (declarationDescriptor instanceof FunctionDescriptor) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor;
thisReceiver = functionDescriptor.getReceiverParameter();
}
else {
throw new UnsupportedOperationException(); // TODO
}
context.trace.record(REFERENCE_TARGET, targetLabel, declarationDescriptor);
context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor);
}
else if (size == 0) {
// This uses the info written by the control flow processor
PsiElement psiElement = BindingContextUtils.resolveToDeclarationPsiElement(context.trace.getBindingContext(), targetLabel);
if (psiElement instanceof JetFunctionLiteralExpression) {
DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiElement);
if (declarationDescriptor instanceof FunctionDescriptor) {
thisReceiver = ((FunctionDescriptor) declarationDescriptor).getReceiverParameter();
if (thisReceiver.exists()) {
context.trace.record(REFERENCE_TARGET, targetLabel, declarationDescriptor);
context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor);
}
}
else {
context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel));
}
}
else {
context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel));
}
}
else {
// context.trace.getErrorHandler().genericError(targetLabel.getNode(), "Ambiguous label");
context.trace.report(AMBIGUOUS_LABEL.on(targetLabel));
}
thisReceiver = labelsResolver.resolveThisLabel(expression, context, thisReceiver, labelName);
}
else {
thisReceiver = context.scope.getImplicitReceiver();
@@ -1861,12 +1874,36 @@ public class JetTypeInferrer {
DataFlowInfo conditionInfo = condition == null ? context.dataFlowInfo : extractDataFlowInfoFromCondition(condition, true, scopeToExtend, context);
getTypeWithNewScopeAndDataFlowInfo(scopeToExtend, body, conditionInfo, context);
}
if (!flowInformationProvider.isBreakable(expression)) {
if (!containsBreak(expression, context)) {
// resultScope = newWritableScopeImpl();
resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false, null, context);
}
return context.services.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType);
}
private boolean containsBreak(final JetLoopExpression loopExpression, final TypeInferenceContext context) {
final boolean[] result = new boolean[1];
result[0] = false;
//todo breaks in inline function literals
loopExpression.visit(new JetTreeVisitor<JetLoopExpression>() {
@Override
public Void visitBreakExpression(JetBreakExpression breakExpression, JetLoopExpression outerLoop) {
JetSimpleNameExpression targetLabel = breakExpression.getTargetLabel();
PsiElement element = targetLabel != null ? context.trace.get(LABEL_TARGET, targetLabel) : null;
if (element == loopExpression || (targetLabel == null && outerLoop == loopExpression)) {
result[0] = true;
}
return null;
}
@Override
public Void visitLoopExpression(JetLoopExpression loopExpression, JetLoopExpression outerLoop) {
return super.visitLoopExpression(loopExpression, loopExpression);
}
}, loopExpression);
return result[0];
}
@Override
public JetType visitDoWhileExpression(JetDoWhileExpression expression, TypeInferenceContext contextWithExpectedType) {
@@ -1891,7 +1928,7 @@ public class JetTypeInferrer {
}
JetExpression condition = expression.getCondition();
checkCondition(conditionScope, condition, context);
if (!flowInformationProvider.isBreakable(expression)) {
if (!containsBreak(expression, context)) {
// resultScope = newWritableScopeImpl();
resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false, null, context);
}
@@ -2276,8 +2313,13 @@ public class JetTypeInferrer {
if (baseExpression == null) return null;
JetSimpleNameExpression operationSign = expression.getOperationSign();
if (JetTokens.LABELS.contains(operationSign.getReferencedNameElementType())) {
String referencedName = operationSign.getReferencedName();
referencedName = referencedName == null ? " <?>" : referencedName;
labelsResolver.enterLabeledElement(referencedName.substring(1), baseExpression);
// TODO : Some processing for the label?
return context.services.checkType(getType(baseExpression, context.replaceExpectedReturnType(context.expectedType)), expression, context);
JetType type = context.services.checkType(getType(baseExpression, context.replaceExpectedReturnType(context.expectedType)), expression, context);
labelsResolver.exitLabeledElement(baseExpression);
return type;
}
IElementType operationType = operationSign.getReferencedNameElementType();
String name = unaryOperationNames.get(operationType);
@@ -2318,6 +2360,7 @@ public class JetTypeInferrer {
else {
result = returnType;
}
return context.services.checkType(result, expression, context);
}
@@ -2341,10 +2384,10 @@ public class JetTypeInferrer {
result = getTypeForBinaryCall(context.scope, binaryOperationNames.get(operationType), context, expression);
}
else if (operationType == JetTokens.EQ) {
result = visitAssignment(expression, context);
result = visitAssignment(expression, contextWithExpectedType);
}
else if (assignmentOperationNames.containsKey(operationType)) {
result = visitAssignmentOperation(expression, context);
result = visitAssignmentOperation(expression, contextWithExpectedType);
}
else if (comparisonOperations.contains(operationType)) {
JetType compareToReturnType = getTypeForBinaryCall(context.scope, "compareTo", context, expression);
@@ -2658,7 +2701,7 @@ public class JetTypeInferrer {
PropertyDescriptor propertyDescriptor = context.classDescriptorResolver.resolveObjectDeclarationAsPropertyDescriptor(scope.getContainingDeclaration(), declaration, classDescriptor);
scope.addVariableDescriptor(propertyDescriptor);
}
return null;
return checkExpectedType(declaration, context);
}
@Override
@@ -2694,7 +2737,7 @@ public class JetTypeInferrer {
}
scope.addVariableDescriptor(propertyDescriptor);
return null;
return checkExpectedType(property, context);
}
@Override
@@ -2702,7 +2745,7 @@ public class JetTypeInferrer {
FunctionDescriptorImpl functionDescriptor = context.classDescriptorResolver.resolveFunctionDescriptor(scope.getContainingDeclaration(), scope, function);
scope.addFunctionDescriptor(functionDescriptor);
context.services.checkFunctionReturnType(context.scope, function, functionDescriptor, context.dataFlowInfo);
return null;
return checkExpectedType(function, context);
}
@Override
@@ -2717,7 +2760,7 @@ public class JetTypeInferrer {
@Override
public JetType visitDeclaration(JetDeclaration dcl, TypeInferenceContext context) {
return visitJetElement(dcl, context);
return checkExpectedType(dcl, context);
}
@Override
@@ -2739,6 +2782,17 @@ public class JetTypeInferrer {
else {
temporaryBindingTrace.commit();
}
return checkExpectedType(expression, context);
}
@Nullable
private JetType checkExpectedType(JetExpression expression, TypeInferenceContext context) {
if (context.expectedType != NO_EXPECTED_TYPE) {
if (JetStandardClasses.isUnit(context.expectedType)) {
return JetStandardClasses.getUnitType();
}
context.trace.report(EXPECTED_TYPE_MISMATCH.on(expression, context.expectedType));
}
return null;
}
@@ -2771,7 +2825,7 @@ public class JetTypeInferrer {
}
}
}
return null;
return checkExpectedType(expression, context);
}
private JetType resolveArrayAccessToLValue(JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide, JetSimpleNameExpression operationSign, TypeInferenceContext context) {
@@ -2794,6 +2848,11 @@ public class JetTypeInferrer {
return context.services.checkType(functionDescriptor.getReturnType(), arrayAccessExpression, context);
}
@Override
public JetType visitAnnotatedExpression(JetAnnotatedExpression expression, TypeInferenceContext data) {
return getType(expression.getBaseExpression(), data);
}
@Override
public JetType visitJetElement(JetElement element, TypeInferenceContext context) {
context.trace.report(UNSUPPORTED.on(element, "in a block"));
@@ -2801,4 +2860,135 @@ public class JetTypeInferrer {
return null;
}
}
private class LabelsResolver {
private final Map<String, Stack<JetElement>> labeledElements = new HashMap<String, Stack<JetElement>>();
public void enterLabeledElement(@NotNull String labelName, @NotNull JetExpression labeledExpression) {
JetExpression deparenthesized = JetPsiUtil.deparenthesize(labeledExpression);
if (deparenthesized != null) {
Stack<JetElement> stack = labeledElements.get(labelName);
if (stack == null) {
stack = new Stack<JetElement>();
labeledElements.put(labelName, stack);
}
stack.push(deparenthesized);
}
}
public void exitLabeledElement(@NotNull JetExpression expression) {
JetExpression deparenthesized = JetPsiUtil.deparenthesize(expression);
// TODO : really suboptimal
for (Iterator<Map.Entry<String, Stack<JetElement>>> mapIter = labeledElements.entrySet().iterator(); mapIter.hasNext(); ) {
Map.Entry<String, Stack<JetElement>> entry = mapIter.next();
Stack<JetElement> stack = entry.getValue();
for (Iterator<JetElement> stackIter = stack.iterator(); stackIter.hasNext(); ) {
JetElement recorded = stackIter.next();
if (recorded == deparenthesized) {
stackIter.remove();
}
}
if (stack.isEmpty()) {
mapIter.remove();
}
}
}
private JetElement resolveControlLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved, TypeInferenceContext context) {
Collection<DeclarationDescriptor> declarationsByLabel = context.scope.getDeclarationsByLabel(labelName);
int size = declarationsByLabel.size();
if (size == 1) {
DeclarationDescriptor declarationDescriptor = declarationsByLabel.iterator().next();
JetElement element;
if (declarationDescriptor instanceof FunctionDescriptor || declarationDescriptor instanceof ClassDescriptor) {
element = (JetElement) context.trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, declarationDescriptor);
}
else {
throw new UnsupportedOperationException(); // TODO
}
context.trace.record(LABEL_TARGET, labelExpression, element);
return element;
}
else if (size == 0) {
return resolveNamedLabel(labelName, labelExpression, reportUnresolved, context);
}
context.trace.report(AMBIGUOUS_LABEL.on(labelExpression));
return null;
}
public void recordLabel(JetLabelQualifiedExpression expression, TypeInferenceContext context) {
JetSimpleNameExpression labelElement = expression.getTargetLabel();
if (labelElement != null) {
String labelName = expression.getLabelName();
assert labelName != null;
resolveControlLabel(labelName, labelElement, true, context);
}
}
private JetElement resolveNamedLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved, TypeInferenceContext context) {
Stack<JetElement> stack = labeledElements.get(labelName);
if (stack == null || stack.isEmpty()) {
if (reportUnresolved) {
context.trace.report(UNRESOLVED_REFERENCE.on(labelExpression));
}
return null;
}
else if (stack.size() > 1) {
context.trace.report(LABEL_NAME_CLASH.on(labelExpression));
}
JetElement result = stack.peek();
context.trace.record(BindingContext.LABEL_TARGET, labelExpression, result);
return result;
}
public ReceiverDescriptor resolveThisLabel(JetThisExpression expression, TypeInferenceContext context, ReceiverDescriptor thisReceiver, String labelName) {
Collection<DeclarationDescriptor> declarationsByLabel = context.scope.getDeclarationsByLabel(labelName);
int size = declarationsByLabel.size();
final JetSimpleNameExpression targetLabel = expression.getTargetLabel();
assert targetLabel != null;
if (size == 1) {
DeclarationDescriptor declarationDescriptor = declarationsByLabel.iterator().next();
if (declarationDescriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
thisReceiver = classDescriptor.getImplicitReceiver();
}
else if (declarationDescriptor instanceof FunctionDescriptor) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor;
thisReceiver = functionDescriptor.getReceiver();
}
else {
throw new UnsupportedOperationException(); // TODO
}
PsiElement element = context.trace.get(DESCRIPTOR_TO_DECLARATION, declarationDescriptor);
assert element != null;
context.trace.record(LABEL_TARGET, targetLabel, element);
context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor);
}
else if (size == 0) {
JetElement element = labelsResolver.resolveNamedLabel(labelName, targetLabel, false, context);
if (element instanceof JetFunctionLiteralExpression) {
DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
if (declarationDescriptor instanceof FunctionDescriptor) {
thisReceiver = ((FunctionDescriptor) declarationDescriptor).getReceiver();
if (thisReceiver.exists()) {
context.trace.record(LABEL_TARGET, targetLabel, element);
context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor);
}
}
else {
context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel));
}
}
else {
context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel));
}
}
else {
context.trace.report(AMBIGUOUS_LABEL.on(targetLabel));
}
return thisReceiver;
}
}
}
@@ -0,0 +1,63 @@
package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import java.util.*;
/**
* @author alex.tkachman
*
* Utility class used by back-end to
*/
public class ProjectionErasingJetType implements JetType {
private final JetType delegate;
private List<TypeProjection> arguments;
public ProjectionErasingJetType(JetType delegate) {
this.delegate = delegate;
arguments = new ArrayList<TypeProjection>();
for(TypeProjection tp : delegate.getArguments()) {
arguments.add(new TypeProjection(Variance.INVARIANT, tp.getType()));
}
}
@NotNull
@Override
public TypeConstructor getConstructor() {
return delegate.getConstructor();
}
@NotNull
@Override
public List<TypeProjection> getArguments() {
return arguments;
}
@Override
public boolean isNullable() {
return false;
}
@NotNull
@Override
public JetScope getMemberScope() {
return delegate.getMemberScope();
}
@Override
public List<AnnotationDescriptor> getAnnotations() {
return delegate.getAnnotations();
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
return ((obj instanceof ProjectionErasingJetType) && delegate.equals(((ProjectionErasingJetType)obj).delegate)) || delegate.equals(obj);
}
}
@@ -136,6 +136,7 @@ public interface JetTokens {
JetKeywordToken CATCH_KEYWORD = JetKeywordToken.softKeyword("catch");
JetKeywordToken OUT_KEYWORD = JetKeywordToken.softKeyword("out");
JetKeywordToken VARARG_KEYWORD = JetKeywordToken.softKeyword("vararg");
JetKeywordToken INLINE_KEYWORD = JetKeywordToken.softKeyword("inline");
JetKeywordToken FINALLY_KEYWORD = JetKeywordToken.softKeyword("finally");
JetKeywordToken FINAL_KEYWORD = JetKeywordToken.softKeyword("final");
@@ -155,12 +156,12 @@ public interface JetTokens {
TokenSet SOFT_KEYWORDS = TokenSet.create(IMPORT_KEYWORD, WHERE_KEYWORD, BY_KEYWORD, GET_KEYWORD,
SET_KEYWORD, ABSTRACT_KEYWORD, ENUM_KEYWORD, OPEN_KEYWORD, ANNOTATION_KEYWORD,
OVERRIDE_KEYWORD, PRIVATE_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD, PROTECTED_KEYWORD,
CATCH_KEYWORD, FINALLY_KEYWORD, REF_KEYWORD, OUT_KEYWORD, FINAL_KEYWORD, VARARG_KEYWORD
CATCH_KEYWORD, FINALLY_KEYWORD, REF_KEYWORD, OUT_KEYWORD, FINAL_KEYWORD, VARARG_KEYWORD, INLINE_KEYWORD
);
TokenSet MODIFIER_KEYWORDS = TokenSet.create(ABSTRACT_KEYWORD, ENUM_KEYWORD,
OPEN_KEYWORD, ANNOTATION_KEYWORD, OVERRIDE_KEYWORD, PRIVATE_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD,
PROTECTED_KEYWORD, REF_KEYWORD, OUT_KEYWORD, IN_KEYWORD, FINAL_KEYWORD, VARARG_KEYWORD
PROTECTED_KEYWORD, REF_KEYWORD, OUT_KEYWORD, IN_KEYWORD, FINAL_KEYWORD, VARARG_KEYWORD, INLINE_KEYWORD
);
TokenSet WHITE_SPACE_OR_COMMENT_BIT_SET = TokenSet.create(WHITE_SPACE, BLOCK_COMMENT, EOL_COMMENT, DOC_COMMENT);
TokenSet WHITESPACES = TokenSet.create(TokenType.WHITE_SPACE);