use of org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver in project kotlin by JetBrains.
the class BasicExpressionTypingVisitor method checkInExpression.
@NotNull
public KotlinTypeInfo checkInExpression(@NotNull KtElement callElement, @NotNull KtSimpleNameExpression operationSign, @NotNull ValueArgument leftArgument, @Nullable KtExpression right, @NotNull ExpressionTypingContext context) {
KtExpression left = leftArgument.getArgumentExpression();
ExpressionTypingContext contextWithNoExpectedType = context.replaceExpectedType(NO_EXPECTED_TYPE);
if (right == null) {
if (left != null)
facade.getTypeInfo(left, contextWithNoExpectedType);
return TypeInfoFactoryKt.noTypeInfo(context);
}
KotlinTypeInfo rightTypeInfo = facade.getTypeInfo(right, contextWithNoExpectedType);
DataFlowInfo dataFlowInfo = rightTypeInfo.getDataFlowInfo();
ExpressionReceiver receiver = safeGetExpressionReceiver(facade, right, contextWithNoExpectedType);
ExpressionTypingContext contextWithDataFlow = context.replaceDataFlowInfo(dataFlowInfo);
OverloadResolutionResults<FunctionDescriptor> resolutionResult = components.callResolver.resolveCallWithGivenName(contextWithDataFlow, CallMaker.makeCall(callElement, receiver, null, operationSign, Collections.singletonList(leftArgument)), operationSign, OperatorNameConventions.CONTAINS);
KotlinType containsType = OverloadResolutionResultsUtil.getResultingType(resolutionResult, context.contextDependency);
ensureBooleanResult(operationSign, OperatorNameConventions.CONTAINS, containsType, context);
if (left != null) {
dataFlowInfo = facade.getTypeInfo(left, contextWithDataFlow).getDataFlowInfo().and(dataFlowInfo);
rightTypeInfo = rightTypeInfo.replaceDataFlowInfo(dataFlowInfo);
}
if (resolutionResult.isSuccess()) {
return rightTypeInfo.replaceType(components.builtIns.getBooleanType());
} else {
return rightTypeInfo.clearType();
}
}
use of org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver in project kotlin by JetBrains.
the class BasicExpressionTypingVisitor method visitUnaryExpression.
@Override
public KotlinTypeInfo visitUnaryExpression(@NotNull KtUnaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
ExpressionTypingContext context = isUnaryExpressionDependentOnExpectedType(expression) ? contextWithExpectedType : contextWithExpectedType.replaceContextDependency(INDEPENDENT).replaceExpectedType(NO_EXPECTED_TYPE);
KtExpression baseExpression = expression.getBaseExpression();
if (baseExpression == null)
return TypeInfoFactoryKt.noTypeInfo(context);
KtSimpleNameExpression operationSign = expression.getOperationReference();
IElementType operationType = operationSign.getReferencedNameElementType();
// Special case for expr!!
if (operationType == KtTokens.EXCLEXCL) {
return visitExclExclExpression(expression, context);
}
// Type check the base expression
KotlinTypeInfo typeInfo = facade.safeGetTypeInfo(baseExpression, context);
KotlinType type = ExpressionTypingUtils.safeGetType(typeInfo);
ExpressionReceiver receiver = ExpressionReceiver.Companion.create(baseExpression, type, context.trace.getBindingContext());
Call call = CallMaker.makeCall(receiver, expression);
// Conventions for unary operations
Name name = OperatorConventions.UNARY_OPERATION_NAMES.get(operationType);
if (name == null) {
context.trace.report(UNSUPPORTED.on(operationSign, "visitUnaryExpression"));
return typeInfo.clearType();
}
// a[i]++/-- takes special treatment because it is actually let j = i, arr = a in arr.set(j, a.get(j).inc())
if ((operationType == KtTokens.PLUSPLUS || operationType == KtTokens.MINUSMINUS) && baseExpression instanceof KtArrayAccessExpression) {
KtExpression stubExpression = ExpressionTypingUtils.createFakeExpressionOfType(baseExpression.getProject(), context.trace, "e", type);
TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve array access set method for unary expression", expression);
ExpressionTypingContext newContext = context.replaceBindingTrace(temporaryBindingTrace);
resolveImplicitArrayAccessSetMethod((KtArrayAccessExpression) baseExpression, stubExpression, newContext, context.trace);
}
// Resolve the operation reference
OverloadResolutionResults<FunctionDescriptor> resolutionResults = components.callResolver.resolveCallWithGivenName(context, call, expression.getOperationReference(), name);
if (!resolutionResults.isSuccess()) {
return typeInfo.clearType();
}
// Computing the return type
KotlinType returnType = resolutionResults.getResultingDescriptor().getReturnType();
KotlinType result;
if (operationType == KtTokens.PLUSPLUS || operationType == KtTokens.MINUSMINUS) {
assert returnType != null : "returnType is null for " + resolutionResults.getResultingDescriptor();
if (KotlinBuiltIns.isUnit(returnType)) {
result = ErrorUtils.createErrorType(components.builtIns.getUnit().getName().asString());
context.trace.report(INC_DEC_SHOULD_NOT_RETURN_UNIT.on(operationSign));
} else {
KotlinType receiverType = receiver.getType();
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(returnType, receiverType)) {
context.trace.report(RESULT_TYPE_MISMATCH.on(operationSign, name.asString(), receiverType, returnType));
} else {
context.trace.record(BindingContext.VARIABLE_REASSIGNMENT, expression);
KtExpression stubExpression = ExpressionTypingUtils.createFakeExpressionOfType(baseExpression.getProject(), context.trace, "e", type);
checkLValue(context.trace, context, baseExpression, stubExpression, expression);
}
// x++ type is x type, but ++x type is x.inc() type
DataFlowValue receiverValue = DataFlowValueFactory.createDataFlowValue((ReceiverValue) call.getExplicitReceiver(), contextWithExpectedType);
if (expression instanceof KtPrefixExpression) {
result = returnType;
} else {
result = receiverType;
// Also record data flow information for x++ value (= x)
DataFlowValue returnValue = DataFlowValueFactory.createDataFlowValue(expression, receiverType, contextWithExpectedType);
typeInfo = typeInfo.replaceDataFlowInfo(typeInfo.getDataFlowInfo().assign(returnValue, receiverValue, components.languageVersionSettings));
}
}
} else {
result = returnType;
}
CompileTimeConstant<?> value = components.constantExpressionEvaluator.evaluateExpression(expression, contextWithExpectedType.trace, contextWithExpectedType.expectedType);
if (value != null) {
return components.dataFlowAnalyzer.createCompileTimeConstantTypeInfo(value, expression, contextWithExpectedType);
}
return components.dataFlowAnalyzer.checkType(typeInfo.replaceType(result), expression, contextWithExpectedType.replaceDataFlowInfo(typeInfo.getDataFlowInfo()));
}
use of org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver in project kotlin by JetBrains.
the class InOperationTranslator method translateInt.
@Nullable
private JsExpression translateInt() {
ResolvedCall<? extends CallableDescriptor> rightCall = CallUtilKt.getResolvedCallWithAssert(right, bindingContext());
if (!(rightCall.getResultingDescriptor() instanceof FunctionDescriptor)) {
return null;
}
FunctionDescriptor callDescriptor = (FunctionDescriptor) rightCall.getResultingDescriptor();
if (!INT_RANGE_TEST.apply(callDescriptor)) {
return null;
}
if (!(rightCall.getDispatchReceiver() instanceof ExpressionReceiver)) {
return null;
}
KtExpression lower = ((ExpressionReceiver) rightCall.getDispatchReceiver()).getExpression();
KtExpression upper = rightCall.getCall().getValueArguments().get(0).getArgumentExpression();
assert upper != null : "Parse error occurred: " + PsiUtilsKt.getTextWithLocation(right);
return translateInt(lower, upper);
}
use of org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver in project kotlin by JetBrains.
the class ExpressionTypingVisitorForStatements method visitAssignmentOperation.
@NotNull
protected KotlinTypeInfo visitAssignmentOperation(KtBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
//There is a temporary binding trace for an opportunity to resolve set method for array if needed (the initial trace should be used there)
TemporaryTraceAndCache temporary = TemporaryTraceAndCache.create(contextWithExpectedType, "trace to resolve array set method for binary expression", expression);
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceTraceAndCache(temporary).replaceContextDependency(INDEPENDENT);
KtSimpleNameExpression operationSign = expression.getOperationReference();
IElementType operationType = operationSign.getReferencedNameElementType();
KtExpression leftOperand = expression.getLeft();
KotlinTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(leftOperand, context, facade);
KotlinType leftType = leftInfo.getType();
KtExpression right = expression.getRight();
KtExpression left = leftOperand == null ? null : deparenthesize(leftOperand);
if (right == null || left == null) {
temporary.commit();
return leftInfo.clearType();
}
if (leftType == null) {
KotlinTypeInfo rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
context.trace.report(UNRESOLVED_REFERENCE.on(operationSign, operationSign));
temporary.commit();
return rightInfo.clearType();
}
ExpressionReceiver receiver = ExpressionReceiver.Companion.create(left, leftType, context.trace.getBindingContext());
// We check that defined only one of '+=' and '+' operations, and call it (in the case '+' we then also assign)
// Check for '+='
Name name = OperatorConventions.ASSIGNMENT_OPERATIONS.get(operationType);
TemporaryTraceAndCache temporaryForAssignmentOperation = TemporaryTraceAndCache.create(context, "trace to check assignment operation like '+=' for", expression);
OverloadResolutionResults<FunctionDescriptor> assignmentOperationDescriptors = components.callResolver.resolveBinaryCall(context.replaceTraceAndCache(temporaryForAssignmentOperation).replaceScope(scope), receiver, expression, name);
KotlinType assignmentOperationType = OverloadResolutionResultsUtil.getResultingType(assignmentOperationDescriptors, context.contextDependency);
OverloadResolutionResults<FunctionDescriptor> binaryOperationDescriptors;
KotlinType binaryOperationType;
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);
if (assignmentOperationType == null || lhsAssignable) {
// Check for '+'
Name counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType));
binaryOperationDescriptors = components.callResolver.resolveBinaryCall(context.replaceTraceAndCache(temporaryForBinaryOperation).replaceScope(scope), receiver, expression, counterpartName);
binaryOperationType = OverloadResolutionResultsUtil.getResultingType(binaryOperationDescriptors, context.contextDependency);
} else {
binaryOperationDescriptors = OverloadResolutionResultsImpl.nameNotFound();
binaryOperationType = null;
}
KotlinType type = assignmentOperationType != null ? assignmentOperationType : binaryOperationType;
KotlinTypeInfo rightInfo = leftInfo;
boolean hasRemAssignOperation = atLeastOneOperation(assignmentOperationDescriptors.getResultingCalls(), OperatorNameConventions.REM_ASSIGN);
boolean hasRemBinaryOperation = atLeastOneOperation(binaryOperationDescriptors.getResultingCalls(), OperatorNameConventions.REM);
boolean oneTypeOfModRemOperations = hasRemAssignOperation == hasRemBinaryOperation;
if (assignmentOperationDescriptors.isSuccess() && binaryOperationDescriptors.isSuccess() && oneTypeOfModRemOperations) {
// Both 'plus()' and 'plusAssign()' available => ambiguity
OverloadResolutionResults<FunctionDescriptor> ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity(assignmentOperationDescriptors, binaryOperationDescriptors);
context.trace.report(ASSIGN_OPERATOR_AMBIGUITY.on(operationSign, ambiguityResolutionResults.getResultingCalls()));
Collection<DeclarationDescriptor> descriptors = Sets.newHashSet();
for (ResolvedCall<?> resolvedCall : ambiguityResolutionResults.getResultingCalls()) {
descriptors.add(resolvedCall.getResultingDescriptor());
}
rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors);
} else if (assignmentOperationType != null && (assignmentOperationDescriptors.isSuccess() || !binaryOperationDescriptors.isSuccess()) && (!hasRemBinaryOperation || !binaryOperationDescriptors.isSuccess())) {
// There's 'plusAssign()', so we do a.plusAssign(b)
temporaryForAssignmentOperation.commit();
if (!KotlinTypeChecker.DEFAULT.equalTypes(components.builtIns.getUnitType(), assignmentOperationType)) {
context.trace.report(ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on(operationSign, assignmentOperationDescriptors.getResultingDescriptor(), operationSign));
}
} else {
// There's only 'plus()', so we try 'a = a + b'
temporaryForBinaryOperation.commit();
context.trace.record(VARIABLE_REASSIGNMENT, expression);
if (left instanceof KtArrayAccessExpression) {
ExpressionTypingContext contextForResolve = context.replaceScope(scope).replaceBindingTrace(TemporaryBindingTrace.create(context.trace, "trace to resolve array set method for assignment", expression));
basic.resolveImplicitArrayAccessSetMethod((KtArrayAccessExpression) left, right, contextForResolve, context.trace);
}
rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
KotlinType expectedType = refineTypeFromPropertySetterIfPossible(context.trace.getBindingContext(), leftOperand, leftType);
components.dataFlowAnalyzer.checkType(binaryOperationType, expression, context.replaceExpectedType(expectedType).replaceDataFlowInfo(rightInfo.getDataFlowInfo()).replaceCallPosition(new CallPosition.PropertyAssignment(left)));
basic.checkLValue(context.trace, context, leftOperand, right, expression);
}
temporary.commit();
return rightInfo.replaceType(checkAssignmentType(type, expression, contextWithExpectedType));
}
use of org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver in project kotlin by JetBrains.
the class ExpressionTypingVisitorForStatements method visitDestructuringDeclaration.
@Override
public KotlinTypeInfo visitDestructuringDeclaration(@NotNull KtDestructuringDeclaration multiDeclaration, ExpressionTypingContext context) {
components.annotationResolver.resolveAnnotationsWithArguments(scope, multiDeclaration.getModifierList(), context.trace);
KtExpression initializer = multiDeclaration.getInitializer();
if (initializer == null) {
context.trace.report(INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION.on(multiDeclaration));
}
ExpressionReceiver expressionReceiver = initializer != null ? ExpressionTypingUtils.getExpressionReceiver(facade, initializer, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT)) : null;
components.destructuringDeclarationResolver.defineLocalVariablesFromDestructuringDeclaration(scope, multiDeclaration, expressionReceiver, initializer, context);
components.modifiersChecker.withTrace(context.trace).checkModifiersForDestructuringDeclaration(multiDeclaration);
components.identifierChecker.checkDeclaration(multiDeclaration, context.trace);
if (expressionReceiver == null) {
return TypeInfoFactoryKt.noTypeInfo(context);
} else {
return facade.getTypeInfo(initializer, context).replaceType(components.dataFlowAnalyzer.checkStatementType(multiDeclaration, context));
}
}
Aggregations