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.types.expressions;
018    
019    import com.google.common.base.Function;
020    import com.intellij.openapi.project.Project;
021    import com.intellij.psi.tree.IElementType;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
025    import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
026    import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
027    import org.jetbrains.jet.lang.descriptors.ScriptDescriptor;
028    import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
029    import org.jetbrains.jet.lang.psi.*;
030    import org.jetbrains.jet.lang.resolve.*;
031    import org.jetbrains.jet.lang.resolve.calls.CallExpressionResolver;
032    import org.jetbrains.jet.lang.resolve.calls.CallResolver;
033    import org.jetbrains.jet.lang.resolve.calls.CallResolverExtension;
034    import org.jetbrains.jet.lang.resolve.calls.CallResolverExtensionProvider;
035    import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
036    import org.jetbrains.jet.lang.resolve.calls.context.ContextDependency;
037    import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext;
038    import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
039    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
040    import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
041    import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
042    import org.jetbrains.jet.lang.types.ErrorUtils;
043    import org.jetbrains.jet.lang.types.JetType;
044    import org.jetbrains.jet.lang.types.JetTypeInfo;
045    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
046    import org.jetbrains.jet.lexer.JetTokens;
047    
048    import javax.inject.Inject;
049    import java.util.Iterator;
050    import java.util.List;
051    
052    import static org.jetbrains.jet.lang.resolve.BindingContext.STATEMENT;
053    import static org.jetbrains.jet.lang.types.TypeUtils.*;
054    import static org.jetbrains.jet.lang.types.expressions.CoercionStrategy.COERCION_TO_UNIT;
055    
056    public class ExpressionTypingServices {
057    
058        @NotNull
059        private ExpressionTypingFacade expressionTypingFacade;
060        @NotNull
061        private Project project;
062        @NotNull
063        private CallResolver callResolver;
064        @NotNull
065        private CallExpressionResolver callExpressionResolver;
066        @NotNull
067        private DescriptorResolver descriptorResolver;
068        @NotNull
069        private TypeResolver typeResolver;
070        @NotNull
071        private AnnotationResolver annotationResolver;
072        @NotNull
073        private PlatformToKotlinClassMap platformToKotlinClassMap;
074        @NotNull
075        private CallResolverExtensionProvider extensionProvider;
076    
077        @NotNull
078        public Project getProject() {
079            return project;
080        }
081    
082        @Inject
083        public void setProject(@NotNull Project project) {
084            this.project = project;
085        }
086    
087        @NotNull
088        public CallResolver getCallResolver() {
089            return callResolver;
090        }
091    
092        @Inject
093        public void setCallResolver(@NotNull CallResolver callResolver) {
094            this.callResolver = callResolver;
095        }
096    
097        @NotNull
098        public CallExpressionResolver getCallExpressionResolver() {
099            return callExpressionResolver;
100        }
101    
102        @Inject
103        public void setCallExpressionResolver(@NotNull CallExpressionResolver callExpressionResolver) {
104            this.callExpressionResolver = callExpressionResolver;
105        }
106    
107        @NotNull
108        public DescriptorResolver getDescriptorResolver() {
109            return descriptorResolver;
110        }
111    
112        @Inject
113        public void setDescriptorResolver(@NotNull DescriptorResolver descriptorResolver) {
114            this.descriptorResolver = descriptorResolver;
115        }
116    
117        @NotNull
118        public TypeResolver getTypeResolver() {
119            return typeResolver;
120        }
121    
122        @Inject
123        public void setTypeResolver(@NotNull TypeResolver typeResolver) {
124            this.typeResolver = typeResolver;
125        }
126    
127        @NotNull
128        public AnnotationResolver getAnnotationResolver() {
129            return annotationResolver;
130        }
131    
132        @Inject
133        public void setAnnotationResolver(@NotNull AnnotationResolver annotationResolver) {
134            this.annotationResolver = annotationResolver;
135        }
136    
137        @Inject
138        public void setPlatformToKotlinClassMap(@NotNull PlatformToKotlinClassMap platformToKotlinClassMap) {
139            this.platformToKotlinClassMap = platformToKotlinClassMap;
140            this.expressionTypingFacade = ExpressionTypingVisitorDispatcher.create(platformToKotlinClassMap);
141        }
142    
143        @NotNull
144        public PlatformToKotlinClassMap getPlatformToKotlinClassMap() {
145            return platformToKotlinClassMap;
146        }
147    
148        @Inject
149        public void setExtensionProvider(@NotNull CallResolverExtensionProvider extensionProvider) {
150            this.extensionProvider = extensionProvider;
151        }
152    
153        @NotNull
154        public JetType safeGetType(@NotNull JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
155            JetType type = getType(scope, expression, expectedType, dataFlowInfo, trace);
156            if (type != null) {
157                return type;
158            }
159            return ErrorUtils.createErrorType("Type for " + expression.getText());
160        }
161    
162        @NotNull
163        public JetTypeInfo getTypeInfo(@NotNull JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
164            ExpressionTypingContext context = ExpressionTypingContext.newContext(this, trace, scope, dataFlowInfo, expectedType);
165            return expressionTypingFacade.getTypeInfo(expression, context);
166        }
167    
168        @NotNull
169        public JetTypeInfo getTypeInfo(@NotNull JetExpression expression, @NotNull ResolutionContext resolutionContext) {
170            return expressionTypingFacade.getTypeInfo(expression, ExpressionTypingContext.newContext(this, resolutionContext));
171        }
172    
173        @Nullable
174        public JetType getType(@NotNull JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo, @NotNull BindingTrace trace) {
175            return getTypeInfo(scope, expression, expectedType, dataFlowInfo, trace).getType();
176        }
177    
178        /////////////////////////////////////////////////////////
179    
180        public void checkFunctionReturnType(@NotNull JetScope functionInnerScope, @NotNull JetDeclarationWithBody function, @NotNull FunctionDescriptor functionDescriptor, @NotNull DataFlowInfo dataFlowInfo, @Nullable JetType expectedReturnType, BindingTrace trace) {
181            if (expectedReturnType == null) {
182                expectedReturnType = functionDescriptor.getReturnType();
183                if (!function.hasBlockBody() && !function.hasDeclaredReturnType()) {
184                    expectedReturnType = NO_EXPECTED_TYPE;
185                }
186            }
187            checkFunctionReturnType(function, ExpressionTypingContext.newContext(
188                    this, trace, functionInnerScope, dataFlowInfo, expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE
189            ));
190        }
191    
192        /*package*/ void checkFunctionReturnType(JetDeclarationWithBody function, ExpressionTypingContext context) {
193            JetExpression bodyExpression = function.getBodyExpression();
194            if (bodyExpression == null) return;
195    
196            boolean blockBody = function.hasBlockBody();
197            ExpressionTypingContext newContext =
198                    blockBody
199                    ? context.replaceExpectedType(NO_EXPECTED_TYPE)
200                    : context;
201    
202            expressionTypingFacade.getTypeInfo(bodyExpression, newContext, blockBody);
203        }
204    
205        @NotNull
206        public JetTypeInfo getBlockReturnedType(
207                @NotNull JetBlockExpression expression,
208                @NotNull CoercionStrategy coercionStrategyForLastExpression,
209                @NotNull ExpressionTypingContext context
210        ) {
211            List<JetElement> block = expression.getStatements();
212    
213            DeclarationDescriptor containingDescriptor = context.scope.getContainingDeclaration();
214            if (containingDescriptor instanceof ScriptDescriptor) {
215                if (!(expression.getParent() instanceof JetScript)) {
216                    // top level script declarations should have ScriptDescriptor parent
217                    // and lower level script declarations should be ScriptCodeDescriptor parent
218                    containingDescriptor = ((ScriptDescriptor) containingDescriptor).getScriptCodeDescriptor();
219                }
220            }
221            WritableScope scope = new WritableScopeImpl(
222                    context.scope, containingDescriptor, new TraceBasedRedeclarationHandler(context.trace), "getBlockReturnedType");
223            scope.changeLockLevel(WritableScope.LockLevel.BOTH);
224    
225            JetTypeInfo r;
226            if (block.isEmpty()) {
227                r = DataFlowUtils.checkType(KotlinBuiltIns.getInstance().getUnitType(), expression, context, context.dataFlowInfo);
228            }
229            else {
230                r = getBlockReturnedTypeWithWritableScope(scope, block, coercionStrategyForLastExpression, context, context.trace);
231            }
232            scope.changeLockLevel(WritableScope.LockLevel.READING);
233    
234            if (containingDescriptor instanceof ScriptDescriptor) {
235                context.trace.record(BindingContext.SCRIPT_SCOPE, (ScriptDescriptor) containingDescriptor, scope);
236            }
237    
238            return r;
239        }
240    
241        @NotNull
242        public JetType getBodyExpressionType(
243                @NotNull BindingTrace trace,
244                @NotNull JetScope outerScope,
245                @NotNull DataFlowInfo dataFlowInfo,
246                @NotNull JetDeclarationWithBody function,
247                @NotNull FunctionDescriptor functionDescriptor
248        ) {
249            JetExpression bodyExpression = function.getBodyExpression();
250            assert bodyExpression != null;
251            JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace);
252    
253            ExpressionTypingContext context = ExpressionTypingContext.newContext(
254                    this, trace, functionInnerScope, dataFlowInfo, NO_EXPECTED_TYPE
255            );
256            JetTypeInfo typeInfo = expressionTypingFacade.getTypeInfo(bodyExpression, context, function.hasBlockBody());
257    
258            trace.record(STATEMENT, bodyExpression, false);
259            JetType type = typeInfo.getType();
260            if (type != null) {
261                return type;
262            }
263            else {
264                return ErrorUtils.createErrorType("Error function type");
265            }
266        }
267    
268        /*package*/ JetTypeInfo getBlockReturnedTypeWithWritableScope(
269                @NotNull WritableScope scope,
270                @NotNull List<? extends JetElement> block,
271                @NotNull CoercionStrategy coercionStrategyForLastExpression,
272                @NotNull ExpressionTypingContext context,
273                @NotNull BindingTrace trace
274        ) {
275            if (block.isEmpty()) {
276                return JetTypeInfo.create(KotlinBuiltIns.getInstance().getUnitType(), context.dataFlowInfo);
277            }
278    
279            ExpressionTypingInternals blockLevelVisitor = ExpressionTypingVisitorDispatcher.createForBlock(platformToKotlinClassMap, scope);
280            ExpressionTypingContext newContext = createContext(context, trace, scope, context.dataFlowInfo, NO_EXPECTED_TYPE);
281    
282            JetTypeInfo result = JetTypeInfo.create(null, context.dataFlowInfo);
283            for (Iterator<? extends JetElement> iterator = block.iterator(); iterator.hasNext(); ) {
284                JetElement statement = iterator.next();
285                if (!(statement instanceof JetExpression)) {
286                    continue;
287                }
288                trace.record(STATEMENT, statement);
289                JetExpression statementExpression = (JetExpression) statement;
290                if (!iterator.hasNext()) {
291                    result = getTypeOfLastExpressionInBlock(
292                            statementExpression, newContext.replaceExpectedType(context.expectedType), coercionStrategyForLastExpression,
293                            blockLevelVisitor);
294                }
295                else {
296                    result = blockLevelVisitor.getTypeInfo(statementExpression, newContext.replaceContextDependency(ContextDependency.INDEPENDENT), true);
297                }
298    
299                DataFlowInfo newDataFlowInfo = result.getDataFlowInfo();
300                if (newDataFlowInfo != context.dataFlowInfo) {
301                    newContext = newContext.replaceDataFlowInfo(newDataFlowInfo);
302                }
303                blockLevelVisitor = ExpressionTypingVisitorDispatcher.createForBlock(platformToKotlinClassMap, scope);
304            }
305            return result;
306        }
307    
308        private JetTypeInfo getTypeOfLastExpressionInBlock(
309                @NotNull JetExpression statementExpression,
310                @NotNull ExpressionTypingContext context,
311                @NotNull CoercionStrategy coercionStrategyForLastExpression,
312                @NotNull ExpressionTypingInternals blockLevelVisitor
313        ) {
314            if (!noExpectedType(context.expectedType) || context.expectedType == UNIT_EXPECTED_TYPE) {
315                JetType expectedType;
316                if (context.expectedType == UNIT_EXPECTED_TYPE ||//the first check is necessary to avoid invocation 'isUnit(UNIT_EXPECTED_TYPE)'
317                    (coercionStrategyForLastExpression == COERCION_TO_UNIT && KotlinBuiltIns.getInstance().isUnit(context.expectedType))) {
318                    expectedType = UNIT_EXPECTED_TYPE;
319                }
320                else {
321                    expectedType = context.expectedType;
322                }
323    
324                return blockLevelVisitor.getTypeInfo(statementExpression, context.replaceExpectedType(expectedType), true);
325            }
326            JetTypeInfo result = blockLevelVisitor.getTypeInfo(statementExpression, context, true);
327            if (coercionStrategyForLastExpression == COERCION_TO_UNIT) {
328                boolean mightBeUnit = false;
329                if (statementExpression instanceof JetDeclaration) {
330                    mightBeUnit = true;
331                }
332                if (statementExpression instanceof JetBinaryExpression) {
333                    JetBinaryExpression binaryExpression = (JetBinaryExpression) statementExpression;
334                    IElementType operationType = binaryExpression.getOperationToken();
335                    //noinspection SuspiciousMethodCalls
336                    if (operationType == JetTokens.EQ || OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
337                        mightBeUnit = true;
338                    }
339                }
340                if (mightBeUnit) {
341                    // ExpressionTypingVisitorForStatements should return only null or Unit for declarations and assignments
342                    assert result.getType() == null || KotlinBuiltIns.getInstance().isUnit(result.getType());
343                    result = JetTypeInfo.create(KotlinBuiltIns.getInstance().getUnitType(), context.dataFlowInfo);
344                }
345            }
346            return result;
347        }
348    
349        private ExpressionTypingContext createContext(ExpressionTypingContext oldContext, BindingTrace trace, WritableScope scope, DataFlowInfo dataFlowInfo, JetType expectedType) {
350            return ExpressionTypingContext.newContext(this, trace, scope, dataFlowInfo, expectedType, oldContext.contextDependency,
351                                                      oldContext.resolutionResultsCache, oldContext.labelResolver,
352                                                      oldContext.callResolverExtension, oldContext.isAnnotationContext);
353        }
354    
355        @Nullable
356        public JetExpression deparenthesizeWithTypeResolution(
357                @Nullable JetExpression expression,
358                @NotNull final ExpressionTypingContext context
359        ) {
360            return JetPsiUtil.deparenthesizeWithResolutionStrategy(expression, true, new Function<JetTypeReference, Void>() {
361                @Override
362                public Void apply(JetTypeReference reference) {
363                    getTypeResolver().resolveType(context.scope, reference, context.trace, true);
364                    return null;
365                }
366            });
367        }
368    
369        public void resolveValueParameters(
370                @NotNull List<JetParameter> valueParameters,
371                @NotNull List<ValueParameterDescriptor> valueParameterDescriptors,
372                @NotNull JetScope declaringScope,
373                @NotNull DataFlowInfo dataFlowInfo,
374                @NotNull BindingTrace trace
375        ) {
376            for (int i = 0; i < valueParameters.size(); i++) {
377                ValueParameterDescriptor valueParameterDescriptor = valueParameterDescriptors.get(i);
378                JetParameter jetParameter = valueParameters.get(i);
379    
380                annotationResolver.resolveAnnotationsArguments(declaringScope, jetParameter.getModifierList(), trace);
381    
382                resolveDefaultValue(declaringScope, valueParameterDescriptor, jetParameter, dataFlowInfo, trace);
383            }
384        }
385    
386        private void resolveDefaultValue(
387                @NotNull JetScope declaringScope,
388                @NotNull ValueParameterDescriptor valueParameterDescriptor,
389                @NotNull JetParameter jetParameter,
390                @NotNull DataFlowInfo dataFlowInfo,
391                @NotNull BindingTrace trace
392        ) {
393            if (valueParameterDescriptor.hasDefaultValue()) {
394                JetExpression defaultValue = jetParameter.getDefaultValue();
395                if (defaultValue != null) {
396                    getType(declaringScope, defaultValue, valueParameterDescriptor.getType(), dataFlowInfo, trace);
397                    if (DescriptorUtils.isAnnotationClass(DescriptorUtils.getContainingClass(declaringScope))) {
398                        CompileTimeConstant<?> constant =
399                                annotationResolver.resolveExpressionToCompileTimeValue(defaultValue, valueParameterDescriptor.getType(), trace);
400                        if (constant != null) {
401                            trace.record(BindingContext.COMPILE_TIME_VALUE, defaultValue, constant);
402                        }
403                    }
404                }
405            }
406        }
407    
408        @NotNull
409        public CallResolverExtension createExtension(@NotNull JetScope scope, boolean isAnnotationContext) {
410            return extensionProvider.createExtension(scope == JetScope.EMPTY ? null : scope.getContainingDeclaration(), isAnnotationContext);
411        }
412    }