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