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());
}
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());
arguments.add(rightHandSide);
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());
}
@@ -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>, Collection<TypeParameterDescriptor>> UNKNOWNS = Slices.createSimpleSlice();
static {
BasicWritableSlice.initSliceDebugNames(ResolutionDebugInfo.class);
}
public static boolean RESOLUTION_DEBUG_INFO_ENABLED = false;
public static boolean isResolutionDebugEnabled() {
@@ -113,4 +109,8 @@ public class ResolutionDebugInfo {
System.out.println(message);
}
}
static {
BasicWritableSlice.initSliceDebugNames(ResolutionDebugInfo.class);
}
}
@@ -30,8 +30,7 @@ import org.jetbrains.jet.lexer.JetTokens;
import java.util.*;
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.REFERENCE_TARGET;
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
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.expressions.ExpressionTypingUtils.*;
@@ -662,8 +661,26 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(UNSUPPORTED.on(operationSign, "visitUnaryExpression"));
return null;
}
ExpressionReceiver receiver = getExpressionReceiver(facade, baseExpression, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceScope(context.scope));
if (receiver == null) return null;
JetType type = 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(
CallMaker.makeCall(receiver, expression),
@@ -891,6 +908,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
return DataFlowUtils.checkType(results.getResultingDescriptor().getReturnType(), expression, contextWithExpectedType);
}
}
context.trace.report(NO_GET_METHOD.on(expression.getIndicesNode()));
return null;
}
@@ -981,4 +999,45 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(UNSUPPORTED.on(element, getClass().getCanonicalName()));
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;
import com.intellij.openapi.project.Project;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
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.VariableDescriptor;
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.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.TraceBasedRedeclarationHandler;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
@@ -20,20 +23,22 @@ import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
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
*/
public class ExpressionTypingUtils {
@Nullable
protected static ExpressionReceiver getExpressionReceiver(@NotNull JetExpression expression, @Nullable JetType type) {
if (type == null) return null;
return new ExpressionReceiver(expression, type);
}
@Nullable
protected static ExpressionReceiver getExpressionReceiver(@NotNull ExpressionTypingFacade facade, @NotNull JetExpression expression, ExpressionTypingContext context) {
JetType type = facade.getType(expression, context);
if (type == null) {
return null;
}
return new ExpressionReceiver(expression, type);
return getExpressionReceiver(expression, facade.getType(expression, context));
}
@NotNull
@@ -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.TemporaryBindingTrace;
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.WritableScope;
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 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.types.expressions.ExpressionTypingUtils.getExpressionReceiver;
/**
* @author abreslav
@@ -161,7 +156,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
if (left instanceof JetArrayAccessExpression) {
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);
if (assignmentOperationType != null) {
@@ -201,7 +196,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
JetExpression right = expression.getRight();
if (left instanceof JetArrayAccessExpression) {
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);
return checkAssignmentType(assignmentType, expression, contextWithExpectedType);
}
@@ -218,33 +213,6 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
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
public JetType visitExpression(JetExpression expression, ExpressionTypingContext context) {
@@ -37,7 +37,7 @@ fun test4() : Boolean {
return true
}
fun test5() : Boolean {
/*fun test5() : Boolean {
var mnr = Array<MyNumber>(2,{MyNumber(42)})
mnr[0]++
if (mnr[0].i != 43) return false
@@ -52,7 +52,6 @@ fun test6() : Boolean {
return true
}
/*
fun test7() : Boolean {
var mnr = ArrayList<MyNumber>()
mnr.add(MyNumber(42))
@@ -79,9 +78,9 @@ fun box() : String {
if (!test2()) return "fail test 2"
if (!test3()) return "fail test 3"
if (!test4()) return "fail test 4"
/*
if (!test5()) return "fail test 5"
if (!test6()) return "fail test 6"
/*
if (!test7()) return "fail test 7"
if (!test8()) return "fail test 8"