001    /*
002     * Copyright 2010-2013 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.jet.lang.resolve.calls;
018    
019    import com.google.common.collect.Lists;
020    import com.intellij.psi.PsiElement;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.jet.lang.descriptors.*;
024    import org.jetbrains.jet.lang.psi.*;
025    import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext;
026    import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
027    import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
028    import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
029    import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
030    import org.jetbrains.jet.lang.types.*;
031    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
032    
033    import java.util.Collections;
034    import java.util.List;
035    
036    import static org.jetbrains.jet.lang.types.TypeUtils.CANT_INFER_TYPE_PARAMETER;
037    import static org.jetbrains.jet.lang.types.TypeUtils.DONT_CARE;
038    
039    public class CallResolverUtil {
040        public static enum ResolveArgumentsMode {
041            RESOLVE_FUNCTION_ARGUMENTS,
042            SHAPE_FUNCTION_ARGUMENTS
043        }
044    
045        private CallResolverUtil() {}
046    
047    
048        public static boolean hasUnknownFunctionParameter(@NotNull JetType type) {
049            assert KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(type);
050            List<TypeProjection> arguments = type.getArguments();
051            // last argument is return type of function type
052            List<TypeProjection> functionParameters = arguments.subList(0, arguments.size() - 1);
053            for (TypeProjection functionParameter : functionParameters) {
054                if (TypeUtils.equalsOrContainsAsArgument(functionParameter.getType(), CANT_INFER_TYPE_PARAMETER, DONT_CARE)) {
055                    return true;
056                }
057            }
058            return false;
059        }
060    
061        public static boolean hasUnknownReturnType(@NotNull JetType type) {
062            assert KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(type);
063            JetType returnTypeFromFunctionType = KotlinBuiltIns.getInstance().getReturnTypeFromFunctionType(type);
064            return ErrorUtils.containsErrorType(returnTypeFromFunctionType);
065        }
066    
067        public static JetType replaceReturnTypeByUnknown(@NotNull JetType type) {
068            assert KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(type);
069            List<TypeProjection> arguments = type.getArguments();
070            List<TypeProjection> newArguments = Lists.newArrayList();
071            newArguments.addAll(arguments.subList(0, arguments.size() - 1));
072            newArguments.add(new TypeProjectionImpl(Variance.INVARIANT, DONT_CARE));
073            return new JetTypeImpl(type.getAnnotations(), type.getConstructor(), type.isNullable(), newArguments, type.getMemberScope());
074        }
075    
076        private static boolean hasReturnTypeDependentOnNotInferredParams(
077                @NotNull CallableDescriptor candidateDescriptor,
078                @NotNull ConstraintSystem constraintSystem
079        ) {
080            JetType returnType = candidateDescriptor.getReturnType();
081            if (returnType == null) return false;
082    
083            for (TypeParameterDescriptor typeVariable : constraintSystem.getTypeVariables()) {
084                JetType inferredValueForTypeVariable = constraintSystem.getTypeBounds(typeVariable).getValue();
085                if (inferredValueForTypeVariable == null) {
086                    if (TypeUtils.dependsOnTypeParameters(returnType, Collections.singleton(typeVariable))) {
087                        return true;
088                    }
089                }
090            }
091            return false;
092        }
093    
094        public static boolean hasInferredReturnType(
095                @NotNull CallableDescriptor candidateDescriptor,
096                @NotNull ConstraintSystem constraintSystem
097        ) {
098            if (hasReturnTypeDependentOnNotInferredParams(candidateDescriptor, constraintSystem)) return false;
099    
100            // Expected type mismatch was reported before as 'TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH'
101            if (constraintSystem.getStatus().hasOnlyErrorsFromPosition(ConstraintPosition.EXPECTED_TYPE_POSITION)) return false;
102            return true;
103        }
104    
105        @Nullable
106        public static CallKey createCallKey(@NotNull BasicCallResolutionContext context) {
107            if (isInvokeCallOnVariable(context.call)) {
108                return null;
109            }
110            PsiElement callElement = context.call.getCallElement();
111            if (!(callElement instanceof JetExpression)) return null;
112            return CallKey.create(context.call.getCallType(), (JetExpression) callElement);
113        }
114    
115        @NotNull
116        public static JetType getErasedReceiverType(
117                @NotNull ReceiverParameterDescriptor receiverParameterDescriptor,
118                @NotNull CallableDescriptor descriptor
119        ) {
120            JetType receiverType = receiverParameterDescriptor.getType();
121            for (TypeParameterDescriptor typeParameter : descriptor.getTypeParameters()) {
122                if (typeParameter.getTypeConstructor().equals(receiverType.getConstructor())) {
123                    receiverType = typeParameter.getUpperBoundsAsType();
124                }
125            }
126            List<TypeProjection> fakeTypeArguments = Lists.newArrayList();
127            for (TypeProjection typeProjection : receiverType.getArguments()) {
128                fakeTypeArguments.add(new TypeProjectionImpl(typeProjection.getProjectionKind(), DONT_CARE));
129            }
130            return new JetTypeImpl(
131                    receiverType.getAnnotations(), receiverType.getConstructor(), receiverType.isNullable(),
132                    fakeTypeArguments, ErrorUtils.createErrorScope("Error scope for erased receiver type", /*throwExceptions=*/true));
133        }
134    
135        public static boolean isOrOverridesSynthesized(@NotNull CallableMemberDescriptor descriptor) {
136            if (descriptor.getKind() == CallableMemberDescriptor.Kind.SYNTHESIZED) {
137                return true;
138            }
139            if (descriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
140                for (CallableMemberDescriptor overridden : descriptor.getOverriddenDescriptors()) {
141                    if (!isOrOverridesSynthesized(overridden)) {
142                        return false;
143                    }
144                }
145                return true;
146            }
147            return false;
148        }
149    
150        public static boolean isInvokeCallOnVariable(@NotNull Call call) {
151            if (call.getCallType() != Call.CallType.INVOKE) return false;
152            ReceiverValue thisObject = call.getThisObject();
153            //calleeExpressionAsThisObject for invoke is always ExpressionReceiver, see CallForImplicitInvoke
154            JetExpression expression = ((ExpressionReceiver) thisObject).getExpression();
155            return expression instanceof JetSimpleNameExpression;
156        }
157    
158        public static boolean isInvokeCallOnExpressionWithBothReceivers(@NotNull Call call) {
159            if (call.getCallType() != Call.CallType.INVOKE || isInvokeCallOnVariable(call)) return false;
160            return call.getExplicitReceiver().exists() && call.getThisObject().exists();
161        }
162    }