001 /*
002 * Copyright 2010-2015 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.kotlin.types.expressions;
018
019 import com.intellij.psi.tree.IElementType;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.annotations.Nullable;
022 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
023 import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
024 import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
025 import org.jetbrains.kotlin.descriptors.ScriptDescriptor;
026 import org.jetbrains.kotlin.lexer.KtTokens;
027 import org.jetbrains.kotlin.psi.*;
028 import org.jetbrains.kotlin.resolve.*;
029 import org.jetbrains.kotlin.resolve.calls.context.ContextDependency;
030 import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
031 import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
032 import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
033 import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
034 import org.jetbrains.kotlin.types.ErrorUtils;
035 import org.jetbrains.kotlin.types.KotlinType;
036 import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
037
038 import java.util.Iterator;
039 import java.util.List;
040
041 import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
042 import static org.jetbrains.kotlin.types.TypeUtils.UNIT_EXPECTED_TYPE;
043 import static org.jetbrains.kotlin.types.expressions.CoercionStrategy.COERCION_TO_UNIT;
044
045 public class ExpressionTypingServices {
046
047 private final ExpressionTypingFacade expressionTypingFacade;
048 private final ExpressionTypingComponents expressionTypingComponents;
049
050 @NotNull private final AnnotationChecker annotationChecker;
051 @NotNull private final StatementFilter statementFilter;
052
053 public ExpressionTypingServices(
054 @NotNull ExpressionTypingComponents components,
055 @NotNull AnnotationChecker annotationChecker,
056 @NotNull StatementFilter statementFilter,
057 @NotNull ExpressionTypingVisitorDispatcher.ForDeclarations facade
058 ) {
059 this.expressionTypingComponents = components;
060 this.annotationChecker = annotationChecker;
061 this.statementFilter = statementFilter;
062 this.expressionTypingFacade = facade;
063 }
064
065 @NotNull public StatementFilter getStatementFilter() {
066 return statementFilter;
067 }
068
069 @NotNull
070 public KotlinType safeGetType(
071 @NotNull LexicalScope scope,
072 @NotNull KtExpression expression,
073 @NotNull KotlinType expectedType,
074 @NotNull DataFlowInfo dataFlowInfo,
075 @NotNull BindingTrace trace
076 ) {
077 KotlinType type = getType(scope, expression, expectedType, dataFlowInfo, trace);
078
079 return type != null ? type : ErrorUtils.createErrorType("Type for " + expression.getText());
080 }
081
082 @NotNull
083 public KotlinTypeInfo getTypeInfo(
084 @NotNull LexicalScope scope,
085 @NotNull KtExpression expression,
086 @NotNull KotlinType expectedType,
087 @NotNull DataFlowInfo dataFlowInfo,
088 @NotNull BindingTrace trace,
089 boolean isStatement
090 ) {
091 ExpressionTypingContext context = ExpressionTypingContext.newContext(
092 trace, scope, dataFlowInfo, expectedType
093 );
094 return expressionTypingFacade.getTypeInfo(expression, context, isStatement);
095 }
096
097 @NotNull
098 public KotlinTypeInfo getTypeInfo(@NotNull KtExpression expression, @NotNull ResolutionContext resolutionContext) {
099 return expressionTypingFacade.getTypeInfo(expression, ExpressionTypingContext.newContext(resolutionContext));
100 }
101
102 @Nullable
103 public KotlinType getType(
104 @NotNull LexicalScope scope,
105 @NotNull KtExpression expression,
106 @NotNull KotlinType expectedType,
107 @NotNull DataFlowInfo dataFlowInfo,
108 @NotNull BindingTrace trace
109 ) {
110 return getTypeInfo(scope, expression, expectedType, dataFlowInfo, trace, false).getType();
111 }
112
113 /////////////////////////////////////////////////////////
114
115 public void checkFunctionReturnType(
116 @NotNull LexicalScope functionInnerScope,
117 @NotNull KtDeclarationWithBody function,
118 @NotNull FunctionDescriptor functionDescriptor,
119 @NotNull DataFlowInfo dataFlowInfo,
120 @Nullable KotlinType expectedReturnType,
121 BindingTrace trace
122 ) {
123 if (expectedReturnType == null) {
124 expectedReturnType = functionDescriptor.getReturnType();
125 if (!function.hasBlockBody() && !function.hasDeclaredReturnType()) {
126 expectedReturnType = NO_EXPECTED_TYPE;
127 }
128 }
129 checkFunctionReturnType(function, ExpressionTypingContext.newContext(
130 trace,
131 functionInnerScope, dataFlowInfo, expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE
132 ));
133 }
134
135 /*package*/ void checkFunctionReturnType(KtDeclarationWithBody function, ExpressionTypingContext context) {
136 KtExpression bodyExpression = function.getBodyExpression();
137 if (bodyExpression == null) return;
138
139 boolean blockBody = function.hasBlockBody();
140 ExpressionTypingContext newContext =
141 blockBody
142 ? context.replaceExpectedType(NO_EXPECTED_TYPE)
143 : context;
144
145 expressionTypingFacade.getTypeInfo(bodyExpression, newContext, blockBody);
146 }
147
148 @NotNull
149 public KotlinTypeInfo getBlockReturnedType(KtBlockExpression expression, ExpressionTypingContext context, boolean isStatement) {
150 return getBlockReturnedType(expression, isStatement ? CoercionStrategy.COERCION_TO_UNIT : CoercionStrategy.NO_COERCION, context);
151 }
152
153 @NotNull
154 public KotlinTypeInfo getBlockReturnedType(
155 @NotNull KtBlockExpression expression,
156 @NotNull CoercionStrategy coercionStrategyForLastExpression,
157 @NotNull ExpressionTypingContext context
158 ) {
159 List<KtExpression> block = StatementFilterKt.filterStatements(statementFilter, expression);
160
161 DeclarationDescriptor containingDescriptor = context.scope.getOwnerDescriptor();
162 if (containingDescriptor instanceof ScriptDescriptor) {
163 if (!(expression.getParent() instanceof KtScript)) {
164 // top level script declarations should have ScriptDescriptor parent
165 // and lower level script declarations should be ScriptCodeDescriptor parent
166 containingDescriptor = ((ScriptDescriptor) containingDescriptor).getScriptCodeDescriptor();
167 }
168 }
169 LexicalWritableScope scope = new LexicalWritableScope(context.scope, containingDescriptor, false, null,
170 new TraceBasedRedeclarationHandler(context.trace), "getBlockReturnedType");
171 scope.changeLockLevel(LexicalWritableScope.LockLevel.BOTH);
172
173 KotlinTypeInfo r;
174 if (block.isEmpty()) {
175 r = expressionTypingComponents.dataFlowAnalyzer
176 .createCheckedTypeInfo(expressionTypingComponents.builtIns.getUnitType(), context, expression);
177 }
178 else {
179 r = getBlockReturnedTypeWithWritableScope(scope, block, coercionStrategyForLastExpression,
180 context.replaceStatementFilter(statementFilter));
181 }
182 scope.changeLockLevel(LexicalWritableScope.LockLevel.READING);
183
184 if (containingDescriptor instanceof ScriptDescriptor) {
185 context.trace.record(BindingContext.SCRIPT_SCOPE, (ScriptDescriptor) containingDescriptor, scope);
186 }
187
188 return r;
189 }
190
191 @NotNull
192 public KotlinType getBodyExpressionType(
193 @NotNull BindingTrace trace,
194 @NotNull LexicalScope outerScope,
195 @NotNull DataFlowInfo dataFlowInfo,
196 @NotNull KtDeclarationWithBody function,
197 @NotNull FunctionDescriptor functionDescriptor
198 ) {
199 KtExpression bodyExpression = function.getBodyExpression();
200 assert bodyExpression != null;
201 LexicalScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace);
202
203 ExpressionTypingContext context = ExpressionTypingContext.newContext(
204 trace, functionInnerScope, dataFlowInfo, NO_EXPECTED_TYPE
205 );
206 KotlinTypeInfo typeInfo = expressionTypingFacade.getTypeInfo(bodyExpression, context, function.hasBlockBody());
207
208 KotlinType type = typeInfo.getType();
209 if (type != null) {
210 return type;
211 }
212 else {
213 return ErrorUtils.createErrorType("Error function type");
214 }
215 }
216
217 /**
218 * Visits block statements propagating data flow information from the first to the last.
219 * Determines block returned type and data flow information at the end of the block AND
220 * at the nearest jump point from the block beginning.
221 */
222 /*package*/ KotlinTypeInfo getBlockReturnedTypeWithWritableScope(
223 @NotNull LexicalWritableScope scope,
224 @NotNull List<? extends KtElement> block,
225 @NotNull CoercionStrategy coercionStrategyForLastExpression,
226 @NotNull ExpressionTypingContext context
227 ) {
228 if (block.isEmpty()) {
229 return TypeInfoFactoryKt.createTypeInfo(expressionTypingComponents.builtIns.getUnitType(), context);
230 }
231
232 ExpressionTypingInternals blockLevelVisitor = new ExpressionTypingVisitorDispatcher.ForBlock(
233 expressionTypingComponents, annotationChecker, scope);
234 ExpressionTypingContext newContext = context.replaceScope(scope).replaceExpectedType(NO_EXPECTED_TYPE);
235
236 KotlinTypeInfo result = TypeInfoFactoryKt.noTypeInfo(context);
237 // Jump point data flow info
238 DataFlowInfo beforeJumpInfo = newContext.dataFlowInfo;
239 boolean jumpOutPossible = false;
240 for (Iterator<? extends KtElement> iterator = block.iterator(); iterator.hasNext(); ) {
241 KtElement statement = iterator.next();
242 if (!(statement instanceof KtExpression)) {
243 continue;
244 }
245 KtExpression statementExpression = (KtExpression) statement;
246 if (!iterator.hasNext()) {
247 result = getTypeOfLastExpressionInBlock(
248 statementExpression, newContext.replaceExpectedType(context.expectedType), coercionStrategyForLastExpression,
249 blockLevelVisitor);
250 }
251 else {
252 result = blockLevelVisitor
253 .getTypeInfo(statementExpression, newContext.replaceContextDependency(ContextDependency.INDEPENDENT), true);
254 }
255
256 DataFlowInfo newDataFlowInfo = result.getDataFlowInfo();
257 // If jump is not possible, we take new data flow info before jump
258 if (!jumpOutPossible) {
259 beforeJumpInfo = result.getJumpFlowInfo();
260 jumpOutPossible = result.getJumpOutPossible();
261 }
262 if (newDataFlowInfo != context.dataFlowInfo) {
263 newContext = newContext.replaceDataFlowInfo(newDataFlowInfo);
264 // We take current data flow info if jump there is not possible
265 }
266 blockLevelVisitor = new ExpressionTypingVisitorDispatcher.ForBlock(expressionTypingComponents, annotationChecker, scope);
267 }
268 return result.replaceJumpOutPossible(jumpOutPossible).replaceJumpFlowInfo(beforeJumpInfo);
269 }
270
271 private KotlinTypeInfo getTypeOfLastExpressionInBlock(
272 @NotNull KtExpression statementExpression,
273 @NotNull ExpressionTypingContext context,
274 @NotNull CoercionStrategy coercionStrategyForLastExpression,
275 @NotNull ExpressionTypingInternals blockLevelVisitor
276 ) {
277 if (context.expectedType != NO_EXPECTED_TYPE) {
278 KotlinType expectedType;
279 if (context.expectedType == UNIT_EXPECTED_TYPE ||//the first check is necessary to avoid invocation 'isUnit(UNIT_EXPECTED_TYPE)'
280 (coercionStrategyForLastExpression == COERCION_TO_UNIT && KotlinBuiltIns.isUnit(context.expectedType))) {
281 expectedType = UNIT_EXPECTED_TYPE;
282 }
283 else {
284 expectedType = context.expectedType;
285 }
286
287 return blockLevelVisitor.getTypeInfo(statementExpression, context.replaceExpectedType(expectedType), true);
288 }
289 KotlinTypeInfo result = blockLevelVisitor.getTypeInfo(statementExpression, context, true);
290 if (coercionStrategyForLastExpression == COERCION_TO_UNIT) {
291 boolean mightBeUnit = false;
292 if (statementExpression instanceof KtDeclaration) {
293 mightBeUnit = true;
294 }
295 if (statementExpression instanceof KtBinaryExpression) {
296 KtBinaryExpression binaryExpression = (KtBinaryExpression) statementExpression;
297 IElementType operationType = binaryExpression.getOperationToken();
298 //noinspection SuspiciousMethodCalls
299 if (operationType == KtTokens.EQ || OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
300 mightBeUnit = true;
301 }
302 }
303 if (mightBeUnit) {
304 // ExpressionTypingVisitorForStatements should return only null or Unit for declarations and assignments,
305 // but (for correct assignment / initialization analysis) data flow info must be preserved
306 assert result.getType() == null || KotlinBuiltIns.isUnit(result.getType());
307 result = result.replaceType(expressionTypingComponents.builtIns.getUnitType());
308 }
309 }
310 return result;
311 }
312
313 }