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