001    /*
002     * Copyright 2010-2015 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.resolve.calls;
018    
019    import com.google.common.collect.Lists;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
022    import org.jetbrains.kotlin.descriptors.CallableDescriptor;
023    import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
024    import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor;
025    import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
026    import org.jetbrains.kotlin.psi.Call;
027    import org.jetbrains.kotlin.psi.JetExpression;
028    import org.jetbrains.kotlin.psi.JetSimpleNameExpression;
029    import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
030    import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
031    import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
032    import org.jetbrains.kotlin.types.*;
033    
034    import java.util.Collections;
035    import java.util.List;
036    
037    import static org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.EXPECTED_TYPE_POSITION;
038    import static org.jetbrains.kotlin.types.TypeUtils.DONT_CARE;
039    
040    public class CallResolverUtil {
041        public static enum ResolveArgumentsMode {
042            RESOLVE_FUNCTION_ARGUMENTS,
043            SHAPE_FUNCTION_ARGUMENTS
044        }
045    
046        private CallResolverUtil() {}
047    
048    
049        public static boolean hasUnknownFunctionParameter(@NotNull JetType type) {
050            assert KotlinBuiltIns.isFunctionOrExtensionFunctionType(type);
051            List<TypeProjection> arguments = type.getArguments();
052            // last argument is return type of function type
053            List<TypeProjection> functionParameters = arguments.subList(0, arguments.size() - 1);
054            for (TypeProjection functionParameter : functionParameters) {
055                if (TypeUtils.containsSpecialType(functionParameter.getType(), DONT_CARE)
056                    || ErrorUtils.containsUninferredParameter(functionParameter.getType())) {
057                    return true;
058                }
059            }
060            return false;
061        }
062    
063        public static boolean hasUnknownReturnType(@NotNull JetType type) {
064            assert KotlinBuiltIns.isFunctionOrExtensionFunctionType(type);
065            JetType returnTypeFromFunctionType = KotlinBuiltIns.getReturnTypeFromFunctionType(type);
066            return ErrorUtils.containsErrorType(returnTypeFromFunctionType);
067        }
068    
069        public static JetType replaceReturnTypeByUnknown(@NotNull JetType type) {
070            assert KotlinBuiltIns.isFunctionOrExtensionFunctionType(type);
071            List<TypeProjection> arguments = type.getArguments();
072            List<TypeProjection> newArguments = Lists.newArrayList();
073            newArguments.addAll(arguments.subList(0, arguments.size() - 1));
074            newArguments.add(new TypeProjectionImpl(Variance.INVARIANT, DONT_CARE));
075            return new JetTypeImpl(type.getAnnotations(), type.getConstructor(), type.isMarkedNullable(), newArguments, type.getMemberScope());
076        }
077    
078        private static boolean hasReturnTypeDependentOnUninferredParams(
079                @NotNull CallableDescriptor candidateDescriptor,
080                @NotNull ConstraintSystem constraintSystem
081        ) {
082            JetType returnType = candidateDescriptor.getReturnType();
083            if (returnType == null) return false;
084    
085            for (TypeParameterDescriptor typeVariable : constraintSystem.getTypeVariables()) {
086                JetType inferredValueForTypeVariable = constraintSystem.getTypeBounds(typeVariable).getValue();
087                if (inferredValueForTypeVariable == null) {
088                    if (TypeUtils.dependsOnTypeParameters(returnType, Collections.singleton(typeVariable))) {
089                        return true;
090                    }
091                }
092            }
093            return false;
094        }
095    
096        public static boolean hasInferredReturnType(
097                @NotNull CallableDescriptor candidateDescriptor,
098                @NotNull ConstraintSystem constraintSystem
099        ) {
100            if (hasReturnTypeDependentOnUninferredParams(candidateDescriptor, constraintSystem)) return false;
101    
102            // Expected type mismatch was reported before as 'TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH'
103            if (constraintSystem.getStatus().hasOnlyErrorsFromPosition(EXPECTED_TYPE_POSITION.position())) return false;
104            return true;
105        }
106    
107        @NotNull
108        public static JetType getErasedReceiverType(
109                @NotNull ReceiverParameterDescriptor receiverParameterDescriptor,
110                @NotNull CallableDescriptor descriptor
111        ) {
112            JetType receiverType = receiverParameterDescriptor.getType();
113            for (TypeParameterDescriptor typeParameter : descriptor.getTypeParameters()) {
114                if (typeParameter.getTypeConstructor().equals(receiverType.getConstructor())) {
115                    receiverType = typeParameter.getUpperBoundsAsType();
116                }
117            }
118            List<TypeProjection> fakeTypeArguments = Lists.newArrayList();
119            for (TypeProjection typeProjection : receiverType.getArguments()) {
120                fakeTypeArguments.add(new TypeProjectionImpl(typeProjection.getProjectionKind(), DONT_CARE));
121            }
122            return new JetTypeImpl(
123                    receiverType.getAnnotations(), receiverType.getConstructor(), receiverType.isMarkedNullable(),
124                    fakeTypeArguments, ErrorUtils.createErrorScope("Error scope for erased receiver type", /*throwExceptions=*/true));
125        }
126    
127        public static boolean isOrOverridesSynthesized(@NotNull CallableMemberDescriptor descriptor) {
128            if (descriptor.getKind() == CallableMemberDescriptor.Kind.SYNTHESIZED) {
129                return true;
130            }
131            if (descriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
132                for (CallableMemberDescriptor overridden : descriptor.getOverriddenDescriptors()) {
133                    if (!isOrOverridesSynthesized(overridden)) {
134                        return false;
135                    }
136                }
137                return true;
138            }
139            return false;
140        }
141    
142        public static boolean isInvokeCallOnVariable(@NotNull Call call) {
143            if (call.getCallType() != Call.CallType.INVOKE) return false;
144            ReceiverValue dispatchReceiver = call.getDispatchReceiver();
145            //calleeExpressionAsDispatchReceiver for invoke is always ExpressionReceiver, see CallForImplicitInvoke
146            JetExpression expression = ((ExpressionReceiver) dispatchReceiver).getExpression();
147            return expression instanceof JetSimpleNameExpression;
148        }
149    
150        public static boolean isInvokeCallOnExpressionWithBothReceivers(@NotNull Call call) {
151            if (call.getCallType() != Call.CallType.INVOKE || isInvokeCallOnVariable(call)) return false;
152            return call.getExplicitReceiver().exists() && call.getDispatchReceiver().exists();
153        }
154    }