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