From 041505f5b8e3d913cd7491f948ab4dbe4e1240c0 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Mon, 17 Jun 2013 19:05:54 +0400 Subject: [PATCH] report UNRESOLVED_REFERENCE_WRONG_RECEIVER mentioning candidates with wrong receiver --- .../jet/lang/diagnostics/Errors.java | 3 +- .../rendering/DefaultErrorMessages.java | 1 + .../resolve/calls/ArgumentTypeResolver.java | 6 +-- .../jet/lang/resolve/calls/CallResolver.java | 23 +++++----- .../lang/resolve/calls/CandidateResolver.java | 42 +++++++++++++------ .../results/OverloadResolutionResults.java | 1 + .../OverloadResolutionResultsImpl.java | 6 ++- .../results/ResolutionResultsHandler.java | 14 +++++-- .../calls/results/ResolutionStatus.java | 11 ++++- .../resolve/calls/tasks/TracingStrategy.java | 10 +++-- .../calls/tasks/TracingStrategyImpl.java | 7 +++- .../diagnostics/tests/extensions/kt3563.kt | 4 +- .../throwOutCandidatesByReceiver.kt | 18 +++++--- .../throwOutCandidatesByReceiver2.kt | 14 +++++++ .../tests/inference/regressions/kt742.kt | 2 +- .../wrongReceiverVsOtherError.resolve | 17 ++++++++ .../checkers/JetDiagnosticsTestGenerated.java | 5 +++ .../jet/resolve/JetResolveTestGenerated.java | 5 +++ .../plugin/highlighter/IdeErrorMessages.java | 2 +- 19 files changed, 142 insertions(+), 49 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver2.kt create mode 100644 compiler/testData/resolve/candidatesPriority/wrongReceiverVsOtherError.resolve 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 4f59ca5d8ca..fb577259e3f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -337,6 +337,7 @@ public interface Errors { DiagnosticFactory1>> OVERLOAD_RESOLUTION_AMBIGUITY = DiagnosticFactory1.create(ERROR); DiagnosticFactory1>> NONE_APPLICABLE = DiagnosticFactory1.create(ERROR); DiagnosticFactory1>> CANNOT_COMPLETE_RESOLVE = DiagnosticFactory1.create(ERROR); + DiagnosticFactory1>> UNRESOLVED_REFERENCE_WRONG_RECEIVER = DiagnosticFactory1.create(ERROR); DiagnosticFactory0 DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED = DiagnosticFactory0.create(WARNING); @@ -548,7 +549,7 @@ public interface Errors { // Error sets ImmutableSet UNRESOLVED_REFERENCE_DIAGNOSTICS = ImmutableSet.of( - UNRESOLVED_REFERENCE, NAMED_PARAMETER_NOT_FOUND); + UNRESOLVED_REFERENCE, NAMED_PARAMETER_NOT_FOUND, UNRESOLVED_REFERENCE_WRONG_RECEIVER); ImmutableSet UNUSED_ELEMENT_DIAGNOSTICS = ImmutableSet.of( UNUSED_VARIABLE, UNUSED_PARAMETER, ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE); ImmutableSet REDECLARATION_DIAGNOSTICS = ImmutableSet.of( diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java index 6cf84bf8dfc..1303f0fd170 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java @@ -410,6 +410,7 @@ public class DefaultErrorMessages { MAP.put(OVERLOAD_RESOLUTION_AMBIGUITY, "Overload resolution ambiguity: {0}", AMBIGUOUS_CALLS); MAP.put(NONE_APPLICABLE, "None of the following functions can be called with the arguments supplied: {0}", AMBIGUOUS_CALLS); MAP.put(CANNOT_COMPLETE_RESOLVE, "Cannot choose among the following candidates without completing type inference: {0}", AMBIGUOUS_CALLS); + MAP.put(UNRESOLVED_REFERENCE_WRONG_RECEIVER, "Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: {0}", AMBIGUOUS_CALLS); MAP.put(NO_VALUE_FOR_PARAMETER, "No value passed for parameter {0}", NAME); MAP.put(MISSING_RECEIVER, "A receiver of type {0} is required", RENDER_TYPE); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java index d2a88eb2d61..8f3b800d54c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java @@ -56,8 +56,6 @@ import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgum import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; public class ArgumentTypeResolver { - @NotNull - private final JetTypeChecker typeChecker = JetTypeChecker.INSTANCE; @NotNull private TypeResolver typeResolver; @@ -74,14 +72,14 @@ public class ArgumentTypeResolver { this.expressionTypingServices = expressionTypingServices; } - public boolean isSubtypeOfForArgumentType(@NotNull JetType subtype, @NotNull JetType supertype) { + public static boolean isSubtypeOfForArgumentType(@NotNull JetType subtype, @NotNull JetType supertype) { if (subtype == PLACEHOLDER_FUNCTION_TYPE) { return isFunctionOrErrorType(supertype) || KotlinBuiltIns.getInstance().isAny(supertype); //todo function type extends } if (supertype == PLACEHOLDER_FUNCTION_TYPE) { return isFunctionOrErrorType(subtype); //todo extends function type } - return typeChecker.isSubtypeOf(subtype, supertype); + return JetTypeChecker.INSTANCE.isSubtypeOf(subtype, supertype); } private static boolean isFunctionOrErrorType(@NotNull JetType supertype) { 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 f5bb8302e8f..2f5ed68b8ec 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 @@ -31,10 +31,7 @@ import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.calls.context.*; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace; -import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults; -import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl; -import org.jetbrains.jet.lang.resolve.calls.results.ResolutionDebugInfo; -import org.jetbrains.jet.lang.resolve.calls.results.ResolutionResultsHandler; +import org.jetbrains.jet.lang.resolve.calls.results.*; import org.jetbrains.jet.lang.resolve.calls.tasks.*; import org.jetbrains.jet.lang.resolve.calls.util.DelegatingCall; import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor; @@ -59,6 +56,7 @@ import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.resolve.BindingContext.NON_DEFAULT_EXPRESSION_DATA_FLOW; import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLUTION_SCOPE; import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS; +import static org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults.Code.*; import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER; import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; @@ -274,8 +272,8 @@ public class CallResolver { private OverloadResolutionResultsImpl doResolveCallOrGetCachedResults( @NotNull ResolutionResultsCache.MemberType memberType, - @NotNull final BasicCallResolutionContext context, - @NotNull final List> prioritizedTasks, + @NotNull BasicCallResolutionContext context, + @NotNull List> prioritizedTasks, @NotNull CallTransformer callTransformer, @NotNull JetReferenceExpression reference ) { @@ -323,7 +321,7 @@ public class CallResolver { @NotNull TracingStrategy tracing ) { if (!results.isSingleResult()) { - if (results.getResultCode() == OverloadResolutionResults.Code.INCOMPLETE_TYPE_INFERENCE) { + if (results.getResultCode() == INCOMPLETE_TYPE_INFERENCE) { argumentTypeResolver.checkTypesWithNoCallee(context, RESOLVE_FUNCTION_ARGUMENTS); } return; @@ -427,11 +425,14 @@ public class CallResolver { resolveFunctionArguments(context, results); return results; } - if (results.getResultCode() == OverloadResolutionResults.Code.INCOMPLETE_TYPE_INFERENCE) { + if (results.getResultCode() == INCOMPLETE_TYPE_INFERENCE) { results.setTrace(taskTrace); return results; } - if (traceForFirstNonemptyCandidateSet == null && !task.getCandidates().isEmpty() && !results.isNothing()) { + boolean updateResults = traceForFirstNonemptyCandidateSet == null + || (resultsForFirstNonemptyCandidateSet.getResultCode() == CANDIDATES_WITH_WRONG_RECEIVER && + results.getResultCode() != CANDIDATES_WITH_WRONG_RECEIVER); + if (!task.getCandidates().isEmpty() && !results.isNothing() && updateResults) { traceForFirstNonemptyCandidateSet = taskTrace; resultsForFirstNonemptyCandidateSet = results; } @@ -488,8 +489,8 @@ public class CallResolver { // {...} // intended to be a returned from the outer literal // } // } - ImmutableSet someFailed = ImmutableSet.of(OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES, - OverloadResolutionResults.Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH); + ImmutableSet someFailed = ImmutableSet.of(MANY_FAILED_CANDIDATES, + SINGLE_CANDIDATE_ARGUMENT_MISMATCH); if (someFailed.contains(results.getResultCode()) && !task.call.getFunctionLiteralArguments().isEmpty() && task.resolveMode == ResolveMode.TOP_LEVEL_CALL) { //For nested calls there are no such cases // We have some candidates that failed for some reason diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java index 9cb99b27291..e2f6585dadd 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java @@ -83,6 +83,8 @@ public class CandidateResolver { ResolvedCallImpl candidateCall = context.candidateCall; D candidate = candidateCall.getCandidateDescriptor(); + candidateCall.addStatus(checkReceiver(context, context.trace, /*checkOnlyReceiverTypeError=*/true)); + if (ErrorUtils.isError(candidate)) { candidateCall.addStatus(SUCCESS); argumentTypeResolver.checkTypesWithNoCallee(context.toBasic()); @@ -110,7 +112,7 @@ public class CandidateResolver { candidateCall, unmappedArguments); if (!argumentMappingStatus.isSuccess()) { if (argumentMappingStatus == ValueArgumentsToParametersMapper.Status.STRONG_ERROR) { - candidateCall.addStatus(STRONG_ERROR); + candidateCall.addStatus(RECEIVER_PRESENCE_ERROR); } else { candidateCall.addStatus(OTHER_ERROR); @@ -563,6 +565,17 @@ public class CandidateResolver { ValueArgumentsCheckingResult checkingResult = checkValueArgumentTypes( context, context.candidateCall, trace, resolveFunctionArgumentBodies); ResolutionStatus resultStatus = checkingResult.status; + resultStatus = resultStatus.combine(checkReceiver(context, trace, false)); + + return new ValueArgumentsCheckingResult(resultStatus, checkingResult.argumentTypes); + } + + private static ResolutionStatus checkReceiver( + @NotNull CallCandidateResolutionContext context, + @NotNull BindingTrace trace, + boolean checkOnlyReceiverTypeError + ) { + ResolutionStatus resultStatus = SUCCESS; ResolvedCall candidateCall = context.candidateCall; // Comment about a very special case. @@ -573,15 +586,15 @@ public class CandidateResolver { resultStatus = resultStatus.combine(checkReceiver( context, candidateCall, trace, candidateCall.getResultingDescriptor().getReceiverParameter(), - candidateCall.getReceiverArgument(), candidateCall.getExplicitReceiverKind().isReceiver(), false)); + candidateCall.getReceiverArgument(), candidateCall.getExplicitReceiverKind().isReceiver(), false, checkOnlyReceiverTypeError)); resultStatus = resultStatus.combine(checkReceiver( context, candidateCall, trace, candidateCall.getResultingDescriptor().getExpectedThisObject(), candidateCall.getThisObject(), candidateCall.getExplicitReceiverKind().isThisObject(), // for the invocation 'foo(1)' where foo is a variable of function type we should mark 'foo' if there is unsafe call error - context.call instanceof CallForImplicitInvoke)); - return new ValueArgumentsCheckingResult(resultStatus, checkingResult.argumentTypes); + context.call instanceof CallForImplicitInvoke, checkOnlyReceiverTypeError)); + return resultStatus; } public ValueArgumentsCheckingResult checkValueArgumentTypes( @@ -623,7 +636,7 @@ public class CandidateResolver { } else { JetType resultingType; - if (expectedType == NO_EXPECTED_TYPE || argumentTypeResolver.isSubtypeOfForArgumentType(type, expectedType)) { + if (expectedType == NO_EXPECTED_TYPE || ArgumentTypeResolver.isSubtypeOfForArgumentType(type, expectedType)) { resultingType = type; } else { @@ -642,7 +655,7 @@ public class CandidateResolver { } @Nullable - private JetType autocastValueArgumentTypeIfPossible( + private static JetType autocastValueArgumentTypeIfPossible( @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull JetType actualType, @@ -653,38 +666,43 @@ public class CandidateResolver { List variants = AutoCastUtils.getAutoCastVariants(trace.getBindingContext(), dataFlowInfo, receiverToCast); for (ReceiverValue receiverValue : variants) { JetType possibleType = receiverValue.getType(); - if (argumentTypeResolver.isSubtypeOfForArgumentType(possibleType, expectedType)) { + if (ArgumentTypeResolver.isSubtypeOfForArgumentType(possibleType, expectedType)) { return possibleType; } } return null; } - private ResolutionStatus checkReceiver( + private static ResolutionStatus checkReceiver( @NotNull CallCandidateResolutionContext context, @NotNull ResolvedCall candidateCall, @NotNull BindingTrace trace, @Nullable ReceiverParameterDescriptor receiverParameter, @NotNull ReceiverValue receiverArgument, boolean isExplicitReceiver, - boolean implicitInvokeCheck + boolean implicitInvokeCheck, + boolean checkOnlyReceiverTypeError ) { if (receiverParameter == null || !receiverArgument.exists()) return SUCCESS; JetType receiverArgumentType = receiverArgument.getType(); JetType effectiveReceiverArgumentType = TypeUtils.makeNotNullable(receiverArgumentType); D candidateDescriptor = candidateCall.getCandidateDescriptor(); - if (!argumentTypeResolver.isSubtypeOfForArgumentType(effectiveReceiverArgumentType, receiverParameter.getType())) { + if (!ArgumentTypeResolver.isSubtypeOfForArgumentType(effectiveReceiverArgumentType, receiverParameter.getType())) { if (CallResolverUtil.checkArgumentCannotBeReceiver(effectiveReceiverArgumentType, candidateDescriptor) && !(candidateDescriptor instanceof ExpressionAsFunctionDescriptor)) { - return STRONG_ERROR; + return RECEIVER_TYPE_ERROR; } - if (!TypeUtils.dependsOnTypeParameters(receiverParameter.getType(), candidateDescriptor.getTypeParameters())) { + //todo + if (!TypeUtils.dependsOnTypeParameters(receiverParameter.getType(), candidateDescriptor.getTypeParameters()) + && !checkOnlyReceiverTypeError) { context.tracing.wrongReceiverType(trace, receiverParameter, receiverArgument); return OTHER_ERROR; } } + if (checkOnlyReceiverTypeError) return SUCCESS; + BindingContext bindingContext = trace.getBindingContext(); boolean safeAccess = isExplicitReceiver && !implicitInvokeCheck && candidateCall.isSafeCall(); AutoCastServiceImpl autoCastService = new AutoCastServiceImpl(context.dataFlowInfo, bindingContext); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadResolutionResults.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadResolutionResults.java index 2e4337d1704..1b7f0eb48c1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadResolutionResults.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadResolutionResults.java @@ -29,6 +29,7 @@ public interface OverloadResolutionResults { SINGLE_CANDIDATE_ARGUMENT_MISMATCH(false), AMBIGUITY(false), MANY_FAILED_CANDIDATES(false), + CANDIDATES_WITH_WRONG_RECEIVER(false), INCOMPLETE_TYPE_INFERENCE(false); private final boolean success; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadResolutionResultsImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadResolutionResultsImpl.java index 50d73d3eede..0dce2322f94 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadResolutionResultsImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/OverloadResolutionResultsImpl.java @@ -41,6 +41,10 @@ public class OverloadResolutionResultsImpl impleme return new OverloadResolutionResultsImpl(Code.MANY_FAILED_CANDIDATES, failedCandidates); } + public static OverloadResolutionResultsImpl candidatesWithWrongReceiver(Collection> failedCandidates) { + return new OverloadResolutionResultsImpl(Code.CANDIDATES_WITH_WRONG_RECEIVER, failedCandidates); + } + public static OverloadResolutionResultsImpl ambiguity(Collection> candidates) { return new OverloadResolutionResultsImpl(Code.AMBIGUITY, candidates); } @@ -94,7 +98,7 @@ public class OverloadResolutionResultsImpl impleme @Override public boolean isSingleResult() { - return results.size() == 1; + return results.size() == 1 && getResultCode() != Code.CANDIDATES_WITH_WRONG_RECEIVER; } @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/ResolutionResultsHandler.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/ResolutionResultsHandler.java index a427b80640e..fc6e393edac 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/ResolutionResultsHandler.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/ResolutionResultsHandler.java @@ -44,6 +44,7 @@ public class ResolutionResultsHandler { Set> successfulCandidates = Sets.newLinkedHashSet(); Set> failedCandidates = Sets.newLinkedHashSet(); Set> incompleteCandidates = Sets.newLinkedHashSet(); + Set> candidatesWithWrongReceiver = Sets.newLinkedHashSet(); for (ResolvedCallWithTrace candidateCall : candidates) { ResolutionStatus status = candidateCall.getStatus(); assert status != UNKNOWN_STATUS : "No resolution for " + candidateCall.getCandidateDescriptor(); @@ -53,7 +54,10 @@ public class ResolutionResultsHandler { else if (status == INCOMPLETE_TYPE_INFERENCE) { incompleteCandidates.add(candidateCall); } - else if (candidateCall.getStatus() != STRONG_ERROR) { + else if (candidateCall.getStatus() == RECEIVER_TYPE_ERROR) { + candidatesWithWrongReceiver.add(candidateCall); + } + else if (candidateCall.getStatus() != RECEIVER_PRESENCE_ERROR) { failedCandidates.add(candidateCall); } } @@ -65,10 +69,12 @@ public class ResolutionResultsHandler { else if (!failedCandidates.isEmpty()) { return computeFailedResult(trace, tracing, failedCandidates); } - else { - tracing.unresolvedReference(trace); - return OverloadResolutionResultsImpl.nameNotFound(); + if (!candidatesWithWrongReceiver.isEmpty()) { + tracing.unresolvedReferenceWrongReceiver(trace, candidatesWithWrongReceiver); + return OverloadResolutionResultsImpl.candidatesWithWrongReceiver(candidatesWithWrongReceiver); } + tracing.unresolvedReference(trace); + return OverloadResolutionResultsImpl.nameNotFound(); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/ResolutionStatus.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/ResolutionStatus.java index 5d5ced260b9..22df4c52148 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/ResolutionStatus.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/results/ResolutionStatus.java @@ -22,7 +22,13 @@ public enum ResolutionStatus { UNKNOWN_STATUS, UNSAFE_CALL_ERROR, OTHER_ERROR, - STRONG_ERROR, + // '1.foo()' shouldn't be resolved to 'fun String.foo()' + // candidates with such error are treated specially + // (are mentioned in 'unresolved' error, if there are no other options) + RECEIVER_TYPE_ERROR, + // 'a.foo()' shouldn't be resolved to package level non-extension 'fun foo()' + // candidates with such error are thrown away completely + RECEIVER_PRESENCE_ERROR, INCOMPLETE_TYPE_INFERENCE, SUCCESS(true); @@ -30,7 +36,8 @@ public enum ResolutionStatus { public static final EnumSet[] SEVERITY_LEVELS = new EnumSet[] { EnumSet.of(UNSAFE_CALL_ERROR), // weakest EnumSet.of(OTHER_ERROR), - EnumSet.of(STRONG_ERROR), // most severe + EnumSet.of(RECEIVER_TYPE_ERROR), + EnumSet.of(RECEIVER_PRESENCE_ERROR), // most severe }; private final boolean success; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategy.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategy.java index c8408c3446b..4e152fcc247 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategy.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategy.java @@ -23,7 +23,6 @@ import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.resolve.BindingTrace; -import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem; import org.jetbrains.jet.lang.resolve.calls.inference.InferenceErrorData; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; @@ -47,7 +46,10 @@ public interface TracingStrategy { public void unresolvedReference(@NotNull BindingTrace trace) {} @Override - public void recordAmbiguity(BindingTrace trace, Collection> candidates) {} + public void unresolvedReferenceWrongReceiver(@NotNull BindingTrace trace, @NotNull Collection> candidates) {} + + @Override + public void recordAmbiguity(@NotNull BindingTrace trace, @NotNull Collection> candidates) {} @Override public void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor expectedReceiver) {} @@ -104,7 +106,9 @@ public interface TracingStrategy { void unresolvedReference(@NotNull BindingTrace trace); - void recordAmbiguity(BindingTrace trace, Collection> candidates); + void unresolvedReferenceWrongReceiver(@NotNull BindingTrace trace, @NotNull Collection> candidates); + + void recordAmbiguity(@NotNull BindingTrace trace, @NotNull Collection> candidates); void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor expectedReceiver); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyImpl.java index 07b192aa225..3236276728a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyImpl.java @@ -78,7 +78,7 @@ public class TracingStrategyImpl implements TracingStrategy { } @Override - public void recordAmbiguity(BindingTrace trace, Collection> candidates) { + public void recordAmbiguity(@NotNull BindingTrace trace, @NotNull Collection> candidates) { Collection descriptors = Sets.newHashSet(); for (ResolvedCallWithTrace candidate : candidates) { descriptors.add(candidate.getCandidateDescriptor()); @@ -91,6 +91,11 @@ public class TracingStrategyImpl implements TracingStrategy { trace.report(UNRESOLVED_REFERENCE.on(reference, reference)); } + @Override + public void unresolvedReferenceWrongReceiver(@NotNull BindingTrace trace, @NotNull Collection> candidates) { + trace.report(UNRESOLVED_REFERENCE_WRONG_RECEIVER.on(reference, candidates)); + } + @Override public void noValueForParameter(@NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter) { JetElement reportOn; diff --git a/compiler/testData/diagnostics/tests/extensions/kt3563.kt b/compiler/testData/diagnostics/tests/extensions/kt3563.kt index e4401193846..03eb70fd746 100644 --- a/compiler/testData/diagnostics/tests/extensions/kt3563.kt +++ b/compiler/testData/diagnostics/tests/extensions/kt3563.kt @@ -9,9 +9,9 @@ class Customer(name: String) fun foo(f: File, c: Customer) { f.name - c.name // name should be unresolved here + c.name // name should be unresolved here } //from standard library val File.name: String - get() = getName() + get() = getName() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver.kt b/compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver.kt index 92a76c68f8b..65b24137aa0 100644 --- a/compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver.kt +++ b/compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver.kt @@ -6,26 +6,28 @@ package bar fun List.a() {} fun test1(i: Int?) { - 1.a() - i.a() + 1.a() + i.a() } fun test2(c: Collection) { - c.a() + c.a() } fun Int.foo() {} fun test3(s: String?) { - "".foo() - s.foo() + "".foo() + s.foo() + "".foo(1) + s.foo("a") } trait A fun T.c() {} fun test4() { - 1.c() + 1.c() } @@ -46,4 +48,8 @@ fun List.b() {} fun test7(l: List) { l.b() +} + +fun test8(l: List?) { + l.b() } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver2.kt b/compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver2.kt new file mode 100644 index 00000000000..dea949656a3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver2.kt @@ -0,0 +1,14 @@ +package a + +class A {} + +fun test(a1: A, a2: A) { + val range = "island".."isle" + + a1..a2 +} + + +public fun > T.rangeTo(that: T): Range { + throw UnsupportedOperationException() +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt742.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt742.kt index 59c9090b75f..b26cfa17e88 100644 --- a/compiler/testData/diagnostics/tests/inference/regressions/kt742.kt +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt742.kt @@ -9,4 +9,4 @@ fun List.map1(f: (T)-> Q): List? = tail!!.map1(f) fun List.map2(f: (T)-> Q): List? = tail.sure().map2(f) -fun List.map3(f: (T)-> Q): List? = tail.sure().map3(f) \ No newline at end of file +fun List.map3(f: (T)-> Q): List? = tail.sure().map3(f) \ No newline at end of file diff --git a/compiler/testData/resolve/candidatesPriority/wrongReceiverVsOtherError.resolve b/compiler/testData/resolve/candidatesPriority/wrongReceiverVsOtherError.resolve new file mode 100644 index 00000000000..36469cebc79 --- /dev/null +++ b/compiler/testData/resolve/candidatesPriority/wrongReceiverVsOtherError.resolve @@ -0,0 +1,17 @@ +fun Int.foo() {} + +open class A { + ~A.foo~fun foo(i: Int) {} +} +open class B {} + +fun test(a: A, b: B) { + with (a) { + with (b) { + // at first we try b.foo, so 'Int.foo' should have less priority to be thrown away + `A.foo`foo(1.0) + } + } +} + +fun with(receiver: T, f: T.() -> R) : R = receiver.f() \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 247de11cbc4..0ea7d1a1d8c 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -2297,6 +2297,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver.kt"); } + @TestMetadata("throwOutCandidatesByReceiver2.kt") + public void testThrowOutCandidatesByReceiver2() throws Exception { + doTest("compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver2.kt"); + } + } @TestMetadata("compiler/testData/diagnostics/tests/functionLiterals") diff --git a/compiler/tests/org/jetbrains/jet/resolve/JetResolveTestGenerated.java b/compiler/tests/org/jetbrains/jet/resolve/JetResolveTestGenerated.java index 3da417da3a5..faf1d4c2435 100644 --- a/compiler/tests/org/jetbrains/jet/resolve/JetResolveTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/resolve/JetResolveTestGenerated.java @@ -238,6 +238,11 @@ public class JetResolveTestGenerated extends AbstractResolveTest { doTest("compiler/testData/resolve/candidatesPriority/receiverVsThisObject2.resolve"); } + @TestMetadata("wrongReceiverVsOtherError.resolve") + public void testWrongReceiverVsOtherError() throws Exception { + doTest("compiler/testData/resolve/candidatesPriority/wrongReceiverVsOtherError.resolve"); + } + } @TestMetadata("compiler/testData/resolve/delegatedProperty") diff --git a/idea/src/org/jetbrains/jet/plugin/highlighter/IdeErrorMessages.java b/idea/src/org/jetbrains/jet/plugin/highlighter/IdeErrorMessages.java index 9e04c861bd9..65185a00894 100644 --- a/idea/src/org/jetbrains/jet/plugin/highlighter/IdeErrorMessages.java +++ b/idea/src/org/jetbrains/jet/plugin/highlighter/IdeErrorMessages.java @@ -21,7 +21,6 @@ import org.jetbrains.jet.lang.diagnostics.rendering.*; import org.jetbrains.jet.renderer.DescriptorRenderer; import static org.jetbrains.jet.lang.diagnostics.Errors.*; -import static org.jetbrains.jet.lang.diagnostics.rendering.Renderers.NAME; import static org.jetbrains.jet.lang.diagnostics.rendering.Renderers.RENDER_CLASS_OR_OBJECT; import static org.jetbrains.jet.lang.diagnostics.rendering.Renderers.TO_STRING; import static org.jetbrains.jet.lang.diagnostics.rendering.TabledDescriptorRenderer.TextElementType; @@ -93,6 +92,7 @@ public class IdeErrorMessages { MAP.put(NONE_APPLICABLE, "None of the following functions can be called with the arguments supplied.
    {0}
", HTML_NONE_APPLICABLE_CALLS); MAP.put(CANNOT_COMPLETE_RESOLVE, "Cannot choose among the following candidates without completing type inference:
    {0}
", HTML_AMBIGUOUS_CALLS); + MAP.put(UNRESOLVED_REFERENCE_WRONG_RECEIVER, "Unresolved reference.
None of the following candidates is applicable because of receiver type mismatch:
    {0}
", HTML_AMBIGUOUS_CALLS); MAP.put(DELEGATE_SPECIAL_FUNCTION_AMBIGUITY, "Overload resolution ambiguity on method ''{0}''. All these functions match.
    {1}
", TO_STRING, HTML_AMBIGUOUS_CALLS); MAP.put(DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE, "Property delegate must have a ''{0}'' method. None of the following functions is suitable.
    {1}
",