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
017package org.jetbrains.jet.lang.resolve.calls;
018
019import com.google.common.collect.Lists;
020import org.jetbrains.annotations.NotNull;
021import org.jetbrains.annotations.Nullable;
022import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
023import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
024import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
025import org.jetbrains.jet.lang.diagnostics.Errors;
026import org.jetbrains.jet.lang.psi.*;
027import org.jetbrains.jet.lang.resolve.BindingTrace;
028import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
029import org.jetbrains.jet.lang.resolve.TypeResolver;
030import org.jetbrains.jet.lang.resolve.calls.context.CallResolutionContext;
031import org.jetbrains.jet.lang.resolve.calls.context.CheckValueArgumentsMode;
032import org.jetbrains.jet.lang.resolve.calls.context.ResolveMode;
033import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl;
034import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
035import org.jetbrains.jet.lang.resolve.scopes.JetScope;
036import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
037import org.jetbrains.jet.lang.types.ErrorUtils;
038import org.jetbrains.jet.lang.types.JetType;
039import org.jetbrains.jet.lang.types.JetTypeInfo;
040import org.jetbrains.jet.lang.types.TypeUtils;
041import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
042import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
043import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
044
045import javax.inject.Inject;
046import java.util.Collections;
047import java.util.List;
048import java.util.Map;
049import java.util.Set;
050
051import static org.jetbrains.jet.lang.resolve.BindingContextUtils.getRecordedTypeInfo;
052import static org.jetbrains.jet.lang.resolve.BindingContextUtils.recordExpressionType;
053import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.*;
054import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS;
055import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.SKIP_FUNCTION_ARGUMENTS;
056import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
057
058public class ArgumentTypeResolver {
059
060    @NotNull
061    private TypeResolver typeResolver;
062    @NotNull
063    private ExpressionTypingServices expressionTypingServices;
064
065    @Inject
066    public void setTypeResolver(@NotNull TypeResolver typeResolver) {
067        this.typeResolver = typeResolver;
068    }
069
070    @Inject
071    public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) {
072        this.expressionTypingServices = expressionTypingServices;
073    }
074
075    public static boolean isSubtypeOfForArgumentType(@NotNull JetType subtype, @NotNull JetType supertype) {
076        if (subtype == PLACEHOLDER_FUNCTION_TYPE) {
077            return isFunctionOrErrorType(supertype) || KotlinBuiltIns.getInstance().isAny(supertype); //todo function type extends
078        }
079        if (supertype == PLACEHOLDER_FUNCTION_TYPE) {
080            return isFunctionOrErrorType(subtype); //todo extends function type
081        }
082        return JetTypeChecker.INSTANCE.isSubtypeOf(subtype, supertype);
083    }
084
085    private static boolean isFunctionOrErrorType(@NotNull JetType supertype) {
086        return KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(supertype) || ErrorUtils.isErrorType(supertype);
087    }
088
089    public void checkTypesWithNoCallee(@NotNull CallResolutionContext<?> context) {
090        checkTypesWithNoCallee(context, SKIP_FUNCTION_ARGUMENTS);
091    }
092
093    public void checkTypesWithNoCallee(@NotNull CallResolutionContext<?> context, @NotNull ResolveArgumentsMode resolveFunctionArgumentBodies) {
094        if (context.checkArguments == CheckValueArgumentsMode.DISABLED) return;
095
096        for (ValueArgument valueArgument : context.call.getValueArguments()) {
097            JetExpression argumentExpression = valueArgument.getArgumentExpression();
098            if (argumentExpression != null && !(argumentExpression instanceof JetFunctionLiteralExpression)) {
099                expressionTypingServices.getType(context.scope, argumentExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
100            }
101        }
102
103        if (resolveFunctionArgumentBodies == RESOLVE_FUNCTION_ARGUMENTS) {
104            checkTypesForFunctionArgumentsWithNoCallee(context);
105        }
106
107        for (JetTypeProjection typeProjection : context.call.getTypeArguments()) {
108            JetTypeReference typeReference = typeProjection.getTypeReference();
109            if (typeReference == null) {
110                context.trace.report(Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(typeProjection));
111            }
112            else {
113                typeResolver.resolveType(context.scope, typeReference, context.trace, true);
114            }
115        }
116    }
117
118    public void checkTypesForFunctionArgumentsWithNoCallee(@NotNull CallResolutionContext<?> context) {
119        if (context.checkArguments == CheckValueArgumentsMode.DISABLED) return;
120
121        for (ValueArgument valueArgument : context.call.getValueArguments()) {
122            JetExpression argumentExpression = valueArgument.getArgumentExpression();
123            if (argumentExpression != null && (argumentExpression instanceof JetFunctionLiteralExpression)) {
124                expressionTypingServices.getType(context.scope, argumentExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
125            }
126        }
127
128        for (JetExpression expression : context.call.getFunctionLiteralArguments()) {
129            expressionTypingServices.getType(context.scope, expression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
130        }
131    }
132
133    public void checkUnmappedArgumentTypes(CallResolutionContext<?> context, Set<ValueArgument> unmappedArguments) {
134        for (ValueArgument valueArgument : unmappedArguments) {
135            JetExpression argumentExpression = valueArgument.getArgumentExpression();
136            if (argumentExpression != null) {
137                expressionTypingServices.getType(context.scope, argumentExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
138            }
139        }
140    }
141
142    public <D extends CallableDescriptor> void checkTypesForFunctionArguments(CallResolutionContext<?> context, ResolvedCallImpl<D> resolvedCall) {
143        Map<ValueParameterDescriptor, ResolvedValueArgument> arguments = resolvedCall.getValueArguments();
144        for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : arguments.entrySet()) {
145            ValueParameterDescriptor valueParameterDescriptor = entry.getKey();
146            JetType varargElementType = valueParameterDescriptor.getVarargElementType();
147            JetType functionType;
148            if (varargElementType != null) {
149                functionType = varargElementType;
150            }
151            else {
152                functionType = valueParameterDescriptor.getType();
153            }
154            ResolvedValueArgument valueArgument = entry.getValue();
155            List<ValueArgument> valueArguments = valueArgument.getArguments();
156            for (ValueArgument argument : valueArguments) {
157                JetExpression expression = argument.getArgumentExpression();
158                if (expression instanceof JetFunctionLiteralExpression) {
159                    expressionTypingServices.getType(context.scope, expression, functionType, context.dataFlowInfo, context.trace);
160                }
161            }
162        }
163    }
164
165    @NotNull
166    public JetTypeInfo getArgumentTypeInfo(
167            @Nullable JetExpression expression,
168            @NotNull CallResolutionContext<?> context,
169            @NotNull ResolveArgumentsMode resolveArgumentsMode,
170            @Nullable TemporaryBindingTrace traceToCommitForCall
171    ) {
172        if (expression == null) {
173            return JetTypeInfo.create(null, context.dataFlowInfo);
174        }
175        if (expression instanceof JetFunctionLiteralExpression) {
176            return getFunctionLiteralTypeInfo((JetFunctionLiteralExpression) expression, context, resolveArgumentsMode);
177        }
178        JetTypeInfo recordedTypeInfo = getRecordedTypeInfo(expression, context.trace.getBindingContext());
179        if (recordedTypeInfo != null) {
180            return recordedTypeInfo;
181        }
182        //todo deparenthesize
183        CallExpressionResolver callExpressionResolver = expressionTypingServices.getCallExpressionResolver();
184        if (!(expression instanceof JetCallExpression) && !(expression instanceof JetQualifiedExpression)) {
185            return expressionTypingServices.getTypeInfo(context.scope, expression, context.expectedType, context.dataFlowInfo, context.trace);
186        }
187
188        JetTypeInfo result;
189        if (expression instanceof JetCallExpression) {
190            result = callExpressionResolver.getCallExpressionTypeInfo(
191                    (JetCallExpression) expression, ReceiverValue.NO_RECEIVER, null,
192                    context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE), ResolveMode.NESTED_CALL, context.resolutionResultsCache);
193        }
194        else { // expression instanceof JetQualifiedExpression
195            result = callExpressionResolver.getQualifiedExpressionTypeInfo(
196                    (JetQualifiedExpression) expression, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE),
197                    ResolveMode.NESTED_CALL, context.resolutionResultsCache);
198        }
199
200        recordExpressionType(expression, context.trace, context.scope, result);
201        if (traceToCommitForCall != null) {
202            traceToCommitForCall.commit();
203        }
204        return result;
205    }
206
207    @NotNull
208    public JetTypeInfo getFunctionLiteralTypeInfo(
209            @NotNull JetFunctionLiteralExpression functionLiteralExpression,
210            @NotNull CallResolutionContext<?> context,
211            @NotNull ResolveArgumentsMode resolveArgumentsMode
212    ) {
213        if (resolveArgumentsMode == SKIP_FUNCTION_ARGUMENTS) {
214            JetType type = getFunctionLiteralType(functionLiteralExpression, context.scope, context.trace);
215            return JetTypeInfo.create(type, context.dataFlowInfo);
216        }
217        return expressionTypingServices.getTypeInfo(context.scope, functionLiteralExpression, context.expectedType, context.dataFlowInfo, context.trace);
218    }
219
220    @Nullable
221    private JetType getFunctionLiteralType(
222            @NotNull JetFunctionLiteralExpression expression,
223            @NotNull JetScope scope,
224            @NotNull BindingTrace trace
225    ) {
226        List<JetParameter> valueParameters = expression.getValueParameters();
227        if (valueParameters.isEmpty()) {
228            return PLACEHOLDER_FUNCTION_TYPE;
229        }
230        TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(
231                trace, "trace to resolve function literal parameter types");
232        List<JetType> parameterTypes = Lists.newArrayList();
233        for (JetParameter parameter : valueParameters) {
234            parameterTypes.add(resolveTypeRefWithDefault(parameter.getTypeReference(), scope, temporaryTrace, DONT_CARE));
235        }
236        JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
237        JetType returnType = resolveTypeRefWithDefault(functionLiteral.getReturnTypeRef(), scope, temporaryTrace, DONT_CARE);
238        assert returnType != null;
239        JetType receiverType = resolveTypeRefWithDefault(functionLiteral.getReceiverTypeRef(), scope, temporaryTrace, null);
240        return KotlinBuiltIns.getInstance().getFunctionType(Collections.<AnnotationDescriptor>emptyList(), receiverType, parameterTypes, returnType);
241    }
242
243    @Nullable
244    public JetType resolveTypeRefWithDefault(
245            @Nullable JetTypeReference returnTypeRef,
246            @NotNull JetScope scope,
247            @NotNull BindingTrace trace,
248            @Nullable JetType defaultValue
249    ) {
250        if (returnTypeRef != null) {
251            return expressionTypingServices.getTypeResolver().resolveType(scope, returnTypeRef, trace, true);
252        }
253        return defaultValue;
254    }
255}