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.collect.Sets;
020 import com.intellij.psi.tree.IElementType;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
024 import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
025 import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
026 import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
027 import org.jetbrains.jet.lang.diagnostics.Errors;
028 import org.jetbrains.jet.lang.evaluate.EvaluatePackage;
029 import org.jetbrains.jet.lang.psi.*;
030 import org.jetbrains.jet.lang.resolve.*;
031 import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
032 import org.jetbrains.jet.lang.resolve.calls.context.TemporaryTraceAndCache;
033 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
034 import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
035 import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsUtil;
036 import org.jetbrains.jet.lang.resolve.name.Name;
037 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
038 import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
039 import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
040 import org.jetbrains.jet.lang.types.JetType;
041 import org.jetbrains.jet.lang.types.JetTypeInfo;
042 import org.jetbrains.jet.lang.types.TypeUtils;
043 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
044 import org.jetbrains.jet.lexer.JetTokens;
045
046 import java.util.Collection;
047
048 import static org.jetbrains.jet.lang.diagnostics.Errors.*;
049 import static org.jetbrains.jet.lang.resolve.BindingContext.AMBIGUOUS_REFERENCE_TARGET;
050 import static org.jetbrains.jet.lang.resolve.BindingContext.VARIABLE_REASSIGNMENT;
051 import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.INDEPENDENT;
052 import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
053 import static org.jetbrains.jet.lang.types.TypeUtils.noExpectedType;
054
055 @SuppressWarnings("SuspiciousMethodCalls")
056 public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisitor {
057 private final WritableScope scope;
058 private final BasicExpressionTypingVisitor basic;
059 private final ControlStructureTypingVisitor controlStructures;
060 private final PatternMatchingTypingVisitor patterns;
061
062 public ExpressionTypingVisitorForStatements(
063 @NotNull ExpressionTypingInternals facade,
064 @NotNull WritableScope scope,
065 BasicExpressionTypingVisitor basic,
066 @NotNull ControlStructureTypingVisitor controlStructures,
067 @NotNull PatternMatchingTypingVisitor patterns) {
068 super(facade);
069 this.scope = scope;
070 this.basic = basic;
071 this.controlStructures = controlStructures;
072 this.patterns = patterns;
073 }
074
075 @Nullable
076 private static JetType checkAssignmentType(
077 @Nullable JetType assignmentType,
078 @NotNull JetBinaryExpression expression,
079 @NotNull ExpressionTypingContext context
080 ) {
081 if (assignmentType != null && !KotlinBuiltIns.getInstance().isUnit(assignmentType) && !noExpectedType(context.expectedType) &&
082 TypeUtils.equalTypes(context.expectedType, assignmentType)) {
083 context.trace.report(Errors.ASSIGNMENT_TYPE_MISMATCH.on(expression, context.expectedType));
084 return null;
085 }
086 return DataFlowUtils.checkStatementType(expression, context);
087 }
088
089 @Override
090 public JetTypeInfo visitObjectDeclaration(@NotNull JetObjectDeclaration declaration, ExpressionTypingContext context) {
091 TopDownAnalyzer.processClassOrObject(
092 components.globalContext,
093 scope, context.replaceScope(scope).replaceContextDependency(INDEPENDENT), scope.getContainingDeclaration(), declaration);
094 return DataFlowUtils.checkStatementType(declaration, context, context.dataFlowInfo);
095 }
096
097 @Override
098 public JetTypeInfo visitProperty(@NotNull JetProperty property, ExpressionTypingContext typingContext) {
099 ExpressionTypingContext context = typingContext.replaceContextDependency(INDEPENDENT).replaceScope(scope);
100 JetTypeReference receiverTypeRef = property.getReceiverTypeRef();
101 if (receiverTypeRef != null) {
102 context.trace.report(LOCAL_EXTENSION_PROPERTY.on(receiverTypeRef));
103 }
104
105 JetPropertyAccessor getter = property.getGetter();
106 if (getter != null) {
107 context.trace.report(LOCAL_VARIABLE_WITH_GETTER.on(getter));
108 }
109
110 JetPropertyAccessor setter = property.getSetter();
111 if (setter != null) {
112 context.trace.report(LOCAL_VARIABLE_WITH_SETTER.on(setter));
113 }
114
115 JetExpression delegateExpression = property.getDelegateExpression();
116 if (delegateExpression != null) {
117 components.expressionTypingServices.getTypeInfo(delegateExpression, context);
118 context.trace.report(LOCAL_VARIABLE_WITH_DELEGATE.on(property.getDelegate()));
119 }
120
121 for (JetTypeParameter typeParameter : property.getTypeParameters()) {
122 AnnotationResolver.reportUnsupportedAnnotationForTypeParameter(typeParameter, context.trace);
123 }
124
125 VariableDescriptor propertyDescriptor = components.expressionTypingServices.getDescriptorResolver().
126 resolveLocalVariableDescriptor(scope, property, context.dataFlowInfo, context.trace);
127 JetExpression initializer = property.getInitializer();
128 DataFlowInfo dataFlowInfo = context.dataFlowInfo;
129 if (initializer != null) {
130 JetType outType = propertyDescriptor.getType();
131 JetTypeInfo typeInfo = facade.getTypeInfo(initializer, context.replaceExpectedType(outType));
132 dataFlowInfo = typeInfo.getDataFlowInfo();
133
134 EvaluatePackage.recordCompileTimeValueForInitializerIfNeeded(propertyDescriptor, initializer, outType, context.trace);
135 }
136
137 {
138 VariableDescriptor olderVariable = scope.getLocalVariable(propertyDescriptor.getName());
139 ExpressionTypingUtils.checkVariableShadowing(context, propertyDescriptor, olderVariable);
140 }
141
142 scope.addVariableDescriptor(propertyDescriptor);
143 ModifiersChecker.create(context.trace).checkModifiersForLocalDeclaration(property);
144 return DataFlowUtils.checkStatementType(property, context, dataFlowInfo);
145 }
146
147 @Override
148 public JetTypeInfo visitMultiDeclaration(@NotNull JetMultiDeclaration multiDeclaration, ExpressionTypingContext context) {
149 components.expressionTypingServices.getAnnotationResolver().resolveAnnotationsWithArguments(
150 scope, multiDeclaration.getModifierList(), context.trace);
151
152 JetExpression initializer = multiDeclaration.getInitializer();
153 if (initializer == null) {
154 context.trace.report(INITIALIZER_REQUIRED_FOR_MULTIDECLARATION.on(multiDeclaration));
155 return JetTypeInfo.create(null, context.dataFlowInfo);
156 }
157 ExpressionReceiver expressionReceiver = ExpressionTypingUtils.getExpressionReceiver(
158 facade, initializer, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT));
159 DataFlowInfo dataFlowInfo = facade.getTypeInfo(initializer, context).getDataFlowInfo();
160 if (expressionReceiver == null) {
161 return JetTypeInfo.create(null, dataFlowInfo);
162 }
163 components.expressionTypingUtils.defineLocalVariablesFromMultiDeclaration(scope, multiDeclaration, expressionReceiver, initializer, context);
164 return DataFlowUtils.checkStatementType(multiDeclaration, context, dataFlowInfo);
165 }
166
167 @Override
168 public JetTypeInfo visitNamedFunction(@NotNull JetNamedFunction function, ExpressionTypingContext context) {
169 SimpleFunctionDescriptor functionDescriptor = components.expressionTypingServices.getDescriptorResolver().
170 resolveFunctionDescriptorWithAnnotationArguments(
171 scope.getContainingDeclaration(), scope, function, context.trace, context.dataFlowInfo);
172
173 scope.addFunctionDescriptor(functionDescriptor);
174 JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(context.scope, functionDescriptor, context.trace);
175 components.expressionTypingServices.checkFunctionReturnType(functionInnerScope, function, functionDescriptor, context.dataFlowInfo, null, context.trace);
176
177 components.expressionTypingServices.resolveValueParameters(function.getValueParameters(), functionDescriptor.getValueParameters(),
178 scope, context.dataFlowInfo, context.trace, /* needCompleteAnalysis = */ true);
179
180 ModifiersChecker.create(context.trace).checkModifiersForLocalDeclaration(function);
181 return DataFlowUtils.checkStatementType(function, context, context.dataFlowInfo);
182 }
183
184 @Override
185 public JetTypeInfo visitClass(@NotNull JetClass klass, ExpressionTypingContext context) {
186 TopDownAnalyzer.processClassOrObject(
187 components.globalContext,
188 scope, context.replaceScope(scope).replaceContextDependency(INDEPENDENT), scope.getContainingDeclaration(), klass);
189 return DataFlowUtils.checkStatementType(klass, context, context.dataFlowInfo);
190 }
191
192 @Override
193 public JetTypeInfo visitTypedef(@NotNull JetTypedef typedef, ExpressionTypingContext context) {
194 return super.visitTypedef(typedef, context); // TODO
195 }
196
197 @Override
198 public JetTypeInfo visitDeclaration(@NotNull JetDeclaration dcl, ExpressionTypingContext context) {
199 return DataFlowUtils.checkStatementType(dcl, context, context.dataFlowInfo);
200 }
201
202 @Override
203 public JetTypeInfo visitBinaryExpression(@NotNull JetBinaryExpression expression, ExpressionTypingContext context) {
204 JetSimpleNameExpression operationSign = expression.getOperationReference();
205 IElementType operationType = operationSign.getReferencedNameElementType();
206 JetTypeInfo result;
207 if (operationType == JetTokens.EQ) {
208 result = visitAssignment(expression, context);
209 }
210 else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
211 result = visitAssignmentOperation(expression, context);
212 }
213 else {
214 return facade.getTypeInfo(expression, context);
215 }
216 return DataFlowUtils.checkType(result.getType(), expression, context, result.getDataFlowInfo());
217 }
218
219 @NotNull
220 protected JetTypeInfo visitAssignmentOperation(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
221 //There is a temporary binding trace for an opportunity to resolve set method for array if needed (the initial trace should be used there)
222 TemporaryTraceAndCache temporary = TemporaryTraceAndCache.create(
223 contextWithExpectedType, "trace to resolve array set method for binary expression", expression);
224 ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE)
225 .replaceTraceAndCache(temporary).replaceContextDependency(INDEPENDENT);
226
227 JetSimpleNameExpression operationSign = expression.getOperationReference();
228 IElementType operationType = operationSign.getReferencedNameElementType();
229 JetExpression leftOperand = expression.getLeft();
230 JetTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(leftOperand, context, facade);
231 JetType leftType = leftInfo.getType();
232 DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo();
233
234 JetExpression right = expression.getRight();
235 JetExpression left = leftOperand == null ? null : JetPsiUtil.deparenthesize(leftOperand);
236 if (right == null || left == null) {
237 temporary.commit();
238 return JetTypeInfo.create(null, dataFlowInfo);
239 }
240
241 if (leftType == null) {
242 dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo();
243 context.trace.report(UNRESOLVED_REFERENCE.on(operationSign, operationSign));
244 temporary.commit();
245 return JetTypeInfo.create(null, dataFlowInfo);
246 }
247 ExpressionReceiver receiver = new ExpressionReceiver(left, leftType);
248
249 // We check that defined only one of '+=' and '+' operations, and call it (in the case '+' we then also assign)
250 // Check for '+='
251 Name name = OperatorConventions.ASSIGNMENT_OPERATIONS.get(operationType);
252 TemporaryTraceAndCache temporaryForAssignmentOperation = TemporaryTraceAndCache.create(
253 context, "trace to check assignment operation like '+=' for", expression);
254 OverloadResolutionResults<FunctionDescriptor> assignmentOperationDescriptors =
255 components.callResolver.resolveBinaryCall(
256 context.replaceTraceAndCache(temporaryForAssignmentOperation).replaceScope(scope),
257 receiver, expression, name
258 );
259 JetType assignmentOperationType = OverloadResolutionResultsUtil.getResultingType(assignmentOperationDescriptors,
260 context.contextDependency);
261
262 // Check for '+'
263 Name counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType));
264 TemporaryTraceAndCache temporaryForBinaryOperation = TemporaryTraceAndCache.create(
265 context, "trace to check binary operation like '+' for", expression);
266 OverloadResolutionResults<FunctionDescriptor> binaryOperationDescriptors = components.callResolver.resolveBinaryCall(
267 context.replaceTraceAndCache(temporaryForBinaryOperation).replaceScope(scope),
268 receiver, expression, counterpartName
269 );
270 JetType binaryOperationType = OverloadResolutionResultsUtil.getResultingType(binaryOperationDescriptors, context.contextDependency);
271
272 JetType type = assignmentOperationType != null ? assignmentOperationType : binaryOperationType;
273 if (assignmentOperationDescriptors.isSuccess() && binaryOperationDescriptors.isSuccess()) {
274 // Both 'plus()' and 'plusAssign()' available => ambiguity
275 OverloadResolutionResults<FunctionDescriptor> ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity(assignmentOperationDescriptors, binaryOperationDescriptors);
276 context.trace.report(ASSIGN_OPERATOR_AMBIGUITY.on(operationSign, ambiguityResolutionResults.getResultingCalls()));
277 Collection<DeclarationDescriptor> descriptors = Sets.newHashSet();
278 for (ResolvedCall<? extends FunctionDescriptor> call : ambiguityResolutionResults.getResultingCalls()) {
279 descriptors.add(call.getResultingDescriptor());
280 }
281 dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo();
282 context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors);
283 }
284 else if (assignmentOperationType != null && (assignmentOperationDescriptors.isSuccess() || !binaryOperationDescriptors.isSuccess())) {
285 // There's 'plusAssign()', so we do a.plusAssign(b)
286 temporaryForAssignmentOperation.commit();
287 if (!KotlinBuiltIns.getInstance().isUnit(assignmentOperationType)) {
288 context.trace.report(ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on(operationSign, assignmentOperationDescriptors.getResultingDescriptor(), operationSign));
289 }
290 }
291 else {
292 // There's only 'plus()', so we try 'a = a + b'
293 temporaryForBinaryOperation.commit();
294 context.trace.record(VARIABLE_REASSIGNMENT, expression);
295 if (left instanceof JetArrayAccessExpression) {
296 ExpressionTypingContext contextForResolve = context.replaceScope(scope).replaceBindingTrace(TemporaryBindingTrace.create(
297 context.trace, "trace to resolve array set method for assignment", expression));
298 basic.resolveArrayAccessSetMethod((JetArrayAccessExpression) left, right, contextForResolve, context.trace);
299 }
300 dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo();
301 BasicExpressionTypingVisitor.checkLValue(context.trace, leftOperand);
302 }
303 temporary.commit();
304 return JetTypeInfo.create(checkAssignmentType(type, expression, contextWithExpectedType), dataFlowInfo);
305 }
306
307 @NotNull
308 protected JetTypeInfo visitAssignment(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
309 ExpressionTypingContext context =
310 contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceScope(scope).replaceContextDependency(INDEPENDENT);
311 JetExpression leftOperand = expression.getLeft();
312 JetExpression left = components.expressionTypingServices.deparenthesizeWithTypeResolution(leftOperand, context);
313 JetExpression right = expression.getRight();
314 if (left instanceof JetArrayAccessExpression) {
315 JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
316 if (right == null) return JetTypeInfo.create(null, context.dataFlowInfo);
317 JetTypeInfo typeInfo = basic.resolveArrayAccessSetMethod(arrayAccessExpression, right, context, context.trace);
318 BasicExpressionTypingVisitor.checkLValue(context.trace, arrayAccessExpression);
319 return JetTypeInfo.create(checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType),
320 typeInfo.getDataFlowInfo());
321 }
322 JetTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(left, context, facade);
323 JetType leftType = leftInfo.getType();
324 DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo();
325 if (right != null) {
326 JetTypeInfo rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(leftType));
327 dataFlowInfo = rightInfo.getDataFlowInfo();
328 }
329 if (leftType != null && leftOperand != null) { //if leftType == null, some other error has been generated
330 BasicExpressionTypingVisitor.checkLValue(context.trace, leftOperand);
331 }
332 return DataFlowUtils.checkStatementType(expression, contextWithExpectedType, dataFlowInfo);
333 }
334
335
336 @Override
337 public JetTypeInfo visitExpression(@NotNull JetExpression expression, ExpressionTypingContext context) {
338 return facade.getTypeInfo(expression, context);
339 }
340
341 @Override
342 public JetTypeInfo visitJetElement(@NotNull JetElement element, ExpressionTypingContext context) {
343 context.trace.report(UNSUPPORTED.on(element, "in a block"));
344 return JetTypeInfo.create(null, context.dataFlowInfo);
345 }
346
347 @Override
348 public JetTypeInfo visitWhileExpression(@NotNull JetWhileExpression expression, ExpressionTypingContext context) {
349 return controlStructures.visitWhileExpression(expression, context, true);
350 }
351
352 @Override
353 public JetTypeInfo visitDoWhileExpression(@NotNull JetDoWhileExpression expression, ExpressionTypingContext context) {
354 return controlStructures.visitDoWhileExpression(expression, context, true);
355 }
356
357 @Override
358 public JetTypeInfo visitForExpression(@NotNull JetForExpression expression, ExpressionTypingContext context) {
359 return controlStructures.visitForExpression(expression, context, true);
360 }
361
362 @Override
363 public JetTypeInfo visitAnnotatedExpression(
364 @NotNull JetAnnotatedExpression expression, ExpressionTypingContext data
365 ) {
366 return basic.visitAnnotatedExpression(expression, data, true);
367 }
368
369 @Override
370 public JetTypeInfo visitIfExpression(@NotNull JetIfExpression expression, ExpressionTypingContext context) {
371 return controlStructures.visitIfExpression(expression, context, true);
372 }
373
374 @Override
375 public JetTypeInfo visitWhenExpression(@NotNull JetWhenExpression expression, ExpressionTypingContext context) {
376 return patterns.visitWhenExpression(expression, context, true);
377 }
378
379 @Override
380 public JetTypeInfo visitBlockExpression(@NotNull JetBlockExpression expression, ExpressionTypingContext context) {
381 return components.expressionTypingServices.getBlockReturnedType(expression, context, true);
382 }
383
384 @Override
385 public JetTypeInfo visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression, ExpressionTypingContext context) {
386 return basic.visitParenthesizedExpression(expression, context, true);
387 }
388
389 @Override
390 public JetTypeInfo visitUnaryExpression(@NotNull JetUnaryExpression expression, ExpressionTypingContext context) {
391 return basic.visitUnaryExpression(expression, context, true);
392 }
393 }