Avoid resolving array-set method several times

While origin problem was in NI, it's also nice to have this change in OI
 in order to slightly improve performance

 #KT-33125 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2019-09-03 19:38:23 +03:00
parent f8449bf15a
commit e21da3a61a
8 changed files with 87 additions and 11 deletions
@@ -797,7 +797,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
context.trace.record(BindingContext.VARIABLE_REASSIGNMENT, expression);
KtExpression stubExpression = ExpressionTypingUtils.createFakeExpressionOfType(
baseExpression.getProject(), context.trace, "e", type);
checkLValue(context.trace, context, baseExpression, stubExpression, expression);
checkLValue(context.trace, context, baseExpression, stubExpression, expression, false);
}
// x++ type is x type, but ++x type is x.inc() type
DataFlowValue receiverValue = components.dataFlowValueFactory.createDataFlowValue(
@@ -930,7 +930,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
@NotNull ExpressionTypingContext context,
@NotNull KtExpression expressionWithParenthesis,
@Nullable KtExpression rightHandSide,
@NotNull KtOperationExpression operationExpression
@NotNull KtOperationExpression operationExpression,
boolean arraySetMethodAlreadyResolved
) {
KtExpression expression = KtPsiUtil.deparenthesize(expressionWithParenthesis);
if (expression instanceof KtArrayAccessExpression) {
@@ -938,14 +939,24 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
KtExpression arrayExpression = arrayAccessExpression.getArrayExpression();
if (arrayExpression == null || rightHandSide == null) return false;
TemporaryBindingTrace ignoreReportsTrace = TemporaryBindingTrace.create(trace, "Trace for checking set function");
ExpressionTypingContext findSetterContext = context.replaceBindingTrace(ignoreReportsTrace);
KotlinTypeInfo info = resolveArrayAccessSetMethod(arrayAccessExpression, rightHandSide, findSetterContext, ignoreReportsTrace);
BindingTrace traceWithIndexedLValue;
boolean methodSetIsResolved;
if (!arraySetMethodAlreadyResolved) {
TemporaryBindingTrace ignoreReportsTrace = TemporaryBindingTrace.create(trace, "Trace for checking set function");
ExpressionTypingContext findSetterContext = context.replaceBindingTrace(ignoreReportsTrace);
KotlinTypeInfo info = resolveArrayAccessSetMethod(arrayAccessExpression, rightHandSide, findSetterContext, ignoreReportsTrace);
traceWithIndexedLValue = ignoreReportsTrace;
methodSetIsResolved = info.getType() != null;
} else {
traceWithIndexedLValue = trace;
methodSetIsResolved = true;
}
IElementType operationType = operationExpression.getOperationReference().getReferencedNameElementType();
if (KtTokens.AUGMENTED_ASSIGNMENTS.contains(operationType)
|| operationType == KtTokens.PLUSPLUS || operationType == KtTokens.MINUSMINUS) {
ResolvedCall<?> resolvedCall = ignoreReportsTrace.get(INDEXED_LVALUE_SET, expression);
ResolvedCall<?> resolvedCall = traceWithIndexedLValue.get(INDEXED_LVALUE_SET, expression);
if (resolvedCall != null && trace.wantsDiagnostics()) {
// Call must be validated with the actual, not temporary trace in order to report operator diagnostic
// Only unary assignment expressions (++, --) and +=/... must be checked, normal assignments have the proper trace
@@ -957,7 +968,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
}
}
return info.getType() != null;
return methodSetIsResolved;
}
VariableDescriptor variable = BindingContextUtils.extractVariableDescriptorFromReference(trace.getBindingContext(), expression);
@@ -233,7 +233,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
TemporaryTraceAndCache temporaryForBinaryOperation = TemporaryTraceAndCache.create(
context, "trace to check binary operation like '+' for", expression);
TemporaryBindingTrace ignoreReportsTrace = TemporaryBindingTrace.create(context.trace, "Trace for checking assignability");
boolean lhsAssignable = basic.checkLValue(ignoreReportsTrace, context, left, right, expression);
boolean lhsAssignable = basic.checkLValue(ignoreReportsTrace, context, left, right, expression, false);
if (assignmentOperationType == null || lhsAssignable) {
// Check for '+'
Name counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType));
@@ -291,7 +291,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
components.dataFlowAnalyzer.checkType(binaryOperationType, expression, context.replaceExpectedType(expectedType)
.replaceDataFlowInfo(rightInfo.getDataFlowInfo()).replaceCallPosition(new CallPosition.PropertyAssignment(left)));
basic.checkLValue(context.trace, context, leftOperand, right, expression);
basic.checkLValue(context.trace, context, leftOperand, right, expression, false);
}
temporary.commit();
return rightInfo.replaceType(checkAssignmentType(type, expression, contextWithExpectedType));
@@ -337,7 +337,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
KtArrayAccessExpression arrayAccessExpression = (KtArrayAccessExpression) left;
if (right == null) return TypeInfoFactoryKt.noTypeInfo(context);
KotlinTypeInfo typeInfo = basic.resolveArrayAccessSetMethod(arrayAccessExpression, right, context, context.trace);
basic.checkLValue(context.trace, context, arrayAccessExpression, right, expression);
basic.checkLValue(context.trace, context, arrayAccessExpression, right, expression, true);
return typeInfo.replaceType(checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType));
}
KotlinTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(left, context, facade);
@@ -362,7 +362,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
resultInfo = leftInfo;
}
if (expectedType != null && leftOperand != null) { //if expectedType == null, some other error has been generated
basic.checkLValue(context.trace, context, leftOperand, right, expression);
basic.checkLValue(context.trace, context, leftOperand, right, expression, false);
}
return resultInfo.replaceType(components.dataFlowAnalyzer.checkStatementType(expression, contextWithExpectedType));
}