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 org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
023    import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
024    import org.jetbrains.jet.lang.diagnostics.Errors;
025    import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator;
026    import org.jetbrains.jet.lang.psi.*;
027    import org.jetbrains.jet.lang.resolve.*;
028    import org.jetbrains.jet.lang.resolve.calls.context.CallResolutionContext;
029    import org.jetbrains.jet.lang.resolve.calls.context.CheckValueArgumentsMode;
030    import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext;
031    import org.jetbrains.jet.lang.resolve.calls.model.MutableDataFlowInfoForArguments;
032    import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstructor;
033    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
034    import org.jetbrains.jet.lang.types.JetType;
035    import org.jetbrains.jet.lang.types.JetTypeInfo;
036    import org.jetbrains.jet.lang.types.TypeUtils;
037    import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
038    import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
039    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
040    
041    import javax.inject.Inject;
042    import java.util.Collections;
043    import java.util.List;
044    
045    import static org.jetbrains.jet.lang.resolve.BindingContextUtils.getRecordedTypeInfo;
046    import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode;
047    import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS;
048    import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS;
049    import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.DEPENDENT;
050    import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.INDEPENDENT;
051    import static org.jetbrains.jet.lang.types.TypeUtils.*;
052    
053    public class ArgumentTypeResolver {
054    
055        @NotNull
056        private TypeResolver typeResolver;
057        @NotNull
058        private ExpressionTypingServices expressionTypingServices;
059    
060        @Inject
061        public void setTypeResolver(@NotNull TypeResolver typeResolver) {
062            this.typeResolver = typeResolver;
063        }
064    
065        @Inject
066        public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) {
067            this.expressionTypingServices = expressionTypingServices;
068        }
069    
070        public static boolean isSubtypeOfForArgumentType(
071                @NotNull JetType actualType,
072                @NotNull JetType expectedType
073        ) {
074            if (actualType == PLACEHOLDER_FUNCTION_TYPE) {
075                return isFunctionOrErrorType(expectedType) || KotlinBuiltIns.getInstance().isAnyOrNullableAny(expectedType); //todo function type extends
076            }
077            return JetTypeChecker.DEFAULT.isSubtypeOf(actualType, expectedType);
078        }
079    
080        private static boolean isFunctionOrErrorType(@NotNull JetType supertype) {
081            return KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(supertype) || supertype.isError();
082        }
083    
084        public void checkTypesWithNoCallee(@NotNull CallResolutionContext<?> context) {
085            checkTypesWithNoCallee(context, SHAPE_FUNCTION_ARGUMENTS);
086        }
087    
088        public void checkTypesWithNoCallee(@NotNull CallResolutionContext<?> context, @NotNull ResolveArgumentsMode resolveFunctionArgumentBodies) {
089            if (context.checkArguments == CheckValueArgumentsMode.DISABLED) return;
090    
091            for (ValueArgument valueArgument : context.call.getValueArguments()) {
092                JetExpression argumentExpression = valueArgument.getArgumentExpression();
093                if (argumentExpression != null && !(argumentExpression instanceof JetFunctionLiteralExpression)) {
094                    checkArgumentTypeWithNoCallee(context, argumentExpression);
095                }
096            }
097    
098            if (resolveFunctionArgumentBodies == RESOLVE_FUNCTION_ARGUMENTS) {
099                checkTypesForFunctionArgumentsWithNoCallee(context);
100            }
101    
102            for (JetTypeProjection typeProjection : context.call.getTypeArguments()) {
103                JetTypeReference typeReference = typeProjection.getTypeReference();
104                if (typeReference == null) {
105                    context.trace.report(Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(typeProjection));
106                }
107                else {
108                    typeResolver.resolveType(context.scope, typeReference, context.trace, true);
109                }
110            }
111        }
112    
113        public void checkTypesForFunctionArgumentsWithNoCallee(@NotNull CallResolutionContext<?> context) {
114            if (context.checkArguments == CheckValueArgumentsMode.DISABLED) return;
115    
116            for (ValueArgument valueArgument : context.call.getValueArguments()) {
117                JetExpression argumentExpression = valueArgument.getArgumentExpression();
118                if (argumentExpression != null && isFunctionLiteralArgument(argumentExpression)) {
119                    checkArgumentTypeWithNoCallee(context, argumentExpression);
120                }
121            }
122        }
123    
124        private void checkArgumentTypeWithNoCallee(CallResolutionContext<?> context, JetExpression argumentExpression) {
125            expressionTypingServices.getTypeInfo(argumentExpression, context.replaceExpectedType(NO_EXPECTED_TYPE));
126            updateResultArgumentTypeIfNotDenotable(context, argumentExpression);
127        }
128    
129        public static boolean isFunctionLiteralArgument(@NotNull JetExpression expression) {
130            return getFunctionLiteralArgumentIfAny(expression) != null;
131        }
132    
133        @NotNull
134        public static JetFunctionLiteralExpression getFunctionLiteralArgument(@NotNull JetExpression expression) {
135            assert isFunctionLiteralArgument(expression);
136            //noinspection ConstantConditions
137            return getFunctionLiteralArgumentIfAny(expression);
138        }
139    
140        @Nullable
141        private static JetFunctionLiteralExpression getFunctionLiteralArgumentIfAny(@NotNull JetExpression expression) {
142            JetExpression deparenthesizedExpression = JetPsiUtil.deparenthesize(expression, false);
143            if (deparenthesizedExpression instanceof JetBlockExpression) {
144                // todo
145                // This case is a temporary hack for 'if' branches.
146                // The right way to implement this logic is to interpret 'if' branches as function literals with explicitly-typed signatures
147                // (no arguments and no receiver) and therefore analyze them straight away (not in the 'complete' phase).
148                JetElement lastStatementInABlock = JetPsiUtil.getLastStatementInABlock((JetBlockExpression) deparenthesizedExpression);
149                if (lastStatementInABlock instanceof JetExpression) {
150                    deparenthesizedExpression = JetPsiUtil.deparenthesize((JetExpression) lastStatementInABlock, false);
151                }
152            }
153            if (deparenthesizedExpression instanceof JetFunctionLiteralExpression) {
154                return (JetFunctionLiteralExpression) deparenthesizedExpression;
155            }
156            return null;
157        }
158    
159        @NotNull
160        public JetTypeInfo getArgumentTypeInfo(
161                @Nullable JetExpression expression,
162                @NotNull CallResolutionContext<?> context,
163                @NotNull ResolveArgumentsMode resolveArgumentsMode
164        ) {
165            if (expression == null) {
166                return JetTypeInfo.create(null, context.dataFlowInfo);
167            }
168            if (isFunctionLiteralArgument(expression)) {
169                return getFunctionLiteralTypeInfo(expression, getFunctionLiteralArgument(expression), context, resolveArgumentsMode);
170            }
171            JetTypeInfo recordedTypeInfo = getRecordedTypeInfo(expression, context.trace.getBindingContext());
172            if (recordedTypeInfo != null) {
173                return recordedTypeInfo;
174            }
175            ResolutionContext newContext = context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(DEPENDENT);
176    
177            return expressionTypingServices.getTypeInfo(expression, newContext);
178        }
179    
180        @NotNull
181        public JetTypeInfo getFunctionLiteralTypeInfo(
182                @NotNull JetExpression expression,
183                @NotNull JetFunctionLiteralExpression functionLiteralExpression,
184                @NotNull CallResolutionContext<?> context,
185                @NotNull ResolveArgumentsMode resolveArgumentsMode
186        ) {
187            if (resolveArgumentsMode == SHAPE_FUNCTION_ARGUMENTS) {
188                JetType type = getShapeTypeOfFunctionLiteral(functionLiteralExpression, context.scope, context.trace, true);
189                return JetTypeInfo.create(type, context.dataFlowInfo);
190            }
191            return expressionTypingServices.getTypeInfo(expression, context.replaceContextDependency(INDEPENDENT));
192        }
193    
194        @Nullable
195        public JetType getShapeTypeOfFunctionLiteral(
196                @NotNull JetFunctionLiteralExpression expression,
197                @NotNull JetScope scope,
198                @NotNull BindingTrace trace,
199                boolean expectedTypeIsUnknown
200        ) {
201            if (expression.getFunctionLiteral().getValueParameterList() == null) {
202                return expectedTypeIsUnknown ? PLACEHOLDER_FUNCTION_TYPE : KotlinBuiltIns.getInstance().getFunctionType(
203                        Annotations.EMPTY, null, Collections.<JetType>emptyList(), DONT_CARE);
204            }
205            List<JetParameter> valueParameters = expression.getValueParameters();
206            TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(
207                    trace, "trace to resolve function literal parameter types");
208            List<JetType> parameterTypes = Lists.newArrayList();
209            for (JetParameter parameter : valueParameters) {
210                parameterTypes.add(resolveTypeRefWithDefault(parameter.getTypeReference(), scope, temporaryTrace, DONT_CARE));
211            }
212            JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
213            JetType returnType = resolveTypeRefWithDefault(functionLiteral.getTypeReference(), scope, temporaryTrace, DONT_CARE);
214            assert returnType != null;
215            JetType receiverType = resolveTypeRefWithDefault(functionLiteral.getReceiverTypeReference(), scope, temporaryTrace, null);
216            return KotlinBuiltIns.getInstance().getFunctionType(Annotations.EMPTY, receiverType, parameterTypes,
217                                                                returnType);
218        }
219    
220        @Nullable
221        public JetType resolveTypeRefWithDefault(
222                @Nullable JetTypeReference returnTypeRef,
223                @NotNull JetScope scope,
224                @NotNull BindingTrace trace,
225                @Nullable JetType defaultValue
226        ) {
227            if (returnTypeRef != null) {
228                return expressionTypingServices.getTypeResolver().resolveType(scope, returnTypeRef, trace, true);
229            }
230            return defaultValue;
231        }
232    
233        public <D extends CallableDescriptor> void analyzeArgumentsAndRecordTypes(
234                @NotNull CallResolutionContext<?> context
235        ) {
236            MutableDataFlowInfoForArguments infoForArguments = context.dataFlowInfoForArguments;
237            infoForArguments.setInitialDataFlowInfo(context.dataFlowInfo);
238    
239            for (ValueArgument argument : context.call.getValueArguments()) {
240                JetExpression expression = argument.getArgumentExpression();
241                if (expression == null) continue;
242    
243                CallResolutionContext<?> newContext = context.replaceDataFlowInfo(infoForArguments.getInfo(argument));
244                JetTypeInfo typeInfoForCall = getArgumentTypeInfo(expression, newContext, SHAPE_FUNCTION_ARGUMENTS);
245                infoForArguments.updateInfo(argument, typeInfoForCall.getDataFlowInfo());
246            }
247        }
248    
249        @Nullable
250        public static JetType updateResultArgumentTypeIfNotDenotable(
251                @NotNull ResolutionContext context,
252                @NotNull JetExpression expression
253        ) {
254            JetType type = context.trace.get(BindingContext.EXPRESSION_TYPE, expression);
255            if (type != null && !type.getConstructor().isDenotable()) {
256                if (type.getConstructor() instanceof IntegerValueTypeConstructor) {
257                    IntegerValueTypeConstructor constructor = (IntegerValueTypeConstructor) type.getConstructor();
258                    JetType primitiveType = TypeUtils.getPrimitiveNumberType(constructor, context.expectedType);
259                    updateNumberType(primitiveType, expression, context.trace);
260                    return primitiveType;
261                }
262            }
263            return type;
264        }
265    
266        public static <D extends CallableDescriptor> void updateNumberType(
267                @NotNull JetType numberType,
268                @Nullable JetExpression expression,
269                @NotNull BindingTrace trace
270        ) {
271            if (expression == null) return;
272            BindingContextUtils.updateRecordedType(numberType, expression, trace, false);
273    
274            if (!(expression instanceof JetConstantExpression)) {
275                JetExpression deparenthesized = JetPsiUtil.deparenthesize(expression, false);
276                if (deparenthesized != expression) {
277                    updateNumberType(numberType, deparenthesized, trace);
278                }
279                if (deparenthesized instanceof JetBlockExpression) {
280                    JetElement lastStatement = JetPsiUtil.getLastStatementInABlock((JetBlockExpression) deparenthesized);
281                    if (lastStatement instanceof JetExpression) {
282                        updateNumberType(numberType, (JetExpression) lastStatement, trace);
283                    }
284                }
285                return;
286            }
287    
288            ConstantExpressionEvaluator.OBJECT$.evaluate(expression, trace, numberType);
289        }
290    }