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