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