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