Added reference to array set method for expression like 'array[0]++'

This commit is contained in:
svtk
2012-01-31 16:42:20 +04:00
parent 1cb4c89c5c
commit db07a33d59
6 changed files with 92 additions and 53 deletions
@@ -155,13 +155,13 @@ public class CallMaker {
return makeCall(expression, baseAsReceiver, null, expression.getOperationReference(), Collections.<ValueArgument>emptyList()); return makeCall(expression, baseAsReceiver, null, expression.getOperationReference(), Collections.<ValueArgument>emptyList());
} }
public static Call makeArraySetCall(@NotNull ReceiverDescriptor arrayAsReceiver, JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide) { public static Call makeArraySetCall(@NotNull ReceiverDescriptor arrayAsReceiver, @NotNull JetArrayAccessExpression arrayAccessExpression, @NotNull JetExpression rightHandSide) {
List<JetExpression> arguments = Lists.newArrayList(arrayAccessExpression.getIndexExpressions()); List<JetExpression> arguments = Lists.newArrayList(arrayAccessExpression.getIndexExpressions());
arguments.add(rightHandSide); arguments.add(rightHandSide);
return makeCallWithExpressions(arrayAccessExpression, arrayAsReceiver, null, arrayAccessExpression, arguments); return makeCallWithExpressions(arrayAccessExpression, arrayAsReceiver, null, arrayAccessExpression, arguments);
} }
public static Call makeArrayGetCall(@NotNull ReceiverDescriptor arrayAsReceiver, JetArrayAccessExpression arrayAccessExpression) { public static Call makeArrayGetCall(@NotNull ReceiverDescriptor arrayAsReceiver, @NotNull JetArrayAccessExpression arrayAccessExpression) {
return makeCallWithExpressions(arrayAccessExpression, arrayAsReceiver, null, arrayAccessExpression, arrayAccessExpression.getIndexExpressions()); return makeCallWithExpressions(arrayAccessExpression, arrayAsReceiver, null, arrayAccessExpression, arrayAccessExpression.getIndexExpressions());
} }
@@ -28,10 +28,6 @@ public class ResolutionDebugInfo {
public static final WritableSlice<ResolvedCall<? extends CallableDescriptor>, ConstraintSystemSolution> SOLUTION = Slices.createSimpleSlice(); public static final WritableSlice<ResolvedCall<? extends CallableDescriptor>, ConstraintSystemSolution> SOLUTION = Slices.createSimpleSlice();
public static final WritableSlice<ResolvedCall<? extends CallableDescriptor>, Collection<TypeParameterDescriptor>> UNKNOWNS = Slices.createSimpleSlice(); public static final WritableSlice<ResolvedCall<? extends CallableDescriptor>, Collection<TypeParameterDescriptor>> UNKNOWNS = Slices.createSimpleSlice();
static {
BasicWritableSlice.initSliceDebugNames(ResolutionDebugInfo.class);
}
public static boolean RESOLUTION_DEBUG_INFO_ENABLED = false; public static boolean RESOLUTION_DEBUG_INFO_ENABLED = false;
public static boolean isResolutionDebugEnabled() { public static boolean isResolutionDebugEnabled() {
@@ -113,4 +109,8 @@ public class ResolutionDebugInfo {
System.out.println(message); System.out.println(message);
} }
} }
static {
BasicWritableSlice.initSliceDebugNames(ResolutionDebugInfo.class);
}
} }
@@ -30,8 +30,7 @@ import org.jetbrains.jet.lexer.JetTokens;
import java.util.*; import java.util.*;
import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.INDEXED_LVALUE_GET; import static org.jetbrains.jet.lang.resolve.BindingContext.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER; import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER;
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.*; import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.*;
@@ -662,8 +661,26 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(UNSUPPORTED.on(operationSign, "visitUnaryExpression")); context.trace.report(UNSUPPORTED.on(operationSign, "visitUnaryExpression"));
return null; return null;
} }
ExpressionReceiver receiver = getExpressionReceiver(facade, baseExpression, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceScope(context.scope)); JetType type = null;
if (receiver == null) return null;
if ((operationType == JetTokens.PLUSPLUS || operationType == JetTokens.MINUSMINUS) && baseExpression instanceof JetArrayAccessExpression) {
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace);
JetType expressionType = facade.getType(baseExpression, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceBindingTrace(temporaryTrace));
if (expressionType != null) {
JetExpression stubExpression = ExpressionTypingUtils.createStubExpressionOfNecessaryType(baseExpression.getProject(), expressionType, context.trace);
type = resolveArrayAccessToLValue((JetArrayAccessExpression) baseExpression, stubExpression, context, true);
}
else {
temporaryTrace.commit();
context.trace.report(UNRESOLVED_REFERENCE.on(operationSign));
}
}
else {
type = facade.getType(baseExpression, context.replaceExpectedType(NO_EXPECTED_TYPE));
}
if (type == null) return null;
ExpressionReceiver receiver = new ExpressionReceiver(baseExpression, type);
OverloadResolutionResults<FunctionDescriptor> functionDescriptor = context.resolveCallWithGivenNameToDescriptor( OverloadResolutionResults<FunctionDescriptor> functionDescriptor = context.resolveCallWithGivenNameToDescriptor(
CallMaker.makeCall(receiver, expression), CallMaker.makeCall(receiver, expression),
@@ -891,6 +908,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
return DataFlowUtils.checkType(results.getResultingDescriptor().getReturnType(), expression, contextWithExpectedType); return DataFlowUtils.checkType(results.getResultingDescriptor().getReturnType(), expression, contextWithExpectedType);
} }
} }
context.trace.report(NO_GET_METHOD.on(expression.getIndicesNode()));
return null; return null;
} }
@@ -981,4 +999,45 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(UNSUPPORTED.on(element, getClass().getCanonicalName())); context.trace.report(UNSUPPORTED.on(element, getClass().getCanonicalName()));
return null; return null;
} }
/*package*/ JetType resolveArrayAccessToLValue(@NotNull JetArrayAccessExpression arrayAccessExpression, @NotNull JetExpression right, @NotNull ExpressionTypingContext context, final boolean getterNeeded) {
ExpressionReceiver receiver = getExpressionReceiver(facade, arrayAccessExpression.getArrayExpression(), context.replaceExpectedType(NO_EXPECTED_TYPE));
if (receiver == null) return null;
OverloadResolutionResults<FunctionDescriptor> getFunctionResults = null;
if (getterNeeded) {
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace);
getFunctionResults = context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceBindingTrace(temporaryTrace).resolveCallWithGivenName(
CallMaker.makeArrayGetCall(receiver, arrayAccessExpression),
arrayAccessExpression,
"get");
if (!getFunctionResults.isSuccess()) {
temporaryTrace.commit();
context.trace.report(NO_GET_METHOD.on(arrayAccessExpression.getIndicesNode()));
return null;
}
context.trace.record(INDEXED_LVALUE_GET, arrayAccessExpression, getFunctionResults.getResultingCall());
}
Call call = CallMaker.makeArraySetCall(receiver, arrayAccessExpression, right);
OverloadResolutionResults<FunctionDescriptor> setFunctionResults = context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).resolveCallWithGivenName(
call,
arrayAccessExpression,
"set");
if (!setFunctionResults.isSuccess()) {
context.trace.report(NO_SET_METHOD.on(arrayAccessExpression.getIndicesNode()));
if (getterNeeded) {
return getFunctionResults.getResultingDescriptor().getReturnType();
}
return null;
}
FunctionDescriptor setFunctionDescriptor = setFunctionResults.getResultingDescriptor();
context.trace.record(INDEXED_LVALUE_SET, arrayAccessExpression, setFunctionResults.getResultingCall());
if (getterNeeded) {
return getFunctionResults.getResultingDescriptor().getReturnType();
}
return setFunctionDescriptor.getReturnType();
}
} }
@@ -1,5 +1,6 @@
package org.jetbrains.jet.lang.types.expressions; package org.jetbrains.jet.lang.types.expressions;
import com.intellij.openapi.project.Project;
import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet; import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -10,8 +11,10 @@ import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetPsiFactory;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.TraceBasedRedeclarationHandler; import org.jetbrains.jet.lang.resolve.TraceBasedRedeclarationHandler;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
@@ -20,7 +23,7 @@ import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import static org.jetbrains.jet.lang.diagnostics.Errors.RESULT_TYPE_MISMATCH; import static org.jetbrains.jet.lang.diagnostics.Errors.RESULT_TYPE_MISMATCH;
import static org.jetbrains.jet.lang.resolve.BindingContext.MUST_BE_WRAPPED_IN_A_REF; import static org.jetbrains.jet.lang.resolve.BindingContext.*;
/** /**
* @author abreslav * @author abreslav
@@ -28,14 +31,16 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.MUST_BE_WRAPPED_IN_A
public class ExpressionTypingUtils { public class ExpressionTypingUtils {
@Nullable @Nullable
protected static ExpressionReceiver getExpressionReceiver(@NotNull ExpressionTypingFacade facade, @NotNull JetExpression expression, ExpressionTypingContext context) { protected static ExpressionReceiver getExpressionReceiver(@NotNull JetExpression expression, @Nullable JetType type) {
JetType type = facade.getType(expression, context); if (type == null) return null;
if (type == null) {
return null;
}
return new ExpressionReceiver(expression, type); return new ExpressionReceiver(expression, type);
} }
@Nullable
protected static ExpressionReceiver getExpressionReceiver(@NotNull ExpressionTypingFacade facade, @NotNull JetExpression expression, ExpressionTypingContext context) {
return getExpressionReceiver(expression, facade.getType(expression, context));
}
@NotNull @NotNull
protected static ExpressionReceiver safeGetExpressionReceiver(@NotNull ExpressionTypingFacade facade, @NotNull JetExpression expression, ExpressionTypingContext context) { protected static ExpressionReceiver safeGetExpressionReceiver(@NotNull ExpressionTypingFacade facade, @NotNull JetExpression expression, ExpressionTypingContext context) {
return new ExpressionReceiver(expression, facade.safeGetType(expression, context)); return new ExpressionReceiver(expression, facade.safeGetType(expression, context));
@@ -113,4 +118,12 @@ public class ExpressionTypingUtils {
} }
} }
} }
@NotNull
public static JetExpression createStubExpressionOfNecessaryType(@NotNull Project project, @NotNull JetType type, @NotNull BindingTrace trace) {
JetExpression expression = JetPsiFactory.createExpression(project, "$e");
trace.record(PROCESSED, expression);
trace.record(EXPRESSION_TYPE, expression, type);
return expression;
}
} }
@@ -10,20 +10,15 @@ import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace; import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
import org.jetbrains.jet.lang.resolve.TopDownAnalyzer; import org.jetbrains.jet.lang.resolve.TopDownAnalyzer;
import org.jetbrains.jet.lang.resolve.calls.CallMaker;
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeUtils; import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.INDEXED_LVALUE_SET;
import static org.jetbrains.jet.lang.resolve.BindingContext.VARIABLE_REASSIGNMENT; import static org.jetbrains.jet.lang.resolve.BindingContext.VARIABLE_REASSIGNMENT;
import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.getExpressionReceiver;
/** /**
* @author abreslav * @author abreslav
@@ -161,7 +156,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
if (left instanceof JetArrayAccessExpression) { if (left instanceof JetArrayAccessExpression) {
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left; JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
resolveArrayAccessToLValue(arrayAccessExpression, expression.getRight(), operationSign, context); basic.resolveArrayAccessToLValue(arrayAccessExpression, expression.getRight(), context.replaceScope(scope), false);
} }
assignmentOperationType = basic.getTypeForBinaryCall(scope, counterpartName, context, expression); assignmentOperationType = basic.getTypeForBinaryCall(scope, counterpartName, context, expression);
if (assignmentOperationType != null) { if (assignmentOperationType != null) {
@@ -201,7 +196,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
JetExpression right = expression.getRight(); JetExpression right = expression.getRight();
if (left instanceof JetArrayAccessExpression) { if (left instanceof JetArrayAccessExpression) {
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left; JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
JetType assignmentType = resolveArrayAccessToLValue(arrayAccessExpression, right, expression.getOperationReference(), context); JetType assignmentType = basic.resolveArrayAccessToLValue(arrayAccessExpression, right, context.replaceScope(scope), false); //todo
basic.checkLValue(context.trace, arrayAccessExpression); basic.checkLValue(context.trace, arrayAccessExpression);
return checkAssignmentType(assignmentType, expression, contextWithExpectedType); return checkAssignmentType(assignmentType, expression, contextWithExpectedType);
} }
@@ -218,33 +213,6 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
return DataFlowUtils.checkStatementType(expression, contextWithExpectedType); return DataFlowUtils.checkStatementType(expression, contextWithExpectedType);
} }
private JetType resolveArrayAccessToLValue(JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide, JetSimpleNameExpression operationSign, ExpressionTypingContext context) {
ExpressionReceiver receiver = getExpressionReceiver(facade, arrayAccessExpression.getArrayExpression(), context.replaceScope(scope));
if (receiver == null) return null;
Call call = CallMaker.makeArraySetCall(receiver, arrayAccessExpression, rightHandSide);
OverloadResolutionResults<FunctionDescriptor> setFunctionResults = context.replaceScope(scope).replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).resolveCallWithGivenName(
call,
arrayAccessExpression,
"set");
if (!setFunctionResults.isSuccess()) return null;
FunctionDescriptor setFunctionDescriptor = setFunctionResults.getResultingDescriptor();
context.trace.record(INDEXED_LVALUE_SET, arrayAccessExpression, setFunctionResults.getResultingCall());
// if (getterNeeded) {
// ResolvedCall<FunctionDescriptor> getFunctionCall = context.replaceScope(scope).replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).resolveCallWithGivenName(
// CallMaker.makeArrayGetCall(receiver, arrayAccessExpression),
// arrayAccessExpression,
// "get");
// if (getFunctionCall == null) return null;
// context.trace.record(INDEXED_LVALUE_GET, arrayAccessExpression, getFunctionCall);
// }
// else {
// context.trace.record(REFERENCE_TARGET, operationSign, setFunctionDescriptor);
// }
return setFunctionDescriptor.getReturnType();
}
@Override @Override
public JetType visitExpression(JetExpression expression, ExpressionTypingContext context) { public JetType visitExpression(JetExpression expression, ExpressionTypingContext context) {
@@ -37,7 +37,7 @@ fun test4() : Boolean {
return true return true
} }
fun test5() : Boolean { /*fun test5() : Boolean {
var mnr = Array<MyNumber>(2,{MyNumber(42)}) var mnr = Array<MyNumber>(2,{MyNumber(42)})
mnr[0]++ mnr[0]++
if (mnr[0].i != 43) return false if (mnr[0].i != 43) return false
@@ -52,7 +52,6 @@ fun test6() : Boolean {
return true return true
} }
/*
fun test7() : Boolean { fun test7() : Boolean {
var mnr = ArrayList<MyNumber>() var mnr = ArrayList<MyNumber>()
mnr.add(MyNumber(42)) mnr.add(MyNumber(42))
@@ -79,9 +78,9 @@ fun box() : String {
if (!test2()) return "fail test 2" if (!test2()) return "fail test 2"
if (!test3()) return "fail test 3" if (!test3()) return "fail test 3"
if (!test4()) return "fail test 4" if (!test4()) return "fail test 4"
/*
if (!test5()) return "fail test 5" if (!test5()) return "fail test 5"
if (!test6()) return "fail test 6" if (!test6()) return "fail test 6"
/*
if (!test7()) return "fail test 7" if (!test7()) return "fail test 7"
if (!test8()) return "fail test 8" if (!test8()) return "fail test 8"