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.Lists;
020 import com.google.common.collect.Maps;
021 import com.intellij.lang.ASTNode;
022 import com.intellij.openapi.diagnostic.Logger;
023 import com.intellij.psi.util.PsiTreeUtil;
024 import org.jetbrains.annotations.NotNull;
025 import org.jetbrains.annotations.Nullable;
026 import org.jetbrains.jet.lang.descriptors.*;
027 import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
028 import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
029 import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
030 import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
031 import org.jetbrains.jet.lang.psi.*;
032 import org.jetbrains.jet.lang.resolve.BindingContextUtils;
033 import org.jetbrains.jet.lang.resolve.BindingTrace;
034 import org.jetbrains.jet.lang.resolve.calls.CallResolver;
035 import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
036 import org.jetbrains.jet.lang.resolve.calls.inference.*;
037 import org.jetbrains.jet.lang.resolve.calls.model.MutableDataFlowInfoForArguments;
038 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
039 import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
040 import org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind;
041 import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate;
042 import org.jetbrains.jet.lang.resolve.calls.tasks.TracingStrategy;
043 import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
044 import org.jetbrains.jet.lang.resolve.name.Name;
045 import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
046 import org.jetbrains.jet.lang.types.*;
047 import org.jetbrains.jet.lexer.JetTokens;
048
049 import java.util.*;
050
051 import static org.jetbrains.jet.lang.resolve.BindingContext.CALL;
052 import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL;
053
054 public class ControlStructureTypingUtils {
055 private static final Logger LOG = Logger.getInstance(ControlStructureTypingUtils.class);
056
057 private final ExpressionTypingServices expressionTypingServices;
058
059 public ControlStructureTypingUtils(@NotNull ExpressionTypingServices expressionTypingServices) {
060 this.expressionTypingServices = expressionTypingServices;
061 }
062
063 /*package*/ ResolvedCall<FunctionDescriptor> resolveSpecialConstructionAsCall(
064 @NotNull Call call,
065 @NotNull String constructionName,
066 @NotNull List<String> argumentNames,
067 @NotNull List<Boolean> isArgumentNullable,
068 @NotNull ExpressionTypingContext context,
069 @Nullable MutableDataFlowInfoForArguments dataFlowInfoForArguments
070 ) {
071 SimpleFunctionDescriptorImpl function = createFunctionDescriptorForSpecialConstruction(
072 constructionName.toUpperCase(), argumentNames, isArgumentNullable);
073 TracingStrategy tracing = createTracingForSpecialConstruction(call, constructionName);
074 ResolutionCandidate<CallableDescriptor> resolutionCandidate = ResolutionCandidate.<CallableDescriptor>create(call, function, null);
075 CallResolver callResolver = expressionTypingServices.getCallResolver();
076 OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallWithKnownCandidate(
077 call, tracing, context, resolutionCandidate, dataFlowInfoForArguments);
078 assert results.isSingleResult() : "Not single result after resolving one known candidate";
079 return results.getResultingCall();
080 }
081
082 private static SimpleFunctionDescriptorImpl createFunctionDescriptorForSpecialConstruction(
083 @NotNull String constructionName,
084 @NotNull List<String> argumentNames,
085 @NotNull List<Boolean> isArgumentNullable
086 ) {
087 assert argumentNames.size() == isArgumentNullable.size();
088
089 Name specialFunctionName = Name.identifierNoValidate("<SPECIAL-FUNCTION-FOR-" + constructionName + "-RESOLVE>");
090
091 SimpleFunctionDescriptorImpl function = SimpleFunctionDescriptorImpl.create(
092 ErrorUtils.getErrorModule(),//todo hack to avoid returning true in 'isError(DeclarationDescriptor)'
093 Annotations.EMPTY, specialFunctionName, CallableMemberDescriptor.Kind.DECLARATION, SourceElement.NO_SOURCE);
094
095 TypeParameterDescriptor typeParameter = TypeParameterDescriptorImpl.createWithDefaultBound(
096 function, Annotations.EMPTY, false, Variance.INVARIANT,
097 Name.identifierNoValidate("<TYPE-PARAMETER-FOR-" + constructionName + "-RESOLVE>"), 0);
098
099 JetType type = typeParameter.getDefaultType();
100 JetType nullableType = TypeUtils.makeNullable(type);
101
102 List<ValueParameterDescriptor> valueParameters = new ArrayList<ValueParameterDescriptor>(argumentNames.size());
103 for (int i = 0; i < argumentNames.size(); i++) {
104 JetType argumentType = isArgumentNullable.get(i) ? nullableType : type;
105 ValueParameterDescriptorImpl valueParameter = new ValueParameterDescriptorImpl(
106 function, null, i, Annotations.EMPTY, Name.identifier(argumentNames.get(i)),
107 argumentType, false, null, SourceElement.NO_SOURCE
108 );
109 valueParameters.add(valueParameter);
110 }
111 function.initialize(
112 null,
113 ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER,
114 Lists.newArrayList(typeParameter),
115 valueParameters,
116 type,
117 Modality.FINAL,
118 Visibilities.PUBLIC
119 );
120 return function;
121 }
122
123 /*package*/ static MutableDataFlowInfoForArguments createIndependentDataFlowInfoForArgumentsForCall(
124 final Map<ValueArgument, DataFlowInfo> dataFlowInfoForArgumentsMap
125 ) {
126 return new MutableDataFlowInfoForArguments() {
127 private DataFlowInfo initialDataFlowInfo;
128
129 @Override
130 public void setInitialDataFlowInfo(@NotNull DataFlowInfo dataFlowInfo) {
131 this.initialDataFlowInfo = dataFlowInfo;
132 }
133
134 @Override
135 public void updateInfo(@NotNull ValueArgument valueArgument, @NotNull DataFlowInfo dataFlowInfo) {
136 //todo
137 }
138
139 @NotNull
140 @Override
141 public DataFlowInfo getInfo(@NotNull ValueArgument valueArgument) {
142 return dataFlowInfoForArgumentsMap.get(valueArgument);
143 }
144
145 @NotNull
146 @Override
147 public DataFlowInfo getResultInfo() {
148 //todo merge and use
149 return initialDataFlowInfo;
150 }
151 };
152 }
153
154 public static MutableDataFlowInfoForArguments createDataFlowInfoForArgumentsForIfCall(
155 @NotNull Call callForIf,
156 @NotNull DataFlowInfo thenInfo,
157 @NotNull DataFlowInfo elseInfo
158 ) {
159 Map<ValueArgument, DataFlowInfo> dataFlowInfoForArgumentsMap = Maps.newHashMap();
160 dataFlowInfoForArgumentsMap.put(callForIf.getValueArguments().get(0), thenInfo);
161 dataFlowInfoForArgumentsMap.put(callForIf.getValueArguments().get(1), elseInfo);
162 return createIndependentDataFlowInfoForArgumentsForCall(dataFlowInfoForArgumentsMap);
163 }
164
165 /*package*/ static Call createCallForSpecialConstruction(
166 @NotNull final JetExpression expression,
167 @NotNull final JetExpression calleeExpression,
168 @NotNull List<? extends JetExpression> arguments
169 ) {
170 final List<ValueArgument> valueArguments = Lists.newArrayList();
171 for (JetExpression argument : arguments) {
172 valueArguments.add(CallMaker.makeValueArgument(argument));
173 }
174 return new Call() {
175 @Nullable
176 @Override
177 public ASTNode getCallOperationNode() {
178 return expression.getNode();
179 }
180
181 @NotNull
182 @Override
183 public ReceiverValue getExplicitReceiver() {
184 return ReceiverValue.NO_RECEIVER;
185 }
186
187 @NotNull
188 @Override
189 public ReceiverValue getThisObject() {
190 return ReceiverValue.NO_RECEIVER;
191 }
192
193 @Nullable
194 @Override
195 public JetExpression getCalleeExpression() {
196 return calleeExpression;
197 }
198
199 @Nullable
200 @Override
201 public JetValueArgumentList getValueArgumentList() {
202 return null;
203 }
204
205 @NotNull
206 @Override
207 public List<? extends ValueArgument> getValueArguments() {
208 return valueArguments;
209 }
210
211 @NotNull
212 @Override
213 public List<JetFunctionLiteralArgument> getFunctionLiteralArguments() {
214 return Collections.emptyList();
215 }
216
217 @NotNull
218 @Override
219 public List<JetTypeProjection> getTypeArguments() {
220 return Collections.emptyList();
221 }
222
223 @Nullable
224 @Override
225 public JetTypeArgumentList getTypeArgumentList() {
226 return null;
227 }
228
229 @NotNull
230 @Override
231 public JetElement getCallElement() {
232 return expression;
233 }
234
235 @NotNull
236 @Override
237 public CallType getCallType() {
238 return CallType.DEFAULT;
239 }
240 };
241 }
242
243 @NotNull
244 /*package*/ static TracingStrategy createTracingForSpecialConstruction(
245 final @NotNull Call call,
246 final @NotNull String constructionName
247 ) {
248 class CheckTypeContext {
249 public BindingTrace trace;
250 public JetType expectedType;
251
252 CheckTypeContext(@NotNull BindingTrace trace, @NotNull JetType expectedType) {
253 this.trace = trace;
254 this.expectedType = expectedType;
255 }
256
257 CheckTypeContext makeTypeNullable() {
258 if (TypeUtils.noExpectedType(expectedType)) return this;
259 return new CheckTypeContext(trace, TypeUtils.makeNullable(expectedType));
260 }
261 }
262
263 final JetVisitor<Void, CheckTypeContext> checkTypeVisitor = new JetVisitor<Void, CheckTypeContext>() {
264 private void checkExpressionType(@Nullable JetExpression expression, CheckTypeContext c) {
265 if (expression == null) return;
266 expression.accept(this, c);
267 }
268
269 @Override
270 public Void visitIfExpression(@NotNull JetIfExpression ifExpression, CheckTypeContext c) {
271 JetExpression thenBranch = ifExpression.getThen();
272 JetExpression elseBranch = ifExpression.getElse();
273 if (thenBranch == null || elseBranch == null) {
274 visitExpression(ifExpression, c);
275 return null;
276 }
277 checkExpressionType(thenBranch, c);
278 checkExpressionType(elseBranch, c);
279 return null;
280 }
281
282 @Override
283 public Void visitBlockExpression(@NotNull JetBlockExpression expression, CheckTypeContext c) {
284 if (expression.getStatements().isEmpty()) {
285 visitExpression(expression, c);
286 return null;
287 }
288 JetElement lastStatement = JetPsiUtil.getLastStatementInABlock(expression);
289 if (lastStatement instanceof JetExpression) {
290 checkExpressionType((JetExpression) lastStatement, c);
291 }
292 return null;
293 }
294
295 @Override
296 public Void visitPostfixExpression(@NotNull JetPostfixExpression expression, CheckTypeContext c) {
297 if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.EXCLEXCL) {
298 checkExpressionType(expression.getBaseExpression(), c.makeTypeNullable());
299 return null;
300 }
301 return super.visitPostfixExpression(expression, c);
302 }
303
304 @Override
305 public Void visitBinaryExpression(@NotNull JetBinaryExpression expression, CheckTypeContext c) {
306 if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.ELVIS) {
307 checkExpressionType(expression.getLeft(), c.makeTypeNullable());
308 checkExpressionType(expression.getRight(), c);
309 return null;
310 }
311 return super.visitBinaryExpression(expression, c);
312 }
313
314 @Override
315 public Void visitExpression(@NotNull JetExpression expression, CheckTypeContext c) {
316 JetTypeInfo typeInfo = BindingContextUtils.getRecordedTypeInfo(expression, c.trace.getBindingContext());
317 if (typeInfo != null) {
318 DataFlowUtils.checkType(typeInfo.getType(), expression, c.expectedType, typeInfo.getDataFlowInfo(), c.trace);
319 }
320 return null;
321 }
322 };
323
324 return new ThrowingOnErrorTracingStrategy("resolve " + constructionName + " as a call") {
325 @Override
326 public <D extends CallableDescriptor> void bindReference(
327 @NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall
328 ) {
329 //do nothing
330 }
331
332 @Override
333 public void bindCall(@NotNull BindingTrace trace, @NotNull Call call) {
334 trace.record(CALL, call.getCalleeExpression(), call);
335 }
336
337 @Override
338 public <D extends CallableDescriptor> void bindResolvedCall(
339 @NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall
340 ) {
341 trace.record(RESOLVED_CALL, call, resolvedCall);
342 }
343
344 @Override
345 public void typeInferenceFailed(
346 @NotNull BindingTrace trace, @NotNull InferenceErrorData data
347 ) {
348 ConstraintSystem constraintSystem = data.constraintSystem;
349 ConstraintSystemStatus status = constraintSystem.getStatus();
350 assert !status.isSuccessful() : "Report error only for not successful constraint system";
351
352 if (status.hasErrorInConstrainingTypes() || status.hasUnknownParameters()) {
353 return;
354 }
355 JetExpression expression = (JetExpression) call.getCallElement();
356 if (status.hasOnlyErrorsFromPosition(ConstraintPosition.EXPECTED_TYPE_POSITION) || status.hasConflictingConstraints()) {
357 expression.accept(checkTypeVisitor, new CheckTypeContext(trace, data.expectedType));
358 return;
359 }
360 JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, JetNamedDeclaration.class);
361 logError("Expression: " + (parentDeclaration != null ? parentDeclaration.getText() : expression.getText()) +
362 "\nConstraint system status: \n" + ConstraintsUtil.getDebugMessageForStatus(status));
363 }
364 };
365 }
366
367 private abstract static class ThrowingOnErrorTracingStrategy implements TracingStrategy {
368 private final String debugName;
369
370 protected ThrowingOnErrorTracingStrategy(String debugName) {
371 this.debugName = debugName;
372 }
373
374 private void logError() {
375 logError(null);
376 }
377
378 protected void logError(@Nullable String additionalInformation) {
379 String errorMessage = "Resolution error of this type shouldn't occur for " + debugName;
380 if (additionalInformation != null) {
381 errorMessage += ".\n" + additionalInformation;
382 }
383 LOG.error(errorMessage);
384 }
385
386 @Override
387 public void unresolvedReference(@NotNull BindingTrace trace) {
388 logError();
389 }
390
391 @Override
392 public <D extends CallableDescriptor> void unresolvedReferenceWrongReceiver(
393 @NotNull BindingTrace trace, @NotNull Collection<? extends ResolvedCall<D>> candidates
394 ) {
395 logError();
396 }
397
398 @Override
399 public <D extends CallableDescriptor> void recordAmbiguity(
400 @NotNull BindingTrace trace, @NotNull Collection<? extends ResolvedCall<D>> candidates
401 ) {
402 logError();
403 }
404
405 @Override
406 public void missingReceiver(
407 @NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor expectedReceiver
408 ) {
409 logError();
410 }
411
412 @Override
413 public void wrongReceiverType(
414 @NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor receiverParameter, @NotNull ReceiverValue receiverArgument
415 ) {
416 logError();
417 }
418
419 @Override
420 public void noReceiverAllowed(@NotNull BindingTrace trace) {
421 logError();
422 }
423
424 @Override
425 public void noValueForParameter(
426 @NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter
427 ) {
428 logError();
429 }
430
431 @Override
432 public void wrongNumberOfTypeArguments(@NotNull BindingTrace trace, int expectedTypeArgumentCount) {
433 logError();
434 }
435
436 @Override
437 public <D extends CallableDescriptor> void ambiguity(
438 @NotNull BindingTrace trace, @NotNull Collection<? extends ResolvedCall<D>> descriptors
439 ) {
440 logError();
441 }
442
443 @Override
444 public <D extends CallableDescriptor> void noneApplicable(
445 @NotNull BindingTrace trace, @NotNull Collection<? extends ResolvedCall<D>> descriptors
446 ) {
447 logError();
448 }
449
450 @Override
451 public <D extends CallableDescriptor> void cannotCompleteResolve(
452 @NotNull BindingTrace trace, @NotNull Collection<? extends ResolvedCall<D>> descriptors
453 ) {
454 logError();
455 }
456
457 @Override
458 public void instantiationOfAbstractClass(@NotNull BindingTrace trace) {
459 logError();
460 }
461
462 @Override
463 public void nestedClassAccessViaInstanceReference(
464 @NotNull BindingTrace trace, @NotNull ClassDescriptor classDescriptor,
465 @NotNull ExplicitReceiverKind explicitReceiverKind
466 ) {
467 logError();
468 }
469
470 @Override
471 public void unsafeCall(
472 @NotNull BindingTrace trace, @NotNull JetType type, boolean isCallForImplicitInvoke
473 ) {
474 logError();
475 }
476
477 @Override
478 public void unnecessarySafeCall(
479 @NotNull BindingTrace trace, @NotNull JetType type
480 ) {
481 logError();
482 }
483
484 @Override
485 public void danglingFunctionLiteralArgumentSuspected(
486 @NotNull BindingTrace trace, @NotNull List<JetFunctionLiteralArgument> functionLiteralArguments
487 ) {
488 logError();
489 }
490
491 @Override
492 public void invisibleMember(
493 @NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor
494 ) {
495 logError();
496 }
497
498 @Override
499 public void typeInferenceFailed(
500 @NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData
501 ) {
502 logError();
503 }
504 }
505 }