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