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