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