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