Merge branch 'master' of ssh://git.labs.intellij.net/jet
Conflicts: compiler/tests/org/jetbrains/jet/cfg/JetControlFlowTest.java
This commit is contained in:
Generated
+1
@@ -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
-2
@@ -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
|
||||
-5
@@ -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();
|
||||
|
||||
|
||||
+11
@@ -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) {
|
||||
|
||||
+4
-4
@@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+20
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+9
-9
@@ -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();
|
||||
}
|
||||
|
||||
+8
-8
@@ -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);
|
||||
|
||||
|
||||
+2
-2
@@ -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) {
|
||||
|
||||
+2
-2
@@ -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
-1
@@ -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;
|
||||
+109
@@ -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;
|
||||
// }
|
||||
|
||||
}
|
||||
+390
@@ -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);
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//}
|
||||
+72
@@ -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;
|
||||
}
|
||||
}
|
||||
+156
@@ -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);
|
||||
|
||||
+8
-1
@@ -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);
|
||||
|
||||
+12
-2
@@ -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
|
||||
|
||||
-25
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+15
@@ -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;
|
||||
|
||||
+133
-60
@@ -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
|
||||
|
||||
+3
-3
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+15
-15
@@ -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;
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -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;
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
|
||||
+7
-7
@@ -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()) {
|
||||
|
||||
+4
-158
@@ -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) {
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+1
-1
@@ -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 {
|
||||
|
||||
+21
-18
@@ -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
Reference in New Issue
Block a user