Merge branch 'master' of ssh://git.labs.intellij.net/jet

Conflicts:
	compiler/tests/org/jetbrains/jet/cfg/JetControlFlowTest.java
This commit is contained in:
svtk
2011-10-21 17:13:09 +04:00
674 changed files with 3276 additions and 1589 deletions
+1
View File
@@ -5,6 +5,7 @@
<module fileurl="file://$PROJECT_DIR$/Jet.iml" filepath="$PROJECT_DIR$/Jet.iml" />
<module fileurl="file://$PROJECT_DIR$/compiler/backend/backend.iml" filepath="$PROJECT_DIR$/compiler/backend/backend.iml" />
<module fileurl="file://$PROJECT_DIR$/compiler/cli/cli.iml" filepath="$PROJECT_DIR$/compiler/cli/cli.iml" />
<module fileurl="file://$PROJECT_DIR$/compiler/tests/compiler-tests.iml" filepath="$PROJECT_DIR$/compiler/tests/compiler-tests.iml" />
<module fileurl="file://$PROJECT_DIR$/examples/examples.iml" filepath="$PROJECT_DIR$/examples/examples.iml" />
<module fileurl="file://$PROJECT_DIR$/compiler/frontend/frontend.iml" filepath="$PROJECT_DIR$/compiler/frontend/frontend.iml" />
<module fileurl="file://$PROJECT_DIR$/compiler/frontend.java/frontend.java.iml" filepath="$PROJECT_DIR$/compiler/frontend.java/frontend.java.iml" />
@@ -2,6 +2,8 @@ package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
import org.objectweb.asm.commons.Method;
@@ -17,9 +19,9 @@ public class CallableMethod implements Callable {
private final int invokeOpcode;
private final List<Type> valueParameterTypes;
private boolean acceptsTypeArguments = false;
private boolean needsReceiverOnStack = false;
private boolean ownerFromCall = false;
private ClassDescriptor receiverClass = null;
private DeclarationDescriptor thisClass = null;
private DeclarationDescriptor receiverClass = null;
private Type generateCalleeType = null;
public CallableMethod(String owner, Method signature, int invokeOpcode, List<Type> valueParameterTypes) {
@@ -57,13 +59,12 @@ public class CallableMethod implements Callable {
this.acceptsTypeArguments = acceptsTypeArguments;
}
public void setNeedsReceiver(@Nullable ClassDescriptor receiverClass) {
needsReceiverOnStack = true;
public void setNeedsReceiver(@Nullable DeclarationDescriptor receiverClass) {
this.receiverClass = receiverClass;
}
public boolean needsReceiverOnStack() {
return needsReceiverOnStack;
public void setNeedsThis(@Nullable DeclarationDescriptor receiverClass) {
this.thisClass = receiverClass;
}
public boolean isOwnerFromCall() {
@@ -74,10 +75,6 @@ public class CallableMethod implements Callable {
this.ownerFromCall = ownerFromCall;
}
public ClassDescriptor getReceiverClass() {
return receiverClass;
}
void invoke(InstructionAdapter v) {
v.visitMethodInsn(getInvokeOpcode(), getOwner(), getSignature().getName(), getSignature().getDescriptor());
}
@@ -89,4 +86,25 @@ public class CallableMethod implements Callable {
public Type getGenerateCalleeType() {
return generateCalleeType;
}
public void invokeWithDefault(InstructionAdapter v, int mask) {
v.iconst(mask);
String desc = getSignature().getDescriptor().replace(")", "I)");
if(getInvokeOpcode() != Opcodes.INVOKESTATIC)
desc = desc.replace("(", "(L" + getOwner() + ";");
v.visitMethodInsn(Opcodes.INVOKESTATIC, getInvokeOpcode() == Opcodes.INVOKEINTERFACE ? getOwner() + "$$TImpl" : getOwner(), getSignature().getName() + "$default", desc);
}
public boolean isNeedsThis() {
return thisClass != null;
}
public boolean isNeedsReceiver() {
return receiverClass != null;
}
public DeclarationDescriptor getThisClass() {
return thisClass;
}
}
@@ -4,19 +4,13 @@
package org.jetbrains.jet.codegen;
import com.intellij.openapi.util.Pair;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetFunctionLiteral;
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.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.*;
import org.objectweb.asm.commons.InstructionAdapter;
import org.objectweb.asm.commons.Method;
import org.objectweb.asm.signature.SignatureWriter;
@@ -26,6 +20,8 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static org.objectweb.asm.Opcodes.*;
public class ClosureCodegen extends FunctionOrClosureCodegen {
public ClosureCodegen(GenerationState state, ExpressionCodegen exprContext, ClassContext context) {
@@ -68,8 +64,8 @@ public class ClosureCodegen extends FunctionOrClosureCodegen {
appendType(signatureWriter, funDescriptor.getReturnType(), '=');
signatureWriter.visitEnd();
cv.visit(Opcodes.V1_6,
Opcodes.ACC_PUBLIC,
cv.visit(V1_6,
ACC_PUBLIC,
name,
null,
funClass,
@@ -79,7 +75,7 @@ public class ClosureCodegen extends FunctionOrClosureCodegen {
generateBridge(name, funDescriptor, cv);
boolean captureThis = generateBody(funDescriptor, cv, fun.getFunctionLiteral());
captureThis = generateBody(funDescriptor, cv, fun.getFunctionLiteral());
final Type enclosingType = context.enclosingClassType(state.getTypeMapper());
if (enclosingType == null) captureThis = false;
@@ -89,6 +85,10 @@ public class ClosureCodegen extends FunctionOrClosureCodegen {
cv.visitField(0, "this$0", enclosingType.getDescriptor(), null, null);
}
if(isConst()) {
generateConstInstance();
}
cv.visitEnd();
final GeneratedAnonymousClassDescriptor answer = new GeneratedAnonymousClassDescriptor(name, constructor, captureThis);
@@ -99,6 +99,48 @@ public class ClosureCodegen extends FunctionOrClosureCodegen {
return answer;
}
private void generateConstInstance() {
cv.visitField(ACC_PRIVATE| ACC_STATIC, "$instance", "Ljava/lang/ref/SoftReference;", null, null);
MethodVisitor mv = cv.visitMethod(ACC_PUBLIC | ACC_STATIC, "$getInstance", "()L" + name + ";", null, new String[0]);
mv.visitCode();
mv.visitFieldInsn(GETSTATIC, name, "$instance", "Ljava/lang/ref/SoftReference;");
mv.visitInsn(DUP);
Label makeNew = new Label();
mv.visitJumpInsn(IFNULL, makeNew);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ref/SoftReference", "get", "()Ljava/lang/Object;");
mv.visitInsn(DUP);
Label ret = new Label();
mv.visitJumpInsn(IFNULL, makeNew);
mv.visitTypeInsn(CHECKCAST, name);
mv.visitJumpInsn(GOTO, ret);
mv.visitLabel(makeNew);
mv.visitInsn(POP);
mv.visitTypeInsn(NEW, "java/lang/ref/SoftReference");
mv.visitInsn(DUP);
mv.visitTypeInsn(NEW, name);
mv.visitInsn(DUP);
mv.visitVarInsn(ASTORE, 0);
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, name, "<init>", "()V");
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/ref/SoftReference", "<init>", "(Ljava/lang/Object;)V");
mv.visitFieldInsn(PUTSTATIC, name, "$instance", "Ljava/lang/ref/SoftReference;");
mv.visitVarInsn(ALOAD, 0);
mv.visitLabel(ret);
mv.visitInsn(ARETURN);
mv.visitMaxs(0,0);
mv.visitEnd();
}
private boolean generateBody(FunctionDescriptor funDescriptor, ClassVisitor cv, JetFunctionLiteral body) {
final ClassContext closureContext = context.intoClosure(name, this);
FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state);
@@ -110,7 +152,7 @@ public class ClosureCodegen extends FunctionOrClosureCodegen {
final Method bridge = erasedInvokeSignature(funDescriptor);
final Method delegate = invokeSignature(funDescriptor);
final MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "invoke", bridge.getDescriptor(), state.getTypeMapper().genericSignature(funDescriptor), new String[0]);
final MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "invoke", bridge.getDescriptor(), state.getTypeMapper().genericSignature(funDescriptor), new String[0]);
mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv);
@@ -164,7 +206,7 @@ public class ClosureCodegen extends FunctionOrClosureCodegen {
}
final Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes);
final MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "<init>", constructor.getDescriptor(), null, new String[0]);
final MethodVisitor mv = cv.visitMethod(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);
@@ -190,7 +232,7 @@ public class ClosureCodegen extends FunctionOrClosureCodegen {
StackValue.field(type, name, fieldName, false).store(iv);
}
iv.visitInsn(Opcodes.RETURN);
iv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
@@ -215,15 +257,4 @@ public class ClosureCodegen extends FunctionOrClosureCodegen {
signatureWriter.visitClassType(rawRetType.getInternalName());
signatureWriter.visitEnd();
}
public static CallableMethod asCallableMethod(FunctionDescriptor fd) {
Method descriptor = erasedInvokeSignature(fd);
String owner = getInternalClassName(fd);
final CallableMethod result = new CallableMethod(owner, descriptor, Opcodes.INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes()));
if (fd.getReceiverParameter().exists()) {
result.setNeedsReceiver(null);
}
result.requestGenerateCallee(Type.getObjectType(getInternalClassName(fd)));
return result;
}
}
@@ -13,6 +13,7 @@ import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
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.calls.*;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor;
import org.jetbrains.jet.lang.types.*;
@@ -26,6 +27,8 @@ import org.objectweb.asm.commons.Method;
import java.util.*;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
/**
* @author max
* @author yole
@@ -76,6 +79,17 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
this.intrinsics = state.getIntrinsics();
}
private CallableMethod asCallableMethod(FunctionDescriptor fd) {
Method descriptor = ClosureCodegen.erasedInvokeSignature(fd);
String owner = ClosureCodegen.getInternalClassName(fd);
final CallableMethod result = new CallableMethod(owner, descriptor, INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes()));
if (fd.getReceiverParameter().exists()) {
result.setNeedsReceiver(fd.getReceiverParameter().getType().getConstructor().getDeclarationDescriptor());
}
result.requestGenerateCallee(Type.getObjectType(ClosureCodegen.getInternalClassName(fd)));
return result;
}
public GenerationState getState() {
return state;
}
@@ -428,9 +442,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
gen(expression.getLoopRange(), loopRangeType);
v.dup();
v.invokevirtual("jet/IntRange", "getStartValue", "()I");
v.invokevirtual("jet/IntRange", "getStart", "()I");
v.store(lookupLocal(parameterDescriptor), Type.INT_TYPE);
v.invokevirtual("jet/IntRange", "getEndValue", "()I");
v.invokevirtual("jet/IntRange", "getEnd", "()I");
v.store(myEndVar, Type.INT_TYPE);
}
}
@@ -543,23 +557,29 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
return generateBlock(expression.getFunctionLiteral().getBodyExpression().getStatements());
}
else {
final GeneratedAnonymousClassDescriptor closure = new ClosureCodegen(state, this, context).gen(expression);
ClosureCodegen closureCodegen = new ClosureCodegen(state, this, context);
final GeneratedAnonymousClassDescriptor closure = closureCodegen.gen(expression);
v.anew(Type.getObjectType(closure.getClassname()));
v.dup();
final Method cons = closure.getConstructor();
if (closure.isCaptureThis()) {
v.load(0, JetTypeMapper.TYPE_OBJECT);
if(closureCodegen.isConst()) {
v.invokestatic(closure.getClassname(), "$getInstance", "()L" + closure.getClassname() + ";");
}
else {
v.anew(Type.getObjectType(closure.getClassname()));
v.dup();
for (int i = 0; i < closure.getArgs().size(); i++) {
StackValue arg = closure.getArgs().get(i);
arg.put(cons.getArgumentTypes()[i], v);
final Method cons = closure.getConstructor();
if (closure.isCaptureThis()) {
v.load(0, JetTypeMapper.TYPE_OBJECT);
}
for (int i = 0; i < closure.getArgs().size(); i++) {
StackValue arg = closure.getArgs().get(i);
arg.put(cons.getArgumentTypes()[i], v);
}
v.invokespecial(closure.getClassname(), "<init>", cons.getDescriptor());
}
v.invokespecial(closure.getClassname(), "<init>", cons.getDescriptor());
return StackValue.onStack(Type.getObjectType(closure.getClassname()));
}
}
@@ -976,7 +996,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
callableMethod = typeMapper.mapToCallableMethod((PsiNamedElement) declarationPsiElement, null);
}
else if (fd instanceof VariableAsFunctionDescriptor) {
callableMethod = ClosureCodegen.asCallableMethod((FunctionDescriptor) fd);
callableMethod = asCallableMethod((FunctionDescriptor) fd);
}
else if (fd instanceof FunctionDescriptor) {
callableMethod = typeMapper.mapToCallableMethod((FunctionDescriptor) fd, null);
@@ -1011,18 +1031,35 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if (callableMethod.isOwnerFromCall()) {
setOwnerFromCall(callableMethod, expression);
}
if (callableMethod.needsReceiverOnStack()) {
if (receiver == StackValue.none()) {
ClassDescriptor receiverClass = callableMethod.getReceiverClass();
receiver = receiverClass == null ? thisExpression() : generateThisOrOuter(receiverClass);
if (callableMethod.isNeedsThis()) {
if(callableMethod.isNeedsReceiver()) {
generateThisOrOuter((ClassDescriptor) callableMethod.getThisClass()).put(JetTypeMapper.TYPE_OBJECT, v);
receiver.put(JetTypeMapper.TYPE_OBJECT, v);
}
else {
if (receiver == StackValue.none()) {
generateThisOrOuter((ClassDescriptor) callableMethod.getThisClass()).put(JetTypeMapper.TYPE_OBJECT, v);;
}
else {
receiver.put(JetTypeMapper.TYPE_OBJECT, v);
}
}
receiver.put(JetTypeMapper.TYPE_OBJECT, v);
}
pushMethodArguments(expression, callableMethod.getValueParameterTypes());
else {
if (callableMethod.isNeedsReceiver()) {
receiver.put(JetTypeMapper.TYPE_OBJECT, v);
}
}
int mask = pushMethodArguments(expression, callableMethod.getValueParameterTypes());
if (callableMethod.acceptsTypeArguments()) {
pushTypeArguments(expression);
}
callableMethod.invoke(v);
if(mask == 0)
callableMethod.invoke(v);
else
callableMethod.invokeWithDefault(v, mask);
}
private void setOwnerFromCall(CallableMethod callableMethod, JetCallElement expression) {
@@ -1118,11 +1155,52 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
return false;
}
private void pushMethodArguments(JetCallElement expression, List<Type> valueParameterTypes) {
private int pushMethodArguments(JetCallElement expression, List<Type> valueParameterTypes) {
ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression());
List<? extends ValueArgument> args = expression.getValueArguments();
for (int i = 0, argsSize = args.size(); i < argsSize; i++) {
ValueArgument arg = args.get(i);
gen(arg.getArgumentExpression(), valueParameterTypes.get(i));
if(resolvedCall != null) {
Map<ValueParameterDescriptor,ResolvedValueArgument> valueArguments = resolvedCall.getValueArguments();
CallableDescriptor fd = resolvedCall.getResultingDescriptor();
int index = 0;
int mask = 0;
for (ValueParameterDescriptor valueParameterDescriptor : fd.getValueParameters()) {
ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameterDescriptor);
if(resolvedValueArgument instanceof ExpressionValueArgument) {
ExpressionValueArgument valueArgument = (ExpressionValueArgument) resolvedValueArgument;
gen(valueArgument.getExpression(), valueParameterTypes.get(index));
}
else if(resolvedValueArgument instanceof DefaultValueArgument) {
Type type = valueParameterTypes.get(index);
if(type.getSort() == Type.OBJECT||type.getSort() == Type.ARRAY)
v.aconst(null);
else if(type.getSort() == Type.FLOAT) {
v.aconst(0f);
}
else if(type.getSort() == Type.DOUBLE) {
v.aconst(0d);
}
else {
v.iconst(0);
}
mask |= (1 << index);
}
else if(resolvedValueArgument instanceof VarargValueArgument) {
throw new UnsupportedOperationException("Varargs are not supported yet");
}
else {
throw new UnsupportedOperationException();
}
index++;
}
return mask;
}
else {
for (int i = 0, argsSize = args.size(); i < argsSize; i++) {
ValueArgument arg = args.get(i);
gen(arg.getArgumentExpression(), valueParameterTypes.get(i));
}
return 0;
}
}
@@ -1739,8 +1817,19 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
}
private void pushTypeArguments(JetCallElement expression) {
for (JetTypeProjection jetTypeArgument : expression.getTypeArguments()) {
pushTypeArgument(jetTypeArgument);
ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression());
if(resolvedCall != null) {
Map<TypeParameterDescriptor, JetType> typeArguments = resolvedCall.getTypeArguments();
CallableDescriptor resultingDescriptor = resolvedCall.getCandidateDescriptor();
for (TypeParameterDescriptor typeParameterDescriptor : resultingDescriptor.getTypeParameters()) {
JetType jetType = typeArguments.get(typeParameterDescriptor);
generateTypeInfo(jetType);
}
}
else {
for (JetTypeProjection jetTypeArgument : expression.getTypeArguments()) {
pushTypeArgument(jetTypeArgument);
}
}
}
@@ -1754,7 +1843,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
Type type = JetTypeMapper.psiClassType(javaClass);
v.anew(type);
v.dup();
final CallableMethod callableMethod = JetTypeMapper.mapToCallableMethod(constructor);
final CallableMethod callableMethod = typeMapper.mapToCallableMethod(constructor);
invokeMethodWithArguments(callableMethod, expression);
return type;
}
@@ -1850,7 +1939,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
assert declaration != null : "No declaration found for " + expression.getText();
final CallableMethod accessor;
if (declaration instanceof PsiMethod) {
accessor = JetTypeMapper.mapToCallableMethod((PsiMethod) declaration);
accessor = typeMapper.mapToCallableMethod((PsiMethod) declaration);
}
else if (declaration instanceof JetNamedFunction) {
accessor = typeMapper.mapToCallableMethod((JetNamedFunction) declaration, null);
@@ -1922,7 +2011,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
@Override
public StackValue visitThisExpression(JetThisExpression expression, StackValue receiver) {
final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getThisReference());
final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference());
if (descriptor instanceof ClassDescriptor) {
return generateThisOrOuter((ClassDescriptor) descriptor);
}
@@ -1,26 +1,22 @@
package org.jetbrains.jet.codegen;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetNamedFunction;
import com.intellij.psi.PsiElement;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.*;
import org.objectweb.asm.commons.InstructionAdapter;
import org.objectweb.asm.commons.Method;
import java.util.List;
import java.util.Set;
import static org.objectweb.asm.Opcodes.*;
/**
* @author max
* @author yole
* @author alex.tkachman
*/
public class FunctionCodegen {
private final ClassContext owner;
@@ -54,74 +50,89 @@ public class FunctionCodegen {
List<ValueParameterDescriptor> paramDescrs = functionDescriptor.getValueParameters();
List<TypeParameterDescriptor> typeParameters = functionDescriptor.getTypeParameters();
int flags = Opcodes.ACC_PUBLIC; // TODO.
int flags = ACC_PUBLIC; // TODO.
OwnerKind kind = context.getContextKind();
if(kind == OwnerKind.TRAIT_IMPL && bodyExpressions == null)
return;
if (kind != OwnerKind.TRAIT_IMPL || bodyExpressions != null) {
boolean isStatic = kind == OwnerKind.NAMESPACE || kind == OwnerKind.TRAIT_IMPL;
if (isStatic) flags |= Opcodes.ACC_STATIC;
boolean isStatic = kind == OwnerKind.NAMESPACE || kind == OwnerKind.TRAIT_IMPL;
if (isStatic) flags |= ACC_STATIC;
boolean isAbstract = !isStatic && (bodyExpressions == null || CodegenUtil.isInterface(functionDescriptor.getContainingDeclaration()));
if (isAbstract) flags |= Opcodes.ACC_ABSTRACT;
boolean isAbstract = !isStatic && (bodyExpressions == null || CodegenUtil.isInterface(functionDescriptor.getContainingDeclaration()));
if (isAbstract) flags |= ACC_ABSTRACT;
final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null);
if (!isAbstract) {
mv.visitCode();
FrameMap frameMap = context.prepareFrame();
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), context, state);
Type[] argTypes = jvmSignature.getArgumentTypes();
for (int i = 0; i < paramDescrs.size(); i++) {
ValueParameterDescriptor parameter = paramDescrs.get(i);
frameMap.enter(parameter, argTypes[i].getSize());
}
for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
int slot = frameMap.enterTemp();
codegen.addTypeParameter(typeParameterDescriptor, StackValue.local(slot, JetTypeMapper.TYPE_TYPEINFO));
}
if (kind instanceof OwnerKind.DelegateKind) {
OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind;
InstructionAdapter iv = new InstructionAdapter(mv);
iv.load(0, JetTypeMapper.TYPE_OBJECT);
dk.getDelegate().put(JetTypeMapper.TYPE_OBJECT, iv);
for (int i = 0; i < argTypes.length; i++) {
Type argType = argTypes[i];
iv.load(i + 1, argType);
final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null);
if(kind != OwnerKind.TRAIT_IMPL) {
int start = functionDescriptor.getReceiverParameter().exists() ? 1 : 0;
for(int i = 0; i != paramDescrs.size(); ++i) {
AnnotationVisitor annotationVisitor = mv.visitParameterAnnotation(i + start, "jet/typeinfo/JetParameterName", true);
annotationVisitor.visit("value", paramDescrs.get(i).getName());
annotationVisitor.visitEnd();
}
iv.invokeinterface(dk.getOwnerClass(), jvmSignature.getName(), jvmSignature.getDescriptor());
iv.areturn(jvmSignature.getReturnType());
}
else {
if (!isAbstract) {
mv.visitCode();
FrameMap frameMap = context.prepareFrame();
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), context, state);
Type[] argTypes = jvmSignature.getArgumentTypes();
for (int i = 0; i < paramDescrs.size(); i++) {
ValueParameterDescriptor parameter = paramDescrs.get(i);
Type sharedVarType = codegen.getSharedVarType(parameter);
Type localVarType = state.getTypeMapper().mapType(parameter.getOutType());
if(sharedVarType != null) {
int index = frameMap.getIndex(parameter);
mv.visitTypeInsn(Opcodes.NEW, sharedVarType.getInternalName());
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, sharedVarType.getInternalName(), "<init>", "()V");
mv.visitVarInsn(localVarType.getOpcode(Opcodes.ILOAD), index);
mv.visitFieldInsn(Opcodes.PUTFIELD, sharedVarType.getInternalName(), "ref", StackValue.refType(localVarType).getDescriptor());
mv.visitVarInsn(sharedVarType.getOpcode(Opcodes.ISTORE), index);
}
frameMap.enter(parameter, argTypes[i].getSize());
}
codegen.returnExpression(bodyExpressions);
}
mv.visitMaxs(0, 0);
mv.visitEnd();
for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
int slot = frameMap.enterTemp();
codegen.addTypeParameter(typeParameterDescriptor, StackValue.local(slot, JetTypeMapper.TYPE_TYPEINFO));
}
generateBridgeIfNeeded(owner, state, v, jvmSignature, functionDescriptor, kind);
if (kind instanceof OwnerKind.DelegateKind) {
OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind;
InstructionAdapter iv = new InstructionAdapter(mv);
iv.load(0, JetTypeMapper.TYPE_OBJECT);
dk.getDelegate().put(JetTypeMapper.TYPE_OBJECT, iv);
for (int i = 0; i < argTypes.length; i++) {
Type argType = argTypes[i];
iv.load(i + 1, argType);
}
iv.invokeinterface(dk.getOwnerClass(), jvmSignature.getName(), jvmSignature.getDescriptor());
iv.areturn(jvmSignature.getReturnType());
}
else {
for (int i = 0; i < paramDescrs.size(); i++) {
ValueParameterDescriptor parameter = paramDescrs.get(i);
Type sharedVarType = codegen.getSharedVarType(parameter);
Type localVarType = state.getTypeMapper().mapType(parameter.getOutType());
if (sharedVarType != null) {
int index = frameMap.getIndex(parameter);
mv.visitTypeInsn(NEW, sharedVarType.getInternalName());
mv.visitInsn(DUP);
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, sharedVarType.getInternalName(), "<init>", "()V");
mv.visitVarInsn(localVarType.getOpcode(ILOAD), index);
mv.visitFieldInsn(PUTFIELD, sharedVarType.getInternalName(), "ref", StackValue.refType(localVarType).getDescriptor());
mv.visitVarInsn(sharedVarType.getOpcode(ISTORE), index);
}
}
codegen.returnExpression(bodyExpressions);
}
try {
mv.visitMaxs(0, 0);
}
catch (Throwable t) {
System.out.println(t);
}
mv.visitEnd();
generateBridgeIfNeeded(owner, state, v, jvmSignature, functionDescriptor, kind);
}
}
generateDefaultIfNeeded(context, state, v, jvmSignature, functionDescriptor, kind);
}
static void generateBridgeIfNeeded(ClassContext owner, GenerationState state, ClassVisitor v, Method jvmSignature, FunctionDescriptor functionDescriptor, OwnerKind kind) {
@@ -135,12 +146,153 @@ public class FunctionCodegen {
}
}
static void generateDefaultIfNeeded(ClassContext owner, GenerationState state, ClassVisitor v, Method jvmSignature, FunctionDescriptor functionDescriptor, OwnerKind kind) {
DeclarationDescriptor contextClass = owner.getContextClass();
if(kind != OwnerKind.TRAIT_IMPL) {
// we don't generate defaults for traits but do for traitImpl
if(contextClass instanceof ClassDescriptor) {
PsiElement psiElement = state.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, contextClass);
if(psiElement instanceof JetClass) {
JetClass element = (JetClass) psiElement;
if(element.isTrait())
return;
}
}
}
boolean needed = false;
for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) {
if(parameterDescriptor.hasDefaultValue()) {
needed = true;
break;
}
}
if(needed) {
boolean hasReceiver = functionDescriptor.getReceiverParameter().exists();
boolean isStatic = kind == OwnerKind.NAMESPACE;
if(kind == OwnerKind.TRAIT_IMPL) {
String correctedDescr = "(" + jvmSignature.getDescriptor().substring(jvmSignature.getDescriptor().indexOf(";") + 1);
jvmSignature = new Method(jvmSignature.getName(), correctedDescr);
}
int flags = ACC_PUBLIC; // TODO.
String ownerInternalName = contextClass instanceof NamespaceDescriptor ?
JetTypeMapper.jvmName((NamespaceDescriptor) contextClass) :
state.getTypeMapper().jvmName((ClassDescriptor) contextClass, OwnerKind.IMPLEMENTATION);
String descriptor = jvmSignature.getDescriptor().replace(")","I)");
if(!isStatic)
descriptor = descriptor.replace("(","(L" + ownerInternalName + ";");
final MethodVisitor mv = v.visitMethod(flags| ACC_STATIC, jvmSignature.getName() + "$default", descriptor, null, null);
InstructionAdapter iv = new InstructionAdapter(mv);
mv.visitCode();
FrameMap frameMap = owner.prepareFrame();
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), owner, state);
int var = 0;
if(!isStatic) {
frameMap.enterTemp();
var++;
}
if(hasReceiver) {
frameMap.enterTemp();
var++;
}
Type[] argTypes = jvmSignature.getArgumentTypes();
List<ValueParameterDescriptor> paramDescrs = functionDescriptor.getValueParameters();
for (int i = 0; i < paramDescrs.size(); i++) {
ValueParameterDescriptor parameter = paramDescrs.get(i);
int size = argTypes[i + (hasReceiver ? 1 : 0)].getSize();
var += size;
frameMap.enter(parameter, size);
}
List<TypeParameterDescriptor> typeParameters = functionDescriptor.getTypeParameters();
for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
int slot = frameMap.enterTemp();
codegen.addTypeParameter(typeParameterDescriptor, StackValue.local(slot, JetTypeMapper.TYPE_TYPEINFO));
var++;
}
frameMap.enterTemp();
int maskIndex = var;
var = 0;
if(!isStatic) {
mv.visitVarInsn(ALOAD, var++);
}
if(hasReceiver) {
mv.visitVarInsn(ALOAD, var++);
}
Type[] argumentTypes = jvmSignature.getArgumentTypes();
for (int index = 0; index < paramDescrs.size(); index++) {
ValueParameterDescriptor parameterDescriptor = paramDescrs.get(index);
Type t = argumentTypes[(hasReceiver ? 1 : 0) + index];
Label endArg = null;
if (parameterDescriptor.hasDefaultValue()) {
iv.load(maskIndex, Type.INT_TYPE);
iv.iconst(1 << index);
iv.and(Type.INT_TYPE);
Label loadArg = new Label();
iv.ifeq(loadArg);
JetParameter jetParameter = (JetParameter) state.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, parameterDescriptor);
codegen.gen(jetParameter.getDefaultValue(), t);
endArg = new Label();
iv.goTo(endArg);
iv.mark(loadArg);
}
iv.load(var, t);
var += t.getSize();
if (parameterDescriptor.hasDefaultValue()) {
iv.mark(endArg);
}
}
for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
iv.load(var++, JetTypeMapper.TYPE_OBJECT);
}
if(!isStatic) {
if(kind == OwnerKind.TRAIT_IMPL) {
iv.invokeinterface(ownerInternalName, jvmSignature.getName(), jvmSignature.getDescriptor());
}
else
iv.invokevirtual(ownerInternalName, jvmSignature.getName(), jvmSignature.getDescriptor());
}
else {
iv.invokestatic(ownerInternalName, jvmSignature.getName(), jvmSignature.getDescriptor());
}
iv.areturn(jvmSignature.getReturnType());
mv.visitMaxs(0, 0);
mv.visitEnd();
}
}
private static void checkOverride(ClassContext owner, GenerationState state, ClassVisitor v, Method jvmSignature, FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenFunction) {
Type type1 = state.getTypeMapper().mapType(overriddenFunction.getOriginal().getReturnType());
Type type2 = state.getTypeMapper().mapType(functionDescriptor.getReturnType());
if(!type1.equals(type2)) {
Method overriden = state.getTypeMapper().mapSignature(overriddenFunction.getName(), overriddenFunction.getOriginal());
int flags = Opcodes.ACC_PUBLIC; // TODO.
int flags = ACC_PUBLIC; // TODO.
final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), overriden.getDescriptor(), null, null);
mv.visitCode();
@@ -13,6 +13,8 @@ import java.util.Map;
* @author alex.tkachman
*/
public class FunctionOrClosureCodegen {
protected boolean captureThis;
public final GenerationState state;
protected final ExpressionCodegen exprContext;
protected final ClassContext context;
@@ -54,4 +56,12 @@ public class FunctionOrClosureCodegen {
return null;
}
public boolean isCaptureThis() {
return captureThis;
}
public boolean isConst () {
return !captureThis && closure.isEmpty();
}
}
@@ -162,40 +162,6 @@ public class JetTypeMapper {
return new Method(method.isConstructor() ? "<init>" : method.getName(), Type.getMethodDescriptor(returnType, parameterTypes));
}
static CallableMethod mapToCallableMethod(PsiMethod method) {
final PsiClass containingClass = method.getContainingClass();
String owner = jvmName(containingClass);
Method signature = getMethodDescriptor(method);
List<Type> valueParameterTypes = new ArrayList<Type>();
Collections.addAll(valueParameterTypes, signature.getArgumentTypes());
int opcode;
boolean needsReceiver = false;
boolean ownerFromCall = false;
if (method.isConstructor()) {
opcode = Opcodes.INVOKESPECIAL;
}
else if (method.hasModifierProperty(PsiModifier.STATIC)) {
opcode = Opcodes.INVOKESTATIC;
}
else {
needsReceiver = true;
assert containingClass != null;
if (containingClass.isInterface()) {
opcode = Opcodes.INVOKEINTERFACE;
}
else {
opcode = Opcodes.INVOKEVIRTUAL;
}
ownerFromCall = true;
}
final CallableMethod result = new CallableMethod(owner, signature, opcode, valueParameterTypes);
if (needsReceiver) {
result.setNeedsReceiver(null);
}
result.setOwnerFromCall(ownerFromCall);
return result;
}
public static Type getBoxedType(final Type type) {
switch (type.getSort()) {
case Type.BYTE:
@@ -518,18 +484,49 @@ public class JetTypeMapper {
return mapToCallableMethod(functionDescriptor, kind);
}
CallableMethod mapToCallableMethod(PsiMethod method) {
final PsiClass containingClass = method.getContainingClass();
String owner = jvmName(containingClass);
Method signature = getMethodDescriptor(method);
List<Type> valueParameterTypes = new ArrayList<Type>();
Collections.addAll(valueParameterTypes, signature.getArgumentTypes());
int opcode;
boolean ownerFromCall = false;
DeclarationDescriptor thisClass = null;
if (method.isConstructor()) {
opcode = Opcodes.INVOKESPECIAL;
}
else if (method.hasModifierProperty(PsiModifier.STATIC)) {
opcode = Opcodes.INVOKESTATIC;
}
else {
assert containingClass != null;
if (containingClass.isInterface()) {
opcode = Opcodes.INVOKEINTERFACE;
}
else {
opcode = Opcodes.INVOKEVIRTUAL;
}
ownerFromCall = true;
thisClass = JetStandardClasses.getAny(); // todo - this is hack, correct descriptor needed
}
final CallableMethod result = new CallableMethod(owner, signature, opcode, valueParameterTypes);
result.setNeedsThis(thisClass);
result.setOwnerFromCall(ownerFromCall);
return result;
}
public CallableMethod mapToCallableMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) {
final DeclarationDescriptor functionParent = functionDescriptor.getContainingDeclaration();
final List<Type> valueParameterTypes = new ArrayList<Type>();
Method descriptor = mapSignature(functionDescriptor.getOriginal(), valueParameterTypes, kind);
String owner;
int invokeOpcode;
boolean needsReceiver;
ClassDescriptor receiverClass = null;
ClassDescriptor thisClass;
if (functionParent instanceof NamespaceDescriptor) {
owner = NamespaceCodegen.getJVMClassName(DescriptorRenderer.getFQName(functionParent));
invokeOpcode = Opcodes.INVOKESTATIC;
needsReceiver = functionDescriptor.getReceiverParameter().exists();
thisClass = null;
}
else if (functionParent instanceof ClassDescriptor) {
ClassDescriptor containingClass = (ClassDescriptor) functionParent;
@@ -537,8 +534,7 @@ public class JetTypeMapper {
invokeOpcode = CodegenUtil.isInterface(containingClass)
? Opcodes.INVOKEINTERFACE
: Opcodes.INVOKEVIRTUAL;
needsReceiver = true;
receiverClass = containingClass;
thisClass = containingClass;
}
else {
throw new UnsupportedOperationException("unknown function parent");
@@ -546,9 +542,11 @@ public class JetTypeMapper {
final CallableMethod result = new CallableMethod(owner, descriptor, invokeOpcode, valueParameterTypes);
result.setAcceptsTypeArguments(true);
if (needsReceiver) {
result.setNeedsReceiver(receiverClass);
result.setNeedsThis(thisClass);
if(functionDescriptor.getReceiverParameter().exists()) {
result.setNeedsReceiver(functionDescriptor.getReceiverParameter().getType().getConstructor().getDeclarationDescriptor());
}
return result;
}
@@ -22,6 +22,8 @@ import org.jetbrains.jet.plugin.JetFileType;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
/**
@@ -34,16 +36,6 @@ public class KotlinCompiler {
System.out.println("Usage: KotlinCompiler <filename>");
return;
}
String javaHome = System.getenv("JAVA_HOME");
if (javaHome == null) {
System.out.println("JAVA_HOME environment variable needs to be defined");
return;
}
File rtJar = findRtJar(javaHome);
if (rtJar == null || !rtJar.exists()) {
System.out.print("No rt.jar found under JAVA_HOME");
return;
}
Disposable root = new Disposable() {
@Override
@@ -51,9 +43,45 @@ public class KotlinCompiler {
}
};
JavaCoreEnvironment environment = new JavaCoreEnvironment(root);
String javaHome = System.getenv("JAVA_HOME");
File rtJar = null;
if (javaHome == null) {
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
if(systemClassLoader instanceof URLClassLoader) {
URLClassLoader loader = (URLClassLoader) systemClassLoader;
for(URL url: loader.getURLs()) {
if("file".equals(url.getProtocol())) {
if(url.getFile().endsWith("/lib/rt.jar")) {
rtJar = new File(url.getFile());
break;
}
if(url.getFile().endsWith("/Classes/classes.jar")) {
rtJar = new File(url.getFile()).getAbsoluteFile();
break;
}
}
}
}
if(rtJar == null) {
System.out.println("JAVA_HOME environment variable needs to be defined");
return;
}
}
else {
rtJar = findRtJar(javaHome);
}
if (rtJar == null || !rtJar.exists()) {
System.out.print("No rt.jar found under JAVA_HOME=" + javaHome);
return;
}
environment.addToClasspath(rtJar);
environment.registerFileType(JetFileType.INSTANCE, "kt");
environment.registerFileType(JetFileType.INSTANCE, "jet");
environment.registerParserDefinition(new JetParserDefinition());
VirtualFile vFile = environment.getLocalFileSystem().findFileByPath(args [0]);
if (vFile == null) {
@@ -1,4 +1,4 @@
package org.jetbrains.jet.plugin;
package org.jetbrains.jet.lang.resolve.java;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
@@ -6,7 +6,6 @@ import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetNamespace;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.JavaDefaultImports;
/**
* @author abreslav
@@ -51,11 +51,6 @@ public class JavaClassMembersScope implements JetScope {
return null;
}
@Override
public DeclarationDescriptor getDeclarationDescriptorForUnqualifiedThis() {
throw new UnsupportedOperationException();
}
@Override
public ClassifierDescriptor getClassifier(@NotNull String name) {
ClassifierDescriptor classifierDescriptor = classifiers.get(name);
@@ -109,6 +109,7 @@ public interface JetNodeTypes {
JetNodeType LABEL_QUALIFIER = new JetNodeType("LABEL_QUALIFIER", JetContainerNode.class);
JetNodeType THIS_EXPRESSION = new JetNodeType("THIS_EXPRESSION", JetThisExpression.class);
JetNodeType SUPER_EXPRESSION = new JetNodeType("SUPER_EXPRESSION", JetSuperExpression.class);
JetNodeType BINARY_EXPRESSION = new JetNodeType("BINARY_EXPRESSION", JetBinaryExpression.class);
JetNodeType BINARY_WITH_TYPE = new JetNodeType("BINARY_WITH_TYPE", JetBinaryExpressionWithTypeRHS.class);
JetNodeType BINARY_WITH_PATTERN = new JetNodeType("BINARY_WITH_PATTERN", JetIsExpression.class); // TODO:
@@ -14,7 +14,7 @@ import java.util.Set;
/**
* @author abreslav
*/
public interface ClassDescriptor extends ClassifierDescriptor {
public interface ClassDescriptor extends ClassifierDescriptor, MemberDescriptor {
@NotNull
JetScope getMemberScope(List<TypeProjection> typeArguments);
@@ -53,9 +53,11 @@ public interface ClassDescriptor extends ClassifierDescriptor {
@NotNull
ClassKind getKind();
@Override
@NotNull
Modality getModality();
@Override
@NotNull
Visibility getVisibility();
@@ -0,0 +1,11 @@
package org.jetbrains.jet.lang.descriptors;
import org.jetbrains.annotations.NotNull;
/**
* @author abreslav
*/
public interface DeclarationDescriptorWithVisibility extends DeclarationDescriptor {
@NotNull
Visibility getVisibility();
}
@@ -5,10 +5,11 @@ import org.jetbrains.annotations.NotNull;
/**
* @author abreslav
*/
public interface MemberDescriptor {
public interface MemberDescriptor extends DeclarationDescriptor, DeclarationDescriptorWithVisibility {
@NotNull
Modality getModality();
@Override
@NotNull
Visibility getVisibility();
}
@@ -1,5 +1,7 @@
package org.jetbrains.jet.lang.descriptors;
import java.util.EnumSet;
/**
* @author svtk
*/
@@ -11,6 +13,8 @@ public enum Visibility {
INTERNAL_PROTECTED(false),
LOCAL(false);
public static final EnumSet<Visibility> INTERNAL_VISIBILITIES = EnumSet.of(PRIVATE, INTERNAL, INTERNAL_PROTECTED, LOCAL);
private final boolean isAPI;
private Visibility(boolean visibleOutside) {
@@ -2,7 +2,7 @@ package org.jetbrains.jet.lang.diagnostics;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl;
import org.jetbrains.jet.resolve.DescriptorRenderer;
import java.util.Collection;
@@ -10,7 +10,7 @@ import java.util.Collection;
/**
* @author abreslav
*/
public class AmbiguousDescriptorDiagnosticFactory extends ParameterizedDiagnosticFactory1<Collection<? extends ResolvedCall<? extends DeclarationDescriptor>>> {
public class AmbiguousDescriptorDiagnosticFactory extends ParameterizedDiagnosticFactory1<Collection<? extends ResolvedCallImpl<? extends DeclarationDescriptor>>> {
public static AmbiguousDescriptorDiagnosticFactory create(String messageTemplate) {
return new AmbiguousDescriptorDiagnosticFactory(messageTemplate);
}
@@ -20,9 +20,9 @@ public class AmbiguousDescriptorDiagnosticFactory extends ParameterizedDiagnosti
}
@Override
protected String makeMessageFor(@NotNull Collection<? extends ResolvedCall<? extends DeclarationDescriptor>> argument) {
protected String makeMessageFor(@NotNull Collection<? extends ResolvedCallImpl<? extends DeclarationDescriptor>> argument) {
StringBuilder stringBuilder = new StringBuilder("\n");
for (ResolvedCall<? extends DeclarationDescriptor> call : argument) {
for (ResolvedCallImpl<? extends DeclarationDescriptor> call : argument) {
stringBuilder.append(DescriptorRenderer.TEXT.render(call.getResultingDescriptor())).append("\n");
}
return stringBuilder.toString();
@@ -162,12 +162,16 @@ public interface Errors {
SimpleDiagnosticFactory EQUALS_MISSING = SimpleDiagnosticFactory.create(ERROR, "No method 'equals(Any?) : Boolean' available");
SimpleDiagnosticFactory ASSIGNMENT_IN_EXPRESSION_CONTEXT = SimpleDiagnosticFactory.create(ERROR, "Assignments are not expressions, and only expressions are allowed in this context");
SimpleDiagnosticFactory NAMESPACE_IS_NOT_AN_EXPRESSION = SimpleDiagnosticFactory.create(ERROR, "'namespace' is not an expression");
SimpleDiagnosticFactory NAMESPACE_IS_NOT_AN_EXPRESSION = SimpleDiagnosticFactory.create(ERROR, "'namespace' is not an expression, it can only be used on the left-hand side of a dot ('.')");
ParameterizedDiagnosticFactory1<String> SUPER_IS_NOT_AN_EXPRESSION = ParameterizedDiagnosticFactory1.create(ERROR, "{0} is not an expression, it can only be used on the left-hand side of a dot ('.')");
SimpleDiagnosticFactory DECLARATION_IN_ILLEGAL_CONTEXT = SimpleDiagnosticFactory.create(ERROR, "Declarations are not allowed in this position");
SimpleDiagnosticFactory REF_SETTER_PARAMETER = SimpleDiagnosticFactory.create(ERROR, "Setter parameters can not be 'ref'");
SimpleDiagnosticFactory SETTER_PARAMETER_WITH_DEFAULT_VALUE = SimpleDiagnosticFactory.create(ERROR, "Setter parameters can not have default values");
SimpleDiagnosticFactory NO_THIS = SimpleDiagnosticFactory.create(ERROR, "'this' is not defined in this context");
SimpleDiagnosticFactory SUPER_NOT_AVAILABLE = SimpleDiagnosticFactory.create(ERROR, "No supertypes are accessible in this context");
SimpleDiagnosticFactory AMBIGUOUS_SUPER = SimpleDiagnosticFactory.create(ERROR, "Many supertypes available, please specify the one you mean in angle brackets, e.g. 'super<Foo>'");
SimpleDiagnosticFactory NOT_A_SUPERTYPE = SimpleDiagnosticFactory.create(ERROR, "Not a supertype");
SimpleDiagnosticFactory TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER = SimpleDiagnosticFactory.create(WARNING, "Type arguments do not need to be specified in a 'super' qualifier");
SimpleDiagnosticFactory NO_WHEN_ENTRIES = SimpleDiagnosticFactory.create(ERROR, "Entries are required for when-expression"); // TODO : Scope, and maybe this should not be an error
SimplePsiElementOnlyDiagnosticFactory<JetBinaryExpressionWithTypeRHS> USELESS_CAST_STATIC_ASSERT_IS_FINE = SimplePsiElementOnlyDiagnosticFactory.create(WARNING, "No cast needed, use ':' instead");
SimplePsiElementOnlyDiagnosticFactory<JetBinaryExpressionWithTypeRHS> USELESS_CAST = SimplePsiElementOnlyDiagnosticFactory.create(WARNING, "No cast needed");
@@ -49,6 +49,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
LPAR, // tuple
THIS_KEYWORD, // this
SUPER_KEYWORD, // super
IF_KEYWORD, // if
WHEN_KEYWORD, // when
@@ -464,7 +465,8 @@ public class JetExpressionParsing extends AbstractJetParsing {
/*
* atomicExpression
* : tupleLiteral // or parenthesized element
* : "this" getEntryPoint? ("<" type ">")?
* : "this" label?
* : "super" ("<" type ">")? label?
* : objectLiteral
* : jump
* : if
@@ -490,6 +492,9 @@ public class JetExpressionParsing extends AbstractJetParsing {
else if (at(THIS_KEYWORD)) {
parseThisExpression();
}
else if (at(SUPER_KEYWORD)) {
parseSuperExpression();
}
else if (at(OBJECT_KEYWORD)) {
parseObjectLiteral();
}
@@ -1593,7 +1598,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
}
/*
* "this" getEntryPoint? ("<" type ">")?
* "this" label?
*/
private void parseThisExpression() {
assert _at(THIS_KEYWORD);
@@ -1605,8 +1610,22 @@ public class JetExpressionParsing extends AbstractJetParsing {
parseLabel();
mark.done(THIS_EXPRESSION);
}
/*
* "this" ("<" type ">")? label?
*/
private void parseSuperExpression() {
assert _at(SUPER_KEYWORD);
PsiBuilder.Marker mark = mark();
PsiBuilder.Marker superReference = mark();
advance(); // SUPER_KEYWORD
superReference.done(REFERENCE_EXPRESSION);
if (at(LT)) {
// This may be "this < foo" or "this<foo>", thus the backtracking
// This may be "super < foo" or "super<foo>", thus the backtracking
PsiBuilder.Marker supertype = mark();
myBuilder.disableNewlines();
@@ -1623,7 +1642,9 @@ public class JetExpressionParsing extends AbstractJetParsing {
}
myBuilder.restoreNewlinesState();
}
mark.done(THIS_EXPRESSION);
parseLabel();
mark.done(SUPER_EXPRESSION);
}
/*
@@ -0,0 +1,20 @@
package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.JetNodeTypes;
/**
* @author abreslav
*/
public abstract class JetLabelQualifiedInstanceExpression extends JetLabelQualifiedExpression {
public JetLabelQualifiedInstanceExpression(@NotNull ASTNode node) {
super(node);
}
@NotNull
public JetReferenceExpression getInstanceReference() {
return (JetReferenceExpression) findChildByType(JetNodeTypes.REFERENCE_EXPRESSION);
}
}
@@ -10,13 +10,14 @@ import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.parsing.JetExpressionParsing;
import org.jetbrains.jet.lexer.JetTokens;
import static org.jetbrains.jet.lexer.JetTokens.*;
/**
* @author max
*/
public class JetSimpleNameExpression extends JetReferenceExpression {
public static final TokenSet REFERENCE_TOKENS = TokenSet.orSet(JetTokens.LABELS, TokenSet.create(JetTokens.IDENTIFIER, JetTokens.FIELD_IDENTIFIER, JetTokens.THIS_KEYWORD));
public static final TokenSet REFERENCE_TOKENS = TokenSet.orSet(LABELS, TokenSet.create(IDENTIFIER, FIELD_IDENTIFIER, THIS_KEYWORD, SUPER_KEYWORD));
public JetSimpleNameExpression(@NotNull ASTNode node) {
super(node);
@@ -0,0 +1,39 @@
package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
/**
* @author max
*/
public class JetSuperExpression extends JetLabelQualifiedInstanceExpression {
public JetSuperExpression(@NotNull ASTNode node) {
super(node);
}
@Override
public void accept(@NotNull JetVisitorVoid visitor) {
visitor.visitSuperExpression(this);
}
@Override
public <R, D> R accept(@NotNull JetVisitor<R, D> visitor, D data) {
return visitor.visitSuperExpression(this, data);
}
/**
* class A : B, C {
* override fun foo() {
* super<B>.foo()
* super<C>.foo()
* }
* }
*/
@Nullable
public JetTypeReference getSuperTypeQualifier() {
return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE);
}
}
@@ -2,13 +2,11 @@ package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
/**
* @author max
*/
public class JetThisExpression extends JetLabelQualifiedExpression {
public class JetThisExpression extends JetLabelQualifiedInstanceExpression {
public JetThisExpression(@NotNull ASTNode node) {
super(node);
@@ -23,23 +21,4 @@ public class JetThisExpression extends JetLabelQualifiedExpression {
public <R, D> R accept(@NotNull JetVisitor<R, D> visitor, D data) {
return visitor.visitThisExpression(this, data);
}
/**
* class A : B, C {
* override fun foo() {
* this<B>.foo()
* this<C>.foo()
* }
* }
*/
@Nullable
public JetTypeReference getSuperTypeQualifier() {
return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE);
}
@NotNull
public JetReferenceExpression getThisReference() {
return (JetReferenceExpression) findChildByType(JetNodeTypes.REFERENCE_EXPRESSION);
}
}
@@ -511,7 +511,15 @@ public class JetTreeVisitor<D> extends JetVisitor<Void, D> {
@Override
public Void visitThisExpression(JetThisExpression expression, D data) {
JetReferenceExpression thisReference = expression.getThisReference();
JetReferenceExpression thisReference = expression.getInstanceReference();
thisReference.accept(this, data);
visitLabelQualifiedExpression(expression, data);
return null;
}
@Override
public Void visitSuperExpression(JetSuperExpression expression, D data) {
JetReferenceExpression thisReference = expression.getInstanceReference();
thisReference.accept(this, data);
JetTypeReference superTypeQualifier = expression.getSuperTypeQualifier();
if (superTypeQualifier != null) {
@@ -280,6 +280,10 @@ public class JetVisitor<R, D> extends PsiElementVisitor {
return visitLabelQualifiedExpression(expression, data);
}
public R visitSuperExpression(JetSuperExpression expression, D data) {
return visitLabelQualifiedExpression(expression, data);
}
public R visitParenthesizedExpression(JetParenthesizedExpression expression, D data) {
return visitExpression(expression, data);
}
@@ -419,4 +423,5 @@ public class JetVisitor<R, D> extends PsiElementVisitor {
public R visitEscapeStringTemplateEntry(JetEscapeStringTemplateEntry entry, D data) {
return visitStringTemplateEntry(entry, data);
}
}
@@ -278,6 +278,10 @@ public class JetVisitorVoid extends PsiElementVisitor {
visitLabelQualifiedExpression(expression);
}
public void visitSuperExpression(JetSuperExpression expression) {
visitLabelQualifiedExpression(expression);
}
public void visitParenthesizedExpression(JetParenthesizedExpression expression) {
visitExpression(expression);
}
@@ -65,11 +65,6 @@ public abstract class AbstractScopeAdapter implements JetScope {
return getWorkerScope().getPropertyByFieldReference(fieldName);
}
@Override
public DeclarationDescriptor getDeclarationDescriptorForUnqualifiedThis() {
return getWorkerScope().getDeclarationDescriptorForUnqualifiedThis();
}
@NotNull
@Override
public Collection<DeclarationDescriptor> getAllDescriptors() {
@@ -10,7 +10,7 @@ import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetModifierList;
import org.jetbrains.jet.lang.resolve.calls.CallMaker;
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
import org.jetbrains.jet.lang.resolve.calls.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
@@ -36,7 +36,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, DataFlowInfo.getEmpty());
this.callResolver = new CallResolver(semanticServices, DataFlowInfo.EMPTY);
}
@NotNull
@@ -7,6 +7,7 @@ import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.DeferredType;
@@ -29,7 +30,7 @@ public interface BindingContext {
WritableSlice<JetReferenceExpression, DeclarationDescriptor> REFERENCE_TARGET = new BasicWritableSlice<JetReferenceExpression, DeclarationDescriptor>("REFERENCE_TARGET", RewritePolicy.DO_NOTHING);
WritableSlice<JetElement, ResolvedCall<? extends CallableDescriptor>> RESOLVED_CALL = new BasicWritableSlice<JetElement, ResolvedCall<? extends CallableDescriptor>>("RESOLVED_CALL", RewritePolicy.DO_NOTHING);
WritableSlice<JetReferenceExpression, Collection<? extends ResolvedCall<? extends DeclarationDescriptor>>> AMBIGUOUS_REFERENCE_TARGET = new BasicWritableSlice<JetReferenceExpression, Collection<? extends ResolvedCall<? extends DeclarationDescriptor>>>("AMBIGUOUS_REFERENCE_TARGET", RewritePolicy.DO_NOTHING);
WritableSlice<JetReferenceExpression, Collection<? extends ResolvedCallImpl<? extends DeclarationDescriptor>>> AMBIGUOUS_REFERENCE_TARGET = new BasicWritableSlice<JetReferenceExpression, Collection<? extends ResolvedCallImpl<? extends DeclarationDescriptor>>>("AMBIGUOUS_REFERENCE_TARGET", RewritePolicy.DO_NOTHING);
WritableSlice<JetExpression, FunctionDescriptor> LOOP_RANGE_ITERATOR = Slices.createSimpleSlice("LOOP_RANGE_ITERATOR");
WritableSlice<JetExpression, CallableDescriptor> LOOP_RANGE_HAS_NEXT = Slices.createSimpleSlice("LOOP_RANGE_HAS_NEXT");
@@ -10,7 +10,7 @@ import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.calls.CallMaker;
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
import org.jetbrains.jet.lang.resolve.calls.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
@@ -176,7 +176,7 @@ public class BodyResolver {
JetTypeReference typeReference = call.getTypeReference();
if (typeReference != null) {
if (descriptor.getUnsubstitutedPrimaryConstructor() != null) {
JetType supertype = new CallResolver(context.getSemanticServices(), DataFlowInfo.getEmpty()).resolveCall(
JetType supertype = new CallResolver(context.getSemanticServices(), DataFlowInfo.EMPTY).resolveCall(
context.getTrace(), scopeForConstructor,
CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call), NO_EXPECTED_TYPE);
if (supertype != null) {
@@ -322,7 +322,7 @@ public class BodyResolver {
private void resolveSecondaryConstructorBody(JetConstructor declaration, final ConstructorDescriptor descriptor, final JetScope declaringScope) {
final JetScope functionInnerScope = getInnerScopeForConstructor(descriptor, declaringScope, false);
final CallResolver callResolver = new CallResolver(context.getSemanticServices(), DataFlowInfo.getEmpty()); // TODO: dataFlowInfo
final CallResolver callResolver = new CallResolver(context.getSemanticServices(), DataFlowInfo.EMPTY); // TODO: dataFlowInfo
JetClass containingClass = PsiTreeUtil.getParentOfType(declaration, JetClass.class);
assert containingClass != null : "This must be guaranteed by the parser";
@@ -20,6 +20,7 @@ import java.util.List;
import static org.jetbrains.jet.lang.diagnostics.Errors.UNRESOLVED_REFERENCE;
import static org.jetbrains.jet.lang.diagnostics.Errors.WRONG_NUMBER_OF_TYPE_ARGUMENTS;
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
/**
* @author abreslav
@@ -240,6 +241,9 @@ public class TypeResolver {
if (classifierDescriptor == null) {
trace.report(UNRESOLVED_REFERENCE.on(userType.getReferenceExpression()));
}
else {
trace.record(REFERENCE_TARGET, userType.getReferenceExpression(), classifierDescriptor);
}
return classifierDescriptor;
}
@@ -1,135 +0,0 @@
package org.jetbrains.jet.lang.resolve.calls;
import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetPsiUtil;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.psi.JetThisExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.scopes.receivers.*;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeChecker;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.jet.lang.diagnostics.Errors.AUTOCAST_IMPOSSIBLE;
import static org.jetbrains.jet.lang.resolve.BindingContext.AUTOCAST;
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
/**
* @author abreslav
*/
public class AutoCastUtils {
private AutoCastUtils() {}
public static List<ReceiverDescriptor> getAutoCastVariants(@NotNull final BindingContext bindingContext, @NotNull final DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiverToCast) {
return receiverToCast.accept(new ReceiverDescriptorVisitor<List<ReceiverDescriptor>, Object>() {
@Override
public List<ReceiverDescriptor> visitNoReceiver(ReceiverDescriptor noReceiver, Object data) {
return Collections.emptyList();
}
@Override
public List<ReceiverDescriptor> visitTransientReceiver(TransientReceiver receiver, Object data) {
return Collections.emptyList();
}
@Override
public List<ReceiverDescriptor> visitExtensionReceiver(ExtensionReceiver receiver, Object data) {
return castThis(dataFlowInfo, receiver);
}
@Override
public List<ReceiverDescriptor> visitClassReceiver(ClassReceiver receiver, Object data) {
return castThis(dataFlowInfo, receiver);
}
@Override
public List<ReceiverDescriptor> visitExpressionReceiver(ExpressionReceiver receiver, Object data) {
JetExpression expression = receiver.getExpression();
VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(bindingContext, expression);
if (variableDescriptor != null) {
List<ReceiverDescriptor> result = Lists.newArrayList();
for (JetType possibleType : dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)) {
result.add(new AutoCastReceiver(receiver, possibleType, isAutoCastable(variableDescriptor)));
}
return result;
}
else if (expression instanceof JetThisExpression) {
return castThis(dataFlowInfo, receiver);
}
return Collections.emptyList();
}
}, null);
}
private static List<ReceiverDescriptor> castThis(@NotNull DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiver) {
assert receiver.exists();
List<ReceiverDescriptor> result = Lists.newArrayList();
for (JetType possibleType : dataFlowInfo.getPossibleTypesForReceiver(receiver)) {
result.add(new AutoCastReceiver(receiver, possibleType, true));
}
return result;
}
@Nullable
public static JetType castExpression(@NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
JetTypeChecker typeChecker = JetTypeChecker.INSTANCE;
VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(trace.getBindingContext(), expression);
if (variableDescriptor != null) {
List<JetType> possibleTypes = Lists.newArrayList(dataFlowInfo.getPossibleTypesForVariable(variableDescriptor));
Collections.reverse(possibleTypes);
for (JetType possibleType : possibleTypes) {
if (typeChecker.isSubtypeOf(possibleType, expectedType)) {
if (isAutoCastable(variableDescriptor)) {
trace.record(AUTOCAST, expression, possibleType);
}
else {
trace.report(AUTOCAST_IMPOSSIBLE.on(expression, possibleType, expression.getText()));
}
return possibleType;
}
}
}
return null;
}
@Nullable
public static VariableDescriptor getVariableDescriptorFromSimpleName(@NotNull BindingContext bindingContext, @NotNull JetExpression expression) {
JetExpression receiver = JetPsiUtil.deparenthesize(expression);
VariableDescriptor variableDescriptor = null;
if (receiver instanceof JetSimpleNameExpression) {
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) receiver;
DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, nameExpression);
if (declarationDescriptor instanceof VariableDescriptor) {
variableDescriptor = (VariableDescriptor) declarationDescriptor;
}
}
return variableDescriptor;
}
public static boolean isAutoCastable(@NotNull VariableDescriptor variableDescriptor) {
if (variableDescriptor.isVar()) return false;
if (variableDescriptor instanceof PropertyDescriptor) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor;
DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
if (containingDeclaration instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
if (classDescriptor.getModality().isOverridable() && propertyDescriptor.getModality().isOverridable()) return false;
}
else {
assert !propertyDescriptor.getModality().isOverridable() : "Property outside a class must not be overridable";
}
PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
if (getter == null || !getter.isDefault()) return false;
}
return true;
}
}
@@ -11,6 +11,8 @@ import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
@@ -25,8 +27,8 @@ import java.util.*;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
import static org.jetbrains.jet.lang.resolve.calls.ResolutionStatus.*;
import static org.jetbrains.jet.lang.resolve.calls.ResolvedCall.MAP_TO_CANDIDATE;
import static org.jetbrains.jet.lang.resolve.calls.ResolvedCall.MAP_TO_RESULT;
import static org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl.MAP_TO_CANDIDATE;
import static org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl.MAP_TO_RESULT;
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER;
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
@@ -149,7 +151,7 @@ public class CallResolver {
trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn));
return checkArgumentTypesAndFail(trace, scope, call);
}
prioritizedTasks.add(new ResolutionTask<FunctionDescriptor>(TaskPrioritizer.convertWithImpliedThis(scope, Collections.<ReceiverDescriptor>singletonList(NO_RECEIVER), constructors), call, DataFlowInfo.getEmpty()));
prioritizedTasks.add(new ResolutionTask<FunctionDescriptor>(TaskPrioritizer.convertWithImpliedThis(scope, Collections.<ReceiverDescriptor>singletonList(NO_RECEIVER), constructors), call, DataFlowInfo.EMPTY));
}
else {
// trace.getErrorHandler().genericError(calleeExpression.getNode(), "Not a class");
@@ -169,7 +171,7 @@ public class CallResolver {
trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn));
return checkArgumentTypesAndFail(trace, scope, call);
}
prioritizedTasks = Collections.singletonList(new ResolutionTask<FunctionDescriptor>(ResolvedCall.convertCollection(constructors), call, DataFlowInfo.getEmpty()));
prioritizedTasks = Collections.singletonList(new ResolutionTask<FunctionDescriptor>(ResolvedCallImpl.convertCollection(constructors), call, DataFlowInfo.EMPTY));
}
else {
throw new UnsupportedOperationException("Type argument inference not implemented for " + call);
@@ -192,12 +194,12 @@ public class CallResolver {
@NotNull JetType expectedType,
@NotNull final List<ResolutionTask<D>> prioritizedTasks, // high to low priority
@NotNull final JetReferenceExpression reference) {
ResolvedCall<D> resolvedCall = doResolveCall(trace, scope, call, expectedType, prioritizedTasks, reference);
ResolvedCallImpl<D> resolvedCall = doResolveCall(trace, scope, call, expectedType, prioritizedTasks, reference);
return resolvedCall == null ? null : resolvedCall.getResultingDescriptor();
}
@Nullable
private <D extends CallableDescriptor> ResolvedCall<D> doResolveCall(
private <D extends CallableDescriptor> ResolvedCallImpl<D> doResolveCall(
@NotNull BindingTrace trace,
@NotNull JetScope scope,
@NotNull final Call call,
@@ -208,7 +210,7 @@ public class CallResolver {
OverloadResolutionResults<D> resultsForFirstNonemptyCandidateSet = null;
TracingStrategy tracing = new TracingStrategy() {
@Override
public <D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall) {
public <D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCallImpl<D> resolvedCall) {
D descriptor = resolvedCall.getCandidateDescriptor();
// if (descriptor instanceof VariableAsFunctionDescriptor) {
// VariableAsFunctionDescriptor variableAsFunctionDescriptor = (VariableAsFunctionDescriptor) descriptor;
@@ -221,7 +223,7 @@ public class CallResolver {
}
@Override
public <D extends CallableDescriptor> void recordAmbiguity(BindingTrace trace, Collection<ResolvedCall<D>> candidates) {
public <D extends CallableDescriptor> void recordAmbiguity(BindingTrace trace, Collection<ResolvedCallImpl<D>> candidates) {
trace.record(AMBIGUOUS_REFERENCE_TARGET, reference, candidates);
}
@@ -270,12 +272,12 @@ public class CallResolver {
}
@Override
public <D extends CallableDescriptor> void ambiguity(@NotNull BindingTrace trace, @NotNull Set<ResolvedCall<D>> descriptors) {
public <D extends CallableDescriptor> void ambiguity(@NotNull BindingTrace trace, @NotNull Set<ResolvedCallImpl<D>> descriptors) {
trace.report(OVERLOAD_RESOLUTION_AMBIGUITY.on(call.getCallNode(), descriptors));
}
@Override
public <D extends CallableDescriptor> void noneApplicable(@NotNull BindingTrace trace, @NotNull Set<ResolvedCall<D>> descriptors) {
public <D extends CallableDescriptor> void noneApplicable(@NotNull BindingTrace trace, @NotNull Set<ResolvedCallImpl<D>> descriptors) {
trace.report(NONE_APPLICABLE.on(reference, descriptors));
}
@@ -301,7 +303,10 @@ public class CallResolver {
JetBinaryExpression binaryExpression = (JetBinaryExpression) callElement;
JetSimpleNameExpression operationReference = binaryExpression.getOperationReference();
String operationString = operationReference.getReferencedNameElementType() == JetTokens.IDENTIFIER ? operationReference.getText() : OperatorConventions.getNameForOperationSymbol(operationReference.getReferencedNameElementType());
trace.report(UNSAFE_INFIX_CALL.on(reference, binaryExpression.getLeft().getText(), operationString, binaryExpression.getRight().getText()));
JetExpression right = binaryExpression.getRight();
if (right != null) {
trace.report(UNSAFE_INFIX_CALL.on(reference, binaryExpression.getLeft().getText(), operationString, right.getText()));
}
}
else {
trace.report(UNSAFE_CALL.on(reference, type));
@@ -347,7 +352,7 @@ public class CallResolver {
@NotNull
private <D extends CallableDescriptor> OverloadResolutionResults<D> performResolution(@NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull JetType expectedType, @NotNull ResolutionTask<D> task, @NotNull TracingStrategy tracing) {
for (ResolvedCall<D> candidateCall : task.getCandidates()) {
for (ResolvedCallImpl<D> candidateCall : task.getCandidates()) {
D candidate = candidateCall.getCandidateDescriptor();
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(trace);
candidateCall.setTrace(temporaryTrace);
@@ -415,6 +420,9 @@ public class CallResolver {
assert substitute != null;
replaceValueParametersWithSubstitutedOnes(candidateCall, substitute);
candidateCall.setResultingDescriptor(substitute);
for (TypeParameterDescriptor typeParameterDescriptor : candidateCall.getCandidateDescriptor().getTypeParameters()) {
candidateCall.recordTypeArgument(typeParameterDescriptor, solution.getValue(typeParameterDescriptor));
}
candidateCall.setStatus(SUCCESS);
}
else {
@@ -454,6 +462,12 @@ public class CallResolver {
candidateCall.setResultingDescriptor(substitutedDescriptor);
replaceValueParametersWithSubstitutedOnes(candidateCall, substitutedDescriptor);
List<TypeParameterDescriptor> typeParameters = candidateCall.getCandidateDescriptor().getTypeParameters();
for (int i = 0; i < typeParameters.size(); i++) {
TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i);
candidateCall.recordTypeArgument(typeParameterDescriptor, typeArguments.get(i));
}
candidateCall.setStatus(checkAllValueArguments(scope, tracing, task, candidateCall));
}
else {
@@ -469,9 +483,9 @@ public class CallResolver {
recordAutoCastIfNecessary(candidateCall.getThisObject(), candidateCall.getTrace());
}
Set<ResolvedCall<D>> successfulCandidates = Sets.newLinkedHashSet();
Set<ResolvedCall<D>> failedCandidates = Sets.newLinkedHashSet();
for (ResolvedCall<D> candidateCall : task.getCandidates()) {
Set<ResolvedCallImpl<D>> successfulCandidates = Sets.newLinkedHashSet();
Set<ResolvedCallImpl<D>> failedCandidates = Sets.newLinkedHashSet();
for (ResolvedCallImpl<D> candidateCall : task.getCandidates()) {
ResolutionStatus status = candidateCall.getStatus();
if (status.isSuccess()) {
successfulCandidates.add(candidateCall);
@@ -541,7 +555,7 @@ public class CallResolver {
// };
// }
private <D extends CallableDescriptor> void replaceValueParametersWithSubstitutedOnes(ResolvedCall<D> candidateCall, @NotNull D substitutedDescriptor) {
private <D extends CallableDescriptor> void replaceValueParametersWithSubstitutedOnes(ResolvedCallImpl<D> candidateCall, @NotNull D substitutedDescriptor) {
Map<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap = Maps.newHashMap();
for (ValueParameterDescriptor valueParameterDescriptor : substitutedDescriptor.getValueParameters()) {
parameterMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor);
@@ -557,14 +571,14 @@ public class CallResolver {
}
}
private <D extends CallableDescriptor> ResolutionStatus checkAllValueArguments(JetScope scope, TracingStrategy tracing, ResolutionTask<D> task, ResolvedCall<D> candidateCall) {
private <D extends CallableDescriptor> ResolutionStatus checkAllValueArguments(JetScope scope, TracingStrategy tracing, ResolutionTask<D> task, ResolvedCallImpl<D> candidateCall) {
ResolutionStatus result = checkValueArgumentTypes(scope, candidateCall);
result = result.combine(checkReceiver(tracing, candidateCall, candidateCall.getResultingDescriptor().getReceiverParameter(), candidateCall.getReceiverArgument(), task));
result = result.combine(checkReceiver(tracing, candidateCall, candidateCall.getResultingDescriptor().getExpectedThisObject(), candidateCall.getThisObject(), task));
return result;
}
private <D extends CallableDescriptor> ResolutionStatus checkReceiver(TracingStrategy tracing, ResolvedCall<D> candidateCall, ReceiverDescriptor receiverParameter, ReceiverDescriptor receiverArgument, ResolutionTask<D> task) {
private <D extends CallableDescriptor> ResolutionStatus checkReceiver(TracingStrategy tracing, ResolvedCallImpl<D> candidateCall, ReceiverDescriptor receiverParameter, ReceiverDescriptor receiverArgument, ResolutionTask<D> task) {
ResolutionStatus result = SUCCESS;
if (receiverParameter.exists() && receiverArgument.exists()) {
ASTNode callOperationNode = task.getCall().getCallOperationNode();
@@ -592,7 +606,7 @@ public class CallResolver {
return result;
}
private <D extends CallableDescriptor> ResolutionStatus checkValueArgumentTypes(JetScope scope, ResolvedCall<D> candidateCall) {
private <D extends CallableDescriptor> ResolutionStatus checkValueArgumentTypes(JetScope scope, ResolvedCallImpl<D> candidateCall) {
ResolutionStatus result = SUCCESS;
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
ValueParameterDescriptor parameterDescriptor = entry.getKey();
@@ -618,7 +632,7 @@ public class CallResolver {
// }
// }
// if (autoCastType != null) {
// if (AutoCastUtils.isAutoCastable(variableDescriptor)) {
// if (AutoCastUtils.isStableVariable(variableDescriptor)) {
// temporaryTrace.record(AUTOCAST, argumentExpression, autoCastType);
// }
// else {
@@ -639,16 +653,16 @@ public class CallResolver {
private <D extends CallableDescriptor> OverloadResolutionResults<D> computeResultAndReportErrors(
BindingTrace trace,
TracingStrategy tracing,
Set<ResolvedCall<D>> successfulCandidates,
Set<ResolvedCall<D>> failedCandidates) {
Set<ResolvedCallImpl<D>> successfulCandidates,
Set<ResolvedCallImpl<D>> failedCandidates) {
// TODO : maybe it's better to filter overrides out first, and only then look for the maximally specific
if (successfulCandidates.size() > 0) {
return chooseAndReportMaximallySpecific(trace, tracing, successfulCandidates);
}
else if (!failedCandidates.isEmpty()) {
if (failedCandidates.size() != 1) {
Set<ResolvedCall<D>> weakErrors = Sets.newLinkedHashSet();
for (ResolvedCall<D> candidate : failedCandidates) {
Set<ResolvedCallImpl<D>> weakErrors = Sets.newLinkedHashSet();
for (ResolvedCallImpl<D> candidate : failedCandidates) {
if (candidate.getStatus().isWeakError()) {
weakErrors.add(candidate);
}
@@ -662,7 +676,7 @@ public class CallResolver {
return OverloadResolutionResults.manyFailedCandidates(results.getResults());
}
Set<ResolvedCall<D>> noOverrides = OverridingUtil.filterOverrides(failedCandidates, MAP_TO_CANDIDATE);
Set<ResolvedCallImpl<D>> noOverrides = OverridingUtil.filterOverrides(failedCandidates, MAP_TO_CANDIDATE);
if (noOverrides.size() != 1) {
// tracing.reportOverallResolutionError(trace, "None of the following functions can be called with the arguments supplied: "
// + makeErrorMessageForMultipleDescriptors(noOverrides));
@@ -672,7 +686,7 @@ public class CallResolver {
}
failedCandidates = noOverrides;
}
ResolvedCall<D> failed = failedCandidates.iterator().next();
ResolvedCallImpl<D> failed = failedCandidates.iterator().next();
failed.getTrace().commit();
return OverloadResolutionResults.singleFailedCandidate(failed);
}
@@ -682,12 +696,12 @@ public class CallResolver {
}
}
private <D extends CallableDescriptor> OverloadResolutionResults<D> chooseAndReportMaximallySpecific(BindingTrace trace, TracingStrategy tracing, Set<ResolvedCall<D>> candidates) {
private <D extends CallableDescriptor> OverloadResolutionResults<D> chooseAndReportMaximallySpecific(BindingTrace trace, TracingStrategy tracing, Set<ResolvedCallImpl<D>> candidates) {
if (candidates.size() != 1) {
Set<ResolvedCall<D>> cleanCandidates = Sets.newLinkedHashSet(candidates);
Set<ResolvedCallImpl<D>> cleanCandidates = Sets.newLinkedHashSet(candidates);
boolean allClean = true;
for (Iterator<ResolvedCall<D>> iterator = cleanCandidates.iterator(); iterator.hasNext(); ) {
ResolvedCall<D> candidate = iterator.next();
for (Iterator<ResolvedCallImpl<D>> iterator = cleanCandidates.iterator(); iterator.hasNext(); ) {
ResolvedCallImpl<D> candidate = iterator.next();
if (candidate.isDirty()) {
iterator.remove();
allClean = false;
@@ -697,17 +711,17 @@ public class CallResolver {
if (cleanCandidates.isEmpty()) {
cleanCandidates = candidates;
}
ResolvedCall<D> maximallySpecific = overloadingConflictResolver.findMaximallySpecific(cleanCandidates, false);
ResolvedCallImpl<D> maximallySpecific = overloadingConflictResolver.findMaximallySpecific(cleanCandidates, false);
if (maximallySpecific != null) {
return OverloadResolutionResults.success(maximallySpecific);
}
ResolvedCall<D> maximallySpecificGenericsDiscriminated = overloadingConflictResolver.findMaximallySpecific(cleanCandidates, true);
ResolvedCallImpl<D> maximallySpecificGenericsDiscriminated = overloadingConflictResolver.findMaximallySpecific(cleanCandidates, true);
if (maximallySpecificGenericsDiscriminated != null) {
return OverloadResolutionResults.success(maximallySpecificGenericsDiscriminated);
}
Set<ResolvedCall<D>> noOverrides = OverridingUtil.filterOverrides(candidates, MAP_TO_RESULT);
Set<ResolvedCallImpl<D>> noOverrides = OverridingUtil.filterOverrides(candidates, MAP_TO_RESULT);
if (allClean) {
// tracing.reportOverallResolutionError(trace, "Overload resolution ambiguity: "
// + makeErrorMessageForMultipleDescriptors(noOverrides));
@@ -719,7 +733,7 @@ public class CallResolver {
return OverloadResolutionResults.ambiguity(noOverrides);
}
else {
ResolvedCall<D> result = candidates.iterator().next();
ResolvedCallImpl<D> result = candidates.iterator().next();
TemporaryBindingTrace temporaryTrace = result.getTrace();
temporaryTrace.commit();
@@ -748,24 +762,24 @@ public class CallResolver {
@NotNull
public OverloadResolutionResults<FunctionDescriptor> resolveExactSignature(@NotNull JetScope scope, @NotNull ReceiverDescriptor receiver, @NotNull String name, @NotNull List<JetType> parameterTypes) {
List<ResolvedCall<FunctionDescriptor>> result = findCandidatesByExactSignature(scope, receiver, name, parameterTypes);
List<ResolvedCallImpl<FunctionDescriptor>> result = findCandidatesByExactSignature(scope, receiver, name, parameterTypes);
BindingTraceContext trace = new BindingTraceContext();
TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create(trace);
Set<ResolvedCall<FunctionDescriptor>> candidates = Sets.newLinkedHashSet();
for (ResolvedCall<FunctionDescriptor> call : result) {
Set<ResolvedCallImpl<FunctionDescriptor>> candidates = Sets.newLinkedHashSet();
for (ResolvedCallImpl<FunctionDescriptor> call : result) {
call.setTrace(temporaryBindingTrace);
candidates.add(call);
}
return computeResultAndReportErrors(trace, TracingStrategy.EMPTY, candidates, Collections.<ResolvedCall<FunctionDescriptor>>emptySet());
return computeResultAndReportErrors(trace, TracingStrategy.EMPTY, candidates, Collections.<ResolvedCallImpl<FunctionDescriptor>>emptySet());
}
private List<ResolvedCall<FunctionDescriptor>> findCandidatesByExactSignature(JetScope scope, ReceiverDescriptor receiver, String name, List<JetType> parameterTypes) {
List<ResolvedCall<FunctionDescriptor>> result = Lists.newArrayList();
private List<ResolvedCallImpl<FunctionDescriptor>> findCandidatesByExactSignature(JetScope scope, ReceiverDescriptor receiver, String name, List<JetType> parameterTypes) {
List<ResolvedCallImpl<FunctionDescriptor>> result = Lists.newArrayList();
if (receiver.exists()) {
Collection<ResolvedCall<FunctionDescriptor>> extensionFunctionDescriptors = ResolvedCall.convertCollection(scope.getFunctions(name));
List<ResolvedCall<FunctionDescriptor>> nonlocal = Lists.newArrayList();
List<ResolvedCall<FunctionDescriptor>> local = Lists.newArrayList();
Collection<ResolvedCallImpl<FunctionDescriptor>> extensionFunctionDescriptors = ResolvedCallImpl.convertCollection(scope.getFunctions(name));
List<ResolvedCallImpl<FunctionDescriptor>> nonlocal = Lists.newArrayList();
List<ResolvedCallImpl<FunctionDescriptor>> local = Lists.newArrayList();
TaskPrioritizer.splitLexicallyLocalDescriptors(extensionFunctionDescriptors, scope.getContainingDeclaration(), local, nonlocal);
@@ -773,7 +787,7 @@ public class CallResolver {
return result;
}
Collection<ResolvedCall<FunctionDescriptor>> functionDescriptors = ResolvedCall.convertCollection(receiver.getType().getMemberScope().getFunctions(name));
Collection<ResolvedCallImpl<FunctionDescriptor>> functionDescriptors = ResolvedCallImpl.convertCollection(receiver.getType().getMemberScope().getFunctions(name));
if (lookupExactSignature(functionDescriptors, parameterTypes, result)) {
return result;
@@ -782,14 +796,14 @@ public class CallResolver {
return result;
}
else {
lookupExactSignature(ResolvedCall.convertCollection(scope.getFunctions(name)), parameterTypes, result);
lookupExactSignature(ResolvedCallImpl.convertCollection(scope.getFunctions(name)), parameterTypes, result);
return result;
}
}
private boolean lookupExactSignature(Collection<ResolvedCall<FunctionDescriptor>> candidates, List<JetType> parameterTypes, List<ResolvedCall<FunctionDescriptor>> result) {
private boolean lookupExactSignature(Collection<ResolvedCallImpl<FunctionDescriptor>> candidates, List<JetType> parameterTypes, List<ResolvedCallImpl<FunctionDescriptor>> result) {
boolean found = false;
for (ResolvedCall<FunctionDescriptor> resolvedCall : candidates) {
for (ResolvedCallImpl<FunctionDescriptor> resolvedCall : candidates) {
FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor();
if (functionDescriptor.getReceiverParameter().exists()) continue;
if (!functionDescriptor.getTypeParameters().isEmpty()) continue;
@@ -800,9 +814,9 @@ public class CallResolver {
return found;
}
private boolean findExtensionFunctions(Collection<ResolvedCall<FunctionDescriptor>> candidates, ReceiverDescriptor receiver, List<JetType> parameterTypes, List<ResolvedCall<FunctionDescriptor>> result) {
private boolean findExtensionFunctions(Collection<ResolvedCallImpl<FunctionDescriptor>> candidates, ReceiverDescriptor receiver, List<JetType> parameterTypes, List<ResolvedCallImpl<FunctionDescriptor>> result) {
boolean found = false;
for (ResolvedCall<FunctionDescriptor> resolvedCall : candidates) {
for (ResolvedCallImpl<FunctionDescriptor> resolvedCall : candidates) {
FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor();
ReceiverDescriptor functionReceiver = functionDescriptor.getReceiverParameter();
if (!functionReceiver.exists()) continue;
@@ -1,224 +0,0 @@
package org.jetbrains.jet.lang.resolve.calls;
import com.google.common.collect.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.util.CommonSuppliers;
import java.util.*;
/**
* @author abreslav
*/
public class DataFlowInfo {
public static abstract class CompositionOperator {
public abstract DataFlowInfo compose(DataFlowInfo a, DataFlowInfo b);
}
public static final CompositionOperator AND = new CompositionOperator() {
@Override
public DataFlowInfo compose(DataFlowInfo a, DataFlowInfo b) {
return a.and(b);
}
};
public static final CompositionOperator OR = new CompositionOperator() {
@Override
public DataFlowInfo compose(DataFlowInfo a, DataFlowInfo b) {
return a.or(b);
}
};
private static DataFlowInfo EMPTY = new DataFlowInfo(ImmutableMap.<Object, NullabilityFlags>of(), Multimaps.newListMultimap(Collections.<Object, Collection<JetType>>emptyMap(), CommonSuppliers.<JetType>getArrayListSupplier()));
public static DataFlowInfo getEmpty() {
return EMPTY;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private final ImmutableMap<Object, NullabilityFlags> nullabilityInfo;
private final ListMultimap<Object, JetType> typeInfo;
private DataFlowInfo(ImmutableMap<Object, NullabilityFlags> nullabilityInfo, ListMultimap<Object, JetType> typeInfo) {
this.nullabilityInfo = nullabilityInfo;
this.typeInfo = typeInfo;
}
@Nullable
public JetType getOutType(@NotNull VariableDescriptor variableDescriptor) {
JetType outType = variableDescriptor.getOutType();
if (outType == null) return null;
if (!outType.isNullable()) return outType;
NullabilityFlags nullabilityFlags = nullabilityInfo.get(variableDescriptor);
if (nullabilityFlags != null && !nullabilityFlags.canBeNull()) {
return TypeUtils.makeNotNullable(outType);
}
return outType;
}
@NotNull
private List<JetType> getPossibleTypes(Object key, @NotNull JetType originalType) {
List<JetType> types = typeInfo.get(key);
NullabilityFlags nullabilityFlags = nullabilityInfo.get(key);
if (nullabilityFlags == null || nullabilityFlags.canBeNull()) {
return types;
}
List<JetType> enrichedTypes = Lists.newArrayListWithCapacity(types.size());
if (originalType.isNullable()) {
enrichedTypes.add(TypeUtils.makeNotNullable(originalType));
}
for (JetType type: types) {
if (type.isNullable()) {
enrichedTypes.add(TypeUtils.makeNotNullable(type));
}
else {
enrichedTypes.add(type);
}
}
return enrichedTypes;
}
@NotNull
public List<JetType> getPossibleTypesForVariable(@NotNull VariableDescriptor variableDescriptor) {
return getPossibleTypes(variableDescriptor, variableDescriptor.getOutType());
}
public List<JetType> getPossibleTypesForReceiver(@NotNull ReceiverDescriptor receiver) {
return getPossibleTypes(receiver, receiver.getType());
}
public DataFlowInfo equalsToNull(@NotNull VariableDescriptor variableDescriptor, boolean notNull) {
return new DataFlowInfo(getEqualsToNullMap(variableDescriptor, notNull), typeInfo);
}
private ImmutableMap<Object, NullabilityFlags> getEqualsToNullMap(VariableDescriptor variableDescriptor, boolean notNull) {
Map<Object, NullabilityFlags> builder = Maps.newHashMap(nullabilityInfo);
NullabilityFlags nullabilityFlags = nullabilityInfo.get(variableDescriptor);
boolean varNotNull = notNull || (nullabilityFlags != null && !nullabilityFlags.canBeNull);
builder.put(variableDescriptor, new NullabilityFlags(!varNotNull, varNotNull));
return ImmutableMap.copyOf(builder);
}
private ImmutableMap<Object, NullabilityFlags> getEqualsToNullMap(VariableDescriptor[] variableDescriptors, boolean notNull) {
if (variableDescriptors.length == 0) return nullabilityInfo;
Map<Object, NullabilityFlags> builder = Maps.newHashMap(nullabilityInfo);
for (VariableDescriptor variableDescriptor : variableDescriptors) {
if (variableDescriptor != null) {
NullabilityFlags nullabilityFlags = nullabilityInfo.get(variableDescriptor);
boolean varNotNull = notNull || (nullabilityFlags != null && !nullabilityFlags.canBeNull);
builder.put(variableDescriptor, new NullabilityFlags(!varNotNull, varNotNull));
}
}
return ImmutableMap.copyOf(builder);
}
public DataFlowInfo isInstanceOf(@NotNull VariableDescriptor variableDescriptor, @NotNull JetType type) {
ListMultimap<Object, JetType> newTypeInfo = copyTypeInfo();
newTypeInfo.put(variableDescriptor, type);
return new DataFlowInfo(getEqualsToNullMap(variableDescriptor, !type.isNullable()), newTypeInfo);
}
public DataFlowInfo isInstanceOf(@NotNull VariableDescriptor[] variableDescriptors, @NotNull JetType type) {
if (variableDescriptors.length == 0) return this;
ListMultimap<Object, JetType> newTypeInfo = copyTypeInfo();
for (VariableDescriptor variableDescriptor : variableDescriptors) {
if (variableDescriptor != null) {
newTypeInfo.put(variableDescriptor, type);
}
}
return new DataFlowInfo(getEqualsToNullMap(variableDescriptors, !type.isNullable()), newTypeInfo);
}
public DataFlowInfo and(DataFlowInfo other) {
Map<Object, NullabilityFlags> nullabilityMapBuilder = Maps.newHashMap();
nullabilityMapBuilder.putAll(nullabilityInfo);
for (Map.Entry<Object, NullabilityFlags> entry : other.nullabilityInfo.entrySet()) {
Object key = entry.getKey();
NullabilityFlags otherFlags = entry.getValue();
NullabilityFlags thisFlags = nullabilityInfo.get(key);
if (thisFlags != null) {
nullabilityMapBuilder.put(key, thisFlags.and(otherFlags));
}
else {
nullabilityMapBuilder.put(key, otherFlags);
}
}
ListMultimap<Object, JetType> newTypeInfo = copyTypeInfo();
newTypeInfo.putAll(other.typeInfo);
return new DataFlowInfo(ImmutableMap.copyOf(nullabilityMapBuilder), newTypeInfo);
}
private ListMultimap<Object, JetType> copyTypeInfo() {
ListMultimap<Object, JetType> newTypeInfo = Multimaps.newListMultimap(Maps.<Object, Collection<JetType>>newHashMap(), CommonSuppliers.<JetType>getArrayListSupplier());
newTypeInfo.putAll(typeInfo);
return newTypeInfo;
}
public DataFlowInfo or(DataFlowInfo other) {
Map<Object, NullabilityFlags> builder = Maps.newHashMap(nullabilityInfo);
builder.keySet().retainAll(other.nullabilityInfo.keySet());
for (Map.Entry<Object, NullabilityFlags> entry : builder.entrySet()) {
Object key = entry.getKey();
NullabilityFlags thisFlags = entry.getValue();
NullabilityFlags otherFlags = other.nullabilityInfo.get(key);
assert (otherFlags != null);
builder.put(key, thisFlags.or(otherFlags));
}
ListMultimap<Object, JetType> newTypeInfo = Multimaps.newListMultimap(Maps.<Object, Collection<JetType>>newHashMap(), CommonSuppliers.<JetType>getArrayListSupplier());
Set<Object> keys = newTypeInfo.keySet();
keys.retainAll(other.typeInfo.keySet());
for (Object key : keys) {
Collection<JetType> thisTypes = typeInfo.get(key);
Collection<JetType> otherTypes = other.typeInfo.get(key);
Collection<JetType> newTypes = Sets.newHashSet(thisTypes);
newTypes.retainAll(otherTypes);
newTypeInfo.putAll(key, newTypes);
}
return new DataFlowInfo(ImmutableMap.copyOf(builder), newTypeInfo);
}
public DataFlowInfo nullabilityOnly() {
return new DataFlowInfo(nullabilityInfo, EMPTY.copyTypeInfo());
}
private static class NullabilityFlags {
private final boolean canBeNull;
private final boolean canBeNonNull;
private NullabilityFlags(boolean canBeNull, boolean canBeNonNull) {
this.canBeNull = canBeNull;
this.canBeNonNull = canBeNonNull;
}
public boolean canBeNull() {
return canBeNull;
}
public boolean canBeNonNull() {
return canBeNonNull;
}
public NullabilityFlags and(NullabilityFlags other) {
return new NullabilityFlags(this.canBeNull && other.canBeNull, this.canBeNonNull && other.canBeNonNull);
}
public NullabilityFlags or(NullabilityFlags other) {
return new NullabilityFlags(this.canBeNull || other.canBeNull, this.canBeNonNull || other.canBeNonNull);
}
}
}
@@ -29,40 +29,40 @@ public class OverloadResolutionResults<D extends CallableDescriptor> {
}
public static <D extends CallableDescriptor> OverloadResolutionResults<D> success(@NotNull ResolvedCall<D> descriptor) {
public static <D extends CallableDescriptor> OverloadResolutionResults<D> success(@NotNull ResolvedCallImpl<D> descriptor) {
return new OverloadResolutionResults<D>(Code.SUCCESS, Collections.singleton(descriptor));
}
public static <D extends CallableDescriptor> OverloadResolutionResults<D> nameNotFound() {
return new OverloadResolutionResults<D>(Code.NAME_NOT_FOUND, Collections.<ResolvedCall<D>>emptyList());
return new OverloadResolutionResults<D>(Code.NAME_NOT_FOUND, Collections.<ResolvedCallImpl<D>>emptyList());
}
public static <D extends CallableDescriptor> OverloadResolutionResults<D> singleFailedCandidate(ResolvedCall<D> candidate) {
public static <D extends CallableDescriptor> OverloadResolutionResults<D> singleFailedCandidate(ResolvedCallImpl<D> candidate) {
return new OverloadResolutionResults<D>(Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH, Collections.singleton(candidate));
}
public static <D extends CallableDescriptor> OverloadResolutionResults<D> manyFailedCandidates(Collection<ResolvedCall<D>> failedCandidates) {
public static <D extends CallableDescriptor> OverloadResolutionResults<D> manyFailedCandidates(Collection<ResolvedCallImpl<D>> failedCandidates) {
return new OverloadResolutionResults<D>(Code.MANY_FAILED_CANDIDATES, failedCandidates);
}
public static <D extends CallableDescriptor> OverloadResolutionResults<D> ambiguity(Collection<ResolvedCall<D>> descriptors) {
public static <D extends CallableDescriptor> OverloadResolutionResults<D> ambiguity(Collection<ResolvedCallImpl<D>> descriptors) {
return new OverloadResolutionResults<D>(Code.AMBIGUITY, descriptors);
}
private final Collection<ResolvedCall<D>> results;
private final Collection<ResolvedCallImpl<D>> results;
private final Code resultCode;
private OverloadResolutionResults(@NotNull Code resultCode, @NotNull Collection<ResolvedCall<D>> results) {
private OverloadResolutionResults(@NotNull Code resultCode, @NotNull Collection<ResolvedCallImpl<D>> results) {
this.results = results;
this.resultCode = resultCode;
}
@NotNull
public Collection<ResolvedCall<D>> getResults() {
public Collection<ResolvedCallImpl<D>> getResults() {
return results;
}
@NotNull
public ResolvedCall<D> getResult() {
public ResolvedCallImpl<D> getResult() {
assert singleDescriptor();
return results.iterator().next();
}
@@ -28,23 +28,23 @@ public class OverloadingConflictResolver {
}
@Nullable
public <D extends CallableDescriptor> ResolvedCall<D> findMaximallySpecific(Set<ResolvedCall<D>> candidates, boolean discriminateGenericDescriptors) {
// Different autocasts may lead to the same candidate descriptor wrapped into different ResolvedCall objects
Set<ResolvedCall<D>> maximallySpecific = new THashSet<ResolvedCall<D>>(new TObjectHashingStrategy<ResolvedCall<D>>() {
public <D extends CallableDescriptor> ResolvedCallImpl<D> findMaximallySpecific(Set<ResolvedCallImpl<D>> candidates, boolean discriminateGenericDescriptors) {
// Different autocasts may lead to the same candidate descriptor wrapped into different ResolvedCallImpl objects
Set<ResolvedCallImpl<D>> maximallySpecific = new THashSet<ResolvedCallImpl<D>>(new TObjectHashingStrategy<ResolvedCallImpl<D>>() {
@Override
public boolean equals(ResolvedCall<D> o1, ResolvedCall<D> o2) {
public boolean equals(ResolvedCallImpl<D> o1, ResolvedCallImpl<D> o2) {
return o1 == null ? o2 == null : o1.getResultingDescriptor().equals(o2.getResultingDescriptor());
}
@Override
public int computeHashCode(ResolvedCall<D> object) {
public int computeHashCode(ResolvedCallImpl<D> object) {
return object == null ? 0 : object.getResultingDescriptor().hashCode();
}
});
meLoop:
for (ResolvedCall<D> candidateCall : candidates) {
for (ResolvedCallImpl<D> candidateCall : candidates) {
D me = candidateCall.getResultingDescriptor();
for (ResolvedCall<D> otherCall : candidates) {
for (ResolvedCallImpl<D> otherCall : candidates) {
D other = otherCall.getResultingDescriptor();
if (other == me) continue;
if (!moreSpecific(me, other, discriminateGenericDescriptors) || moreSpecific(other, me, discriminateGenericDescriptors)) {
@@ -54,7 +54,7 @@ public class OverloadingConflictResolver {
maximallySpecific.add(candidateCall);
}
if (maximallySpecific.size() == 1) {
ResolvedCall<D> result = maximallySpecific.iterator().next();
ResolvedCallImpl<D> result = maximallySpecific.iterator().next();
result.getTrace().commit();
return result;
}
@@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.psi.Call;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import java.util.Collection;
@@ -12,13 +13,13 @@ import java.util.Collection;
*/
/*package*/ class ResolutionTask<D extends CallableDescriptor> {
private final Call call;
private final Collection<ResolvedCall<D>> candidates;
private final Collection<ResolvedCallImpl<D>> candidates;
private final DataFlowInfo dataFlowInfo;
private DescriptorCheckStrategy checkingStrategy;
public ResolutionTask(
@NotNull Collection<ResolvedCall<D>> candidates,
@NotNull Collection<ResolvedCallImpl<D>> candidates,
@NotNull Call call,
@NotNull DataFlowInfo dataFlowInfo
) {
@@ -33,7 +34,7 @@ import java.util.Collection;
}
@NotNull
public Collection<ResolvedCall<D>> getCandidates() {
public Collection<ResolvedCallImpl<D>> getCandidates() {
return candidates;
}
@@ -1,147 +1,39 @@
package org.jetbrains.jet.lang.resolve.calls;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static org.jetbrains.jet.lang.resolve.calls.ResolutionStatus.UNKNOWN_STATUS;
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER;
/**
* @author abreslav
*/
public class ResolvedCall<D extends CallableDescriptor> {
public static final Function<ResolvedCall<? extends CallableDescriptor>, CallableDescriptor> MAP_TO_CANDIDATE = new Function<ResolvedCall<? extends CallableDescriptor>, CallableDescriptor>() {
@Override
public CallableDescriptor fun(ResolvedCall<? extends CallableDescriptor> resolvedCall) {
return resolvedCall.getCandidateDescriptor();
}
};
public static final Function<ResolvedCall<? extends CallableDescriptor>, CallableDescriptor> MAP_TO_RESULT = new Function<ResolvedCall<? extends CallableDescriptor>, CallableDescriptor>() {
@Override
public CallableDescriptor fun(ResolvedCall<? extends CallableDescriptor> resolvedCall) {
return resolvedCall.getResultingDescriptor();
}
};
public interface ResolvedCall<D extends CallableDescriptor> {
/** A target callable descriptor as it was accessible in the corresponding scope, i.e. with type parameters not substituted */
@NotNull
public static <D extends CallableDescriptor> ResolvedCall<D> create(@NotNull D descriptor) {
return new ResolvedCall<D>(descriptor);
}
D getCandidateDescriptor();
/** Type parameters are substituted */
@NotNull
public static <D extends CallableDescriptor> List<ResolvedCall<D>> convertCollection(@NotNull Collection<D> descriptors) {
List<ResolvedCall<D>> result = Lists.newArrayList();
for (D descriptor : descriptors) {
result.add(create(descriptor));
}
return result;
}
private final D candidateDescriptor;
private D resultingDescriptor; // Probably substituted
private ReceiverDescriptor thisObject = NO_RECEIVER; // receiver object of a method
private ReceiverDescriptor receiverArgument = NO_RECEIVER; // receiver of an extension function
private final Map<TypeParameterDescriptor, JetType> typeArguments = Maps.newLinkedHashMap();
private final Map<ValueParameterDescriptor, JetType> autoCasts = Maps.newHashMap();
private final Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = Maps.newHashMap();
private boolean someArgumentHasNoType = false;
private TemporaryBindingTrace trace;
private ResolutionStatus status = UNKNOWN_STATUS;
private ResolvedCall(@NotNull D candidateDescriptor) {
this.candidateDescriptor = candidateDescriptor;
}
D getResultingDescriptor();
/** If the target was an extension function or property, this is the value for its receiver parameter */
@NotNull
public ResolutionStatus getStatus() {
return status;
}
public void setStatus(@NotNull ResolutionStatus status) {
this.status = status;
}
ReceiverDescriptor getReceiverArgument();
/** If the target was a member of a class, this is the object of that class to call it on */
@NotNull
public TemporaryBindingTrace getTrace() {
return trace;
}
public void setTrace(@NotNull TemporaryBindingTrace trace) {
this.trace = trace;
}
ReceiverDescriptor getThisObject();
/** Values (arguments) for value parameters */
@NotNull
public D getCandidateDescriptor() {
return candidateDescriptor;
}
Map<ValueParameterDescriptor, ResolvedValueArgument> getValueArguments();
/** What's substituted for type parameters */
@NotNull
public D getResultingDescriptor() {
return resultingDescriptor == null ? candidateDescriptor : resultingDescriptor;
}
public ResolvedCall<D> setResultingDescriptor(@NotNull D resultingDescriptor) {
this.resultingDescriptor = resultingDescriptor;
return this;
}
public void recordTypeArgument(@NotNull TypeParameterDescriptor typeParameter, @NotNull JetType typeArgument) {
assert !typeArguments.containsKey(typeParameter);
typeArguments.put(typeParameter, typeArgument);
}
public void recordValueArgument(@NotNull ValueParameterDescriptor valueParameter, @NotNull ResolvedValueArgument valueArgument) {
assert !valueArguments.containsKey(valueParameter);
valueArguments.put(valueParameter, valueArgument);
}
public void autoCastValueArgument(@NotNull ValueParameterDescriptor parameter, @NotNull JetType target) {
assert !autoCasts.containsKey(parameter);
autoCasts.put(parameter, target);
}
@NotNull
public ReceiverDescriptor getReceiverArgument() {
return receiverArgument;
}
public void setReceiverArgument(@NotNull ReceiverDescriptor receiverParameter) {
this.receiverArgument = receiverParameter;
}
@NotNull
public ReceiverDescriptor getThisObject() {
return thisObject;
}
public void setThisObject(@NotNull ReceiverDescriptor thisObject) {
this.thisObject = thisObject;
}
@NotNull
public Map<ValueParameterDescriptor, ResolvedValueArgument> getValueArguments() {
return valueArguments;
}
public void argumentHasNoType() {
this.someArgumentHasNoType = true;
}
public boolean isDirty() {
return someArgumentHasNoType;
}
Map<TypeParameterDescriptor, JetType> getTypeArguments();
}
@@ -0,0 +1,159 @@
package org.jetbrains.jet.lang.resolve.calls;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static org.jetbrains.jet.lang.resolve.calls.ResolutionStatus.UNKNOWN_STATUS;
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER;
/**
* @author abreslav
*/
public class ResolvedCallImpl<D extends CallableDescriptor> implements ResolvedCall<D> {
public static final Function<ResolvedCallImpl<? extends CallableDescriptor>, CallableDescriptor> MAP_TO_CANDIDATE = new Function<ResolvedCallImpl<? extends CallableDescriptor>, CallableDescriptor>() {
@Override
public CallableDescriptor fun(ResolvedCallImpl<? extends CallableDescriptor> resolvedCall) {
return resolvedCall.getCandidateDescriptor();
}
};
public static final Function<ResolvedCallImpl<? extends CallableDescriptor>, CallableDescriptor> MAP_TO_RESULT = new Function<ResolvedCallImpl<? extends CallableDescriptor>, CallableDescriptor>() {
@Override
public CallableDescriptor fun(ResolvedCallImpl<? extends CallableDescriptor> resolvedCall) {
return resolvedCall.getResultingDescriptor();
}
};
@NotNull
public static <D extends CallableDescriptor> ResolvedCallImpl<D> create(@NotNull D descriptor) {
return new ResolvedCallImpl<D>(descriptor);
}
@NotNull
public static <D extends CallableDescriptor> List<ResolvedCallImpl<D>> convertCollection(@NotNull Collection<D> descriptors) {
List<ResolvedCallImpl<D>> result = Lists.newArrayList();
for (D descriptor : descriptors) {
result.add(create(descriptor));
}
return result;
}
private final D candidateDescriptor;
private D resultingDescriptor; // Probably substituted
private ReceiverDescriptor thisObject = NO_RECEIVER; // receiver object of a method
private ReceiverDescriptor receiverArgument = NO_RECEIVER; // receiver of an extension function
private final Map<TypeParameterDescriptor, JetType> typeArguments = Maps.newLinkedHashMap();
private final Map<ValueParameterDescriptor, JetType> autoCasts = Maps.newHashMap();
private final Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = Maps.newHashMap();
private boolean someArgumentHasNoType = false;
private TemporaryBindingTrace trace;
private ResolutionStatus status = UNKNOWN_STATUS;
private ResolvedCallImpl(@NotNull D candidateDescriptor) {
this.candidateDescriptor = candidateDescriptor;
}
@NotNull
public ResolutionStatus getStatus() {
return status;
}
public void setStatus(@NotNull ResolutionStatus status) {
this.status = status;
}
@NotNull
public TemporaryBindingTrace getTrace() {
return trace;
}
public void setTrace(@NotNull TemporaryBindingTrace trace) {
this.trace = trace;
}
@Override
@NotNull
public D getCandidateDescriptor() {
return candidateDescriptor;
}
@Override
@NotNull
public D getResultingDescriptor() {
return resultingDescriptor == null ? candidateDescriptor : resultingDescriptor;
}
public ResolvedCallImpl<D> setResultingDescriptor(@NotNull D resultingDescriptor) {
this.resultingDescriptor = resultingDescriptor;
return this;
}
public void recordTypeArgument(@NotNull TypeParameterDescriptor typeParameter, @NotNull JetType typeArgument) {
assert !typeArguments.containsKey(typeParameter);
typeArguments.put(typeParameter, typeArgument);
}
public void recordValueArgument(@NotNull ValueParameterDescriptor valueParameter, @NotNull ResolvedValueArgument valueArgument) {
assert !valueArguments.containsKey(valueParameter);
valueArguments.put(valueParameter, valueArgument);
}
public void autoCastValueArgument(@NotNull ValueParameterDescriptor parameter, @NotNull JetType target) {
assert !autoCasts.containsKey(parameter);
autoCasts.put(parameter, target);
}
@Override
@NotNull
public ReceiverDescriptor getReceiverArgument() {
return receiverArgument;
}
public void setReceiverArgument(@NotNull ReceiverDescriptor receiverParameter) {
this.receiverArgument = receiverParameter;
}
@Override
@NotNull
public ReceiverDescriptor getThisObject() {
return thisObject;
}
public void setThisObject(@NotNull ReceiverDescriptor thisObject) {
this.thisObject = thisObject;
}
@Override
@NotNull
public Map<ValueParameterDescriptor, ResolvedValueArgument> getValueArguments() {
return valueArguments;
}
public void argumentHasNoType() {
this.someArgumentHasNoType = true;
}
public boolean isDirty() {
return someArgumentHasNoType;
}
@NotNull
@Override
public Map<TypeParameterDescriptor, JetType> getTypeArguments() {
return typeArguments;
}
}
@@ -8,6 +8,9 @@ import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.psi.Call;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastService;
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
@@ -26,9 +29,9 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
/*package*/ abstract class TaskPrioritizer<D extends CallableDescriptor> {
public static <D extends CallableDescriptor> void splitLexicallyLocalDescriptors(
Collection<ResolvedCall<D>> allDescriptors, DeclarationDescriptor containerOfTheCurrentLocality, Collection<ResolvedCall<D>> local, Collection<ResolvedCall<D>> nonlocal) {
Collection<ResolvedCallImpl<D>> allDescriptors, DeclarationDescriptor containerOfTheCurrentLocality, Collection<ResolvedCallImpl<D>> local, Collection<ResolvedCallImpl<D>> nonlocal) {
for (ResolvedCall<D> resolvedCall : allDescriptors) {
for (ResolvedCallImpl<D> resolvedCall : allDescriptors) {
if (isLocal(containerOfTheCurrentLocality, resolvedCall.getCandidateDescriptor())) {
local.add(resolvedCall);
}
@@ -93,13 +96,13 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
if (receiver.exists()) {
List<ReceiverDescriptor> variantsForExplicitReceiver = autoCastService.getVariantsForReceiver(receiver);
Collection<ResolvedCall<D>> extensionFunctions = convertWithImpliedThis(scope, variantsForExplicitReceiver, getExtensionsByName(scope, name));
List<ResolvedCall<D>> nonlocals = Lists.newArrayList();
List<ResolvedCall<D>> locals = Lists.newArrayList();
Collection<ResolvedCallImpl<D>> extensionFunctions = convertWithImpliedThis(scope, variantsForExplicitReceiver, getExtensionsByName(scope, name));
List<ResolvedCallImpl<D>> nonlocals = Lists.newArrayList();
List<ResolvedCallImpl<D>> locals = Lists.newArrayList();
//noinspection unchecked,RedundantTypeArguments
TaskPrioritizer.<D>splitLexicallyLocalDescriptors(extensionFunctions, scope.getContainingDeclaration(), locals, nonlocals);
Collection<ResolvedCall<D>> members = Lists.newArrayList();
Collection<ResolvedCallImpl<D>> members = Lists.newArrayList();
for (ReceiverDescriptor variant : variantsForExplicitReceiver) {
Collection<D> membersForThisVariant = getMembersByName(variant.getType(), name);
convertWithReceivers(membersForThisVariant, Collections.singletonList(variant), Collections.singletonList(NO_RECEIVER), members);
@@ -117,10 +120,10 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
addTask(result, call, nonlocals, dataFlowInfo);
}
else {
Collection<ResolvedCall<D>> functions = convertWithImpliedThis(scope, Collections.singletonList(receiver), getNonExtensionsByName(scope, name));
Collection<ResolvedCallImpl<D>> functions = convertWithImpliedThis(scope, Collections.singletonList(receiver), getNonExtensionsByName(scope, name));
List<ResolvedCall<D>> nonlocals = Lists.newArrayList();
List<ResolvedCall<D>> locals = Lists.newArrayList();
List<ResolvedCallImpl<D>> nonlocals = Lists.newArrayList();
List<ResolvedCallImpl<D>> locals = Lists.newArrayList();
//noinspection unchecked,RedundantTypeArguments
TaskPrioritizer.<D>splitLexicallyLocalDescriptors(functions, scope.getContainingDeclaration(), locals, nonlocals);
@@ -134,18 +137,18 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
}
}
private Collection<ResolvedCall<D>> convertWithReceivers(Collection<D> descriptors, Iterable<ReceiverDescriptor> thisObjects, Iterable<ReceiverDescriptor> receiverParameters) {
Collection<ResolvedCall<D>> result = Lists.newArrayList();
private Collection<ResolvedCallImpl<D>> convertWithReceivers(Collection<D> descriptors, Iterable<ReceiverDescriptor> thisObjects, Iterable<ReceiverDescriptor> receiverParameters) {
Collection<ResolvedCallImpl<D>> result = Lists.newArrayList();
convertWithReceivers(descriptors, thisObjects, receiverParameters, result);
return result;
}
private void convertWithReceivers(Collection<D> descriptors, Iterable<ReceiverDescriptor> thisObjects, Iterable<ReceiverDescriptor> receiverParameters, Collection<ResolvedCall<D>> result) {
// Collection<ResolvedCall<D>> result = Lists.newArrayList();
private void convertWithReceivers(Collection<D> descriptors, Iterable<ReceiverDescriptor> thisObjects, Iterable<ReceiverDescriptor> receiverParameters, Collection<ResolvedCallImpl<D>> result) {
// Collection<ResolvedCallImpl<D>> result = Lists.newArrayList();
for (ReceiverDescriptor thisObject : thisObjects) {
for (ReceiverDescriptor receiverParameter : receiverParameters) {
for (D extension : descriptors) {
ResolvedCall<D> resolvedCall = ResolvedCall.create(extension);
ResolvedCallImpl<D> resolvedCall = ResolvedCallImpl.create(extension);
resolvedCall.setThisObject(thisObject);
resolvedCall.setReceiverArgument(receiverParameter);
result.add(resolvedCall);
@@ -155,11 +158,11 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
// return result;
}
public static <D extends CallableDescriptor> Collection<ResolvedCall<D>> convertWithImpliedThis(JetScope scope, Iterable<ReceiverDescriptor> receiverParameters, Collection<D> descriptors) {
Collection<ResolvedCall<D>> result = Lists.newArrayList();
public static <D extends CallableDescriptor> Collection<ResolvedCallImpl<D>> convertWithImpliedThis(JetScope scope, Iterable<ReceiverDescriptor> receiverParameters, Collection<D> descriptors) {
Collection<ResolvedCallImpl<D>> result = Lists.newArrayList();
for (ReceiverDescriptor receiverParameter : receiverParameters) {
for (D extension : descriptors) {
ResolvedCall<D> resolvedCall = ResolvedCall.create(extension);
ResolvedCallImpl<D> resolvedCall = ResolvedCallImpl.create(extension);
resolvedCall.setReceiverArgument(receiverParameter);
if (setImpliedThis(scope, resolvedCall)) {
result.add(resolvedCall);
@@ -169,7 +172,7 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
return result;
}
private static <D extends CallableDescriptor> boolean setImpliedThis(@NotNull JetScope scope, ResolvedCall<D> resolvedCall) {
private static <D extends CallableDescriptor> boolean setImpliedThis(@NotNull JetScope scope, ResolvedCallImpl<D> resolvedCall) {
ReceiverDescriptor expectedThisObject = resolvedCall.getCandidateDescriptor().getExpectedThisObject();
if (!expectedThisObject.exists()) return true;
List<ReceiverDescriptor> receivers = Lists.newArrayList();
@@ -184,7 +187,7 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
return false;
}
private void addTask(@NotNull List<ResolutionTask<D>> result, @NotNull Call call, @NotNull Collection<ResolvedCall<D>> candidates, @NotNull DataFlowInfo dataFlowInfo) {
private void addTask(@NotNull List<ResolutionTask<D>> result, @NotNull Call call, @NotNull Collection<ResolvedCallImpl<D>> candidates, @NotNull DataFlowInfo dataFlowInfo) {
if (candidates.isEmpty()) return;
result.add(new ResolutionTask<D>(candidates, call, dataFlowInfo));
}
@@ -16,13 +16,13 @@ import java.util.Set;
/*package*/ interface TracingStrategy {
TracingStrategy EMPTY = new TracingStrategy() {
@Override
public <D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall) {}
public <D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCallImpl<D> resolvedCall) {}
@Override
public void unresolvedReference(@NotNull BindingTrace trace) {}
@Override
public <D extends CallableDescriptor> void recordAmbiguity(BindingTrace trace, Collection<ResolvedCall<D>> candidates) {}
public <D extends CallableDescriptor> void recordAmbiguity(BindingTrace trace, Collection<ResolvedCallImpl<D>> candidates) {}
@Override
public void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor expectedReceiver) {}
@@ -40,10 +40,10 @@ import java.util.Set;
public void wrongNumberOfTypeArguments(@NotNull BindingTrace trace, int expectedTypeArgumentCount) {}
@Override
public <D extends CallableDescriptor> void ambiguity(@NotNull BindingTrace trace, @NotNull Set<ResolvedCall<D>> descriptors) {}
public <D extends CallableDescriptor> void ambiguity(@NotNull BindingTrace trace, @NotNull Set<ResolvedCallImpl<D>> descriptors) {}
@Override
public <D extends CallableDescriptor> void noneApplicable(@NotNull BindingTrace trace, @NotNull Set<ResolvedCall<D>> descriptors) {}
public <D extends CallableDescriptor> void noneApplicable(@NotNull BindingTrace trace, @NotNull Set<ResolvedCallImpl<D>> descriptors) {}
@Override
public void instantiationOfAbstractClass(@NotNull BindingTrace trace) {}
@@ -58,11 +58,11 @@ import java.util.Set;
public void unnecessarySafeCall(@NotNull BindingTrace trace, @NotNull JetType type) {}
};
<D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall);
<D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCallImpl<D> resolvedCall);
void unresolvedReference(@NotNull BindingTrace trace);
<D extends CallableDescriptor> void recordAmbiguity(BindingTrace trace, Collection<ResolvedCall<D>> candidates);
<D extends CallableDescriptor> void recordAmbiguity(BindingTrace trace, Collection<ResolvedCallImpl<D>> candidates);
void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor expectedReceiver);
@@ -74,9 +74,9 @@ import java.util.Set;
void wrongNumberOfTypeArguments(@NotNull BindingTrace trace, int expectedTypeArgumentCount);
<D extends CallableDescriptor> void ambiguity(@NotNull BindingTrace trace, @NotNull Set<ResolvedCall<D>> descriptors);
<D extends CallableDescriptor> void ambiguity(@NotNull BindingTrace trace, @NotNull Set<ResolvedCallImpl<D>> descriptors);
<D extends CallableDescriptor> void noneApplicable(@NotNull BindingTrace trace, @NotNull Set<ResolvedCall<D>> descriptors);
<D extends CallableDescriptor> void noneApplicable(@NotNull BindingTrace trace, @NotNull Set<ResolvedCallImpl<D>> descriptors);
void instantiationOfAbstractClass(@NotNull BindingTrace trace);
@@ -23,7 +23,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
public static <D extends CallableDescriptor> boolean mapValueArgumentsToParameters(
@NotNull ResolutionTask<D> task,
@NotNull TracingStrategy tracing,
@NotNull ResolvedCall<D> candidateCall
@NotNull ResolvedCallImpl<D> candidateCall
) {
TemporaryBindingTrace temporaryTrace = candidateCall.getTrace();
@@ -181,7 +181,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
return error;
}
private static <D extends CallableDescriptor> void put(ResolvedCall<D> candidateCall, ValueParameterDescriptor valueParameterDescriptor, ValueArgument valueArgument, Map<ValueParameterDescriptor, VarargValueArgument> varargs) {
private static <D extends CallableDescriptor> void put(ResolvedCallImpl<D> candidateCall, ValueParameterDescriptor valueParameterDescriptor, ValueArgument valueArgument, Map<ValueParameterDescriptor, VarargValueArgument> varargs) {
if (valueParameterDescriptor.isVararg()) {
VarargValueArgument vararg = varargs.get(valueParameterDescriptor);
if (vararg == null) {
@@ -1,4 +1,4 @@
package org.jetbrains.jet.lang.resolve.calls;
package org.jetbrains.jet.lang.resolve.calls.autocasts;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
@@ -13,7 +13,7 @@ public interface AutoCastService {
AutoCastService NO_AUTO_CASTS = new AutoCastService() {
@Override
public DataFlowInfo getDataFlowInfo() {
return DataFlowInfo.getEmpty();
return DataFlowInfo.EMPTY;
}
@Override
@@ -1,4 +1,4 @@
package org.jetbrains.jet.lang.resolve.calls;
package org.jetbrains.jet.lang.resolve.calls.autocasts;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.BindingContext;
@@ -0,0 +1,109 @@
package org.jetbrains.jet.lang.resolve.calls.autocasts;
import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.calls.AutoCastReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.*;
import org.jetbrains.jet.lang.types.JetType;
import java.util.Collections;
import java.util.List;
/**
* @author abreslav
*/
public class AutoCastUtils {
private AutoCastUtils() {}
public static List<ReceiverDescriptor> getAutoCastVariants(@NotNull final BindingContext bindingContext, @NotNull final DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiverToCast) {
return receiverToCast.accept(new ReceiverDescriptorVisitor<List<ReceiverDescriptor>, Object>() {
@Override
public List<ReceiverDescriptor> visitNoReceiver(ReceiverDescriptor noReceiver, Object data) {
return Collections.emptyList();
}
@Override
public List<ReceiverDescriptor> visitTransientReceiver(TransientReceiver receiver, Object data) {
return Collections.emptyList();
}
@Override
public List<ReceiverDescriptor> visitExtensionReceiver(ExtensionReceiver receiver, Object data) {
return castThis(dataFlowInfo, receiver);
}
@Override
public List<ReceiverDescriptor> visitClassReceiver(ClassReceiver receiver, Object data) {
return castThis(dataFlowInfo, receiver);
}
@Override
public List<ReceiverDescriptor> visitExpressionReceiver(ExpressionReceiver receiver, Object data) {
// JetExpression expression = receiver.getExpression();
// VariableDescriptor variableDescriptor = DataFlowValueFactory.getVariableDescriptorFromSimpleName(bindingContext, expression);
// if (variableDescriptor != null) {
// List<ReceiverDescriptor> result = Lists.newArrayList();
// for (JetType possibleType : dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)) {
// result.add(new AutoCastReceiver(receiver, possibleType, DataFlowValueFactory.isStableVariable(variableDescriptor)));
// }
// return result;
// }
// else if (expression instanceof JetThisExpression) {
// return castThis(dataFlowInfo, receiver);
// }
DataFlowValue dataFlowValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(receiver.getExpression(),receiver.getType(), bindingContext);
List<ReceiverDescriptor> result = Lists.newArrayList();
for (JetType possibleType : dataFlowInfo.getPossibleTypes(dataFlowValue)) {
result.add(new AutoCastReceiver(receiver, possibleType, dataFlowValue.isStableIdentifier()));
}
return result;
}
}, null);
}
private static List<ReceiverDescriptor> castThis(@NotNull DataFlowInfo dataFlowInfo, @NotNull ThisReceiverDescriptor receiver) {
assert receiver.exists();
List<ReceiverDescriptor> result = Lists.newArrayList();
for (JetType possibleType : dataFlowInfo.getPossibleTypes(DataFlowValueFactory.INSTANCE.createDataFlowValue(receiver))) {
result.add(new AutoCastReceiver(receiver, possibleType, true));
}
return result;
}
// @Nullable
// public static JetType castExpression(@NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
// JetTypeChecker typeChecker = JetTypeChecker.INSTANCE;
// DataFlowValue dataFlowValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(expression, trace.getBindingContext());
// for (JetType possibleType : dataFlowInfo.getPossibleTypes(dataFlowValue)) {
// if (typeChecker.isSubtypeOf(possibleType, expectedType)) {
// if (dataFlowValue.isStableIdentifier()) {
// trace.record(AUTOCAST, expression, possibleType);
// }
// else {
// trace.report(AUTOCAST_IMPOSSIBLE.on(expression, possibleType, expression.getText()));
// }
// return possibleType;
// }
// }
//// VariableDescriptor variableDescriptor = DataFlowValueFactory.getVariableDescriptorFromSimpleName(trace.getBindingContext(), expression);
//// if (variableDescriptor != null) {
//// List<JetType> possibleTypes = Lists.newArrayList(dataFlowInfo.getPossibleTypes(variableDescriptor));
//// Collections.reverse(possibleTypes);
//// for (JetType possibleType : possibleTypes) {
//// if (typeChecker.isSubtypeOf(possibleType, expectedType)) {
//// if (DataFlowValueFactory.isStableVariable(variableDescriptor)) {
//// trace.record(AUTOCAST, expression, possibleType);
//// }
//// else {
//// trace.report(AUTOCAST_IMPOSSIBLE.on(expression, possibleType, expression.getText()));
//// }
//// return possibleType;
//// }
//// }
//// }
// return null;
// }
}
@@ -0,0 +1,390 @@
package org.jetbrains.jet.lang.resolve.calls.autocasts;
import com.google.common.collect.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.util.CommonSuppliers;
import java.util.*;
import static org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability.NOT_NULL;
/**
* @author abreslav
*/
public class DataFlowInfo {
public static abstract class CompositionOperator {
public abstract DataFlowInfo compose(DataFlowInfo a, DataFlowInfo b);
}
public static final CompositionOperator AND = new CompositionOperator() {
@Override
public DataFlowInfo compose(DataFlowInfo a, DataFlowInfo b) {
return a.and(b);
}
};
public static final CompositionOperator OR = new CompositionOperator() {
@Override
public DataFlowInfo compose(DataFlowInfo a, DataFlowInfo b) {
return a.or(b);
}
};
public static DataFlowInfo EMPTY = new DataFlowInfo(ImmutableMap.<DataFlowValue, Nullability>of(), Multimaps.newListMultimap(Collections.<DataFlowValue, Collection<JetType>>emptyMap(), CommonSuppliers.<JetType>getArrayListSupplier()));
private final ImmutableMap<DataFlowValue, Nullability> nullabilityInfo;
private final ListMultimap<DataFlowValue, JetType> typeInfo;
private DataFlowInfo(ImmutableMap<DataFlowValue, Nullability> nullabilityInfo, ListMultimap<DataFlowValue, JetType> typeInfo) {
this.nullabilityInfo = nullabilityInfo;
this.typeInfo = typeInfo;
}
@NotNull
private Nullability getNullability(@NotNull DataFlowValue a) {
if (!a.isStableIdentifier()) return a.getImmanentNullability();
Nullability nullability = nullabilityInfo.get(a);
if (nullability == null) {
nullability = a.getImmanentNullability();
}
return nullability;
}
private boolean putNullability(@NotNull Map<DataFlowValue, Nullability> map, @NotNull DataFlowValue value, @NotNull Nullability nullability) {
if (!value.isStableIdentifier()) return false;
return map.put(value, nullability) != nullability;
}
@NotNull
public List<JetType> getPossibleTypes(DataFlowValue key) {
JetType originalType = key.getType();
List<JetType> types = typeInfo.get(key);
Nullability nullability = getNullability(key);
if (nullability.canBeNull()) {
return types;
}
List<JetType> enrichedTypes = Lists.newArrayListWithCapacity(types.size());
if (originalType.isNullable()) {
enrichedTypes.add(TypeUtils.makeNotNullable(originalType));
}
for (JetType type: types) {
if (type.isNullable()) {
enrichedTypes.add(TypeUtils.makeNotNullable(type));
}
else {
enrichedTypes.add(type);
}
}
return enrichedTypes;
}
@NotNull
public DataFlowInfo equate(@NotNull DataFlowValue a, @NotNull DataFlowValue b) {
Map<DataFlowValue, Nullability> builder = Maps.newHashMap(nullabilityInfo);
Nullability nullabilityOfA = getNullability(a);
Nullability nullabilityOfB = getNullability(b);
boolean changed = false;
changed |= putNullability(builder, a, nullabilityOfA.refine(nullabilityOfB));
changed |= putNullability(builder, b, nullabilityOfA.refine(nullabilityOfA));
return changed ? new DataFlowInfo(ImmutableMap.copyOf(builder), typeInfo) : this;
}
@NotNull
public DataFlowInfo disequate(@NotNull DataFlowValue a, @NotNull DataFlowValue b) {
Map<DataFlowValue, Nullability> builder = Maps.newHashMap(nullabilityInfo);
Nullability nullabilityOfA = getNullability(a);
Nullability nullabilityOfB = getNullability(b);
boolean changed = false;
changed |= putNullability(builder, a, nullabilityOfA.refine(nullabilityOfB.invert()));
changed |= putNullability(builder, b, nullabilityOfA.refine(nullabilityOfA.invert()));
return changed ? new DataFlowInfo(ImmutableMap.copyOf(builder), typeInfo) : this;
}
@NotNull
public DataFlowInfo establishSubtyping(@NotNull DataFlowValue[] values, @NotNull JetType type) {
ListMultimap<DataFlowValue, JetType> newTypeInfo = copyTypeInfo();
Map<DataFlowValue, Nullability> newNullabilityInfo = Maps.newHashMap(nullabilityInfo);
boolean changed = false;
for (DataFlowValue value : values) {
// if (!value.isStableIdentifier()) continue;
changed = true;
newTypeInfo.put(value, type);
if (!type.isNullable()) {
putNullability(newNullabilityInfo, value, NOT_NULL);
}
}
if (!changed) return this;
return new DataFlowInfo(ImmutableMap.copyOf(newNullabilityInfo), newTypeInfo);
}
private ListMultimap<DataFlowValue, JetType> copyTypeInfo() {
ListMultimap<DataFlowValue, JetType> newTypeInfo = Multimaps.newListMultimap(Maps.<DataFlowValue, Collection<JetType>>newHashMap(), CommonSuppliers.<JetType>getArrayListSupplier());
newTypeInfo.putAll(typeInfo);
return newTypeInfo;
}
public DataFlowInfo and(DataFlowInfo other) {
Map<DataFlowValue, Nullability> nullabilityMapBuilder = Maps.newHashMap();
nullabilityMapBuilder.putAll(nullabilityInfo);
for (Map.Entry<DataFlowValue, Nullability> entry : other.nullabilityInfo.entrySet()) {
DataFlowValue key = entry.getKey();
Nullability otherFlags = entry.getValue();
Nullability thisFlags = nullabilityInfo.get(key);
if (thisFlags != null) {
nullabilityMapBuilder.put(key, thisFlags.and(otherFlags));
}
else {
nullabilityMapBuilder.put(key, otherFlags);
}
}
ListMultimap<DataFlowValue, JetType> newTypeInfo = copyTypeInfo();
newTypeInfo.putAll(other.typeInfo);
return new DataFlowInfo(ImmutableMap.copyOf(nullabilityMapBuilder), newTypeInfo);
}
public DataFlowInfo or(DataFlowInfo other) {
Map<DataFlowValue, Nullability> builder = Maps.newHashMap(nullabilityInfo);
builder.keySet().retainAll(other.nullabilityInfo.keySet());
for (Map.Entry<DataFlowValue, Nullability> entry : builder.entrySet()) {
DataFlowValue key = entry.getKey();
Nullability thisFlags = entry.getValue();
Nullability otherFlags = other.nullabilityInfo.get(key);
assert (otherFlags != null);
builder.put(key, thisFlags.or(otherFlags));
}
ListMultimap<DataFlowValue, JetType> newTypeInfo = Multimaps.newListMultimap(Maps.<DataFlowValue, Collection<JetType>>newHashMap(), CommonSuppliers.<JetType>getArrayListSupplier());
Set<DataFlowValue> keys = newTypeInfo.keySet();
keys.retainAll(other.typeInfo.keySet());
for (DataFlowValue key : keys) {
Collection<JetType> thisTypes = typeInfo.get(key);
Collection<JetType> otherTypes = other.typeInfo.get(key);
Collection<JetType> newTypes = Sets.newHashSet(thisTypes);
newTypes.retainAll(otherTypes);
newTypeInfo.putAll(key, newTypes);
}
return new DataFlowInfo(ImmutableMap.copyOf(builder), newTypeInfo);
}
}
//public class DataFlowInfo {
//
// public static abstract class CompositionOperator {
//
// public abstract DataFlowInfo compose(DataFlowInfo a, DataFlowInfo b);
// }
// public static final CompositionOperator AND = new CompositionOperator() {
// @Override
// public DataFlowInfo compose(DataFlowInfo a, DataFlowInfo b) {
// return a.and(b);
// }
// };
//
// public static final CompositionOperator OR = new CompositionOperator() {
// @Override
// public DataFlowInfo compose(DataFlowInfo a, DataFlowInfo b) {
// return a.or(b);
// }
// };
//
// private static DataFlowInfo EMPTY = new DataFlowInfo(ImmutableMap.<Object, NullabilityFlags>of(), Multimaps.newListMultimap(Collections.<Object, Collection<JetType>>emptyMap(), CommonSuppliers.<JetType>getArrayListSupplier()));
//
// public static DataFlowInfo getEmpty() {
// return EMPTY;
// }
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// private final ImmutableMap<Object, NullabilityFlags> nullabilityInfo;
//
// private final ListMultimap<Object, JetType> typeInfo;
//
// private DataFlowInfo(ImmutableMap<Object, NullabilityFlags> nullabilityInfo, ListMultimap<Object, JetType> typeInfo) {
// this.nullabilityInfo = nullabilityInfo;
// this.typeInfo = typeInfo;
// }
//
// @Nullable
// public JetType getOutType(@NotNull VariableDescriptor variableDescriptor) {
// JetType outType = variableDescriptor.getOutType();
// if (outType == null) return null;
// if (!outType.isNullable()) return outType;
// NullabilityFlags nullabilityFlags = nullabilityInfo.get(variableDescriptor);
// if (nullabilityFlags != null && !nullabilityFlags.canBeNull()) {
// return TypeUtils.makeNotNullable(outType);
// }
// return outType;
// }
//
// @NotNull
// private List<JetType> getPossibleTypes(Object key, @NotNull JetType originalType) {
// List<JetType> types = typeInfo.get(key);
// NullabilityFlags nullabilityFlags = nullabilityInfo.get(key);
// if (nullabilityFlags == null || nullabilityFlags.canBeNull()) {
// return types;
// }
// List<JetType> enrichedTypes = Lists.newArrayListWithCapacity(types.size());
// if (originalType.isNullable()) {
// enrichedTypes.add(TypeUtils.makeNotNullable(originalType));
// }
// for (JetType type: types) {
// if (type.isNullable()) {
// enrichedTypes.add(TypeUtils.makeNotNullable(type));
// }
// else {
// enrichedTypes.add(type);
// }
// }
// return enrichedTypes;
// }
//
// @NotNull
// public List<JetType> getPossibleTypesForVariable(@NotNull VariableDescriptor variableDescriptor) {
// return getPossibleTypes(variableDescriptor, variableDescriptor.getOutType());
// }
//
// public List<JetType> getPossibleTypesForReceiver(@NotNull ReceiverDescriptor receiver) {
// return getPossibleTypes(receiver, receiver.getType());
// }
//
// public DataFlowInfo establishEqualityToNull(@NotNull VariableDescriptor variableDescriptor, boolean notNull) {
// return new DataFlowInfo(getEqualsToNullMap(variableDescriptor, notNull), typeInfo);
// }
//
// private ImmutableMap<Object, NullabilityFlags> getEqualsToNullMap(VariableDescriptor variableDescriptor, boolean notNull) {
// Map<Object, NullabilityFlags> builder = Maps.newHashMap(nullabilityInfo);
// NullabilityFlags nullabilityFlags = nullabilityInfo.get(variableDescriptor);
// boolean varNotNull = notNull || (nullabilityFlags != null && !nullabilityFlags.canBeNull);
// builder.put(variableDescriptor, new NullabilityFlags(!varNotNull, varNotNull));
// return ImmutableMap.copyOf(builder);
// }
//
// private ImmutableMap<Object, NullabilityFlags> getEqualsToNullMap(VariableDescriptor[] variableDescriptors, boolean notNull) {
// if (variableDescriptors.length == 0) return nullabilityInfo;
// Map<Object, NullabilityFlags> builder = Maps.newHashMap(nullabilityInfo);
// for (VariableDescriptor variableDescriptor : variableDescriptors) {
// if (variableDescriptor != null) {
// NullabilityFlags nullabilityFlags = nullabilityInfo.get(variableDescriptor);
// boolean varNotNull = notNull || (nullabilityFlags != null && !nullabilityFlags.canBeNull);
// builder.put(variableDescriptor, new NullabilityFlags(!varNotNull, varNotNull));
// }
// }
// return ImmutableMap.copyOf(builder);
// }
//
// public DataFlowInfo isInstanceOf(@NotNull VariableDescriptor variableDescriptor, @NotNull JetType type) {
// ListMultimap<Object, JetType> newTypeInfo = copyTypeInfo();
// newTypeInfo.put(variableDescriptor, type);
// return new DataFlowInfo(getEqualsToNullMap(variableDescriptor, !type.isNullable()), newTypeInfo);
// }
//
// public DataFlowInfo isInstanceOf(@NotNull VariableDescriptor[] variableDescriptors, @NotNull JetType type) {
// if (variableDescriptors.length == 0) return this;
// ListMultimap<Object, JetType> newTypeInfo = copyTypeInfo();
// for (VariableDescriptor variableDescriptor : variableDescriptors) {
// if (variableDescriptor != null) {
// newTypeInfo.put(variableDescriptor, type);
// }
// }
// return new DataFlowInfo(getEqualsToNullMap(variableDescriptors, !type.isNullable()), newTypeInfo);
// }
//
// public DataFlowInfo and(DataFlowInfo other) {
// Map<Object, NullabilityFlags> nullabilityMapBuilder = Maps.newHashMap();
// nullabilityMapBuilder.putAll(nullabilityInfo);
// for (Map.Entry<Object, NullabilityFlags> entry : other.nullabilityInfo.entrySet()) {
// Object key = entry.getKey();
// NullabilityFlags otherFlags = entry.getValue();
// NullabilityFlags thisFlags = nullabilityInfo.get(key);
// if (thisFlags != null) {
// nullabilityMapBuilder.put(key, thisFlags.and(otherFlags));
// }
// else {
// nullabilityMapBuilder.put(key, otherFlags);
// }
// }
//
// ListMultimap<Object, JetType> newTypeInfo = copyTypeInfo();
// newTypeInfo.putAll(other.typeInfo);
// return new DataFlowInfo(ImmutableMap.copyOf(nullabilityMapBuilder), newTypeInfo);
// }
//
// private ListMultimap<Object, JetType> copyTypeInfo() {
// ListMultimap<Object, JetType> newTypeInfo = Multimaps.newListMultimap(Maps.<Object, Collection<JetType>>newHashMap(), CommonSuppliers.<JetType>getArrayListSupplier());
// newTypeInfo.putAll(typeInfo);
// return newTypeInfo;
// }
//
// public DataFlowInfo or(DataFlowInfo other) {
// Map<Object, NullabilityFlags> builder = Maps.newHashMap(nullabilityInfo);
// builder.keySet().retainAll(other.nullabilityInfo.keySet());
// for (Map.Entry<Object, NullabilityFlags> entry : builder.entrySet()) {
// Object key = entry.getKey();
// NullabilityFlags thisFlags = entry.getValue();
// NullabilityFlags otherFlags = other.nullabilityInfo.get(key);
// assert (otherFlags != null);
// builder.put(key, thisFlags.or(otherFlags));
// }
//
// ListMultimap<Object, JetType> newTypeInfo = Multimaps.newListMultimap(Maps.<Object, Collection<JetType>>newHashMap(), CommonSuppliers.<JetType>getArrayListSupplier());
//
// Set<Object> keys = newTypeInfo.keySet();
// keys.retainAll(other.typeInfo.keySet());
//
// for (Object key : keys) {
// Collection<JetType> thisTypes = typeInfo.get(key);
// Collection<JetType> otherTypes = other.typeInfo.get(key);
//
// Collection<JetType> newTypes = Sets.newHashSet(thisTypes);
// newTypes.retainAll(otherTypes);
//
// newTypeInfo.putAll(key, newTypes);
// }
//
// return new DataFlowInfo(ImmutableMap.copyOf(builder), newTypeInfo);
// }
//
// public DataFlowInfo nullabilityOnly() {
// return new DataFlowInfo(nullabilityInfo, EMPTY.copyTypeInfo());
// }
//
// private static class NullabilityFlags {
// private final boolean canBeNull;
// private final boolean canBeNonNull;
//
// private NullabilityFlags(boolean canBeNull, boolean canBeNonNull) {
// this.canBeNull = canBeNull;
// this.canBeNonNull = canBeNonNull;
// }
//
// public boolean canBeNull() {
// return canBeNull;
// }
//
// public boolean canBeNonNull() {
// return canBeNonNull;
// }
//
// public NullabilityFlags and(NullabilityFlags other) {
// return new NullabilityFlags(this.canBeNull && other.canBeNull, this.canBeNonNull && other.canBeNonNull);
// }
//
// public NullabilityFlags or(NullabilityFlags other) {
// return new NullabilityFlags(this.canBeNull || other.canBeNull, this.canBeNonNull || other.canBeNonNull);
// }
//
// }
//}
@@ -0,0 +1,72 @@
package org.jetbrains.jet.lang.resolve.calls.autocasts;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
/**
* @author abreslav
*/
public class DataFlowValue {
public static final DataFlowValue NULL = new DataFlowValue(new Object(), JetStandardClasses.getNullableNothingType(), false, Nullability.NULL);
public static final DataFlowValue NULLABLE = new DataFlowValue(new Object(), JetStandardClasses.getNullableAnyType(), false, Nullability.UNKNOWN);
private final boolean stableIdentifier;
private final JetType type;
private final Object id;
private final Nullability immanentNullability;
// Use DataFlowValueFactory
/*package*/ DataFlowValue(Object id, JetType type, boolean stableIdentifier, Nullability immanentNullability) {
this.stableIdentifier = stableIdentifier;
this.type = type;
this.id = id;
this.immanentNullability = immanentNullability;
}
@NotNull
public Nullability getImmanentNullability() {
return immanentNullability;
}
/**
* Stable identifier is a non-literal value that is statically known to be immutable
* @return
*/
public boolean isStableIdentifier() {
return stableIdentifier;
}
@NotNull
public JetType getType() {
return type;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DataFlowValue that = (DataFlowValue) o;
if (stableIdentifier != that.stableIdentifier) return false;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
if (type != null ? !type.equals(that.type) : that.type != null) return false;
return true;
}
@Override
public String toString() {
return (stableIdentifier ? "stable " : "unstable ") + (id == null ? null : id.toString()) + " " + immanentNullability;
}
@Override
public int hashCode() {
int result = (stableIdentifier ? 1 : 0);
result = 31 * result + (type != null ? type.hashCode() : 0);
result = 31 * result + (id != null ? id.hashCode() : 0);
return result;
}
}
@@ -0,0 +1,156 @@
package org.jetbrains.jet.lang.resolve.calls.autocasts;
import com.intellij.openapi.util.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.JetModuleUtil;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ThisReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeChecker;
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
/**
* @author abreslav
*/
public class DataFlowValueFactory {
public static final DataFlowValueFactory INSTANCE = new DataFlowValueFactory();
private DataFlowValueFactory() {}
@NotNull
public DataFlowValue createDataFlowValue(@NotNull JetExpression expression, @NotNull JetType type, @NotNull BindingContext bindingContext) {
if (expression instanceof JetConstantExpression) {
JetConstantExpression constantExpression = (JetConstantExpression) expression;
if (constantExpression.getNode().getElementType() == JetNodeTypes.NULL) return DataFlowValue.NULL;
}
if (JetTypeChecker.INSTANCE.equalTypes(type, JetStandardClasses.getNullableNothingType())) return DataFlowValue.NULL; // 'null' is the only inhabitant of 'Nothing?'
Pair<Object, Boolean> result = getIdForStableIdentifier(expression, bindingContext, false);
return new DataFlowValue(result.first == null ? expression : result.first, type, result.second, getImmanentNullability(type));
}
@NotNull
public DataFlowValue createDataFlowValue(@NotNull ThisReceiverDescriptor receiver) {
JetType type = receiver.getType();
return new DataFlowValue(receiver.getDeclarationDescriptor(), type, true, getImmanentNullability(type));
}
@NotNull
public DataFlowValue createDataFlowValue(@NotNull VariableDescriptor variableDescriptor) {
JetType type = variableDescriptor.getOutType();
return new DataFlowValue(variableDescriptor, type, isStableVariable(variableDescriptor), getImmanentNullability(type));
}
private Nullability getImmanentNullability(JetType type) {
return type.isNullable() ? Nullability.UNKNOWN : Nullability.NOT_NULL;
}
@NotNull
private static Pair<Object, Boolean> getIdForStableIdentifier(@NotNull JetExpression expression, @NotNull BindingContext bindingContext, boolean allowNamespaces) {
if (expression instanceof JetParenthesizedExpression) {
JetParenthesizedExpression parenthesizedExpression = (JetParenthesizedExpression) expression;
JetExpression innerExpression = parenthesizedExpression.getExpression();
if (innerExpression == null) {
return Pair.create(null, false);
}
return getIdForStableIdentifier(innerExpression, bindingContext, allowNamespaces);
}
else if (expression instanceof JetQualifiedExpression) {
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) expression;
JetExpression selectorExpression = qualifiedExpression.getSelectorExpression();
if (selectorExpression == null) {
return Pair.create(null, false);
}
Pair<Object, Boolean> receiverId = getIdForStableIdentifier(qualifiedExpression.getReceiverExpression(), bindingContext, true);
Pair<Object, Boolean> selectorId = getIdForStableIdentifier(selectorExpression, bindingContext, allowNamespaces);
return receiverId.second ? selectorId : Pair.create(receiverId.first, false);
}
if (expression instanceof JetSimpleNameExpression) {
JetSimpleNameExpression simpleNameExpression = (JetSimpleNameExpression) expression;
DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, simpleNameExpression);
if (declarationDescriptor instanceof VariableDescriptor) {
return Pair.create((Object) declarationDescriptor, isStableVariable((VariableDescriptor) declarationDescriptor));
}
if (declarationDescriptor instanceof NamespaceDescriptor) {
return Pair.create((Object) declarationDescriptor, allowNamespaces);
}
if (declarationDescriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
return Pair.create((Object) classDescriptor, classDescriptor.isClassObjectAValue());
}
}
else if (expression instanceof JetThisExpression) {
JetThisExpression thisExpression = (JetThisExpression) expression;
DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, thisExpression.getInstanceReference());
if (declarationDescriptor instanceof CallableDescriptor) {
return Pair.create((Object) ((CallableDescriptor) declarationDescriptor).getReceiverParameter(), true);
}
if (declarationDescriptor instanceof ClassDescriptor) {
return Pair.create((Object) ((ClassDescriptor) declarationDescriptor).getImplicitReceiver(), true);
}
return Pair.create(null, true);
}
else if (expression instanceof JetRootNamespaceExpression) {
return Pair.create((Object) JetModuleUtil.getRootNamespaceType(expression), allowNamespaces);
}
return Pair.create(null, false);
}
@Nullable
public static VariableDescriptor getVariableDescriptorFromSimpleName(@NotNull BindingContext bindingContext, @NotNull JetExpression expression) {
JetExpression receiver = JetPsiUtil.deparenthesize(expression);
VariableDescriptor variableDescriptor = null;
if (receiver instanceof JetSimpleNameExpression) {
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) receiver;
DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, nameExpression);
if (declarationDescriptor instanceof VariableDescriptor) {
variableDescriptor = (VariableDescriptor) declarationDescriptor;
}
}
return variableDescriptor;
}
public static boolean isStableVariable(@NotNull VariableDescriptor variableDescriptor) {
if (variableDescriptor.isVar()) return false;
if (variableDescriptor instanceof PropertyDescriptor) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor;
if (!isInternal(propertyDescriptor)) return false;
if (!isFinal(propertyDescriptor)) return false;
if (!hasDefaultGetter(propertyDescriptor)) return false;
}
return true;
}
private static boolean isFinal(PropertyDescriptor propertyDescriptor) {
DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
if (containingDeclaration instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
if (classDescriptor.getModality().isOverridable() && propertyDescriptor.getModality().isOverridable()) return false;
}
else {
assert !propertyDescriptor.getModality().isOverridable() : "Property outside a class must not be overridable";
}
return true;
}
private static boolean isInternal(@NotNull DeclarationDescriptorWithVisibility descriptor) {
if (Visibility.INTERNAL_VISIBILITIES.contains(descriptor.getVisibility())) return true;
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (!(containingDeclaration instanceof DeclarationDescriptorWithVisibility)) {
return false;
}
return isInternal((DeclarationDescriptorWithVisibility) containingDeclaration);
}
private static boolean hasDefaultGetter(PropertyDescriptor propertyDescriptor) {
PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
return getter == null || getter.isDefault();
}
}
@@ -0,0 +1,83 @@
package org.jetbrains.jet.lang.resolve.calls.autocasts;
import org.jetbrains.annotations.NotNull;
/**
* @author abreslav
*/
public enum Nullability {
NULL(true, false),
NOT_NULL(false, true),
UNKNOWN(true, true),
IMPOSSIBLE(false, false);
@NotNull
public static Nullability fromFlags(boolean canBeNull, boolean canBeNonNull) {
if (!canBeNull && !canBeNonNull) return IMPOSSIBLE;
if (!canBeNull && canBeNonNull) return NOT_NULL;
if (canBeNull && !canBeNonNull) return NULL;
return UNKNOWN;
}
private final boolean canBeNull;
private final boolean canBeNonNull;
Nullability(boolean canBeNull, boolean canBeNonNull) {
this.canBeNull = canBeNull;
this.canBeNonNull = canBeNonNull;
}
public boolean canBeNull() {
return canBeNull;
}
public boolean canBeNonNull() {
return canBeNonNull;
}
@NotNull
public Nullability refine(@NotNull Nullability other) {
switch (this) {
case UNKNOWN:
return other;
case IMPOSSIBLE:
return other;
case NULL:
switch (other) {
case NOT_NULL: return NOT_NULL;
default: return NULL;
}
case NOT_NULL:
switch (other) {
case NULL: return NOT_NULL;
default: return NOT_NULL;
}
}
throw new IllegalStateException();
}
@NotNull
public Nullability invert() {
switch (this) {
case NULL:
return NOT_NULL;
case NOT_NULL:
return UNKNOWN;
case UNKNOWN:
return UNKNOWN;
case IMPOSSIBLE:
return UNKNOWN;
}
throw new IllegalStateException();
}
@NotNull
public Nullability and(@NotNull Nullability other) {
return fromFlags(this.canBeNull && other.canBeNull, this.canBeNonNull && other.canBeNonNull);
}
@NotNull
public Nullability or(@NotNull Nullability other) {
return fromFlags(this.canBeNull || other.canBeNull, this.canBeNonNull || other.canBeNonNull);
}
}
@@ -3,7 +3,6 @@ package org.jetbrains.jet.lang.resolve.scopes;
import com.google.common.collect.Sets;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import java.util.Collection;
@@ -109,21 +108,6 @@ public class ChainedScope implements JetScope {
return null;
}
@Override
public DeclarationDescriptor getDeclarationDescriptorForUnqualifiedThis() {
if (DescriptorUtils.definesItsOwnThis(getContainingDeclaration())) {
return getContainingDeclaration();
}
for (JetScope jetScope : scopeChain) {
DeclarationDescriptor containingDeclaration = jetScope.getContainingDeclaration();
if (DescriptorUtils.definesItsOwnThis(containingDeclaration)) {
return containingDeclaration;
}
}
return null;
}
@NotNull
@Override
public Collection<DeclarationDescriptor> getAllDescriptors() {
@@ -17,7 +17,7 @@ public interface JetScope {
@NotNull
@Override
public DeclarationDescriptor getContainingDeclaration() {
throw new UnsupportedOperationException();
throw new UnsupportedOperationException("Don't take containing declaration of the EMPTY scope");
}
@Override
@@ -51,9 +51,6 @@ public interface JetScope {
@Nullable
PropertyDescriptor getPropertyByFieldReference(@NotNull String fieldName);
@Nullable
DeclarationDescriptor getDeclarationDescriptorForUnqualifiedThis();
@NotNull
Collection<DeclarationDescriptor> getAllDescriptors();
@@ -51,11 +51,6 @@ public abstract class JetScopeImpl implements JetScope {
return null;
}
@Override
public DeclarationDescriptor getDeclarationDescriptorForUnqualifiedThis() {
return null;
}
@NotNull
@Override
public Collection<DeclarationDescriptor> getAllDescriptors() {
@@ -109,12 +109,6 @@ public class SubstitutingScope implements JetScope {
throw new UnsupportedOperationException(); // TODO
}
@Override
@Nullable
public DeclarationDescriptor getDeclarationDescriptorForUnqualifiedThis() {
return workerScope.getDeclarationDescriptorForUnqualifiedThis();
}
@NotNull
@Override
public Collection<DeclarationDescriptor> getAllDescriptors() {
@@ -1,10 +1,12 @@
package org.jetbrains.jet.lang.resolve.scopes;
import com.google.common.collect.*;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.util.CommonSuppliers;
@@ -51,14 +53,6 @@ public class WritableScopeImpl extends WritableScopeWithImports {
return ownerDeclarationDescriptor;
}
@Override
public DeclarationDescriptor getDeclarationDescriptorForUnqualifiedThis() {
if (DescriptorUtils.definesItsOwnThis(ownerDeclarationDescriptor)) {
return ownerDeclarationDescriptor;
}
return super.getDeclarationDescriptorForUnqualifiedThis();
}
@Override
public void importScope(@NotNull JetScope imported) {
super.importScope(imported);
@@ -2,12 +2,13 @@ package org.jetbrains.jet.lang.resolve.scopes.receivers;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.types.JetType;
/**
* @author abreslav
*/
public class ClassReceiver implements ReceiverDescriptor {
public class ClassReceiver implements ThisReceiverDescriptor {
private final ClassDescriptor classDescriptor;
@@ -26,6 +27,12 @@ public class ClassReceiver implements ReceiverDescriptor {
return classDescriptor.getDefaultType();
}
@NotNull
@Override
public DeclarationDescriptor getDeclarationDescriptor() {
return classDescriptor;
}
@Override
public <R, D> R accept(@NotNull ReceiverDescriptorVisitor<R, D> visitor, D data) {
return visitor.visitClassReceiver(this, data);
@@ -2,15 +2,25 @@ package org.jetbrains.jet.lang.resolve.scopes.receivers;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.types.JetType;
/**
* @author abreslav
*/
public class ExtensionReceiver extends ImplicitReceiverDescriptor {
public class ExtensionReceiver extends AbstractReceiverDescriptor implements ThisReceiverDescriptor {
private final CallableDescriptor descriptor;
public ExtensionReceiver(@NotNull CallableDescriptor callableDescriptor, @NotNull JetType receiverType) {
super(callableDescriptor, receiverType);
super(receiverType);
this.descriptor = callableDescriptor;
}
@NotNull
@Override
public DeclarationDescriptor getDeclarationDescriptor() {
return descriptor;
}
@Override
@@ -1,25 +0,0 @@
package org.jetbrains.jet.lang.resolve.scopes.receivers;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.types.JetType;
/**
* Describes a "this" receiver
*
* @author abreslav
*/
public abstract class ImplicitReceiverDescriptor extends AbstractReceiverDescriptor {
private final DeclarationDescriptor declarationDescriptor;
protected ImplicitReceiverDescriptor(@NotNull DeclarationDescriptor declarationDescriptor, @NotNull JetType receiverType) {
super(receiverType);
this.declarationDescriptor = declarationDescriptor;
}
@NotNull
public DeclarationDescriptor getDeclarationDescriptor() {
return declarationDescriptor;
}
}
@@ -0,0 +1,15 @@
package org.jetbrains.jet.lang.resolve.scopes.receivers;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
/**
* Describes a "this" receiver
*
* @author abreslav
*/
public interface ThisReceiverDescriptor extends ReceiverDescriptor {
@NotNull
DeclarationDescriptor getDeclarationDescriptor();
}
@@ -64,11 +64,6 @@ public class ErrorUtils {
return null; // TODO : review
}
@Override
public DeclarationDescriptor getDeclarationDescriptorForUnqualifiedThis() {
return ERROR_CLASS; // TODO : review
}
@NotNull
@Override
public Collection<DeclarationDescriptor> getAllDescriptors() {
@@ -39,12 +39,12 @@ public class JetStandardClasses {
@Override
public Iterator<JetType> iterator() {
throw new UnsupportedOperationException();
throw new UnsupportedOperationException("Don't enumerate supertypes of Nothing");
}
@Override
public int size() {
throw new UnsupportedOperationException();
throw new UnsupportedOperationException("Supertypes of Nothing do not constitute a valid collection");
}
},
JetScope.EMPTY,
@@ -278,8 +278,13 @@ public class JetStandardClasses {
}
public static boolean isNothing(@NotNull JetType type) {
return !(type instanceof NamespaceType) &&
type.getConstructor() == NOTHING_CLASS.getTypeConstructor();
return isNothingOrNullableNothing(type)
&& !type.isNullable();
}
public static boolean isNothingOrNullableNothing(@NotNull JetType type) {
return !(type instanceof NamespaceType)
&& type.getConstructor() == NOTHING_CLASS.getTypeConstructor();
}
public static boolean isUnit(@NotNull JetType type) {
@@ -81,7 +81,7 @@ public class JetTypeChecker {
JetType type = iterator.next();
assert type != null;
// TODO : This admits 'Nothing?'. Review
if (JetStandardClasses.isNothing(type)) {
if (JetStandardClasses.isNothingOrNullableNothing(type)) {
iterator.remove();
}
nullable |= type.isNullable();
@@ -564,7 +564,7 @@ public class JetTypeChecker {
if (!supertype.isNullable() && subtype.isNullable()) {
return fail();
}
if (JetStandardClasses.isNothing(subtype)) {
if (JetStandardClasses.isNothingOrNullableNothing(subtype)) {
return StatusAction.DONE_WITH_CURRENT_TYPE;
}
return StatusAction.PROCEED;
@@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.types.expressions;
import com.google.common.collect.Lists;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -10,13 +11,15 @@ import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.CallMaker;
import org.jetbrains.jet.lang.resolve.calls.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.constants.*;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ClassReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ThisReceiverDescriptor;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lexer.JetTokens;
@@ -49,7 +52,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
}
else {
context.trace.record(REFERENCE_TARGET, expression, property);
return checkType(property.getOutType(), expression, context);
return DataFlowUtils.checkType(property.getOutType(), expression, context);
}
}
else {
@@ -74,14 +77,14 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (result == null) {
return ErrorUtils.createErrorType("No class object in " + expression.getReferencedName());
}
return checkType(result, expression, context);
return DataFlowUtils.checkType(result, expression, context);
}
}
JetType[] result = new JetType[1];
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace);
if (furtherNameLookup(expression, referencedName, result, context.replaceBindingTrace(temporaryTrace))) {
temporaryTrace.commit();
return checkType(result[0], expression, context);
return DataFlowUtils.checkType(result[0], expression, context);
}
// To report NO_CLASS_OBJECT when no namespace found
if (classifier != null) {
@@ -122,7 +125,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (innerExpression == null) {
return null;
}
return checkType(facade.getType(innerExpression, context.replaceScope(context.scope)), expression, context);
return DataFlowUtils.checkType(facade.getType(innerExpression, context.replaceScope(context.scope)), expression, context);
}
@Override
@@ -162,7 +165,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
}
else {
context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, value);
return checkType(value.getType(standardLibrary), expression, context);
return DataFlowUtils.checkType(value.getType(standardLibrary), expression, context);
}
}
@@ -197,7 +200,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
else {
facade.getType(expression.getLeft(), context.replaceExpectedType(NO_EXPECTED_TYPE));
}
return checkType(result, expression, context);
return DataFlowUtils.checkType(result, expression, context);
}
private boolean checkBinaryWithTypeRHS(JetBinaryExpressionWithTypeRHS expression, ExpressionTypingContext context, @NotNull JetType targetType, @NotNull JetType expectedType, TemporaryBindingTrace temporaryTrace) {
@@ -259,7 +262,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
}
}
// TODO : labels
return checkType(JetStandardClasses.getTupleType(types), expression, context);
return DataFlowUtils.checkType(JetStandardClasses.getTupleType(types), expression, context);
}
@NotNull
@@ -269,7 +272,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
}
List<JetType> result = Lists.newArrayListWithCapacity(arguments.size());
for (int i = 0, argumentTypesSize = argumentTypes.size(); i < argumentTypesSize; i++) {
result.add(checkType(argumentTypes.get(i), arguments.get(i), context.replaceExpectedType(expectedArgumentTypes.get(i).getType())));
result.add(DataFlowUtils.checkType(argumentTypes.get(i), arguments.get(i), context.replaceExpectedType(expectedArgumentTypes.get(i).getType())));
}
return result;
}
@@ -277,60 +280,130 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
@Override
public JetType visitThisExpression(JetThisExpression expression, ExpressionTypingContext context) {
JetType result = null;
ReceiverDescriptor thisReceiver = null;
String labelName = expression.getLabelName();
if (labelName != null) {
thisReceiver = context.labelResolver.resolveThisLabel(expression, context, thisReceiver, labelName);
}
else {
thisReceiver = context.scope.getImplicitReceiver();
DeclarationDescriptor declarationDescriptorForUnqualifiedThis = context.scope.getDeclarationDescriptorForUnqualifiedThis();
if (declarationDescriptorForUnqualifiedThis != null) {
context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptorForUnqualifiedThis);
}
}
ReceiverDescriptor thisReceiver = resolveToReceiver(expression, context, false);
if (thisReceiver != null) {
if (!thisReceiver.exists()) {
context.trace.report(NO_THIS.on(expression));
}
else {
JetTypeReference superTypeQualifier = expression.getSuperTypeQualifier();
if (superTypeQualifier != null) {
JetTypeElement superTypeElement = superTypeQualifier.getTypeElement();
// Errors are reported by the parser
if (superTypeElement instanceof JetUserType) {
JetUserType typeElement = (JetUserType) superTypeElement;
result = thisReceiver.getType();
context.trace.record(BindingContext.EXPRESSION_TYPE, expression.getInstanceReference(), result);
}
}
return DataFlowUtils.checkType(result, expression, context);
}
ClassifierDescriptor classifierCandidate = context.getTypeResolver().resolveClass(context.scope, typeElement);
if (classifierCandidate instanceof ClassDescriptor) {
ClassDescriptor superclass = (ClassDescriptor) classifierCandidate;
@Override
public JetType visitSuperExpression(JetSuperExpression expression, ExpressionTypingContext context) {
if (!context.namespacesAllowed) {
context.trace.report(SUPER_IS_NOT_AN_EXPRESSION.on(expression, expression.getText()));
return null;
}
JetType result = null;
JetType thisType = thisReceiver.getType();
Collection<? extends JetType> supertypes = thisType.getConstructor().getSupertypes();
TypeSubstitutor substitutor = TypeSubstitutor.create(thisType);
for (JetType declaredSupertype : supertypes) {
if (declaredSupertype.getConstructor().equals(superclass.getTypeConstructor())) {
result = substitutor.safeSubstitute(declaredSupertype, Variance.INVARIANT);
break;
}
}
if (result == null) {
context.trace.report(NOT_A_SUPERTYPE.on(superTypeElement));
}
}
ReceiverDescriptor thisReceiver = resolveToReceiver(expression, context, true);
if (thisReceiver == null) return null;
if (!thisReceiver.exists()) {
context.trace.report(SUPER_NOT_AVAILABLE.on(expression));
}
else {
JetType thisType = thisReceiver.getType();
Collection<? extends JetType> supertypes = thisType.getConstructor().getSupertypes();
TypeSubstitutor substitutor = TypeSubstitutor.create(thisType);
JetTypeReference superTypeQualifier = expression.getSuperTypeQualifier();
if (superTypeQualifier != null) {
JetTypeElement typeElement = superTypeQualifier.getTypeElement();
DeclarationDescriptor classifierCandidate = null;
JetType supertype = null;
PsiElement redundantTypeArguments = null;
if (typeElement instanceof JetUserType) {
JetUserType userType = (JetUserType) typeElement;
// This may be just a superclass name even if the superclass is generic
if (userType.getTypeArguments().isEmpty()) {
classifierCandidate = context.getTypeResolver().resolveClass(context.scope, userType);
}
else {
supertype = context.getTypeResolver().resolveType(context.scope, superTypeQualifier);
redundantTypeArguments = userType.getTypeArgumentList();
}
}
else {
result = thisReceiver.getType();
supertype = context.getTypeResolver().resolveType(context.scope, superTypeQualifier);
}
if (result != null) {
context.trace.record(BindingContext.EXPRESSION_TYPE, expression.getThisReference(), result);
if (supertype != null) {
if (supertypes.contains(supertype)) {
result = supertype;
}
}
else if (classifierCandidate instanceof ClassDescriptor) {
ClassDescriptor superclass = (ClassDescriptor) classifierCandidate;
for (JetType declaredSupertype : supertypes) {
if (declaredSupertype.getConstructor().equals(superclass.getTypeConstructor())) {
result = substitutor.safeSubstitute(declaredSupertype, Variance.INVARIANT);
break;
}
}
}
boolean validClassifier = classifierCandidate != null && !ErrorUtils.isError(classifierCandidate);
boolean validType = supertype != null && !ErrorUtils.isErrorType(supertype);
if (result == null && (validClassifier || validType)) {
context.trace.report(NOT_A_SUPERTYPE.on(superTypeQualifier));
}
else if (redundantTypeArguments != null) {
context.trace.report(TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER.on(redundantTypeArguments));
}
}
else {
if (supertypes.size() > 1) {
context.trace.report(AMBIGUOUS_SUPER.on(expression));
}
else {
// supertypes may be empty when all the supertypes are error types (are not resolved, for example)
JetType type = supertypes.isEmpty() ? JetStandardClasses.getAnyType() : supertypes.iterator().next();
result = substitutor.substitute(type, Variance.INVARIANT);
}
}
if (result != null) {
context.trace.record(BindingContext.EXPRESSION_TYPE, expression.getInstanceReference(), result);
context.trace.record(BindingContext.REFERENCE_TARGET, expression.getInstanceReference(), result.getConstructor().getDeclarationDescriptor());
}
}
return checkType(result, expression, context);
return DataFlowUtils.checkType(result, expression, context);
}
@Nullable // No class receivers
private ReceiverDescriptor resolveToReceiver(JetLabelQualifiedInstanceExpression expression, ExpressionTypingContext context, boolean onlyClassReceivers) {
ReceiverDescriptor thisReceiver = null;
String labelName = expression.getLabelName();
if (labelName != null) {
thisReceiver = context.labelResolver.resolveThisLabel(expression.getInstanceReference(), expression.getTargetLabel(), context, thisReceiver, labelName);
}
else {
if (onlyClassReceivers) {
List<ReceiverDescriptor> receivers = Lists.newArrayList();
context.scope.getImplicitReceiversHierarchy(receivers);
for (ReceiverDescriptor receiver : receivers) {
if (receiver instanceof ClassReceiver) {
thisReceiver = receiver;
break;
}
}
}
else {
thisReceiver = context.scope.getImplicitReceiver();
}
if (thisReceiver instanceof ThisReceiverDescriptor) {
context.trace.record(REFERENCE_TARGET, expression.getInstanceReference(), ((ThisReceiverDescriptor) thisReceiver).getDeclarationDescriptor());
}
}
return thisReceiver;
}
@Override
@@ -386,7 +459,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (result != null) {
context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, result);
}
return checkType(result, expression, contextWithExpectedType);
return DataFlowUtils.checkType(result, expression, contextWithExpectedType);
}
private void propagateConstantValues(JetQualifiedExpression expression, ExpressionTypingContext context, JetSimpleNameExpression selectorExpression) {
@@ -432,14 +505,14 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
VariableDescriptor variableDescriptor = context.replaceBindingTrace(temporaryTrace).resolveSimpleProperty(receiver, callOperationNode, nameExpression);
if (variableDescriptor != null) {
temporaryTrace.commit();
return checkType(variableDescriptor.getOutType(), nameExpression, context);
return DataFlowUtils.checkType(variableDescriptor.getOutType(), nameExpression, context);
}
ExpressionTypingContext newContext = receiver.exists() ? context.replaceScope(receiver.getType().getMemberScope()) : context;
JetType jetType = lookupNamespaceOrClassObject(nameExpression, nameExpression.getReferencedName(), newContext);
if (jetType == null) {
context.trace.report(UNRESOLVED_REFERENCE.on(nameExpression));
}
return checkType(jetType, nameExpression, context);
return DataFlowUtils.checkType(jetType, nameExpression, context);
}
else if (selectorExpression instanceof JetQualifiedExpression) {
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) selectorExpression;
@@ -460,7 +533,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
@Override
public JetType visitCallExpression(JetCallExpression expression, ExpressionTypingContext context) {
JetType expressionType = context.resolveCall(NO_RECEIVER, null, expression);
return checkType(expressionType, expression, context);
return DataFlowUtils.checkType(expressionType, expression, context);
}
@Override
@@ -473,7 +546,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
referencedName = referencedName == null ? " <?>" : referencedName;
context.labelResolver.enterLabeledElement(referencedName.substring(1), baseExpression);
// TODO : Some processing for the label?
JetType type = checkType(facade.getType(baseExpression, context.replaceExpectedReturnType(context.expectedType)), expression, context);
JetType type = DataFlowUtils.checkType(facade.getType(baseExpression, context.replaceExpectedReturnType(context.expectedType)), expression, context);
context.labelResolver.exitLabeledElement(baseExpression);
return type;
}
@@ -516,7 +589,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
result = returnType;
}
return checkType(result, expression, context);
return DataFlowUtils.checkType(result, expression, context);
}
@Override
@@ -599,7 +672,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
else if (operationType == JetTokens.ANDAND || operationType == JetTokens.OROR) {
JetType leftType = facade.getType(left, context.replaceScope(context.scope));
WritableScopeImpl leftScope = newWritableScopeImpl(context).setDebugName("Left scope of && or ||");
DataFlowInfo flowInfoLeft = extractDataFlowInfoFromCondition(left, operationType == JetTokens.ANDAND, leftScope, context); // TODO: This gets computed twice: here and in extractDataFlowInfoFromCondition() for the whole condition
DataFlowInfo flowInfoLeft = DataFlowUtils.extractDataFlowInfoFromCondition(left, operationType == JetTokens.ANDAND, leftScope, context); // TODO: This gets computed twice: here and in extractDataFlowInfoFromCondition() for the whole condition
WritableScopeImpl rightScope = operationType == JetTokens.ANDAND ? leftScope : newWritableScopeImpl(context).setDebugName("Right scope of && or ||");
JetType rightType = right == null ? null : facade.getType(right, context.replaceDataFlowInfo(flowInfoLeft).replaceScope(rightScope));
if (leftType != null && !isBoolean(context.semanticServices, leftType)) {
@@ -618,7 +691,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(USELESS_ELVIS.on(expression, left, leftType));
}
if (rightType != null) {
checkType(TypeUtils.makeNullableAsSpecified(leftType, rightType.isNullable()), left, contextWithExpectedType);
DataFlowUtils.checkType(TypeUtils.makeNullableAsSpecified(leftType, rightType.isNullable()), left, contextWithExpectedType);
return TypeUtils.makeNullableAsSpecified(context.semanticServices.getTypeChecker().commonSupertype(leftType, rightType), rightType.isNullable());
}
}
@@ -626,7 +699,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
else {
context.trace.report(UNSUPPORTED.on(operationSign, "Unknown operation"));
}
return checkType(result, expression, contextWithExpectedType);
return DataFlowUtils.checkType(result, expression, contextWithExpectedType);
}
public void checkInExpression(JetElement callElement, @NotNull JetSimpleNameExpression operationSign, @NotNull JetExpression left, @NotNull JetExpression right, ExpressionTypingContext context) {
@@ -685,7 +758,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
"get",
receiver);
if (functionDescriptor != null) {
return checkType(functionDescriptor.getReturnType(), expression, contextWithExpectedType);
return DataFlowUtils.checkType(functionDescriptor.getReturnType(), expression, contextWithExpectedType);
}
}
return null;
@@ -714,7 +787,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
@Override
public JetType visitRootNamespaceExpression(JetRootNamespaceExpression expression, ExpressionTypingContext context) {
if (context.namespacesAllowed) {
return ExpressionTypingUtils.checkType(JetModuleUtil.getRootNamespaceType(expression), expression, context);
return DataFlowUtils.checkType(JetModuleUtil.getRootNamespaceType(expression), expression, context);
}
context.trace.report(NAMESPACE_IS_NOT_AN_EXPRESSION.on(expression));
return null;
@@ -764,7 +837,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (value[0] != CompileTimeConstantResolver.OUT_OF_RANGE) {
context.trace.record(BindingContext.COMPILE_TIME_VALUE, expression, new StringValue(builder.toString()));
}
return checkType(context.semanticServices.getStandardLibrary().getStringType(), expression, contextWithExpectedType);
return DataFlowUtils.checkType(context.semanticServices.getStandardLibrary().getStringType(), expression, contextWithExpectedType);
}
@Override
@@ -55,7 +55,7 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
ObservableBindingTrace traceAdapter = new ObservableBindingTrace(context.trace);
traceAdapter.addHandler(CLASS, handler);
TopDownAnalyzer.processObject(context.semanticServices, traceAdapter, context.scope, context.scope.getContainingDeclaration(), expression.getObjectDeclaration());
return ExpressionTypingUtils.checkType(result[0], expression, context);
return DataFlowUtils.checkType(result[0], expression, context);
}
@Override
@@ -152,11 +152,11 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
JetType expectedReturnType = JetStandardClasses.getReturnType(expectedType);
if (JetStandardClasses.isUnit(expectedReturnType)) {
functionDescriptor.setReturnType(expectedReturnType);
return ExpressionTypingUtils.checkType(JetStandardClasses.getFunctionType(Collections.<AnnotationDescriptor>emptyList(), effectiveReceiverType, parameterTypes, expectedReturnType), expression, context);
return DataFlowUtils.checkType(JetStandardClasses.getFunctionType(Collections.<AnnotationDescriptor>emptyList(), effectiveReceiverType, parameterTypes, expectedReturnType), expression, context);
}
}
return ExpressionTypingUtils.checkType(JetStandardClasses.getFunctionType(Collections.<AnnotationDescriptor>emptyList(), effectiveReceiverType, parameterTypes, safeReturnType), expression, context);
return DataFlowUtils.checkType(JetStandardClasses.getFunctionType(Collections.<AnnotationDescriptor>emptyList(), effectiveReceiverType, parameterTypes, safeReturnType), expression, context);
}
}
@@ -7,7 +7,7 @@ import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.calls.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
@@ -65,8 +65,8 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
JetExpression thenBranch = expression.getThen();
WritableScopeImpl thenScope = newWritableScopeImpl(context).setDebugName("Then scope");
DataFlowInfo thenInfo = extractDataFlowInfoFromCondition(condition, true, thenScope, context);
DataFlowInfo elseInfo = extractDataFlowInfoFromCondition(condition, false, null, context);
DataFlowInfo thenInfo = DataFlowUtils.extractDataFlowInfoFromCondition(condition, true, thenScope, context);
DataFlowInfo elseInfo = DataFlowUtils.extractDataFlowInfoFromCondition(condition, false, null, context);
if (elseBranch == null) {
if (thenBranch != null) {
@@ -75,7 +75,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
facade.setResultingDataFlowInfo(elseInfo);
// resultScope = elseScope;
}
return checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType);
return DataFlowUtils.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType);
}
return null;
}
@@ -85,7 +85,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
facade.setResultingDataFlowInfo(thenInfo);
// resultScope = thenScope;
}
return checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType);
return DataFlowUtils.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType);
}
JetType thenType = getTypeWithNewScopeAndDataFlowInfo(thenScope, thenBranch, thenInfo, contextWithExpectedType);
JetType elseType = getTypeWithNewScopeAndDataFlowInfo(context.scope, elseBranch, elseInfo, contextWithExpectedType);
@@ -121,13 +121,13 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
JetExpression body = expression.getBody();
if (body != null) {
WritableScopeImpl scopeToExtend = newWritableScopeImpl(context).setDebugName("Scope extended in while's condition");
DataFlowInfo conditionInfo = condition == null ? context.dataFlowInfo : extractDataFlowInfoFromCondition(condition, true, scopeToExtend, context);
DataFlowInfo conditionInfo = condition == null ? context.dataFlowInfo : DataFlowUtils.extractDataFlowInfoFromCondition(condition, true, scopeToExtend, context);
getTypeWithNewScopeAndDataFlowInfo(scopeToExtend, body, conditionInfo, context);
}
if (!containsBreak(expression, context)) {
facade.setResultingDataFlowInfo(extractDataFlowInfoFromCondition(condition, false, null, context));
facade.setResultingDataFlowInfo(DataFlowUtils.extractDataFlowInfoFromCondition(condition, false, null, context));
}
return checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType);
return DataFlowUtils.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType);
}
private boolean containsBreak(final JetLoopExpression loopExpression, final ExpressionTypingContext context) {
@@ -178,9 +178,9 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
JetExpression condition = expression.getCondition();
checkCondition(conditionScope, condition, context);
if (!containsBreak(expression, context)) {
facade.setResultingDataFlowInfo(extractDataFlowInfoFromCondition(condition, false, null, context));
facade.setResultingDataFlowInfo(DataFlowUtils.extractDataFlowInfoFromCondition(condition, false, null, context));
}
return checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType);
return DataFlowUtils.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType);
}
@Override
@@ -225,7 +225,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
facade.getType(body, context.replaceScope(loopScope));
}
return checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType);
return DataFlowUtils.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType);
}
@Nullable
@@ -372,7 +372,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
JetType type = facade.getType(thrownExpression, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceScope(context.scope));
// TODO : check that it inherits Throwable
}
return checkType(JetStandardClasses.getNothingType(), expression, context);
return DataFlowUtils.checkType(JetStandardClasses.getNothingType(), expression, context);
}
@Override
@@ -395,19 +395,19 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(RETURN_TYPE_MISMATCH.on(expression, context.expectedReturnType));
}
}
return checkType(JetStandardClasses.getNothingType(), expression, context);
return DataFlowUtils.checkType(JetStandardClasses.getNothingType(), expression, context);
}
@Override
public JetType visitBreakExpression(JetBreakExpression expression, ExpressionTypingContext context) {
context.labelResolver.recordLabel(expression, context);
return checkType(JetStandardClasses.getNothingType(), expression, context);
return DataFlowUtils.checkType(JetStandardClasses.getNothingType(), expression, context);
}
@Override
public JetType visitContinueExpression(JetContinueExpression expression, ExpressionTypingContext context) {
context.labelResolver.recordLabel(expression, context);
return checkType(JetStandardClasses.getNothingType(), expression, context);
return DataFlowUtils.checkType(JetStandardClasses.getNothingType(), expression, context);
}
@@ -0,0 +1,157 @@
package org.jetbrains.jet.lang.types.expressions;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValue;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValueFactory;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeChecker;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.List;
import static org.jetbrains.jet.lang.diagnostics.Errors.AUTOCAST_IMPOSSIBLE;
import static org.jetbrains.jet.lang.diagnostics.Errors.TYPE_MISMATCH;
import static org.jetbrains.jet.lang.resolve.BindingContext.AUTOCAST;
/**
* @author abreslav
*/
public class DataFlowUtils {
@NotNull
public static DataFlowInfo extractDataFlowInfoFromCondition(@Nullable JetExpression condition, final boolean conditionValue, @Nullable final WritableScope scopeToExtend, final ExpressionTypingContext context) {
if (condition == null) return context.dataFlowInfo;
final Ref<DataFlowInfo> result = new Ref<DataFlowInfo>(context.dataFlowInfo);
condition.accept(new JetVisitorVoid() {
@Override
public void visitIsExpression(JetIsExpression expression) {
if (conditionValue && !expression.isNegated() || !conditionValue && expression.isNegated()) {
JetPattern pattern = expression.getPattern();
result.set(context.patternsToDataFlowInfo.get(pattern));
if (scopeToExtend != null) {
List<VariableDescriptor> descriptors = context.patternsToBoundVariableLists.get(pattern);
if (descriptors != null) {
for (VariableDescriptor variableDescriptor : descriptors) {
scopeToExtend.addVariableDescriptor(variableDescriptor);
}
}
}
}
}
@Override
public void visitBinaryExpression(JetBinaryExpression expression) {
IElementType operationToken = expression.getOperationToken();
if (operationToken == JetTokens.ANDAND || operationToken == JetTokens.OROR) {
WritableScope actualScopeToExtend;
if (operationToken == JetTokens.ANDAND) {
actualScopeToExtend = conditionValue ? scopeToExtend : null;
}
else {
actualScopeToExtend = conditionValue ? null : scopeToExtend;
}
DataFlowInfo dataFlowInfo = extractDataFlowInfoFromCondition(expression.getLeft(), conditionValue, actualScopeToExtend, context);
JetExpression expressionRight = expression.getRight();
if (expressionRight != null) {
DataFlowInfo rightInfo = extractDataFlowInfoFromCondition(expressionRight, conditionValue, actualScopeToExtend, context);
DataFlowInfo.CompositionOperator operator;
if (operationToken == JetTokens.ANDAND) {
operator = conditionValue ? DataFlowInfo.AND : DataFlowInfo.OR;
}
else {
operator = conditionValue ? DataFlowInfo.OR : DataFlowInfo.AND;
}
dataFlowInfo = operator.compose(dataFlowInfo, rightInfo);
}
result.set(dataFlowInfo);
}
else {
JetExpression left = expression.getLeft();
JetExpression right = expression.getRight();
if (right == null) return;
JetType lhsType = context.trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, left);
if (lhsType == null) return;
JetType rhsType = context.trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, right);
if (rhsType == null) return;
BindingContext bindingContext = context.trace.getBindingContext();
DataFlowValue leftValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(left, lhsType, bindingContext);
DataFlowValue rightValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(right, rhsType, bindingContext);
Boolean equals = null;
if (operationToken == JetTokens.EQEQ || operationToken == JetTokens.EQEQEQ) {
equals = true;
}
else if (operationToken == JetTokens.EXCLEQ || operationToken == JetTokens.EXCLEQEQEQ) {
equals = false;
}
if (equals != null) {
if (equals == conditionValue) { // this means: equals && conditionValue || !equals && !conditionValue
result.set(context.dataFlowInfo.equate(leftValue, rightValue));
}
else {
result.set(context.dataFlowInfo.disequate(leftValue, rightValue));
}
}
}
}
@Override
public void visitUnaryExpression(JetUnaryExpression expression) {
IElementType operationTokenType = expression.getOperationSign().getReferencedNameElementType();
if (operationTokenType == JetTokens.EXCL) {
JetExpression baseExpression = expression.getBaseExpression();
if (baseExpression != null) {
result.set(extractDataFlowInfoFromCondition(baseExpression, !conditionValue, scopeToExtend, context));
}
}
}
@Override
public void visitParenthesizedExpression(JetParenthesizedExpression expression) {
JetExpression body = expression.getExpression();
if (body != null) {
body.accept(this);
}
}
});
if (result.get() == null) {
return context.dataFlowInfo;
}
return result.get();
}
@Nullable
public static JetType checkType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ExpressionTypingContext context) {
if (expressionType == null || context.expectedType == null || context.expectedType == TypeUtils.NO_EXPECTED_TYPE ||
context.semanticServices.getTypeChecker().isSubtypeOf(expressionType, context.expectedType)) {
return expressionType;
}
DataFlowValue dataFlowValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(expression, expressionType, context.trace.getBindingContext());
for (JetType possibleType : context.dataFlowInfo.getPossibleTypes(dataFlowValue)) {
if (JetTypeChecker.INSTANCE.isSubtypeOf(possibleType, context.expectedType)) {
if (dataFlowValue.isStableIdentifier()) {
context.trace.record(AUTOCAST, expression, possibleType);
}
else {
context.trace.report(AUTOCAST_IMPOSSIBLE.on(expression, possibleType, expression.getText()));
}
return possibleType;
}
}
context.trace.report(TYPE_MISMATCH.on(expression, context.expectedType, expressionType));
return expressionType;
}
}
@@ -12,7 +12,7 @@ import org.jetbrains.jet.lang.resolve.ClassDescriptorResolver;
import org.jetbrains.jet.lang.resolve.TypeResolver;
import org.jetbrains.jet.lang.resolve.calls.CallMaker;
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
import org.jetbrains.jet.lang.resolve.calls.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
@@ -65,6 +65,7 @@ import java.util.Map;
public final Map<JetPattern, List<VariableDescriptor>> patternsToBoundVariableLists;
public final LabelResolver labelResolver;
// true for positions on the lhs of a '.', i.e. allows namespace results and 'super'
public final boolean namespacesAllowed;
private CallResolver callResolver;
@@ -6,7 +6,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.resolve.calls.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
@@ -14,7 +14,7 @@ import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.diagnostics.DiagnosticWithPsiElement;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
@@ -56,7 +56,7 @@ public class ExpressionTypingServices {
ExpressionTypingContext context = ExpressionTypingContext.newContext(
semanticServices,
new HashMap<JetPattern, DataFlowInfo>(), new HashMap<JetPattern, List<VariableDescriptor>>(), new LabelResolver(),
trace, scope, DataFlowInfo.getEmpty(), expectedType, FORBIDDEN, false
trace, scope, DataFlowInfo.EMPTY, expectedType, FORBIDDEN, false
);
return expressionTypingFacade.getType(expression, context);
}
@@ -65,14 +65,14 @@ public class ExpressionTypingServices {
ExpressionTypingContext context = ExpressionTypingContext.newContext(
semanticServices,
new HashMap<JetPattern, DataFlowInfo>(), new HashMap<JetPattern, List<VariableDescriptor>>(), new LabelResolver(),
trace, scope, DataFlowInfo.getEmpty(), NO_EXPECTED_TYPE, FORBIDDEN,
trace, scope, DataFlowInfo.EMPTY, NO_EXPECTED_TYPE, FORBIDDEN,
true);
return expressionTypingFacade.getType(expression, context);
// return ((ExpressionTypingContext) ExpressionTyperVisitorWithNamespaces).INSTANCE.getType(expression, ExpressionTypingContext.newRootContext(semanticServices, trace, scope, DataFlowInfo.getEmpty(), TypeUtils.NO_EXPECTED_TYPE, TypeUtils.NO_EXPECTED_TYPE));
}
public void checkFunctionReturnType(@NotNull JetScope outerScope, @NotNull JetDeclarationWithBody function, @NotNull FunctionDescriptor functionDescriptor) {
checkFunctionReturnType(outerScope, function, functionDescriptor, DataFlowInfo.getEmpty());
checkFunctionReturnType(outerScope, function, functionDescriptor, DataFlowInfo.EMPTY);
}
@NotNull
@@ -87,7 +87,7 @@ public class ExpressionTypingServices {
public void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, @NotNull final JetType expectedReturnType) {
checkFunctionReturnType(function, ExpressionTypingContext.newContext(
semanticServices, new HashMap<JetPattern, DataFlowInfo>(), new HashMap<JetPattern, List<VariableDescriptor>>(), new LabelResolver(),
trace, functionInnerScope, DataFlowInfo.getEmpty(), NO_EXPECTED_TYPE, expectedReturnType, false
trace, functionInnerScope, DataFlowInfo.EMPTY, NO_EXPECTED_TYPE, expectedReturnType, false
));
}
@@ -128,7 +128,7 @@ public class ExpressionTypingServices {
/*package*/ JetType getBlockReturnedType(@NotNull JetScope outerScope, @NotNull JetBlockExpression expression, @NotNull CoercionStrategy coercionStrategyForLastExpression, ExpressionTypingContext context) {
List<JetElement> block = expression.getStatements();
if (block.isEmpty()) {
return ExpressionTypingUtils.checkType(JetStandardClasses.getUnitType(), expression, context);
return DataFlowUtils.checkType(JetStandardClasses.getUnitType(), expression, context);
}
DeclarationDescriptor containingDescriptor = outerScope.getContainingDeclaration();
@@ -145,7 +145,7 @@ public class ExpressionTypingServices {
assert bodyExpression != null;
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace);
expressionTypingFacade.getType(bodyExpression, ExpressionTypingContext.newContext(semanticServices, new HashMap<JetPattern, DataFlowInfo>(), new HashMap<JetPattern, List<VariableDescriptor>>(), new LabelResolver(),
trace, functionInnerScope, DataFlowInfo.getEmpty(), NO_EXPECTED_TYPE, FORBIDDEN, false));
trace, functionInnerScope, DataFlowInfo.EMPTY, NO_EXPECTED_TYPE, FORBIDDEN, false));
//todo function literals
final Collection<JetExpression> returnedExpressions = Lists.newArrayList();
if (function.hasBlockBody()) {
@@ -9,23 +9,16 @@ import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.resolve.TraceBasedRedeclarationHandler;
import org.jetbrains.jet.lang.resolve.calls.AutoCastUtils;
import org.jetbrains.jet.lang.resolve.calls.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValueFactory;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.List;
import static org.jetbrains.jet.lang.diagnostics.Errors.RESULT_TYPE_MISMATCH;
import static org.jetbrains.jet.lang.diagnostics.Errors.TYPE_MISMATCH;
import static org.jetbrains.jet.lang.resolve.BindingContext.MUST_BE_WRAPPED_IN_A_REF;
/**
@@ -97,140 +90,6 @@ public class ExpressionTypingUtils {
}
}
@NotNull
public static DataFlowInfo extractDataFlowInfoFromCondition(@Nullable JetExpression condition, final boolean conditionValue, @Nullable final WritableScope scopeToExtend, final ExpressionTypingContext context) {
if (condition == null) return context.dataFlowInfo;
final DataFlowInfo[] result = new DataFlowInfo[] {context.dataFlowInfo};
condition.accept(new JetVisitorVoid() {
@Override
public void visitIsExpression(JetIsExpression expression) {
if (conditionValue && !expression.isNegated() || !conditionValue && expression.isNegated()) {
JetPattern pattern = expression.getPattern();
result[0] = context.patternsToDataFlowInfo.get(pattern);
if (scopeToExtend != null) {
List<VariableDescriptor> descriptors = context.patternsToBoundVariableLists.get(pattern);
if (descriptors != null) {
for (VariableDescriptor variableDescriptor : descriptors) {
scopeToExtend.addVariableDescriptor(variableDescriptor);
}
}
}
}
}
@Override
public void visitBinaryExpression(JetBinaryExpression expression) {
IElementType operationToken = expression.getOperationToken();
if (operationToken == JetTokens.ANDAND || operationToken == JetTokens.OROR) {
WritableScope actualScopeToExtend;
if (operationToken == JetTokens.ANDAND) {
actualScopeToExtend = conditionValue ? scopeToExtend : null;
}
else {
actualScopeToExtend = conditionValue ? null : scopeToExtend;
}
DataFlowInfo dataFlowInfo = extractDataFlowInfoFromCondition(expression.getLeft(), conditionValue, actualScopeToExtend, context);
JetExpression expressionRight = expression.getRight();
if (expressionRight != null) {
DataFlowInfo rightInfo = extractDataFlowInfoFromCondition(expressionRight, conditionValue, actualScopeToExtend, context);
DataFlowInfo.CompositionOperator operator;
if (operationToken == JetTokens.ANDAND) {
operator = conditionValue ? DataFlowInfo.AND : DataFlowInfo.OR;
}
else {
operator = conditionValue ? DataFlowInfo.OR : DataFlowInfo.AND;
}
dataFlowInfo = operator.compose(dataFlowInfo, rightInfo);
}
result[0] = dataFlowInfo;
}
else if (operationToken == JetTokens.EQEQ
|| operationToken == JetTokens.EXCLEQ
|| operationToken == JetTokens.EQEQEQ
|| operationToken == JetTokens.EXCLEQEQEQ) {
JetExpression left = expression.getLeft();
JetExpression right = expression.getRight();
if (right == null) return;
if (!(left instanceof JetSimpleNameExpression)) {
JetExpression tmp = left;
left = right;
right = tmp;
if (!(left instanceof JetSimpleNameExpression)) {
return;
}
}
VariableDescriptor variableDescriptor = AutoCastUtils.getVariableDescriptorFromSimpleName(context.trace.getBindingContext(), left);
if (variableDescriptor == null) return;
// TODO : validate that DF makes sense for this variable: local, val, internal w/backing field, etc
// Comparison to a non-null expression
JetType rhsType = context.trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, right);
if (rhsType != null && !rhsType.isNullable()) {
extendDataFlowWithNullComparison(operationToken, variableDescriptor, !conditionValue);
return;
}
VariableDescriptor rightVariable = AutoCastUtils.getVariableDescriptorFromSimpleName(context.trace.getBindingContext(), right);
if (rightVariable != null) {
JetType lhsType = context.trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, left);
if (lhsType != null && !lhsType.isNullable()) {
extendDataFlowWithNullComparison(operationToken, rightVariable, !conditionValue);
return;
}
}
// Comparison to 'null'
if (!(right instanceof JetConstantExpression)) {
return;
}
JetConstantExpression constantExpression = (JetConstantExpression) right;
if (constantExpression.getNode().getElementType() != JetNodeTypes.NULL) {
return;
}
extendDataFlowWithNullComparison(operationToken, variableDescriptor, conditionValue);
}
}
private void extendDataFlowWithNullComparison(IElementType operationToken, @NotNull VariableDescriptor variableDescriptor, boolean equalsToNull) {
if (operationToken == JetTokens.EQEQ || operationToken == JetTokens.EQEQEQ) {
result[0] = context.dataFlowInfo.equalsToNull(variableDescriptor, !equalsToNull);
}
else if (operationToken == JetTokens.EXCLEQ || operationToken == JetTokens.EXCLEQEQEQ) {
result[0] = context.dataFlowInfo.equalsToNull(variableDescriptor, equalsToNull);
}
}
@Override
public void visitUnaryExpression(JetUnaryExpression expression) {
IElementType operationTokenType = expression.getOperationSign().getReferencedNameElementType();
if (operationTokenType == JetTokens.EXCL) {
JetExpression baseExpression = expression.getBaseExpression();
if (baseExpression != null) {
result[0] = extractDataFlowInfoFromCondition(baseExpression, !conditionValue, scopeToExtend, context);
}
}
}
@Override
public void visitParenthesizedExpression(JetParenthesizedExpression expression) {
JetExpression body = expression.getExpression();
if (body != null) {
body.accept(this);
}
}
});
if (result[0] == null) {
return context.dataFlowInfo;
}
return result[0];
}
public static boolean isTypeFlexible(@Nullable JetExpression expression) {
if (expression == null) return false;
@@ -240,23 +99,10 @@ public class ExpressionTypingUtils {
).contains(expression.getNode().getElementType());
}
@Nullable
public static JetType checkType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ExpressionTypingContext context) {
if (expressionType == null || context.expectedType == null || context.expectedType == TypeUtils.NO_EXPECTED_TYPE ||
context.semanticServices.getTypeChecker().isSubtypeOf(expressionType, context.expectedType)) {
return expressionType;
}
if (AutoCastUtils.castExpression(expression, context.expectedType, context.dataFlowInfo, context.trace) == null) {
context.trace.report(TYPE_MISMATCH.on(expression, context.expectedType, expressionType));
return expressionType;
}
return context.expectedType;
}
public static void checkWrappingInRef(JetExpression expression, ExpressionTypingContext context) {
if (!(expression instanceof JetSimpleNameExpression)) return;
JetSimpleNameExpression simpleName = (JetSimpleNameExpression) expression;
VariableDescriptor variable = AutoCastUtils.getVariableDescriptorFromSimpleName(context.trace.getBindingContext(), simpleName);
VariableDescriptor variable = DataFlowValueFactory.getVariableDescriptorFromSimpleName(context.trace.getBindingContext(), simpleName);
if (variable != null) {
DeclarationDescriptor containingDeclaration = variable.getContainingDeclaration();
if (context.scope.getContainingDeclaration() != containingDeclaration && containingDeclaration instanceof CallableDescriptor) {
@@ -6,7 +6,7 @@ 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.calls.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.DeferredType;
@@ -164,7 +164,7 @@ public class ExpressionTypingVisitorWithWritableScope extends BasicExpressionTyp
"set", receiver);
if (functionDescriptor == null) return null;
context.trace.record(REFERENCE_TARGET, operationSign, functionDescriptor);
return ExpressionTypingUtils.checkType(functionDescriptor.getReturnType(), arrayAccessExpression, context);
return DataFlowUtils.checkType(functionDescriptor.getReturnType(), arrayAccessExpression, context);
}
@Override
@@ -106,10 +106,9 @@ public class LabelResolver {
return result;
}
public ReceiverDescriptor resolveThisLabel(JetThisExpression expression, ExpressionTypingContext context, ReceiverDescriptor thisReceiver, String labelName) {
public ReceiverDescriptor resolveThisLabel(JetReferenceExpression thisReference, JetSimpleNameExpression targetLabel, ExpressionTypingContext 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();
@@ -127,7 +126,7 @@ public class LabelResolver {
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);
context.trace.record(REFERENCE_TARGET, thisReference, declarationDescriptor);
}
else if (size == 0) {
JetElement element = resolveNamedLabel(labelName, targetLabel, false, context);
@@ -137,7 +136,7 @@ public class LabelResolver {
thisReceiver = ((FunctionDescriptor) declarationDescriptor).getReceiverParameter();
if (thisReceiver.exists()) {
context.trace.record(LABEL_TARGET, targetLabel, element);
context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor);
context.trace.record(REFERENCE_TARGET, thisReference, declarationDescriptor);
}
}
else {
@@ -2,12 +2,14 @@ package org.jetbrains.jet.lang.types.expressions;
import com.google.common.collect.Sets;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.Ref;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.calls.AutoCastUtils;
import org.jetbrains.jet.lang.resolve.calls.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValue;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValueFactory;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
@@ -19,8 +21,6 @@ import java.util.List;
import java.util.Set;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.diagnostics.Errors.INCOMPATIBLE_TYPES;
import static org.jetbrains.jet.lang.diagnostics.Errors.UNSUPPORTED;
import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.ensureBooleanResultWithCustomSubject;
import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.newWritableScopeImpl;
@@ -35,15 +35,16 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
@Override
public JetType visitIsExpression(JetIsExpression expression, ExpressionTypingContext contextWithExpectedType) {
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE);
JetType knownType = facade.safeGetType(expression.getLeftHandSide(), context.replaceScope(context.scope));
JetExpression leftHandSide = expression.getLeftHandSide();
JetType knownType = facade.safeGetType(leftHandSide, context.replaceScope(context.scope));
JetPattern pattern = expression.getPattern();
if (pattern != null) {
WritableScopeImpl scopeToExtend = newWritableScopeImpl(context).setDebugName("Scope extended in 'is'");
DataFlowInfo newDataFlowInfo = checkPatternType(pattern, knownType, scopeToExtend, context, AutoCastUtils.getVariableDescriptorFromSimpleName(context.trace.getBindingContext(), expression.getLeftHandSide()));
DataFlowInfo newDataFlowInfo = checkPatternType(pattern, knownType, scopeToExtend, context, DataFlowValueFactory.INSTANCE.createDataFlowValue(leftHandSide, knownType, context.trace.getBindingContext()));
context.patternsToDataFlowInfo.put(pattern, newDataFlowInfo);
context.patternsToBoundVariableLists.put(pattern, scopeToExtend.getDeclaredVariables());
}
return ExpressionTypingUtils.checkType(context.semanticServices.getStandardLibrary().getBooleanType(), expression, contextWithExpectedType);
return DataFlowUtils.checkType(context.semanticServices.getStandardLibrary().getBooleanType(), expression, contextWithExpectedType);
}
@Override
@@ -53,7 +54,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
final JetExpression subjectExpression = expression.getSubjectExpression();
final JetType subjectType = subjectExpression != null ? context.getServices().safeGetType(context.scope, subjectExpression, TypeUtils.NO_EXPECTED_TYPE) : ErrorUtils.createErrorType("Unknown type");
final VariableDescriptor variableDescriptor = subjectExpression != null ? AutoCastUtils.getVariableDescriptorFromSimpleName(context.trace.getBindingContext(), subjectExpression) : null;
final DataFlowValue variableDescriptor = subjectExpression != null ? DataFlowValueFactory.INSTANCE.createDataFlowValue(subjectExpression, subjectType, context.trace.getBindingContext()) : null;
// TODO : exhaustive patterns
@@ -108,7 +109,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
return null;
}
private DataFlowInfo checkWhenCondition(@Nullable final JetExpression subjectExpression, final JetType subjectType, JetWhenCondition condition, final WritableScope scopeToExtend, final ExpressionTypingContext context, final VariableDescriptor... subjectVariables) {
private DataFlowInfo checkWhenCondition(@Nullable final JetExpression subjectExpression, final JetType subjectType, JetWhenCondition condition, final WritableScope scopeToExtend, final ExpressionTypingContext context, final DataFlowValue... subjectVariables) {
final DataFlowInfo[] newDataFlowInfo = new DataFlowInfo[]{context.dataFlowInfo};
condition.accept(new JetVisitorVoid() {
@@ -151,8 +152,8 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
return newDataFlowInfo[0];
}
private DataFlowInfo checkPatternType(@NotNull JetPattern pattern, @NotNull final JetType subjectType, @NotNull final WritableScope scopeToExtend, final ExpressionTypingContext context, @NotNull final VariableDescriptor... subjectVariables) {
final DataFlowInfo[] result = new DataFlowInfo[] {context.dataFlowInfo};
private DataFlowInfo checkPatternType(@NotNull JetPattern pattern, @NotNull final JetType subjectType, @NotNull final WritableScope scopeToExtend, final ExpressionTypingContext context, @NotNull final DataFlowValue... subjectVariables) {
final Ref<DataFlowInfo> result = new Ref<DataFlowInfo>(context.dataFlowInfo);
pattern.accept(new JetVisitorVoid() {
@Override
public void visitTypePattern(JetTypePattern typePattern) {
@@ -160,7 +161,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
if (typeReference != null) {
JetType type = context.getTypeResolver().resolveType(context.scope, typeReference);
checkTypeCompatibility(type, subjectType, typePattern);
result[0] = context.dataFlowInfo.isInstanceOf(subjectVariables, type);
result.set(context.dataFlowInfo.establishSubtyping(subjectVariables, type));
}
}
@@ -187,7 +188,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
JetPattern entryPattern = entry.getPattern();
if (entryPattern != null) {
result[0] = result[0].and(checkPatternType(entryPattern, type, scopeToExtend, context));
result.set(result.get().and(checkPatternType(entryPattern, type, scopeToExtend, context)));
}
}
}
@@ -200,7 +201,9 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
ReceiverDescriptor receiver = new TransientReceiver(subjectType);
JetType selectorReturnType = facade.getSelectorReturnType(receiver, null, decomposerExpression, context);
result[0] = checkPatternType(pattern.getArgumentList(), selectorReturnType == null ? ErrorUtils.createErrorType("No type") : selectorReturnType, scopeToExtend, context);
result.set(checkPatternType(pattern.getArgumentList(), selectorReturnType == null
? ErrorUtils.createErrorType("No type")
: selectorReturnType, scopeToExtend, context));
}
}
@@ -235,10 +238,10 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
JetWhenCondition condition = pattern.getCondition();
if (condition != null) {
int oldLength = subjectVariables.length;
VariableDescriptor[] newSubjectVariables = new VariableDescriptor[oldLength + 1];
DataFlowValue[] newSubjectVariables = new DataFlowValue[oldLength + 1];
System.arraycopy(subjectVariables, 0, newSubjectVariables, 0, oldLength);
newSubjectVariables[oldLength] = variableDescriptor;
result[0] = checkWhenCondition(null, subjectType, condition, scopeToExtend, context, newSubjectVariables);
newSubjectVariables[oldLength] = DataFlowValueFactory.INSTANCE.createDataFlowValue(variableDescriptor);
result.set(checkWhenCondition(null, subjectType, condition, scopeToExtend, context, newSubjectVariables));
}
}
@@ -259,7 +262,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(UNSUPPORTED.on(element, getClass().getCanonicalName()));
}
});
return result[0];
return result.get();
}
}
@@ -168,6 +168,7 @@ LONG_TEMPLATE_ENTRY_END=\}
"trait" { return JetTokens.TRAIT_KEYWORD ;}
"throw" { return JetTokens.THROW_KEYWORD ;}
"false" { return JetTokens.FALSE_KEYWORD ;}
"super" { return JetTokens.SUPER_KEYWORD ;}
"when" { return JetTokens.WHEN_KEYWORD ;}
"true" { return JetTokens.TRUE_KEYWORD ;}
"type" { return JetTokens.TYPE_KEYWORD ;}
@@ -36,6 +36,7 @@ public interface JetTokens {
JetKeywordToken TYPE_KEYWORD = JetKeywordToken.keyword("type");
JetKeywordToken CLASS_KEYWORD = JetKeywordToken.keyword("class");
JetKeywordToken THIS_KEYWORD = JetKeywordToken.keyword("this");
JetKeywordToken SUPER_KEYWORD = JetKeywordToken.keyword("super");
JetKeywordToken VAL_KEYWORD = JetKeywordToken.keyword("val");
JetKeywordToken VAR_KEYWORD = JetKeywordToken.keyword("var");
JetKeywordToken FUN_KEYWORD = JetKeywordToken.keyword("fun");
@@ -145,7 +146,7 @@ public interface JetTokens {
JetKeywordToken REF_KEYWORD = JetKeywordToken.softKeyword("ref");
TokenSet KEYWORDS = TokenSet.create(NAMESPACE_KEYWORD, AS_KEYWORD, TYPE_KEYWORD, CLASS_KEYWORD, TRAIT_KEYWORD,
THIS_KEYWORD, VAL_KEYWORD, VAR_KEYWORD, FUN_KEYWORD, FOR_KEYWORD,
THIS_KEYWORD, SUPER_KEYWORD, VAL_KEYWORD, VAR_KEYWORD, FUN_KEYWORD, FOR_KEYWORD,
NULL_KEYWORD,
TRUE_KEYWORD, FALSE_KEYWORD, IS_KEYWORD,
IN_KEYWORD, THROW_KEYWORD, RETURN_KEYWORD, BREAK_KEYWORD, CONTINUE_KEYWORD, OBJECT_KEYWORD, IF_KEYWORD,
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More