diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index f3c486994ac..dfe0f691574 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -239,7 +239,7 @@ public interface Errors { return constraintOwner.getName(); } }; - ParameterizedDiagnosticFactory2 AUTOCAST_IMPOSSIBLE = ParameterizedDiagnosticFactory2.create(ERROR, "Automatic cast to {0} is impossible, because variable {1} is mutable", NAME); + ParameterizedDiagnosticFactory2 AUTOCAST_IMPOSSIBLE = ParameterizedDiagnosticFactory2.create(ERROR, "Automatic cast to {0} is impossible, because {1} could have changed since the is-check"); ParameterizedDiagnosticFactory2 TYPE_MISMATCH_IN_FOR_LOOP = ParameterizedDiagnosticFactory2.create(ERROR, "The loop iterates over values of type {0} but the parameter is declared to be {1}"); ParameterizedDiagnosticFactory1 TYPE_MISMATCH_IN_CONDITION = ParameterizedDiagnosticFactory1.create(ERROR, "Condition must be of type Boolean, but was of type {0}"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/Call.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/Call.java index 6813fdfdbaf..4983bafe6d2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/Call.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/Call.java @@ -1,7 +1,9 @@ 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.lang.resolve.scopes.receivers.ReceiverDescriptor; import java.util.List; @@ -9,6 +11,14 @@ import java.util.List; * @author abreslav */ public interface Call { + + // SAFE_ACCESS or DOT or so + @Nullable + ASTNode getCallOperationNode(); + + @NotNull + ReceiverDescriptor getExplicitReceiver(); + @Nullable JetExpression getCalleeExpression(); @@ -26,4 +36,7 @@ public interface Call { @Nullable JetTypeArgumentList getTypeArgumentList(); + + @NotNull + ASTNode getCallNode(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallElement.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallElement.java index a9a1a38d6e0..5fffa5f8131 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallElement.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallElement.java @@ -9,6 +9,22 @@ import java.util.List; /** * @author abreslav */ -public interface JetCallElement extends PsiElement, Call { +public interface JetCallElement extends PsiElement { + @Nullable + JetExpression getCalleeExpression(); + @Nullable + JetValueArgumentList getValueArgumentList(); + + @NotNull + List getValueArguments(); + + @NotNull + List getFunctionLiteralArguments(); + + @NotNull + List getTypeArguments(); + + @Nullable + JetTypeArgumentList getTypeArgumentList(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java index f00643ae6cb..6b1d2f73006 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java @@ -13,10 +13,7 @@ import org.jetbrains.jet.lang.resolve.calls.CallResolver; 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; -import org.jetbrains.jet.lang.types.DataFlowInfo; -import org.jetbrains.jet.lang.types.ErrorUtils; -import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.JetTypeInferrer; +import org.jetbrains.jet.lang.types.*; import java.util.Collections; import java.util.List; @@ -53,7 +50,7 @@ public class AnnotationResolver { } public void resolveAnnotationStub(@NotNull JetScope scope, @NotNull JetAnnotationEntry entryElement, @NotNull AnnotationDescriptor descriptor) { - JetType jetType = callResolver.resolveCall(trace, scope, ReceiverDescriptor.NO_RECEIVER, entryElement, NO_EXPECTED_TYPE); + JetType jetType = callResolver.resolveCall(trace, scope, CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, entryElement), NO_EXPECTED_TYPE); descriptor.setAnnotationType(jetType == null ? ErrorUtils.createErrorType("Unresolved annotation type") : jetType); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java index 4ee7c5c2fa7..a5e6b491cea 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -172,7 +172,9 @@ public class BodyResolver { JetTypeReference typeReference = call.getTypeReference(); if (typeReference != null) { if (descriptor.getUnsubstitutedPrimaryConstructor() != null) { - JetType supertype = typeInferrer.getCallResolver().resolveCall(context.getTrace(), scopeForConstructor, ReceiverDescriptor.NO_RECEIVER, call, NO_EXPECTED_TYPE); + JetType supertype = typeInferrer.getCallResolver().resolveCall( + context.getTrace(), scopeForConstructor, + CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call), NO_EXPECTED_TYPE); if (supertype != null) { recordSupertype(typeReference, supertype); ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype); @@ -334,7 +336,8 @@ public class BodyResolver { public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) { JetTypeReference typeReference = call.getTypeReference(); if (typeReference != null) { - typeInferrerForInitializers.getCallResolver().resolveCall(context.getTrace(), functionInnerScope, ReceiverDescriptor.NO_RECEIVER, call, NO_EXPECTED_TYPE); + typeInferrerForInitializers.getCallResolver().resolveCall(context.getTrace(), functionInnerScope, + CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call), NO_EXPECTED_TYPE); } } @@ -346,7 +349,7 @@ public class BodyResolver { typeInferrerForInitializers.getCallResolver().resolveCall(context.getTrace(), functionInnerScope, - ReceiverDescriptor.NO_RECEIVER, call, NO_EXPECTED_TYPE); + CallMaker.makeCall(ReceiverDescriptor.NO_RECEIVER, null, call), NO_EXPECTED_TYPE); // call.getThisReference(), // classDescriptor, // classDescriptor.getDefaultType(), diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastReceiver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastReceiver.java index bd72418a622..f778639e41b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastReceiver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastReceiver.java @@ -11,10 +11,16 @@ import org.jetbrains.jet.lang.types.JetType; */ public class AutoCastReceiver extends AbstractReceiverDescriptor { private final ReceiverDescriptor original; + private final boolean canCast; - public AutoCastReceiver(@NotNull ReceiverDescriptor original, @NotNull JetType castTo) { + public AutoCastReceiver(@NotNull ReceiverDescriptor original, @NotNull JetType castTo, boolean canCast) { super(castTo); this.original = original; + this.canCast = canCast; + } + + public boolean canCast() { + return canCast; } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastUtils.java index 52444691797..26e8588e666 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastUtils.java @@ -4,19 +4,22 @@ 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.JetBinaryExpressionWithTypeRHS; 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.DataFlowInfo; import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lexer.JetTokens; +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; /** @@ -26,36 +29,36 @@ public class AutoCastUtils { private AutoCastUtils() {} - public static List getAutoCastVariants(@NotNull final BindingContext bindingContext, @NotNull final DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiverToCast) { - return receiverToCast.accept(new ReceiverDescriptorVisitor, Object>() { + public static List getAutoCastVariants(@NotNull final BindingContext bindingContext, @NotNull final DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiverToCast) { + return receiverToCast.accept(new ReceiverDescriptorVisitor, Object>() { @Override - public List visitNoReceiver(ReceiverDescriptor noReceiver, Object data) { + public List visitNoReceiver(ReceiverDescriptor noReceiver, Object data) { return Collections.emptyList(); } @Override - public List visitTransientReceiver(TransientReceiver receiver, Object data) { + public List visitTransientReceiver(TransientReceiver receiver, Object data) { return Collections.emptyList(); } @Override - public List visitExtensionReceiver(ExtensionReceiver receiver, Object data) { + public List visitExtensionReceiver(ExtensionReceiver receiver, Object data) { return castThis(dataFlowInfo, receiver); } @Override - public List visitClassReceiver(ClassReceiver receiver, Object data) { + public List visitClassReceiver(ClassReceiver receiver, Object data) { return castThis(dataFlowInfo, receiver); } @Override - public List visitExpressionReceiver(ExpressionReceiver receiver, Object data) { + public List visitExpressionReceiver(ExpressionReceiver receiver, Object data) { JetExpression expression = receiver.getExpression(); VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(bindingContext, expression); - if (variableDescriptor != null && isAutocastable(variableDescriptor)) { + if (variableDescriptor != null) { List result = Lists.newArrayList(); for (JetType possibleType : dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)) { - result.add(new AutoCastReceiver(receiver, possibleType)); + result.add(new AutoCastReceiver(receiver, possibleType, isAutoCastable(variableDescriptor))); } return result; } @@ -67,26 +70,56 @@ public class AutoCastUtils { }, null); } - private static List castThis(@NotNull DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiver) { + private static List castThis(@NotNull DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiver) { assert receiver.exists(); List result = Lists.newArrayList(); for (JetType possibleType : dataFlowInfo.getPossibleTypesForReceiver(receiver)) { - result.add(new AutoCastReceiver(receiver, possibleType)); + result.add(new AutoCastReceiver(receiver, possibleType, true)); } return result; } @Nullable - public static VariableDescriptor getVariableDescriptorFromSimpleName(@NotNull BindingContext bindingContext, @NotNull JetExpression receiverExpression) { - if (receiverExpression instanceof JetBinaryExpressionWithTypeRHS) { - JetBinaryExpressionWithTypeRHS expression = (JetBinaryExpressionWithTypeRHS) receiverExpression; - if (expression.getOperationSign().getReferencedNameElementType() == JetTokens.COLON) { - return getVariableDescriptorFromSimpleName(bindingContext, expression.getLeft()); + 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); +// boolean appropriateTypeFound = false; + if (variableDescriptor != null) { + List 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; + } } +// if (!appropriateTypeFound) { +// JetType notnullType = dataFlowInfo.getOutType(variableDescriptor); +// if (notnullType != null && typeChecker.isSubtypeOf(notnullType, expectedType)) { +// appropriateTypeFound = true; +// } +// } } + return null; + } + + @Nullable + public static VariableDescriptor getVariableDescriptorFromSimpleName(@NotNull BindingContext bindingContext, @NotNull JetExpression expression) { +// if (expression instanceof JetBinaryExpressionWithTypeRHS) { +// JetBinaryExpressionWithTypeRHS expression = (JetBinaryExpressionWithTypeRHS) expression; +// if (expression.getOperationSign().getReferencedNameElementType() == JetTokens.COLON) { +// return getVariableDescriptorFromSimpleName(bindingContext, expression.getLeft()); +// } +// } + JetExpression receiver = JetPsiUtil.deparenthesize(expression); VariableDescriptor variableDescriptor = null; - if (receiverExpression instanceof JetSimpleNameExpression) { - JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) receiverExpression; + if (receiver instanceof JetSimpleNameExpression) { + JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) receiver; DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, nameExpression); if (declarationDescriptor instanceof VariableDescriptor) { variableDescriptor = (VariableDescriptor) declarationDescriptor; @@ -95,7 +128,7 @@ public class AutoCastUtils { return variableDescriptor; } - public static boolean isAutocastable(@NotNull VariableDescriptor variableDescriptor) { + public static boolean isAutoCastable(@NotNull VariableDescriptor variableDescriptor) { if (variableDescriptor.isVar()) return false; if (variableDescriptor instanceof PropertyDescriptor) { PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index dbd4505e471..aa3b60642aa 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -1,12 +1,9 @@ package org.jetbrains.jet.lang.resolve.calls; -import com.google.common.base.Function; -import com.google.common.base.Functions; import com.google.common.collect.Lists; import com.google.common.collect.Maps; 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.JetSemanticServices; @@ -55,21 +52,19 @@ public class CallResolver { if (referencedName == null) { return null; } - Call call = CallMaker.makePropertyCall(nameExpression); - List> prioritizedTasks = TaskPrioritizers.PROPERTY_TASK_PRIORITIZER.computePrioritizedTasks(scope, receiver, call, referencedName, trace.getBindingContext(), dataFlowInfo); + Call call = CallMaker.makePropertyCall(receiver, null, nameExpression); + List> prioritizedTasks = TaskPrioritizers.PROPERTY_TASK_PRIORITIZER.computePrioritizedTasks(scope, call, referencedName, trace.getBindingContext(), dataFlowInfo); return resolveCallToDescriptor(trace, scope, call, nameExpression.getNode(), expectedType, prioritizedTasks, nameExpression); } - @Nullable public JetType resolveCall( @NotNull BindingTrace trace, @NotNull JetScope scope, - @NotNull ReceiverDescriptor receiver, - @NotNull JetCallElement call, + @NotNull Call call, @NotNull JetType expectedType ) { - FunctionDescriptor functionDescriptor = resolveSimpleCallToFunctionDescriptor(trace, scope, receiver, call, expectedType); + FunctionDescriptor functionDescriptor = resolveSimpleCallToFunctionDescriptor(trace, scope, call, expectedType); return functionDescriptor == null ? null : functionDescriptor.getReturnType(); } @@ -80,9 +75,8 @@ public class CallResolver { @NotNull final Call call, @NotNull final JetReferenceExpression functionReference, @NotNull String name, - @NotNull ReceiverDescriptor receiver, @NotNull JetType expectedType) { - List> tasks = TaskPrioritizers.FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, receiver, call, name, trace.getBindingContext(), dataFlowInfo); + List> tasks = TaskPrioritizers.FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, call, name, trace.getBindingContext(), dataFlowInfo); return resolveCallToDescriptor(trace, scope, call, functionReference.getNode(), expectedType, tasks, functionReference); } @@ -90,8 +84,7 @@ public class CallResolver { public FunctionDescriptor resolveSimpleCallToFunctionDescriptor( @NotNull BindingTrace trace, @NotNull JetScope scope, - @NotNull ReceiverDescriptor receiver, - @NotNull final JetCallElement call, + @NotNull final Call call, @NotNull JetType expectedType ) { List> prioritizedTasks; @@ -105,7 +98,7 @@ public class CallResolver { String name = expression.getReferencedName(); if (name == null) return checkArgumentTypesAndFail(trace, scope, call); - prioritizedTasks = TaskPrioritizers.FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, receiver, call, name, trace.getBindingContext(), dataFlowInfo); + prioritizedTasks = TaskPrioritizers.FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, call, name, trace.getBindingContext(), dataFlowInfo); ResolutionTask.DescriptorCheckStrategy abstractConstructorCheck = new ResolutionTask.DescriptorCheckStrategy() { @Override public boolean performAdvancedChecks(D descriptor, BindingTrace trace, TracingStrategy tracing) { @@ -126,9 +119,9 @@ public class CallResolver { } else { JetValueArgumentList valueArgumentList = call.getValueArgumentList(); - ASTNode reportAbsenceOn = valueArgumentList == null ? call.getNode() : valueArgumentList.getNode(); + ASTNode reportAbsenceOn = valueArgumentList == null ? call.getCallNode() : valueArgumentList.getNode(); if (calleeExpression instanceof JetConstructorCalleeExpression) { - assert !receiver.exists(); + assert !call.getExplicitReceiver().exists(); prioritizedTasks = Lists.newArrayList(); @@ -172,14 +165,14 @@ public class CallResolver { prioritizedTasks = Collections.singletonList(new ResolutionTask(ResolvedCall.convertCollection(constructors), call, DataFlowInfo.getEmpty())); } else { - throw new UnsupportedOperationException("Type argument inference not implemented for " + call.getText()); + throw new UnsupportedOperationException("Type argument inference not implemented for " + call); } } - return resolveCallToDescriptor(trace, scope, call, call.getNode(), expectedType, prioritizedTasks, functionReference); + return resolveCallToDescriptor(trace, scope, call, call.getCallNode(), expectedType, prioritizedTasks, functionReference); } - private FunctionDescriptor checkArgumentTypesAndFail(BindingTrace trace, JetScope scope, JetCallElement call) { + private FunctionDescriptor checkArgumentTypesAndFail(BindingTrace trace, JetScope scope, Call call) { checkTypesWithNoCallee(trace, scope, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments()); return null; } @@ -234,19 +227,6 @@ public class CallResolver { @Override public void noValueForParameter(@NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter) { -// ASTNode node; -// -// JetValueArgumentList valueArgumentList = call.getValueArgumentList(); -// if (valueArgumentList != null) { -// node = valueArgumentList.getNode(); -// } -// else if (!call.getFunctionLiteralArguments().isEmpty()) { -// node = call.getFunctionLiteralArguments().get(0).getNode(); -// } -// else { -// node = callNode; -// } -// trace.report(NO_VALUE_FOR_PARAMETER.on(node, valueParameter)); trace.report(NO_VALUE_FOR_PARAMETER.on(reference, valueParameter)); } @@ -325,7 +305,6 @@ public class CallResolver { private OverloadResolutionResults performResolution(@NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull JetType expectedType, @NotNull ResolutionTask task, @NotNull TracingStrategy tracing) { Set> successfulCandidates = Sets.newLinkedHashSet(); Set> failedCandidates = Sets.newLinkedHashSet(); - Set> dirtyCandidates = Sets.newLinkedHashSet(); for (ResolvedCall candidateCall : task.getCandidates()) { D candidate = candidateCall.getCandidateDescriptor(); @@ -341,8 +320,8 @@ public class CallResolver { } - Map argumentsToParameters = Maps.newHashMap(); - boolean error = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(task, tracing, candidate, temporaryTrace, argumentsToParameters); +// Map argumentsToParameters = Maps.newHashMap(); + boolean error = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(task, tracing, candidateCall); if (error) { failedCandidates.add(candidateCall); @@ -350,18 +329,8 @@ public class CallResolver { continue; } - Ref dirty = new Ref(false); if (task.getTypeArguments().isEmpty()) { - if (candidate.getTypeParameters().isEmpty()) { - if (checkValueArgumentTypes(scope, temporaryTrace, argumentsToParameters, dirty, Functions.identity()) - && checkReceiver(candidateCall, tracing, candidate, temporaryTrace)) { - successfulCandidates.add(candidateCall.setResultingDescriptor(candidate)); - } - else { - failedCandidates.add(candidateCall); - } - } - else { + if (!candidate.getTypeParameters().isEmpty()) { // Type argument inference ConstraintSystem constraintSystem = new ConstraintSystem(); @@ -369,23 +338,25 @@ public class CallResolver { constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO } - for (Map.Entry entry : argumentsToParameters.entrySet()) { - ValueArgument valueArgument = entry.getKey(); - ValueParameterDescriptor valueParameterDescriptor = entry.getValue(); + for (Map.Entry entry : candidateCall.getValueArguments().entrySet()) { + ResolvedValueArgument valueArgument = entry.getValue(); + ValueParameterDescriptor valueParameterDescriptor = entry.getKey(); - JetExpression expression = valueArgument.getArgumentExpression(); - // TODO : more attempts, with different expected types - JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace); - JetType type = temporaryServices.getType(scope, expression, NO_EXPECTED_TYPE); - if (type != null) { - constraintSystem.addSubtypingConstraint(type, valueParameterDescriptor.getOutType()); - } - else { - dirty.set(true); + for (JetExpression expression : valueArgument.getArgumentExpressions()) { +// JetExpression expression = valueArgument.getArgumentExpression(); + // TODO : more attempts, with different expected types + JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace); + JetType type = temporaryServices.getType(scope, expression, NO_EXPECTED_TYPE); + if (type != null) { + constraintSystem.addSubtypingConstraint(type, valueParameterDescriptor.getOutType()); + } + else { + candidateCall.argumentHasNoType(); + } } } - checkReceiverAbsence(candidateCall, tracing, candidate, temporaryTrace); + checkReceiverAbsence(candidateCall, tracing, candidate); // Error is already reported if something is missing ReceiverDescriptor receiverParameter = candidateCall.getReceiverParameter(); ReceiverDescriptor candidateReceiver = candidate.getReceiver(); @@ -402,6 +373,7 @@ public class CallResolver { if (solution.isSuccessful()) { D substitute = (D) candidate.substitute(solution.getSubstitutor()); assert substitute != null; + replaceValueParametersWithSubstitutedOnes(candidateCall, substitute); successfulCandidates.add(candidateCall.setResultingDescriptor(substitute)); } else { @@ -409,6 +381,15 @@ public class CallResolver { failedCandidates.add(candidateCall); } } + else { + if (checkValueArgumentTypes(scope, candidateCall) + && checkReceiver(candidateCall, tracing, candidate)) { + successfulCandidates.add(candidateCall.setResultingDescriptor(candidate)); + } + else { + failedCandidates.add(candidateCall); + } + } } else { // Explicit type arguments passed @@ -436,12 +417,12 @@ public class CallResolver { checkGenericBoundsInAFunctionCall(jetTypeArguments, typeArguments, candidate, temporaryTrace); Map substitutionContext = FunctionDescriptorUtil.createSubstitutionContext((FunctionDescriptor) candidate, typeArguments); - D substitutedFunctionDescriptor = (D) candidate.substitute(TypeSubstitutor.create(substitutionContext)); + D substitutedDescriptor = (D) candidate.substitute(TypeSubstitutor.create(substitutionContext)); - Function mapFunction = createMapFunction(substitutedFunctionDescriptor); - if (checkValueArgumentTypes(scope, temporaryTrace, argumentsToParameters, dirty, mapFunction) - && checkReceiver(candidateCall, tracing, substitutedFunctionDescriptor, temporaryTrace)) { - successfulCandidates.add(candidateCall.setResultingDescriptor(substitutedFunctionDescriptor)); + replaceValueParametersWithSubstitutedOnes(candidateCall, substitutedDescriptor); + if (checkValueArgumentTypes(scope, candidateCall) + && checkReceiver(candidateCall, tracing, substitutedDescriptor)) { + successfulCandidates.add(candidateCall.setResultingDescriptor(substitutedDescriptor)); } else { failedCandidates.add(candidateCall); @@ -454,16 +435,13 @@ public class CallResolver { } } - if (dirty.get()) { - dirtyCandidates.add(candidateCall); - } task.performAdvancedChecks(candidate, temporaryTrace, tracing); recordAutoCastIfNecessary(candidateCall.getReceiverParameter(), candidateCall.getTrace()); recordAutoCastIfNecessary(candidateCall.getThisObject(), candidateCall.getTrace()); } - OverloadResolutionResults results = computeResultAndReportErrors(trace, tracing, successfulCandidates, failedCandidates, dirtyCandidates); + OverloadResolutionResults results = computeResultAndReportErrors(trace, tracing, successfulCandidates, failedCandidates); if (!results.singleDescriptor()) { checkTypesWithNoCallee(trace, scope, task.getTypeArguments(), task.getValueArguments(), task.getFunctionLiteralArguments()); } @@ -476,7 +454,15 @@ public class CallResolver { ReceiverDescriptor original = autoCastReceiver.getOriginal(); if (original instanceof ExpressionReceiver) { ExpressionReceiver expressionReceiver = (ExpressionReceiver) original; - trace.record(AUTOCAST, expressionReceiver.getExpression(), autoCastReceiver.getType()); + if (autoCastReceiver.canCast()) { + trace.record(AUTOCAST, expressionReceiver.getExpression(), autoCastReceiver.getType()); + } + else { + trace.report(AUTOCAST_IMPOSSIBLE.on(expressionReceiver.getExpression(), autoCastReceiver.getType(), expressionReceiver.getExpression().getText())); + } + } + else { + assert autoCastReceiver.canCast() : "A non-expression receiver must always be autocastabe: " + original; } } } @@ -498,45 +484,127 @@ public class CallResolver { } } - private Function createMapFunction(D substitutedFunctionDescriptor) { - assert substitutedFunctionDescriptor != null; - final Map parameterMap = Maps.newHashMap(); - for (ValueParameterDescriptor valueParameterDescriptor : substitutedFunctionDescriptor.getValueParameters()) { +// private Function createMapFunction(D substitutedFunctionDescriptor) { +// assert substitutedFunctionDescriptor != null; +// final Map parameterMap = Maps.newHashMap(); +// for (ValueParameterDescriptor valueParameterDescriptor : substitutedFunctionDescriptor.getValueParameters()) { +// parameterMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor); +// } +// +// return new Function() { +// @Override +// public ValueParameterDescriptor apply(ValueParameterDescriptor input) { +// return parameterMap.get(input.getOriginal()); +// } +// }; +// } + + private void replaceValueParametersWithSubstitutedOnes(ResolvedCall candidateCall, @NotNull D substitutedDescriptor) { + Map parameterMap = Maps.newHashMap(); + for (ValueParameterDescriptor valueParameterDescriptor : substitutedDescriptor.getValueParameters()) { parameterMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor); } - return new Function() { - @Override - public ValueParameterDescriptor apply(ValueParameterDescriptor input) { - return parameterMap.get(input.getOriginal()); - } - }; + Map valueArguments = candidateCall.getValueArguments(); + Map originalValueArguments = Maps.newHashMap(valueArguments); + valueArguments.clear(); + for (Map.Entry entry : originalValueArguments.entrySet()) { + ValueParameterDescriptor substitutedVersion = parameterMap.get(entry.getKey().getOriginal()); + assert substitutedVersion != null : entry.getKey(); + valueArguments.put(substitutedVersion, entry.getValue()); + } } - private boolean checkReceiver(ResolvedCall resolvedCall, TracingStrategy tracing, D candidate, TemporaryBindingTrace temporaryTrace) { - if (!checkReceiverAbsence(resolvedCall, tracing, candidate, temporaryTrace)) return false; + private boolean checkValueArgumentTypes( + JetScope scope, + ResolvedCall candidateCall) { + boolean result = true; + for (Map.Entry entry : candidateCall.getValueArguments().entrySet()) { + ValueParameterDescriptor parameterDescriptor = entry.getKey(); + ResolvedValueArgument resolvedArgument = entry.getValue(); + + JetType parameterType = parameterDescriptor.getOutType(); + + List argumentExpressions = resolvedArgument.getArgumentExpressions(); + for (JetExpression argumentExpression : argumentExpressions) { + JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(candidateCall.getTrace()); + JetType type = temporaryServices.getType(scope, argumentExpression, parameterType); + if (type == null) { + candidateCall.argumentHasNoType(); + } + else if (!semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) { +// VariableDescriptor variableDescriptor = AutoCastUtils.getVariableDescriptorFromSimpleName(temporaryTrace.getBindingContext(), argumentExpression); +// if (variableDescriptor != null) { +// JetType autoCastType = null; +// for (JetType possibleType : dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)) { +// if (semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) { +// autoCastType = possibleType; +// break; +// } +// } +// if (autoCastType != null) { +// if (AutoCastUtils.isAutoCastable(variableDescriptor)) { +// temporaryTrace.record(AUTOCAST, argumentExpression, autoCastType); +// } +// else { +// temporaryTrace.report(AUTOCAST_IMPOSSIBLE.on(argumentExpression, autoCastType, variableDescriptor)); +// result = false; +// } +// } +// } +// else { + result = false; + } + } + } +// for (Map.Entry entry : argumentsToParameters.entrySet()) { +// ValueArgument valueArgument = entry.getKey(); +// ValueParameterDescriptor valueParameterDescriptor = entry.getValue(); +// +// ValueParameterDescriptor substitutedParameter = parameterMap.apply(valueParameterDescriptor); +// +// assert substitutedParameter != null; +// +// JetType parameterType = substitutedParameter.getOutType(); +// JetExpression argumentExpression = valueArgument.getArgumentExpression(); +// if (argumentExpression != null) { +// JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace); +// JetType type = temporaryServices.getType(scope, argumentExpression, parameterType); +// if (type == null) { +// dirty.set(true); +// } +// else if (!semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) { +// result = false; +// } +// } +// } + return result; + } + + private boolean checkReceiver(ResolvedCall resolvedCall, TracingStrategy tracing, D candidate) { + if (!checkReceiverAbsence(resolvedCall, tracing, candidate)) return false; ReceiverDescriptor receiver = resolvedCall.getReceiverParameter(); ReceiverDescriptor candidateReceiver = candidate.getReceiver(); if (receiver.exists() && candidateReceiver.exists() && !semanticServices.getTypeChecker().isSubtypeOf(receiver.getType(), candidateReceiver.getType())) { - tracing.missingReceiver(temporaryTrace, candidateReceiver); + tracing.missingReceiver(resolvedCall.getTrace(), candidateReceiver); return false; } return true; } - private boolean checkReceiverAbsence(ResolvedCall resolvedCall, TracingStrategy tracing, D candidate, TemporaryBindingTrace temporaryTrace) { + private boolean checkReceiverAbsence(ResolvedCall resolvedCall, TracingStrategy tracing, D candidate) { ReceiverDescriptor receiver = resolvedCall.getReceiverParameter(); ReceiverDescriptor candidateReceiver = candidate.getReceiver(); if (receiver.exists()) { if (!candidateReceiver.exists()) { - tracing.noReceiverAllowed(temporaryTrace); + tracing.noReceiverAllowed(resolvedCall.getTrace()); return false; } } else if (candidateReceiver.exists()) { - tracing.missingReceiver(temporaryTrace, candidateReceiver); + tracing.missingReceiver(resolvedCall.getTrace(), candidateReceiver); return false; } return true; @@ -547,13 +615,20 @@ public class CallResolver { BindingTrace trace, TracingStrategy tracing, Set> successfulCandidates, // original -> substituted - Set> failedCandidates, - Set> dirtyCandidates) { + Set> failedCandidates) { // TODO : maybe it's better to filter overrides out first, and only then look for the maximally specific if (successfulCandidates.size() > 0) { if (successfulCandidates.size() != 1) { Set> cleanCandidates = Sets.newLinkedHashSet(successfulCandidates); - cleanCandidates.removeAll(dirtyCandidates); + boolean allClean = true; + for (Iterator> iterator = cleanCandidates.iterator(); iterator.hasNext(); ) { + ResolvedCall candidate = iterator.next(); + if (candidate.isDirty()) { + iterator.remove(); + allClean = false; + } + } + if (cleanCandidates.isEmpty()) { cleanCandidates = successfulCandidates; } @@ -568,7 +643,7 @@ public class CallResolver { } Set> noOverrides = OverridingUtil.filterOverrides(successfulCandidates, MAP_TO_RESULT); - if (dirtyCandidates.isEmpty()) { + if (allClean) { // tracing.reportOverallResolutionError(trace, "Overload resolution ambiguity: " // + makeErrorMessageForMultipleDescriptors(noOverrides)); tracing.ambiguity(trace, noOverrides); @@ -608,58 +683,6 @@ public class CallResolver { } } - private boolean checkValueArgumentTypes( - JetScope scope, - BindingTrace temporaryTrace, - Map argumentsToParameters, - Ref dirty, - Function parameterMap) { - boolean result = true; - for (Map.Entry entry : argumentsToParameters.entrySet()) { - ValueArgument valueArgument = entry.getKey(); - ValueParameterDescriptor valueParameterDescriptor = entry.getValue(); - - ValueParameterDescriptor substitutedParameter = parameterMap.apply(valueParameterDescriptor); - - assert substitutedParameter != null; - - JetType parameterType = substitutedParameter.getOutType(); - JetExpression argumentExpression = valueArgument.getArgumentExpression(); - if (argumentExpression != null) { - JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace); - JetType type = temporaryServices.getType(scope, argumentExpression, parameterType); - if (type == null) { - dirty.set(true); - } - else if (!semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) { -// VariableDescriptor variableDescriptor = AutoCastUtils.getVariableDescriptorFromSimpleName(temporaryTrace.getBindingContext(), argumentExpression); -// if (variableDescriptor != null) { -// JetType autoCastType = null; -// for (JetType possibleType : dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)) { -// if (semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) { -// autoCastType = possibleType; -// break; -// } -// } -// if (autoCastType != null) { -// if (AutoCastUtils.isAutocastable(variableDescriptor)) { -// temporaryTrace.record(AUTOCAST, argumentExpression, autoCastType); -// } -// else { -// temporaryTrace.report(AUTOCAST_IMPOSSIBLE.on(argumentExpression, autoCastType, variableDescriptor)); -// result = false; -// } -// } -// } -// else { - result = false; -// } - } - } - } - return result; - } - public void checkGenericBoundsInAFunctionCall(List jetTypeArguments, List typeArguments, CallableDescriptor functionDescriptor, BindingTrace trace) { Map context = Maps.newHashMap(); @@ -690,7 +713,7 @@ public class CallResolver { call.setTrace(temporaryBindingTrace); candidates.add(call); } - return computeResultAndReportErrors(trace, TracingStrategy.EMPTY, candidates, Collections.>emptySet(), Collections.>emptySet()); + return computeResultAndReportErrors(trace, TracingStrategy.EMPTY, candidates, Collections.>emptySet()); } private List> findCandidatesByExactSignature(JetScope scope, ReceiverDescriptor receiver, String name, List parameterTypes) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DefaultValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DefaultValueArgument.java index 07aeb6be9f2..2303269f5be 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DefaultValueArgument.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DefaultValueArgument.java @@ -1,10 +1,22 @@ package org.jetbrains.jet.lang.resolve.calls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetExpression; + +import java.util.Collections; +import java.util.List; + /** * @author abreslav */ public class DefaultValueArgument implements ResolvedValueArgument { public static final DefaultValueArgument DEFAULT = new DefaultValueArgument(); - DefaultValueArgument() {} + private DefaultValueArgument() {} + + @NotNull + @Override + public List getArgumentExpressions() { + return Collections.emptyList(); //throw new UnsupportedOperationException("Look into the default value of the parameter"); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionValueArgument.java index 045d4c4f1c0..02abdc635eb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionValueArgument.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionValueArgument.java @@ -1,20 +1,32 @@ package org.jetbrains.jet.lang.resolve.calls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.JetExpression; +import java.util.Collections; +import java.util.List; + /** * @author abreslav */ public class ExpressionValueArgument implements ResolvedValueArgument { private final JetExpression expression; - public ExpressionValueArgument(@NotNull JetExpression expression) { + public ExpressionValueArgument(@Nullable JetExpression expression) { this.expression = expression; } - @NotNull + // Nullable when something like f(a, , b) was in the source code + @Nullable public JetExpression getExpression() { return expression; } + + @NotNull + @Override + public List getArgumentExpressions() { + if (expression == null) return Collections.emptyList(); + return Collections.singletonList(expression); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java index bf729832db2..af2341f1bb8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/OverloadingConflictResolver.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.lang.resolve.calls; -import com.google.common.collect.Sets; +import gnu.trove.THashSet; +import gnu.trove.TObjectHashingStrategy; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.JetSemanticServices; @@ -28,7 +29,18 @@ public class OverloadingConflictResolver { @Nullable public ResolvedCall findMaximallySpecific(Set> candidates, boolean discriminateGenericDescriptors) { - Set> maximallySpecific = Sets.newHashSet(); + // Different autocasts may lead to the same candidate descriptor wrapped into different ResolvedCall objects + Set> maximallySpecific = new THashSet>(new TObjectHashingStrategy>() { + @Override + public boolean equals(ResolvedCall o1, ResolvedCall o2) { + return o1 == null ? o2 == null : o1.getResultingDescriptor().equals(o2.getResultingDescriptor()); + } + + @Override + public int computeHashCode(ResolvedCall object) { + return object == null ? 0 : object.getResultingDescriptor().hashCode(); + } + }); meLoop: for (ResolvedCall candidateCall : candidates) { D me = candidateCall.getResultingDescriptor(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java index 88ef0180dfc..491524d6172 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java @@ -54,9 +54,10 @@ public class ResolvedCall { private D resultingDescriptor; // Probably substituted private ReceiverDescriptor thisObject = NO_RECEIVER; // receiver object of a method private ReceiverDescriptor receiverParameter = NO_RECEIVER; // receiver of an extension function - private final Map typeArguments = Maps.newHashMap(); + private final Map typeArguments = Maps.newLinkedHashMap(); private final Map autoCasts = Maps.newHashMap(); private final Map valueArguments = Maps.newHashMap(); + private boolean someArgumentHasNoType = false; private TemporaryBindingTrace trace; private ResolvedCall(@NotNull D candidateDescriptor) { @@ -120,4 +121,16 @@ public class ResolvedCall { this.thisObject = thisObject; } + @NotNull + public Map getValueArguments() { + return valueArguments; + } + + public void argumentHasNoType() { + this.someArgumentHasNoType = true; + } + + public boolean isDirty() { + return someArgumentHasNoType; + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedValueArgument.java index 4f3216e8a91..6aa676ca955 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedValueArgument.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedValueArgument.java @@ -1,8 +1,15 @@ package org.jetbrains.jet.lang.resolve.calls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetExpression; + +import java.util.List; + /** * @author abreslav */ public interface ResolvedValueArgument { + @NotNull + List getArgumentExpressions(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java index a7a1036d579..2abfc50d1dc 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java @@ -11,6 +11,7 @@ import org.jetbrains.jet.lang.types.DataFlowInfo; import org.jetbrains.jet.lang.types.JetType; import java.util.Collection; +import java.util.Collections; import java.util.List; import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER; @@ -70,43 +71,89 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor // return result; // } - public List> computePrioritizedTasks(@NotNull JetScope scope, @NotNull ReceiverDescriptor explicitReceiver, @NotNull Call call, @NotNull String name, @NotNull BindingContext bindingContext, @NotNull DataFlowInfo dataFlowInfo) { + public List> computePrioritizedTasks(@NotNull JetScope scope, @NotNull Call call, @NotNull String name, @NotNull BindingContext bindingContext, @NotNull DataFlowInfo dataFlowInfo) { List> result = Lists.newArrayList(); - doComputeTasks(scope, explicitReceiver, call, name, result, DataFlowInfo.getEmpty()); + ReceiverDescriptor explicitReceiver = call.getExplicitReceiver(); + doComputeTasks(scope, explicitReceiver, call, name, result, NO_AUTO_CASTS); ReceiverDescriptor receiverToCast = explicitReceiver.exists() ? explicitReceiver : scope.getImplicitReceiver(); if (receiverToCast.exists()) { - doComputeTasks(scope, receiverToCast, call, name, result, dataFlowInfo); + doComputeTasks(scope, receiverToCast, call, name, result, new AutoCastServiceImpl(dataFlowInfo, bindingContext)); } return result; } - private void doComputeTasks(JetScope scope, ReceiverDescriptor explicitReceiver, Call call, String name, List> result, @NotNull DataFlowInfo dataFlowInfo) { + private interface AutoCastService { + List getVariantsForReceiver(ReceiverDescriptor receiverDescriptor); + DataFlowInfo getDataFlowInfo(); + } + + private static class AutoCastServiceImpl implements AutoCastService { + private final DataFlowInfo dataFlowInfo; + private final BindingContext bindingContext; + + private AutoCastServiceImpl(DataFlowInfo dataFlowInfo, BindingContext bindingContext) { + this.dataFlowInfo = dataFlowInfo; + this.bindingContext = bindingContext; + } + + @Override + public List getVariantsForReceiver(ReceiverDescriptor receiverDescriptor) { + return AutoCastUtils.getAutoCastVariants(bindingContext, dataFlowInfo, receiverDescriptor); + } + + @Override + public DataFlowInfo getDataFlowInfo() { + return dataFlowInfo; + } + } + + private static AutoCastService NO_AUTO_CASTS = new AutoCastService() { + @Override + public DataFlowInfo getDataFlowInfo() { + return DataFlowInfo.getEmpty(); + } + + @Override + public List getVariantsForReceiver(ReceiverDescriptor receiverDescriptor) { + return Collections.singletonList(receiverDescriptor); + } + }; + + private void doComputeTasks(JetScope scope, ReceiverDescriptor explicitReceiver, Call call, String name, List> result, @NotNull AutoCastService autoCastService) { + DataFlowInfo dataFlowInfo = autoCastService.getDataFlowInfo(); List implicitReceivers = Lists.newArrayList(); scope.getImplicitReceiversHierarchy(implicitReceivers); + // AutoCastUtils.getAutoCastVariants(bindingContext, dataFlowInfo, receiverToCast) if (explicitReceiver.exists()) { - Collection> extensionFunctions = convertWithImpliedThis(explicitReceiver, getExtensionsByName(scope, name)); + List variantsForExplicitReceiver = autoCastService.getVariantsForReceiver(explicitReceiver); + + Collection> extensionFunctions = convertWithImpliedThis(variantsForExplicitReceiver, getExtensionsByName(scope, name)); List> nonlocals = Lists.newArrayList(); List> locals = Lists.newArrayList(); //noinspection unchecked,RedundantTypeArguments TaskPrioritizer.splitLexicallyLocalDescriptors(extensionFunctions, scope.getContainingDeclaration(), locals, nonlocals); - // AutoCastUtils.getAutoCastVariants(bindingContext, dataFlowInfo, receiverToCast) - Collection members = getMembersByName(explicitReceiver.getType(), name); + Collection> members = Lists.newArrayList(); + for (ReceiverDescriptor variant : variantsForExplicitReceiver) { + Collection membersForThisVariant = getMembersByName(variant.getType(), name); + convertWithReceivers(membersForThisVariant, Collections.singletonList(variant), Collections.singletonList(NO_RECEIVER), members); + } addTask(result, call, locals, dataFlowInfo); - addTask(result, call, convertWithReceivers(members, explicitReceiver, NO_RECEIVER), dataFlowInfo); + addTask(result, call, members, dataFlowInfo); for (ReceiverDescriptor implicitReceiver : implicitReceivers) { Collection memberExtensions = getExtensionsByName(implicitReceiver.getType().getMemberScope(), name); - addTask(result, call, convertWithReceivers(memberExtensions, implicitReceiver, explicitReceiver), dataFlowInfo); + List variantsForImplicitReceiver = autoCastService.getVariantsForReceiver(implicitReceiver); + addTask(result, call, convertWithReceivers(memberExtensions, variantsForImplicitReceiver, variantsForExplicitReceiver), dataFlowInfo); } addTask(result, call, nonlocals, dataFlowInfo); } else { - Collection> functions = convertWithImpliedThis(explicitReceiver, getNonExtensionsByName(scope, name)); + Collection> functions = convertWithImpliedThis(Collections.singletonList(explicitReceiver), getNonExtensionsByName(scope, name)); List> nonlocals = Lists.newArrayList(); List> locals = Lists.newArrayList(); @@ -116,31 +163,43 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor addTask(result, call, locals, dataFlowInfo); for (ReceiverDescriptor implicitReceiver : implicitReceivers) { - doComputeTasks(scope, implicitReceiver, call, name, result, dataFlowInfo); + doComputeTasks(scope, implicitReceiver, call, name, result, autoCastService); } addTask(result, call, nonlocals, dataFlowInfo); } } - private Collection> convertWithReceivers(Collection descriptors, ReceiverDescriptor thisObject, ReceiverDescriptor receiverParameter) { + private Collection> convertWithReceivers(Collection descriptors, Iterable thisObjects, Iterable receiverParameters) { Collection> result = Lists.newArrayList(); - for (D extension : descriptors) { - ResolvedCall resolvedCall = ResolvedCall.create(extension); - resolvedCall.setThisObject(thisObject); - resolvedCall.setReceiverParameter(receiverParameter); - result.add(resolvedCall); - } + convertWithReceivers(descriptors, thisObjects, receiverParameters, result); return result; } - private Collection> convertWithImpliedThis(ReceiverDescriptor receiverParameter, Collection descriptors) { + private void convertWithReceivers(Collection descriptors, Iterable thisObjects, Iterable receiverParameters, Collection> result) { +// Collection> result = Lists.newArrayList(); + for (ReceiverDescriptor thisObject : thisObjects) { + for (ReceiverDescriptor receiverParameter : receiverParameters) { + for (D extension : descriptors) { + ResolvedCall resolvedCall = ResolvedCall.create(extension); + resolvedCall.setThisObject(thisObject); + resolvedCall.setReceiverParameter(receiverParameter); + result.add(resolvedCall); + } + } + } +// return result; + } + + private Collection> convertWithImpliedThis(Iterable receiverParameters, Collection descriptors) { Collection> result = Lists.newArrayList(); - for (D extension : descriptors) { - ResolvedCall resolvedCall = ResolvedCall.create(extension); - resolvedCall.setReceiverParameter(receiverParameter); - setImpliedThis(resolvedCall); - result.add(resolvedCall); + for (ReceiverDescriptor receiverParameter : receiverParameters) { + for (D extension : descriptors) { + ResolvedCall resolvedCall = ResolvedCall.create(extension); + resolvedCall.setReceiverParameter(receiverParameter); + setImpliedThis(resolvedCall); + result.add(resolvedCall); + } } return result; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java index a044f24d0da..25ffed7b609 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java @@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lang.resolve.BindingTrace; +import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace; import org.jetbrains.jet.lang.types.CallMaker; import java.util.List; @@ -20,15 +20,17 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; * @author abreslav */ /*package*/ class ValueArgumentsToParametersMapper { - public static boolean mapValueArgumentsToParameters( - @NotNull ResolutionTask task, + public static boolean mapValueArgumentsToParameters( + @NotNull ResolutionTask task, @NotNull TracingStrategy tracing, - @NotNull Descriptor candidate, - @NotNull BindingTrace temporaryTrace, - @NotNull Map argumentsToParameters + @NotNull ResolvedCall candidateCall ) { + + TemporaryBindingTrace temporaryTrace = candidateCall.getTrace(); + Map varargs = Maps.newHashMap(); Set usedParameters = Sets.newHashSet(); + D candidate = candidateCall.getCandidateDescriptor(); List valueParameters = candidate.getValueParameters(); Map parameterByName = Maps.newHashMap(); @@ -58,7 +60,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; temporaryTrace.report(ARGUMENT_PASSED_TWICE.on(nameReference)); } temporaryTrace.record(REFERENCE_TARGET, nameReference, valueParameterDescriptor); - argumentsToParameters.put(valueArgument, valueParameterDescriptor); + put(candidateCall, valueParameterDescriptor, valueArgument, varargs); } if (somePositioned) { // temporaryTrace.getErrorHandler().genericError(nameNode, "Mixing named and positioned arguments in not allowed"); @@ -78,12 +80,12 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; if (i < parameterCount) { ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(i); usedParameters.add(valueParameterDescriptor); - argumentsToParameters.put(valueArgument, valueParameterDescriptor); + put(candidateCall, valueParameterDescriptor, valueArgument, varargs); } else if (!valueParameters.isEmpty()) { ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1); if (valueParameterDescriptor.isVararg()) { - argumentsToParameters.put(valueArgument, valueParameterDescriptor); + put(candidateCall, valueParameterDescriptor, valueArgument, varargs); usedParameters.add(valueParameterDescriptor); } else { @@ -109,7 +111,8 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; // temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), getTooManyArgumentsMessage(candidate)); temporaryTrace.report(TOO_MANY_ARGUMENTS.on(possiblyLabeledFunctionLiteral, candidate)); error = true; - } else { + } + else { JetFunctionLiteralExpression functionLiteral; if (possiblyLabeledFunctionLiteral instanceof JetLabelQualifiedExpression) { JetLabelQualifiedExpression labeledFunctionLiteral = (JetLabelQualifiedExpression) possiblyLabeledFunctionLiteral; @@ -119,20 +122,20 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; functionLiteral = (JetFunctionLiteralExpression) possiblyLabeledFunctionLiteral; } - ValueParameterDescriptor parameterDescriptor = valueParameters.get(valueParameters.size() - 1); - if (parameterDescriptor.isVararg()) { + ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1); + if (valueParameterDescriptor.isVararg()) { // temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), "Passing value as a vararg is only allowed inside a parenthesized argument list"); temporaryTrace.report(VARARG_OUTSIDE_PARENTHESES.on(possiblyLabeledFunctionLiteral)); error = true; } else { - if (!usedParameters.add(parameterDescriptor)) { + if (!usedParameters.add(valueParameterDescriptor)) { // temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), getTooManyArgumentsMessage(candidate)); temporaryTrace.report(TOO_MANY_ARGUMENTS.on(possiblyLabeledFunctionLiteral, candidate)); error = true; } else { - argumentsToParameters.put(CallMaker.makeValueArgument(functionLiteral), parameterDescriptor); + put(candidateCall, valueParameterDescriptor, CallMaker.makeValueArgument(functionLiteral), varargs); } } } @@ -148,8 +151,14 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; for (ValueParameterDescriptor valueParameter : valueParameters) { if (!usedParameters.contains(valueParameter)) { - if (!valueParameter.hasDefaultValue() && !valueParameter.isVararg()) { -// tracing.reportWrongValueArguments(temporaryTrace, "No value passed for parameter " + valueParameter.getName()); + if (valueParameter.hasDefaultValue()) { + candidateCall.recordValueArgument(valueParameter, DefaultValueArgument.DEFAULT); + } + else if (valueParameter.isVararg()) { + candidateCall.recordValueArgument(valueParameter, new VarargValueArgument()); + } + else { + // tracing.reportWrongValueArguments(temporaryTrace, "No value passed for parameter " + valueParameter.getName()); tracing.noValueForParameter(temporaryTrace, valueParameter); error = true; } @@ -158,6 +167,22 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; return error; } + private static void put(ResolvedCall candidateCall, ValueParameterDescriptor valueParameterDescriptor, ValueArgument valueArgument, Map varargs) { + if (valueParameterDescriptor.isVararg()) { + VarargValueArgument vararg = varargs.get(valueParameterDescriptor); + if (vararg == null) { + vararg = new VarargValueArgument(); + varargs.put(valueParameterDescriptor, vararg); + candidateCall.recordValueArgument(valueParameterDescriptor, vararg); + } + vararg.getArgumentExpressions().add(valueArgument.getArgumentExpression()); + } + else { + ResolvedValueArgument argument = new ExpressionValueArgument(valueArgument.getArgumentExpression()); + candidateCall.recordValueArgument(valueParameterDescriptor, argument); + } + } + // private static String getTooManyArgumentsMessage(Descriptor candidate) { // return "Too many arguments for " + DescriptorRenderer.TEXT.render(candidate); // } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/VarargValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/VarargValueArgument.java index 483400bba7a..3430aa4f8e5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/VarargValueArgument.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/VarargValueArgument.java @@ -13,7 +13,8 @@ public class VarargValueArgument implements ResolvedValueArgument { private final List values = Lists.newArrayList(); @NotNull - public List getValues() { + @Override + public List getArgumentExpressions() { return values; } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/CallMaker.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/CallMaker.java index 8da61d725d0..ff80325db84 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/CallMaker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/CallMaker.java @@ -1,10 +1,12 @@ package org.jetbrains.jet.lang.types; import com.google.common.collect.Lists; +import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import java.util.Collections; import java.util.List; @@ -17,8 +19,8 @@ public class CallMaker { private static class ExpressionValueArgument implements ValueArgument { private final JetExpression expression; - private final PsiElement reportErrorsOn; + private final PsiElement reportErrorsOn; private ExpressionValueArgument(@NotNull JetExpression expression) { this(expression, expression); } @@ -60,18 +62,60 @@ public class CallMaker { } } - private static abstract class CallStub implements Call { + + private static class CallImpl implements Call { + + private final ASTNode callNode; + private final ReceiverDescriptor explicitReceiver; + private ASTNode callOperationNode; + private final JetExpression calleeExpression; + private final List valueArguments; + protected CallImpl(@NotNull ASTNode callNode, @NotNull ReceiverDescriptor explicitReceiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression calleeExpression, @NotNull List valueArguments) { + this.callNode = callNode; + this.explicitReceiver = explicitReceiver; + this.callOperationNode = callOperationNode; + this.calleeExpression = calleeExpression; + this.valueArguments = valueArguments; + } + + @Override + public ASTNode getCallOperationNode() { + return callOperationNode; + } + + @NotNull + @Override + public ReceiverDescriptor getExplicitReceiver() { + return explicitReceiver; + } + + @Override + public JetExpression getCalleeExpression() { + return calleeExpression; + } + + @NotNull + @Override + public List getValueArguments() { + return valueArguments; + } + + @NotNull + @Override + public ASTNode getCallNode() { + return callNode; + } @Override public JetValueArgumentList getValueArgumentList() { return null; } + @NotNull @Override public List getFunctionLiteralArguments() { return Collections.emptyList(); } - @NotNull @Override public List getTypeArguments() { @@ -84,41 +128,31 @@ public class CallMaker { } } - public static Call makeCallWithArguments(final JetExpression calleeExpression, final List valueArguments) { - return new CallStub() { - @Override - public JetExpression getCalleeExpression() { - return calleeExpression; - } - @NotNull - @Override - public List getValueArguments() { - return valueArguments; - } - }; - } - - public static Call makeCall(final JetExpression calleeExpression, final List argumentExpressions) { + public static Call makeCallWithExpressions(@NotNull JetElement callElement, @NotNull ReceiverDescriptor explicitReceiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression calleeExpression, @NotNull List argumentExpressions) { List arguments = Lists.newArrayList(); for (JetExpression argumentExpression : argumentExpressions) { arguments.add(makeValueArgument(argumentExpression, calleeExpression)); } - return makeCallWithArguments(calleeExpression, arguments); + return makeCall(callElement, explicitReceiver, callOperationNode, calleeExpression, arguments); } - public static Call makeCall(final JetBinaryExpression expression) { - return makeCall(expression.getOperationReference(), Collections.singletonList(expression.getRight())); + public static Call makeCall(JetElement callElement, ReceiverDescriptor explicitReceiver, @Nullable ASTNode callOperationNode, JetExpression calleeExpression, List arguments) { + return new CallImpl(callElement.getNode(), explicitReceiver, callOperationNode, calleeExpression, arguments); } - public static Call makeCall(final JetUnaryExpression expression) { - return makeCallWithArguments(expression.getOperationSign(), Collections.emptyList()); + public static Call makeCall(@NotNull ReceiverDescriptor leftAsReceiver, JetBinaryExpression expression) { + return makeCallWithExpressions(expression, leftAsReceiver, null, expression.getOperationReference(), Collections.singletonList(expression.getRight())); } - public static Call makeCall(final JetArrayAccessExpression arrayAccessExpression, final JetExpression rightHandSide) { + public static Call makeCall(@NotNull ReceiverDescriptor baseAsReceiver, JetUnaryExpression expression) { + return makeCall(expression, baseAsReceiver, null, expression.getOperationSign(), Collections.emptyList()); + } + + public static Call makeCall(@NotNull ReceiverDescriptor arrayAsReceiver,JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide) { List arguments = Lists.newArrayList(arrayAccessExpression.getIndexExpressions()); arguments.add(rightHandSide); - return makeCall(arrayAccessExpression, arguments); + return makeCallWithExpressions(arrayAccessExpression, arrayAsReceiver, null, arrayAccessExpression, arguments); } public static ValueArgument makeValueArgument(@NotNull JetExpression expression) { @@ -129,7 +163,58 @@ public class CallMaker { return new ExpressionValueArgument(expression, reportErrorsOn); } - public static Call makePropertyCall(@NotNull JetSimpleNameExpression nameExpression) { - return makeCall(nameExpression, Collections.emptyList()); + public static Call makePropertyCall(@NotNull ReceiverDescriptor explicitReceiver, @Nullable ASTNode callOperationNode, @NotNull JetSimpleNameExpression nameExpression) { + return makeCallWithExpressions(nameExpression, explicitReceiver, callOperationNode, nameExpression, Collections.emptyList()); + } + + public static Call makeCall(@NotNull final ReceiverDescriptor explicitReceiver, @Nullable final ASTNode callOperationNode, @NotNull final JetCallElement callElement) { + return new Call() { + @Override + public ASTNode getCallOperationNode() { + return callOperationNode; + } + + @NotNull + @Override + public ReceiverDescriptor getExplicitReceiver() { + return explicitReceiver; + } + + @Nullable + public JetExpression getCalleeExpression() { + return callElement.getCalleeExpression(); + } + + @Nullable + public JetValueArgumentList getValueArgumentList() { + return callElement.getValueArgumentList(); + } + + @NotNull + public List getValueArguments() { + return callElement.getValueArguments(); + } + + @NotNull + public List getFunctionLiteralArguments() { + return callElement.getFunctionLiteralArguments(); + } + + @NotNull + public List getTypeArguments() { + return callElement.getTypeArguments(); + } + + @Nullable + public JetTypeArgumentList getTypeArgumentList() { + return callElement.getTypeArgumentList(); + } + + @NotNull + @Override + public ASTNode getCallNode() { + return callElement.getNode(); + } + }; } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 0f31a0bc99d..1cf27e2b015 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -19,6 +19,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.AutoCastUtils; import org.jetbrains.jet.lang.resolve.calls.CallResolver; import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults; import org.jetbrains.jet.lang.resolve.constants.*; @@ -36,14 +37,14 @@ 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.scopes.receivers.ReceiverDescriptor.NO_RECEIVER; /** * @author abreslav */ public class JetTypeInferrer { - private static final Set numberConversions = new HashSet(); - + private static final Set numberConversions = Sets.newHashSet(); static { numberConversions.add("dbl"); numberConversions.add("flt"); @@ -216,33 +217,33 @@ public class JetTypeInferrer { return callResolver; } - //TODO JetElement -> JetWhenConditionCall || JetQualifiedExpression - private void checkNullSafety(@Nullable JetType receiverType, @NotNull ASTNode operationTokenNode, @Nullable FunctionDescriptor callee, @NotNull JetElement element) { - if (receiverType != null && callee != null) { - boolean namespaceType = receiverType instanceof NamespaceType; - boolean nullableReceiver = !namespaceType && receiverType.isNullable(); - ReceiverDescriptor calleeReceiver = callee.getReceiver(); - boolean calleeForbidsNullableReceiver = !calleeReceiver.exists() || !calleeReceiver.getType().isNullable(); - - IElementType operationSign = operationTokenNode.getElementType(); - if (nullableReceiver && calleeForbidsNullableReceiver && operationSign == JetTokens.DOT) { -// trace.getErrorHandler().genericError(operationTokenNode, "Only safe calls (?.) are allowed on a nullable receiver of type " + receiverType); - trace.report(UNSAFE_CALL.on(operationTokenNode, receiverType)); - } - else if ((!nullableReceiver || !calleeForbidsNullableReceiver) && operationSign == JetTokens.SAFE_ACCESS) { - if (namespaceType) { -// trace.getErrorHandler().genericError(operationTokenNode, "Safe calls are not allowed on namespaces"); - trace.report(SAFE_CALLS_ARE_NOT_ALLOWED_ON_NAMESPACES.on(operationTokenNode)); - } - else { -// trace.getErrorHandler().genericWarning(operationTokenNode, "Unnecessary safe call on a non-null receiver of type " + receiverType); - - trace.report(UNNECESSARY_SAFE_CALL.on(element, operationTokenNode, receiverType)); - - } - } - } - } +// TODO JetElement -> JetWhenConditionCall || JetQualifiedExpression +// private void checkNullSafety(@Nullable JetType receiverType, @NotNull ASTNode operationTokenNode, @Nullable FunctionDescriptor callee, @NotNull JetElement element) { +// if (receiverType != null && callee != null) { +// boolean namespaceType = receiverType instanceof NamespaceType; +// boolean nullableReceiver = !namespaceType && receiverType.isNullable(); +// ReceiverDescriptor calleeReceiver = callee.getReceiver(); +// boolean calleeForbidsNullableReceiver = !calleeReceiver.exists() || !calleeReceiver.getType().isNullable(); +// +// IElementType operationSign = operationTokenNode.getElementType(); +// if (nullableReceiver && calleeForbidsNullableReceiver && operationSign == JetTokens.DOT) { +//// trace.getErrorHandler().genericError(operationTokenNode, "Only safe calls (?.) are allowed on a nullable receiver of type " + receiverType); +// trace.report(UNSAFE_CALL.on(operationTokenNode, receiverType)); +// } +// else if ((!nullableReceiver || !calleeForbidsNullableReceiver) && operationSign == JetTokens.SAFE_ACCESS) { +// if (namespaceType) { +//// trace.getErrorHandler().genericError(operationTokenNode, "Safe calls are not allowed on namespaces"); +// trace.report(SAFE_CALLS_ARE_NOT_ALLOWED_ON_NAMESPACES.on(operationTokenNode)); +// } +// else { +//// trace.getErrorHandler().genericWarning(operationTokenNode, "Unnecessary safe call on a non-null receiver of type " + receiverType); +// +// trace.report(UNNECESSARY_SAFE_CALL.on(element, operationTokenNode, receiverType)); +// +// } +// } +// } +// } public void checkFunctionReturnType(@NotNull JetScope outerScope, @NotNull JetDeclarationWithBody function, @NotNull FunctionDescriptor functionDescriptor) { checkFunctionReturnType(outerScope, function, functionDescriptor, DataFlowInfo.getEmpty()); @@ -483,67 +484,67 @@ public class JetTypeInferrer { }; } - //TODO - private JetType enrichOutType(JetExpression expression, JetType initialType, @NotNull TypeInferenceContext context) { - if (expression == null) return initialType; - VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(expression, context); - if (variableDescriptor != null) { - return context.dataFlowInfo.getOutType(variableDescriptor); - } - return initialType; - } +// //TODO +// private JetType enrichOutType(JetExpression expression, JetType initialType, @NotNull TypeInferenceContext context) { +// if (expression == null) return initialType; +// VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(expression, context); +// if (variableDescriptor != null) { +// return context.dataFlowInfo.getOutType(variableDescriptor); +// } +// return initialType; +// } + +// @Nullable +// private JetType checkType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull TypeInferenceContext context) { +// if (expressionType != null && context.expectedType != null && context.expectedType != NO_EXPECTED_TYPE) { +// if (!semanticServices.getTypeChecker().isSubtypeOf(expressionType, context.expectedType)) { +// context.trace.report(TYPE_MISMATCH.on(expression, context.expectedType, expressionType)); +// } +// } +// return expressionType; +// } @Nullable private JetType checkType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull TypeInferenceContext context) { - if (expressionType != null && context.expectedType != null && context.expectedType != NO_EXPECTED_TYPE) { - if (!semanticServices.getTypeChecker().isSubtypeOf(expressionType, context.expectedType)) { - context.trace.report(TYPE_MISMATCH.on(expression, context.expectedType, expressionType)); - } - } - return expressionType; - } - - @Nullable - private JetType checkEnrichedType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull TypeInferenceContext context) { if (expressionType == null || context.expectedType == null || context.expectedType == NO_EXPECTED_TYPE || semanticServices.getTypeChecker().isSubtypeOf(expressionType, context.expectedType)) { return expressionType; } - VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(expression, context); - boolean appropriateTypeFound = false; - if (variableDescriptor != null) { - List possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)); - Collections.reverse(possibleTypes); - for (JetType possibleType : possibleTypes) { - if (semanticServices.getTypeChecker().isSubtypeOf(possibleType, context.expectedType)) { - appropriateTypeFound = true; - break; - } - } - if (!appropriateTypeFound) { - JetType notnullType = context.dataFlowInfo.getOutType(variableDescriptor); - if (notnullType != null && semanticServices.getTypeChecker().isSubtypeOf(notnullType, context.expectedType)) { - appropriateTypeFound = true; - } - } - } - if (!appropriateTypeFound) { +// VariableDescriptor variableDescriptor = AutoCastUtils.getVariableDescriptorFromSimpleName(context.trace.getBindingContext(), expression); +// boolean appropriateTypeFound = false; +// if (variableDescriptor != null) { +// List possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)); +// Collections.reverse(possibleTypes); +// for (JetType possibleType : possibleTypes) { +// if (semanticServices.getTypeChecker().isSubtypeOf(possibleType, context.expectedType)) { +// appropriateTypeFound = true; +// break; +// } +// } +// if (!appropriateTypeFound) { +// JetType notnullType = context.dataFlowInfo.getOutType(variableDescriptor); +// if (notnullType != null && semanticServices.getTypeChecker().isSubtypeOf(notnullType, context.expectedType)) { +// appropriateTypeFound = true; +// } +// } +// } + if (AutoCastUtils.castExpression(expression, context.expectedType, context.dataFlowInfo, context.trace) == null) { // context.trace.getErrorHandler().typeMismatch(expression, context.expectedType, expressionType); context.trace.report(TYPE_MISMATCH.on(expression, context.expectedType, expressionType)); return expressionType; } - checkAutoCast(expression, context.expectedType, variableDescriptor, context.trace); +// checkAutoCast(expression, context.expectedType, variableDescriptor, context.trace); return context.expectedType; } - private void checkAutoCast(JetExpression expression, JetType type, VariableDescriptor variableDescriptor, BindingTrace trace) { - if (variableDescriptor.isVar()) { -// trace.getErrorHandler().genericError(expression.getNode(), "Automatic cast to " + type + " is impossible, because variable " + variableDescriptor.getName() + " is mutable"); - trace.report(AUTOCAST_IMPOSSIBLE.on(expression, type, variableDescriptor)); - } else { - trace.record(BindingContext.AUTOCAST, expression, type); - } - } +// private void checkAutoCast(JetExpression expression, JetType type, VariableDescriptor variableDescriptor, BindingTrace trace) { +// if (variableDescriptor.isVar()) { +//// trace.getErrorHandler().genericError(expression.getNode(), "Automatic cast to " + type + " is impossible, because variable " + variableDescriptor.getName() + " is mutable"); +// trace.report(AUTOCAST_IMPOSSIBLE.on(expression, type, variableDescriptor)); +// } else { +// trace.record(BindingContext.AUTOCAST, expression, type); +// } +// } @NotNull private List checkArgumentTypes(@NotNull List argumentTypes, @NotNull List arguments, @NotNull List expectedArgumentTypes, @NotNull TypeInferenceContext context) { @@ -552,7 +553,7 @@ public class JetTypeInferrer { } List result = Lists.newArrayListWithCapacity(arguments.size()); for (int i = 0, argumentTypesSize = argumentTypes.size(); i < argumentTypesSize; i++) { - result.add(checkEnrichedType(argumentTypes.get(i), arguments.get(i), context.replaceExpectedType(expectedArgumentTypes.get(i).getType()))); + result.add(checkType(argumentTypes.get(i), arguments.get(i), context.replaceExpectedType(expectedArgumentTypes.get(i).getType()))); } return result; } @@ -675,12 +676,12 @@ public class JetTypeInferrer { @Nullable public FunctionDescriptor resolveCallWithGivenName(@NotNull Call call, @NotNull JetReferenceExpression functionReference, @NotNull String name, @NotNull ReceiverDescriptor receiver) { - return getCallResolver().resolveCallWithGivenName(trace, scope, call, functionReference, name, receiver, expectedType); + return getCallResolver().resolveCallWithGivenName(trace, scope, call, functionReference, name, expectedType); } @Nullable - public JetType resolveCall(@NotNull ReceiverDescriptor receiver, @NotNull JetCallElement call) { - return getCallResolver().resolveCall(trace, scope, receiver, call, expectedType); + public JetType resolveCall(@NotNull ReceiverDescriptor receiver, @NotNull JetCallExpression callExpression) { + return getCallResolver().resolveCall(trace, scope, CallMaker.makeCall(receiver, (ASTNode) null, callExpression), expectedType); } @Nullable @@ -802,11 +803,11 @@ public class JetTypeInferrer { } else { context.trace.record(REFERENCE_TARGET, expression, property); - return context.services.checkEnrichedType(property.getOutType(), expression, context); + return context.services.checkType(property.getOutType(), expression, context); } } else { - return getSelectorReturnType(ReceiverDescriptor.NO_RECEIVER, expression, context); // TODO : Extensions to this + return getSelectorReturnType(NO_RECEIVER, expression, context); // TODO : Extensions to this // assert JetTokens.IDENTIFIER == expression.getReferencedNameElementType(); // if (referencedName != null) { // VariableDescriptor variable = context.scope.getVariable(referencedName); @@ -816,7 +817,7 @@ public class JetTypeInferrer { // if (result == null) { // context.trace.getErrorHandler().genericError(expression.getNode(), "This variable is not readable in this context"); // } -// return context.services.checkEnrichedType(result, expression, context); +// return context.services.checkType(result, expression, context); // } // else { // return lookupNamespaceOrClassObject(expression, referencedName, context); @@ -831,12 +832,12 @@ public class JetTypeInferrer { // context.trace.getErrorHandler().genericError(expression.getNode(), "Classifier " + classifier.getName() + " does not have a class object"); // } // context.trace.record(REFERENCE_TARGET, expression, classifier); -// return context.services.checkEnrichedType(result, expression, context); +// return context.services.checkType(result, expression, context); // } // else { // JetType[] result = new JetType[1]; // if (furtherNameLookup(expression, referencedName, result, context)) { -// return context.services.checkEnrichedType(result[0], expression, context); +// return context.services.checkType(result[0], expression, context); // } // // } @@ -863,12 +864,12 @@ public class JetTypeInferrer { if (result == null) { return ErrorUtils.createErrorType("No class object in " + expression.getReferencedName()); } - return context.services.checkEnrichedType(result, expression, context); + return context.services.checkType(result, expression, context); } else { JetType[] result = new JetType[1]; if (furtherNameLookup(expression, referencedName, result, context)) { - return context.services.checkEnrichedType(result[0], expression, context); + return context.services.checkType(result[0], expression, context); } } @@ -1440,7 +1441,7 @@ public class JetTypeInferrer { assert subjectExpression != null; JetType selectorReturnType = getSelectorReturnType(new ExpressionReceiver(subjectExpression, subjectType), callSuffixExpression, context);//getType(compositeScope, callSuffixExpression, false, context); ensureBooleanResultWithCustomSubject(callSuffixExpression, selectorReturnType, "This expression", context); - context.services.checkNullSafety(subjectType, condition.getOperationTokenNode(), getCalleeFunctionDescriptor(callSuffixExpression, context), condition); +// context.services.checkNullSafety(subjectType, condition.getOperationTokenNode(), getCalleeFunctionDescriptor(callSuffixExpression, context), condition); } } @@ -1449,7 +1450,7 @@ public class JetTypeInferrer { JetExpression rangeExpression = condition.getRangeExpression(); if (rangeExpression != null) { assert subjectExpression != null; - checkInExpression(condition.getOperationReference(), subjectExpression, rangeExpression, context); + checkInExpression(condition, condition.getOperationReference(), subjectExpression, rangeExpression, context); } } @@ -2042,9 +2043,9 @@ public class JetTypeInferrer { } // Clean resolution: no autocasts - TemporaryBindingTrace cleanResolutionTrace = TemporaryBindingTrace.create(context.trace); - TypeInferenceContext cleanResolutionContext = context.replaceBindingTrace(cleanResolutionTrace); - JetType selectorReturnType = getSelectorReturnType(new ExpressionReceiver(receiverExpression, receiverType), selectorExpression, cleanResolutionContext); +// TemporaryBindingTrace cleanResolutionTrace = TemporaryBindingTrace.create(context.trace); +// TypeInferenceContext cleanResolutionContext = context.replaceBindingTrace(cleanResolutionTrace); + JetType selectorReturnType = getSelectorReturnType(new ExpressionReceiver(receiverExpression, receiverType), selectorExpression, context); //TODO move further if (expression.getOperationSign() == JetTokens.SAFE_ACCESS) { @@ -2052,40 +2053,40 @@ public class JetTypeInferrer { selectorReturnType = TypeUtils.makeNullable(selectorReturnType); } } - if (selectorReturnType != null) { - cleanResolutionTrace.addAllMyDataTo(context.trace); - } - else { - VariableDescriptor variableDescriptor = cleanResolutionContext.services.getVariableDescriptorFromSimpleName(receiverExpression, context); - boolean somethingFound = false; - if (variableDescriptor != null) { - List possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)); - Collections.reverse(possibleTypes); - - TemporaryBindingTrace autocastResolutionTrace = TemporaryBindingTrace.create(context.trace); - TypeInferenceContext autocastResolutionContext = context.replaceBindingTrace(autocastResolutionTrace); - for (JetType possibleType : possibleTypes) { - selectorReturnType = getSelectorReturnType(new ExpressionReceiver(receiverExpression, possibleType), selectorExpression, autocastResolutionContext); - if (selectorReturnType != null) { - context.services.checkAutoCast(receiverExpression, possibleType, variableDescriptor, autocastResolutionTrace); - autocastResolutionTrace.commit(); - somethingFound = true; - break; - } - else { - autocastResolutionTrace = TemporaryBindingTrace.create(context.trace); - autocastResolutionContext = context.replaceBindingTrace(autocastResolutionTrace); - } - } - } - if (!somethingFound) { - cleanResolutionTrace.commit(); - } - } +// if (selectorReturnType != null) { +// cleanResolutionTrace.addAllMyDataTo(context.trace); +// } +// else { +// VariableDescriptor variableDescriptor = cleanResolutionContext.services.getVariableDescriptorFromSimpleName(receiverExpression, context); +// boolean somethingFound = false; +// if (variableDescriptor != null) { +// List possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)); +// Collections.reverse(possibleTypes); +// +// TemporaryBindingTrace autocastResolutionTrace = TemporaryBindingTrace.create(context.trace); +// TypeInferenceContext autocastResolutionContext = context.replaceBindingTrace(autocastResolutionTrace); +// for (JetType possibleType : possibleTypes) { +// selectorReturnType = getSelectorReturnType(new ExpressionReceiver(receiverExpression, possibleType), selectorExpression, autocastResolutionContext); +// if (selectorReturnType != null) { +// context.services.checkAutoCast(receiverExpression, possibleType, variableDescriptor, autocastResolutionTrace); +// autocastResolutionTrace.commit(); +// somethingFound = true; +// break; +// } +// else { +// autocastResolutionTrace = TemporaryBindingTrace.create(context.trace); +// autocastResolutionContext = context.replaceBindingTrace(autocastResolutionTrace); +// } +// } +// } +// if (!somethingFound) { +// cleanResolutionTrace.commit(); +// } +// } JetType result; if (expression.getOperationSign() == JetTokens.QUEST) { - if (selectorReturnType != null && !isBoolean(selectorReturnType) && selectorExpression != null) { + if (selectorReturnType != null && !isBoolean(selectorReturnType)) { // TODO : more comprehensible error message // context.trace.getErrorHandler().typeMismatch(selectorExpression, semanticServices.getStandardLibrary().getBooleanType(), selectorReturnType); context.trace.report(TYPE_MISMATCH.on(selectorExpression, semanticServices.getStandardLibrary().getBooleanType(), selectorReturnType)); @@ -2095,16 +2096,15 @@ public class JetTypeInferrer { else { result = selectorReturnType; } - if (selectorExpression != null && result != null) { + // TODO : this is suspicious: remove this code? + if (result != null) { context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, result); } if (selectorReturnType != null) { - // TODO : extensions to 'Any?' - if (selectorExpression != null) { - receiverType = context.services.enrichOutType(receiverExpression, receiverType, context); - - context.services.checkNullSafety(receiverType, expression.getOperationTokenNode(), getCalleeFunctionDescriptor(selectorExpression, context), expression); - } +// // TODO : extensions to 'Any?' +// receiverType = context.services.enrichOutType(receiverExpression, receiverType, context); +// +// context.services.checkNullSafety(receiverType, expression.getOperationTokenNode(), getCalleeFunctionDescriptor(selectorExpression, context), expression); } return context.services.checkType(result, expression, contextWithExpectedType); } @@ -2139,58 +2139,58 @@ public class JetTypeInferrer { } } - - @NotNull - private FunctionDescriptor getCalleeFunctionDescriptor(@NotNull JetExpression selectorExpression, final TypeInferenceContext context) { - final FunctionDescriptor[] result = new FunctionDescriptor[1]; - selectorExpression.accept(new JetVisitorVoid() { - @Override - public void visitCallExpression(JetCallExpression callExpression) { - JetExpression calleeExpression = callExpression.getCalleeExpression(); - if (calleeExpression != null) { - calleeExpression.accept(this); - } - } - - @Override - public void visitReferenceExpression(JetReferenceExpression referenceExpression) { - DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(REFERENCE_TARGET, referenceExpression); - if (declarationDescriptor instanceof FunctionDescriptor) { - result[0] = (FunctionDescriptor) declarationDescriptor; - } - } - - @Override - public void visitArrayAccessExpression(JetArrayAccessExpression expression) { - expression.getArrayExpression().accept(this); - } - - @Override - public void visitBinaryExpression(JetBinaryExpression expression) { - expression.getLeft().accept(this); - } - - @Override - public void visitQualifiedExpression(JetQualifiedExpression expression) { - expression.getReceiverExpression().accept(this); - } - - @Override - public void visitJetElement(JetElement element) { -// context.trace.getErrorHandler().genericError(element.getNode(), "Unsupported [getCalleeFunctionDescriptor]: " + element); - context.trace.report(UNSUPPORTED.on(element, "getCalleeFunctionDescriptor")); - } - }); - if (result[0] == null) { - result[0] = ErrorUtils.createErrorFunction(0, Collections.emptyList()); - } - return result[0]; - } +// @NotNull +// private FunctionDescriptor getCalleeFunctionDescriptor(@NotNull JetExpression selectorExpression, final TypeInferenceContext context) { +// final FunctionDescriptor[] result = new FunctionDescriptor[1]; +// selectorExpression.accept(new JetVisitorVoid() { +// @Override +// public void visitCallExpression(JetCallExpression callExpression) { +// JetExpression calleeExpression = callExpression.getCalleeExpression(); +// if (calleeExpression != null) { +// calleeExpression.accept(this); +// } +// } +// +// @Override +// public void visitReferenceExpression(JetReferenceExpression referenceExpression) { +// DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(REFERENCE_TARGET, referenceExpression); +// if (declarationDescriptor instanceof FunctionDescriptor) { +// result[0] = (FunctionDescriptor) declarationDescriptor; +// } +// } +// +// @Override +// public void visitArrayAccessExpression(JetArrayAccessExpression expression) { +// expression.getArrayExpression().accept(this); +// } +// +// @Override +// public void visitBinaryExpression(JetBinaryExpression expression) { +// expression.getLeft().accept(this); +// } +// +// @Override +// public void visitQualifiedExpression(JetQualifiedExpression expression) { +// expression.getReceiverExpression().accept(this); +// } +// +// @Override +// public void visitJetElement(JetElement element) { +//// context.trace.getErrorHandler().genericError(element.getNode(), "Unsupported [getCalleeFunctionDescriptor]: " + element); +// context.trace.report(UNSUPPORTED.on(element, "getCalleeFunctionDescriptor")); +// } +// }); +// if (result[0] == null) { +// result[0] = ErrorUtils.createErrorFunction(0, Collections.emptyList()); +// } +// return result[0]; +// } @Nullable private JetType getSelectorReturnType(@NotNull ReceiverDescriptor receiver, @NotNull JetExpression selectorExpression, @NotNull TypeInferenceContext context) { if (selectorExpression instanceof JetCallExpression) { - return context.resolveCall(receiver, (JetCallExpression) selectorExpression); + JetCallExpression callExpression = (JetCallExpression) selectorExpression; + return context.resolveCall(receiver, callExpression); } else if (selectorExpression instanceof JetSimpleNameExpression) { JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) selectorExpression; @@ -2199,14 +2199,14 @@ public class JetTypeInferrer { VariableDescriptor variableDescriptor = context.replaceBindingTrace(temporaryTrace).resolveSimpleProperty(receiver, nameExpression); if (variableDescriptor != null) { temporaryTrace.commit(); - return context.services.checkEnrichedType(variableDescriptor.getOutType(), nameExpression, context); + return context.services.checkType(variableDescriptor.getOutType(), nameExpression, context); } TypeInferenceContext 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 context.services.checkEnrichedType(jetType, nameExpression, context); + return context.services.checkType(jetType, nameExpression, context); // JetScope scope = receiverType != null ? receiverType.getMemberScope() : context.scope; // return getType(selectorExpression, context.replaceScope(scope)); } @@ -2229,7 +2229,7 @@ public class JetTypeInferrer { @Override public JetType visitCallExpression(JetCallExpression expression, TypeInferenceContext context) { - JetType expressionType = context.resolveCall(ReceiverDescriptor.NO_RECEIVER, expression); + JetType expressionType = context.resolveCall(NO_RECEIVER, expression); return context.services.checkType(expressionType, expression, context); } @@ -2267,7 +2267,7 @@ public class JetTypeInferrer { if (receiver == null) return null; FunctionDescriptor functionDescriptor = context.resolveCallWithGivenName( - CallMaker.makeCall(expression), + CallMaker.makeCall(receiver, expression), expression.getOperationSign(), name, receiver); @@ -2379,7 +2379,7 @@ public class JetTypeInferrer { result = ErrorUtils.createErrorType("No right argument"); // TODO return null; } - checkInExpression(operationSign, left, right, context); + checkInExpression(expression, expression.getOperationReference(), expression.getLeft(), expression.getRight(), context); result = semanticServices.getStandardLibrary().getBooleanType(); } else if (operationType == JetTokens.ANDAND || operationType == JetTokens.OROR) { @@ -2419,11 +2419,11 @@ public class JetTypeInferrer { return context.services.checkType(result, expression, contextWithExpectedType); } - private void checkInExpression(JetSimpleNameExpression operationSign, JetExpression left, JetExpression right, TypeInferenceContext context) { + private void checkInExpression(JetElement callElement, @NotNull JetSimpleNameExpression operationSign, @NotNull JetExpression left, @NotNull JetExpression right, TypeInferenceContext context) { String name = "contains"; ExpressionReceiver receiver = safeGetExpressionReceiver(right, context.replaceExpectedType(NO_EXPECTED_TYPE)); FunctionDescriptor functionDescriptor = context.resolveCallWithGivenName( - CallMaker.makeCall(operationSign, Collections.singletonList(left)), + CallMaker.makeCallWithExpressions(callElement, receiver, null, operationSign, Collections.singletonList(left)), operationSign, name, receiver); JetType containsType = functionDescriptor != null ? functionDescriptor.getReturnType() : null; @@ -2492,7 +2492,7 @@ public class JetTypeInferrer { if (receiver != null) { FunctionDescriptor functionDescriptor = context.resolveCallWithGivenName( - CallMaker.makeCall(expression, expression.getIndexExpressions()), + CallMaker.makeCallWithExpressions(expression, receiver, null, expression, expression.getIndexExpressions()), expression, "get", receiver); @@ -2507,7 +2507,7 @@ public class JetTypeInferrer { protected JetType getTypeForBinaryCall(JetScope scope, String name, TypeInferenceContext context, JetBinaryExpression binaryExpression) { ExpressionReceiver receiver = safeGetExpressionReceiver(binaryExpression.getLeft(), context.replaceScope(scope)); FunctionDescriptor functionDescriptor = context.replaceScope(scope).resolveCallWithGivenName( - CallMaker.makeCall(binaryExpression), + CallMaker.makeCall(receiver, binaryExpression), binaryExpression.getOperationReference(), name, receiver); @@ -2755,7 +2755,7 @@ public class JetTypeInferrer { ExpressionReceiver receiver = getExpressionReceiver(arrayAccessExpression.getArrayExpression(), context.replaceScope(scope)); if (receiver == null) return null; // - Call call = CallMaker.makeCall(arrayAccessExpression, rightHandSide); + Call call = CallMaker.makeCall(receiver, arrayAccessExpression, rightHandSide); // // TODO : nasty hack: effort is duplicated // callResolver.resolveCallWithGivenName( // scope, diff --git a/idea/testData/checkerWithErrorTypes/quick/AutocastAmbiguitites.jet b/idea/testData/checkerWithErrorTypes/quick/AutocastAmbiguitites.jet new file mode 100644 index 00000000000..614374e9521 --- /dev/null +++ b/idea/testData/checkerWithErrorTypes/quick/AutocastAmbiguitites.jet @@ -0,0 +1,16 @@ +trait B { + fun bar() {} +} + +class C() { + fun bar() { + } +} + +fun test(a : Any?) { + if (a is B) { + if (a is C) { + a.bar(); + } + } +}