diff --git a/idea/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index 98923827d9d..7aa5f76c3c8 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -99,7 +99,7 @@ public class CallResolver { functionReference = expression; String name = expression.getReferencedName(); - if (name == null) return null; + if (name == null) return checkArgumentTypesAndFail(trace, scope, call); prioritizedTasks = FUNCTION_TASK_PRIORITIZER.computePrioritizedTasks(scope, receiverType, call, name); } @@ -111,7 +111,7 @@ public class CallResolver { JetConstructorCalleeExpression expression = (JetConstructorCalleeExpression) calleeExpression; functionReference = expression.getConstructorReferenceExpression(); if (functionReference == null) { - return null; // No type there + return checkArgumentTypesAndFail(trace, scope, call); // No type there } JetTypeReference typeReference = expression.getTypeReference(); assert typeReference != null; @@ -122,13 +122,13 @@ public class CallResolver { Set constructors = classDescriptor.getConstructors().getFunctionDescriptors(); if (constructors.isEmpty()) { trace.getErrorHandler().genericError(call.getValueArgumentList().getNode(), "This class does not have a constructor"); - return null; + return checkArgumentTypesAndFail(trace, scope, call); } prioritizedTasks.add(new ResolutionTask(constructors, null, call)); } else { trace.getErrorHandler().genericError(calleeExpression.getNode(), "Not a class"); - return null; + return checkArgumentTypesAndFail(trace, scope, call); } } else if (calleeExpression instanceof JetThisReferenceExpression) { functionReference = (JetThisReferenceExpression) calleeExpression; @@ -140,7 +140,7 @@ public class CallResolver { Set constructors = classDescriptor.getConstructors().getFunctionDescriptors(); if (constructors.isEmpty()) { trace.getErrorHandler().genericError(call.getValueArgumentList().getNode(), "This class does not have a constructor"); - return null; + return checkArgumentTypesAndFail(trace, scope, call); } prioritizedTasks = Collections.singletonList(new ResolutionTask(constructors, null, call)); } @@ -151,17 +151,22 @@ public class CallResolver { return resolveCallToDescriptor(trace, scope, call, call.getNode(), expectedType, prioritizedTasks, functionReference); } + private FunctionDescriptor checkArgumentTypesAndFail(BindingTrace trace, JetScope scope, JetCallElement call) { + checkTypesWithNoCallee(trace, scope, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments()); + return null; + } - private Descriptor resolveCallToDescriptor( + private D resolveCallToDescriptor( @NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull final Call call, @NotNull final ASTNode callNode, @NotNull JetType expectedType, - @NotNull final List> prioritizedTasks, // high to low priority + @NotNull final List> prioritizedTasks, // high to low priority @NotNull final JetReferenceExpression reference) { TemporaryBindingTrace traceForFirstNonemptyCandidateSet = null; + OverloadResolutionResult resultForFirstNonemptyCandidateSet = null; TracingStrategy tracing = new TracingStrategy() { @Override public void bindReference(@NotNull BindingTrace trace, @NotNull CallableDescriptor descriptor) { @@ -213,22 +218,28 @@ public class CallResolver { } }; - for (ResolutionTask task : prioritizedTasks) { + for (ResolutionTask task : prioritizedTasks) { TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(trace); - OverloadResolutionResult result = performResolution(temporaryTrace, scope, expectedType, task, tracing); + OverloadResolutionResult result = performResolution(temporaryTrace, scope, expectedType, task, tracing); if (result.isSuccess()) { temporaryTrace.commit(); return result.getDescriptor(); } if (traceForFirstNonemptyCandidateSet == null && !task.getCandidates().isEmpty()) { traceForFirstNonemptyCandidateSet = temporaryTrace; + resultForFirstNonemptyCandidateSet = result; } } if (traceForFirstNonemptyCandidateSet != null) { traceForFirstNonemptyCandidateSet.commit(); + assert resultForFirstNonemptyCandidateSet != null; + if (resultForFirstNonemptyCandidateSet.singleDescriptor()) { + return resultForFirstNonemptyCandidateSet.getDescriptor(); + } } else { trace.getErrorHandler().unresolvedReference(reference); + checkTypesWithNoCallee(trace, scope, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments()); } return null; } @@ -236,14 +247,14 @@ public class CallResolver { ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @NotNull - private OverloadResolutionResult performResolution(@NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull JetType expectedType, @NotNull ResolutionTask task, @NotNull TracingStrategy tracing) { - Map successfulCandidates = Maps.newLinkedHashMap(); - Set failedCandidates = Sets.newLinkedHashSet(); - Set dirtyCandidates = Sets.newLinkedHashSet(); - Map solutions = Maps.newHashMap(); - Map traces = Maps.newHashMap(); + private OverloadResolutionResult performResolution(@NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull JetType expectedType, @NotNull ResolutionTask task, @NotNull TracingStrategy tracing) { + Map successfulCandidates = Maps.newLinkedHashMap(); + Set failedCandidates = Sets.newLinkedHashSet(); + Set dirtyCandidates = Sets.newLinkedHashSet(); + Map solutions = Maps.newHashMap(); + Map traces = Maps.newHashMap(); - for (Descriptor candidate : task.getCandidates()) { + for (D candidate : task.getCandidates()) { TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(trace); traces.put(candidate, temporaryTrace); JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace); @@ -313,7 +324,7 @@ public class CallResolver { ConstraintSystem.Solution solution = constraintSystem.solve(); solutions.put(candidate, solution); if (solution.isSuccessful()) { - Descriptor substitute = (Descriptor) candidate.substitute(solution.getSubstitutor()); + D substitute = (D) candidate.substitute(solution.getSubstitutor()); assert substitute != null; successfulCandidates.put(candidate, substitute); } @@ -347,7 +358,7 @@ public class CallResolver { checkGenericBoundsInAFunctionCall(jetTypeArguments, typeArguments, candidate); Map substitutionContext = FunctionDescriptorUtil.createSubstitutionContext((FunctionDescriptor) candidate, typeArguments); - Descriptor substitutedFunctionDescriptor = (Descriptor) candidate.substitute(TypeSubstitutor.create(substitutionContext)); + D substitutedFunctionDescriptor = (D) candidate.substitute(TypeSubstitutor.create(substitutionContext)); Function mapFunction = createMapFunction(substitutedFunctionDescriptor); if (checkValueArgumentTypes(scope, temporaryServices, argumentsToParameters, dirty, mapFunction) @@ -369,26 +380,30 @@ public class CallResolver { } } - OverloadResolutionResult result = computeResultAndReportErrors(trace, tracing, successfulCandidates, failedCandidates, dirtyCandidates, traces); + OverloadResolutionResult result = computeResultAndReportErrors(trace, tracing, successfulCandidates, failedCandidates, dirtyCandidates, traces); if (!result.singleDescriptor()) { - for (ValueArgument valueArgument : task.getValueArguments()) { - JetExpression argumentExpression = valueArgument.getArgumentExpression(); - if (argumentExpression != null) { - typeInferrer.getServices(trace).getType(scope, argumentExpression, NO_EXPECTED_TYPE); - } - } - - for (JetExpression expression : task.getFunctionLiteralArguments()) { - typeInferrer.getServices(trace).getType(scope, expression, NO_EXPECTED_TYPE); - } - - for (JetTypeProjection typeProjection : task.getTypeArguments()) { - new TypeResolver(semanticServices, trace, true).resolveType(scope, typeProjection.getTypeReference()); - } + checkTypesWithNoCallee(trace, scope, task.getTypeArguments(), task.getValueArguments(), task.getFunctionLiteralArguments()); } return result; } + private void checkTypesWithNoCallee(BindingTrace trace, JetScope scope, List typeArguments, List valueArguments, List functionLiteralArguments) { + for (ValueArgument valueArgument : valueArguments) { + JetExpression argumentExpression = valueArgument.getArgumentExpression(); + if (argumentExpression != null) { + typeInferrer.getServices(trace).getType(scope, argumentExpression, NO_EXPECTED_TYPE); + } + } + + for (JetExpression expression : functionLiteralArguments) { + typeInferrer.getServices(trace).getType(scope, expression, NO_EXPECTED_TYPE); + } + + for (JetTypeProjection typeProjection : typeArguments) { + new TypeResolver(semanticServices, trace, true).resolveType(scope, typeProjection.getTypeReference()); + } + } + private Function createMapFunction(Descriptor substitutedFunctionDescriptor) { assert substitutedFunctionDescriptor != null; final Map parameterMap = Maps.newHashMap(); diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 4761631e13e..1d9fb452b2a 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -564,18 +564,7 @@ public class JetTypeInferrer { @NotNull DataFlowInfo dataFlowInfo, @NotNull JetType expectedType, @NotNull JetType expectedReturnType) { - return newContextForCallResolution(trace, scope, scope, dataFlowInfo, expectedType, expectedReturnType); - } - - @NotNull - private TypeInferenceContext newContextForCallResolution( - @NotNull BindingTrace trace, - @NotNull JetScope scope, - @NotNull JetScope scopeForTopLevelCall, - @NotNull DataFlowInfo dataFlowInfo, - @NotNull JetType expectedType, - @NotNull JetType expectedReturnType) { - return new TypeInferenceContext(trace, scope, scopeForTopLevelCall, dataFlowInfo, expectedType, expectedReturnType); + return new TypeInferenceContext(trace, scope, dataFlowInfo, expectedType, expectedReturnType); } private class TypeInferenceContext { @@ -585,7 +574,6 @@ public class JetTypeInferrer { public final TypeResolver typeResolver; public final ClassDescriptorResolver classDescriptorResolver; public final JetScope scope; - public final JetScope scopeForTopLevelCall; public final Services services; public final DataFlowInfo dataFlowInfo; @@ -597,7 +585,6 @@ public class JetTypeInferrer { private TypeInferenceContext( @NotNull BindingTrace trace, @NotNull JetScope scope, - @NotNull JetScope scopeForTopLevelCall, @NotNull DataFlowInfo dataFlowInfo, @NotNull JetType expectedType, @NotNull JetType expectedReturnType) { @@ -605,7 +592,6 @@ public class JetTypeInferrer { this.typeResolver = new TypeResolver(semanticServices, trace, true); this.classDescriptorResolver = semanticServices.getClassDescriptorResolver(trace); this.scope = scope; - this.scopeForTopLevelCall = scopeForTopLevelCall; this.services = getServices(trace); this.dataFlowInfo = dataFlowInfo; this.expectedType = expectedType; @@ -613,36 +599,36 @@ public class JetTypeInferrer { } public TypeInferenceContext replaceDataFlowInfo(DataFlowInfo newDataFlowInfo) { - return newContextForCallResolution(trace, scope, scopeForTopLevelCall, newDataFlowInfo, expectedType, expectedReturnType); + return newContext(trace, scope, newDataFlowInfo, expectedType, expectedReturnType); } public TypeInferenceContext replaceExpectedType(@Nullable JetType newExpectedType) { if (newExpectedType == null) return replaceExpectedType(NO_EXPECTED_TYPE); if (expectedType == newExpectedType) return this; - return newContextForCallResolution(trace, scope, scopeForTopLevelCall, dataFlowInfo, newExpectedType, expectedReturnType); + return newContext(trace, scope, dataFlowInfo, newExpectedType, expectedReturnType); } public TypeInferenceContext replaceExpectedReturnType(@Nullable JetType newExpectedReturnType) { if (newExpectedReturnType == null) return replaceExpectedReturnType(NO_EXPECTED_TYPE); if (expectedReturnType == newExpectedReturnType) return this; - return newContextForCallResolution(trace, scope, scopeForTopLevelCall, dataFlowInfo, expectedType, newExpectedReturnType); + return newContext(trace, scope, dataFlowInfo, expectedType, newExpectedReturnType); } public TypeInferenceContext replaceBindingTrace(@NotNull BindingTrace newTrace) { if (newTrace == trace) return this; - return newContextForCallResolution(newTrace, scope, scopeForTopLevelCall, dataFlowInfo, expectedType, expectedReturnType); + return newContext(newTrace, scope, dataFlowInfo, expectedType, expectedReturnType); } @NotNull public TypeInferenceContext replaceScope(@NotNull JetScope newScope) { if (newScope == scope) return this; - return newContextForCallResolution(trace, newScope, scopeForTopLevelCall, dataFlowInfo, expectedType, expectedReturnType); + return newContext(trace, newScope, dataFlowInfo, expectedType, expectedReturnType); } @NotNull public TypeInferenceContext replaceExpectedTypes(@NotNull JetType newExpectedType, @NotNull JetType newExpectedReturnType) { if (expectedType == newExpectedType && expectedReturnType == newExpectedReturnType) return this; - return newContextForCallResolution(trace, scope, scopeForTopLevelCall, dataFlowInfo, newExpectedType, newExpectedReturnType); + return newContext(trace, scope, dataFlowInfo, newExpectedType, newExpectedReturnType); } } @@ -683,7 +669,7 @@ public class JetTypeInferrer { result = null; } - if (!(boolean) context.trace.get(BindingContext.PROCESSED, expression)) { + if (!context.trace.get(BindingContext.PROCESSED, expression)) { context.trace.record(BindingContext.RESOLUTION_SCOPE, expression, context.scope); } context.trace.record(BindingContext.PROCESSED, expression); @@ -691,7 +677,7 @@ public class JetTypeInferrer { } private JetType getTypeWithNewScopeAndDataFlowInfo(@NotNull JetScope scope, @NotNull JetExpression expression, @NotNull DataFlowInfo newDataFlowInfo, @NotNull TypeInferenceContext context) { - return getType(expression, newContextForCallResolution(context.trace, scope, context.scopeForTopLevelCall, newDataFlowInfo, context.expectedType, context.expectedReturnType)); + return getType(expression, newContext(context.trace, scope, newDataFlowInfo, context.expectedType, context.expectedReturnType)); } diff --git a/idea/testData/resolve/ClassObjects.jet b/idea/testData/resolve/ClassObjects.jet index b4e898550d1..f698650f962 100644 --- a/idea/testData/resolve/ClassObjects.jet +++ b/idea/testData/resolve/ClassObjects.jet @@ -11,5 +11,5 @@ namespace Jet86 } val a = `A`A.`A.x`x -val c = `B`B.`!null`x +val c = `B`B.`!error`x val d = B().`B.x`x \ No newline at end of file diff --git a/idea/testData/resolve/ExtensionFunctions.jet b/idea/testData/resolve/ExtensionFunctions.jet index 1570a549f4e..73d2ac45cfc 100644 --- a/idea/testData/resolve/ExtensionFunctions.jet +++ b/idea/testData/resolve/ExtensionFunctions.jet @@ -13,7 +13,7 @@ fun <~T~T, ~E~E> `T`T.foo(x : `E`E, y : `A`A) : `T`T { ~+1~fun `A`A.plus(a : Any) { 1.`foo`foo() - true.`foo`foo() + true.`!null`foo() 1 } diff --git a/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java b/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java index 37d37903b6f..78500d879ff 100644 --- a/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java +++ b/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java @@ -13,6 +13,7 @@ import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; +import org.jetbrains.jet.lang.types.ErrorUtils; import org.jetbrains.jet.lang.types.JetStandardLibrary; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeConstructor; @@ -132,7 +133,16 @@ public class ExpectedResolveData { "Must have been resolved to null: " + renderReferenceInContext(referenceExpression) + " but was resolved to " + DescriptorRenderer.TEXT.render(bindingContext.get(BindingContext.REFERENCE_TARGET, referenceExpression)), - bindingContext.get(BindingContext.EXPRESSION_TYPE, referenceExpression) == null + bindingContext.get(BindingContext.REFERENCE_TARGET, referenceExpression) == null + ); + continue; + } + else if ("!error".equals(name)) { + assertTrue( + "Must have been resolved to error: " + + renderReferenceInContext(referenceExpression) + + " but was resolved to " + DescriptorRenderer.TEXT.render(bindingContext.get(BindingContext.REFERENCE_TARGET, referenceExpression)), + ErrorUtils.isError(bindingContext.get(BindingContext.REFERENCE_TARGET, referenceExpression)) ); continue; }