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 16d91912ca6..2fefffa8b9c 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 @@ -266,6 +266,23 @@ public class CallResolver { CallTransformer.FUNCTION_CALL_TRANSFORMER, functionReference); } + public OverloadResolutionResults resolveCallWithKnownCandidate( + @NotNull Call call, + @Nullable TracingStrategy tracing, + @NotNull JetReferenceExpression reference, + @NotNull ResolutionContext context, + @NotNull CallableDescriptor candidate + ) { + Collection> resolutionCandidates = Lists.newArrayList(); + resolutionCandidates.add(ResolutionCandidate.create(candidate, null)); + BasicCallResolutionContext basicCallResolutionContext = BasicCallResolutionContext.create(context, call, CheckValueArgumentsMode.ENABLED); + + List> tasks = TaskPrioritizer + .computePrioritizedTasksFromCandidates(basicCallResolutionContext, reference, resolutionCandidates, tracing); + return doResolveCallOrGetCachedResults(ResolutionResultsCache.FUNCTION_MEMBER_TYPE, basicCallResolutionContext, tasks, + CallTransformer.FUNCTION_CALL_TRANSFORMER, reference); + } + private OverloadResolutionResultsImpl doResolveCallOrGetCachedResults( @NotNull ResolutionResultsCache.MemberType memberType, @NotNull BasicCallResolutionContext context, diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/ResolutionCandidate.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/ResolutionCandidate.java index 45535013ef6..aaf0126b241 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/ResolutionCandidate.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/ResolutionCandidate.java @@ -47,8 +47,9 @@ public class ResolutionCandidate { return new ResolutionCandidate(descriptor, NO_RECEIVER, NO_RECEIVER, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, null); } - public static ResolutionCandidate create(@NotNull D descriptor, boolean isSafeCall) { - return create(descriptor, NO_RECEIVER, NO_RECEIVER, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, isSafeCall); + /* 'null' for isSafeCall parameter if it should be set later (with 'setSafeCall') */ + public static ResolutionCandidate create(@NotNull D descriptor, @Nullable Boolean isSafeCall) { + return new ResolutionCandidate(descriptor, NO_RECEIVER, NO_RECEIVER, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, isSafeCall); } public static ResolutionCandidate create(@NotNull D descriptor, @NotNull ReceiverValue thisObject, diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingUtils.java new file mode 100644 index 00000000000..f6a5ef05af3 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingUtils.java @@ -0,0 +1,347 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.types.expressions; + +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.descriptors.*; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl; +import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl; +import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl; +import org.jetbrains.jet.lang.psi.*; +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.ResolvedCall; +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.tasks.TracingStrategy; +import org.jetbrains.jet.lang.resolve.calls.tasks.TracingStrategyImpl; +import org.jetbrains.jet.lang.resolve.calls.util.CallMaker; +import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; +import org.jetbrains.jet.lang.types.ErrorUtils; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.JetTypeImpl; +import org.jetbrains.jet.lang.types.Variance; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static org.jetbrains.jet.lang.diagnostics.Errors.TYPE_MISMATCH; +import static org.jetbrains.jet.lang.resolve.BindingContext.CALL; +import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL; + +public class ControlStructureTypingUtils { + private ControlStructureTypingUtils() { + } + + /*package*/ static ResolvedCall resolveIfAsCall( + @NotNull Call callForIf, + @NotNull ExpressionTypingContext context + ) { + List noAnnotations = Collections.emptyList(); + Name specialFunctionName = Name.identifierNoValidate(""); + + SimpleFunctionDescriptorImpl ifFunction = new SimpleFunctionDescriptorImpl( + ErrorUtils.getErrorModule(),//todo hack to avoid returning true in 'isError(DeclarationDescriptor)' + noAnnotations, specialFunctionName, CallableMemberDescriptor.Kind.DECLARATION); + + TypeParameterDescriptor typeParameter = TypeParameterDescriptorImpl.createWithDefaultBound( + ifFunction, noAnnotations, false, Variance.INVARIANT, Name.identifier("T"), 0); + + JetType type = new JetTypeImpl(typeParameter.getTypeConstructor(), JetScope.EMPTY); + + ValueParameterDescriptorImpl thenValueParameter = new ValueParameterDescriptorImpl( + ifFunction, 0, noAnnotations, Name.identifier("thenBranch"), type, false, null); + ValueParameterDescriptorImpl elseValueParameter = new ValueParameterDescriptorImpl( + ifFunction, 1, noAnnotations, Name.identifier("elseBranch"), type, false, null); + ifFunction.initialize( + null, + ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER, + Lists.newArrayList(typeParameter), + Lists.newArrayList(thenValueParameter, elseValueParameter), + type, + Modality.FINAL, + Visibilities.PUBLIC, + /*isInline = */ false + ); + + JetReferenceExpression ifReference = JetPsiFactory.createSimpleName(context.expressionTypingServices.getProject(), "fakeIfCall"); + TracingStrategy tracingForIf = createTracingForIf(callForIf); + OverloadResolutionResults + results = context.expressionTypingServices.getCallResolver().resolveCallWithKnownCandidate( + callForIf, tracingForIf, ifReference, context, ifFunction); + assert results.isSingleResult() : "Not single result after resolving one known candidate"; + return results.getResultingCall(); + } + + + + /*package*/ static Call createCallForIf( + final JetIfExpression ifExpression, + @NotNull JetExpression thenBranch, + @NotNull JetExpression elseBranch + ) { + final List valueArguments = Lists.newArrayList( + CallMaker.makeValueArgument(thenBranch, thenBranch), + CallMaker.makeValueArgument(elseBranch, elseBranch)); + return new Call() { + @Nullable + @Override + public ASTNode getCallOperationNode() { + return ifExpression.getNode(); + } + + @NotNull + @Override + public ReceiverValue getExplicitReceiver() { + return ReceiverValue.NO_RECEIVER; + } + + @NotNull + @Override + public ReceiverValue getThisObject() { + return ReceiverValue.NO_RECEIVER; + } + + @Nullable + @Override + public JetExpression getCalleeExpression() { + return ifExpression; + } + + @Nullable + @Override + public JetValueArgumentList getValueArgumentList() { + return null; + } + + @NotNull + @Override + public List getValueArguments() { + return valueArguments; + } + + @NotNull + @Override + public List getFunctionLiteralArguments() { + return Collections.emptyList(); + } + + @NotNull + @Override + public List getTypeArguments() { + return Collections.emptyList(); + } + + @Nullable + @Override + public JetTypeArgumentList getTypeArgumentList() { + return null; + } + + @NotNull + @Override + public PsiElement getCallElement() { + return ifExpression; + } + + @NotNull + @Override + public CallType getCallType() { + return CallType.DEFAULT; + } + }; + } + + /*package*/ static TracingStrategy createTracingForIf(final @NotNull Call callForIf) { + + return new ThrowingOnErrorTracingStrategy("resolve 'if' as a call") { + @Override + public void bindReference( + @NotNull BindingTrace trace, @NotNull ResolvedCallWithTrace resolvedCall + ) { + //do nothing + } + + @Override + public void bindResolvedCall( + @NotNull BindingTrace trace, @NotNull ResolvedCallWithTrace resolvedCall + ) { + trace.record(RESOLVED_CALL, callForIf.getCalleeExpression(), resolvedCall); + trace.record(CALL, callForIf.getCalleeExpression(), callForIf); + + } + + @Override + public void typeInferenceFailed( + @NotNull BindingTrace trace, @NotNull InferenceErrorData.ExtendedInferenceErrorData data + ) { + ConstraintSystem constraintSystem = data.constraintSystem; + assert !constraintSystem.isSuccessful() : "Report error only for not successful constraint system"; + + if (constraintSystem.hasErrorInConstrainingTypes()) { + return; + } + if (constraintSystem.hasOnlyExpectedTypeMismatch()) { + JetExpression ifExpression = callForIf.getCalleeExpression(); + assert ifExpression != null; + TracingStrategyImpl.reportTypeInferenceExpectedTypeMismatch(TYPE_MISMATCH, ifExpression, data, trace); + return; + } + super.typeInferenceFailed(trace, data); + } + }; + } + + private abstract static class ThrowingOnErrorTracingStrategy implements TracingStrategy { + private final String debugName; + + protected ThrowingOnErrorTracingStrategy(String debugName) { + this.debugName = debugName; + } + + private void throwError() { + throw new IllegalStateException("Resolution error of this type shouldn't occur for " + debugName); + } + + @Override + public void unresolvedReference(@NotNull BindingTrace trace) { + throwError(); + } + + @Override + public void unresolvedReferenceWrongReceiver( + @NotNull BindingTrace trace, @NotNull Collection> candidates + ) { + throwError(); + } + + @Override + public void recordAmbiguity( + @NotNull BindingTrace trace, @NotNull Collection> candidates + ) { + throwError(); + } + + @Override + public void missingReceiver( + @NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor expectedReceiver + ) { + throwError(); + } + + @Override + public void wrongReceiverType( + @NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor receiverParameter, @NotNull ReceiverValue receiverArgument + ) { + throwError(); + } + + @Override + public void noReceiverAllowed(@NotNull BindingTrace trace) { + throwError(); + } + + @Override + public void noValueForParameter( + @NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter + ) { + throwError(); + } + + @Override + public void wrongNumberOfTypeArguments(@NotNull BindingTrace trace, int expectedTypeArgumentCount) { + throwError(); + } + + @Override + public void ambiguity( + @NotNull BindingTrace trace, @NotNull Collection> descriptors + ) { + throwError(); + } + + @Override + public void noneApplicable( + @NotNull BindingTrace trace, @NotNull Collection> descriptors + ) { + throwError(); + } + + @Override + public void cannotCompleteResolve( + @NotNull BindingTrace trace, @NotNull Collection> descriptors + ) { + throwError(); + } + + @Override + public void instantiationOfAbstractClass(@NotNull BindingTrace trace) { + throwError(); + } + + @Override + public void unsafeCall( + @NotNull BindingTrace trace, @NotNull JetType type, boolean isCallForImplicitInvoke + ) { + throwError(); + } + + @Override + public void unnecessarySafeCall( + @NotNull BindingTrace trace, @NotNull JetType type + ) { + throwError(); + } + + @Override + public void danglingFunctionLiteralArgumentSuspected( + @NotNull BindingTrace trace, @NotNull List functionLiteralArguments + ) { + throwError(); + } + + @Override + public void invisibleMember( + @NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor + ) { + throwError(); + } + + @Override + public void typeInferenceFailed( + @NotNull BindingTrace trace, @NotNull InferenceErrorData.ExtendedInferenceErrorData inferenceErrorData + ) { + throwError(); + } + + @Override + public void upperBoundViolated( + @NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData + ) { + throwError(); + } + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java index 7f0a56372ff..f7aebe40fd2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java @@ -22,10 +22,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; -import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor; -import org.jetbrains.jet.lang.descriptors.VariableDescriptor; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory1; import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; @@ -54,6 +51,7 @@ import java.util.List; import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.resolve.BindingContext.*; +import static org.jetbrains.jet.lang.types.TypeUtils.UNKNOWN_EXPECTED_TYPE; import static org.jetbrains.jet.lang.types.TypeUtils.noExpectedType; import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.*; @@ -89,13 +87,13 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { return visitIfExpression(expression, context, false); } - public JetTypeInfo visitIfExpression(JetIfExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) { + public JetTypeInfo visitIfExpression(JetIfExpression ifExpression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) { ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE); - JetExpression condition = expression.getCondition(); + JetExpression condition = ifExpression.getCondition(); DataFlowInfo conditionDataFlowInfo = checkCondition(context.scope, condition, context); - JetExpression elseBranch = expression.getElse(); - JetExpression thenBranch = expression.getThen(); + JetExpression elseBranch = ifExpression.getElse(); + JetExpression thenBranch = ifExpression.getThen(); WritableScopeImpl thenScope = newWritableScopeImpl(context, "Then scope"); WritableScopeImpl elseScope = newWritableScopeImpl(context, "Else scope"); @@ -105,17 +103,35 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { if (elseBranch == null) { if (thenBranch != null) { return getTypeInfoWhenOnlyOneBranchIsPresent( - thenBranch, thenScope, thenInfo, elseInfo, contextWithExpectedType, expression, isStatement); + thenBranch, thenScope, thenInfo, elseInfo, contextWithExpectedType, ifExpression, isStatement); } return JetTypeInfo.create(null, context.dataFlowInfo); } if (thenBranch == null) { return getTypeInfoWhenOnlyOneBranchIsPresent( - elseBranch, elseScope, elseInfo, thenInfo, contextWithExpectedType, expression, isStatement); + elseBranch, elseScope, elseInfo, thenInfo, contextWithExpectedType, ifExpression, isStatement); + } + + JetTypeInfo thenTypeInfo; + JetTypeInfo elseTypeInfo; + + if (contextWithExpectedType.expectedType == UNKNOWN_EXPECTED_TYPE) { + Call callForIf = ControlStructureTypingUtils.createCallForIf(ifExpression, thenBranch, elseBranch); + ResolvedCall resultingCall = + ControlStructureTypingUtils.resolveIfAsCall(callForIf, contextWithExpectedType); + + List valueParameters = resultingCall.getResultingDescriptor().getValueParameters(); + ValueParameterDescriptor thenParameter = valueParameters.get(0); + ValueParameterDescriptor elseParameter = valueParameters.get(1); + //todo correct dataFlowInfo + thenTypeInfo = JetTypeInfo.create(thenParameter.getType(), context.dataFlowInfo); + elseTypeInfo = JetTypeInfo.create(elseParameter.getType(), context.dataFlowInfo); + } + else { + CoercionStrategy coercionStrategy = isStatement ? CoercionStrategy.COERCION_TO_UNIT : CoercionStrategy.NO_COERCION; + thenTypeInfo = context.expressionTypingServices.getBlockReturnedTypeWithWritableScope(thenScope, Collections.singletonList(thenBranch), coercionStrategy, contextWithExpectedType.replaceDataFlowInfo(thenInfo), context.trace); + elseTypeInfo = context.expressionTypingServices.getBlockReturnedTypeWithWritableScope(elseScope, Collections.singletonList(elseBranch), coercionStrategy, contextWithExpectedType.replaceDataFlowInfo(elseInfo), context.trace); } - CoercionStrategy coercionStrategy = isStatement ? CoercionStrategy.COERCION_TO_UNIT : CoercionStrategy.NO_COERCION; - JetTypeInfo thenTypeInfo = context.expressionTypingServices.getBlockReturnedTypeWithWritableScope(thenScope, Collections.singletonList(thenBranch), coercionStrategy, contextWithExpectedType.replaceDataFlowInfo(thenInfo), context.trace); - JetTypeInfo elseTypeInfo = context.expressionTypingServices.getBlockReturnedTypeWithWritableScope(elseScope, Collections.singletonList(elseBranch), coercionStrategy, contextWithExpectedType.replaceDataFlowInfo(elseInfo), context.trace); JetType thenType = thenTypeInfo.getType(); JetType elseType = elseTypeInfo.getType(); DataFlowInfo thenDataFlowInfo = thenTypeInfo.getDataFlowInfo(); @@ -138,7 +154,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { result = JetTypeInfo.create(CommonSupertypes.commonSupertype(Arrays.asList(thenType, elseType)), thenDataFlowInfo.or(elseDataFlowInfo)); } - return DataFlowUtils.checkImplicitCast(result.getType(), expression, contextWithExpectedType, isStatement, result.getDataFlowInfo()); + return DataFlowUtils.checkImplicitCast(result.getType(), ifExpression, contextWithExpectedType, isStatement, result.getDataFlowInfo()); } @NotNull