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 /*isInline = */ false
124 );
125 return function;
126 }
127
128 /*package*/ static MutableDataFlowInfoForArguments createIndependentDataFlowInfoForArgumentsForCall(
129 final Map<ValueArgument, DataFlowInfo> dataFlowInfoForArgumentsMap
130 ) {
131 return new MutableDataFlowInfoForArguments() {
132 private DataFlowInfo initialDataFlowInfo;
133
134 @Override
135 public void setInitialDataFlowInfo(@NotNull DataFlowInfo dataFlowInfo) {
136 this.initialDataFlowInfo = dataFlowInfo;
137 }
138
139 @Override
140 public void updateInfo(@NotNull ValueArgument valueArgument, @NotNull DataFlowInfo dataFlowInfo) {
141 //todo
142 }
143
144 @NotNull
145 @Override
146 public DataFlowInfo getInfo(@NotNull ValueArgument valueArgument) {
147 return dataFlowInfoForArgumentsMap.get(valueArgument);
148 }
149
150 @NotNull
151 @Override
152 public DataFlowInfo getResultInfo() {
153 //todo merge and use
154 return initialDataFlowInfo;
155 }
156 };
157 }
158
159 public static MutableDataFlowInfoForArguments createDataFlowInfoForArgumentsForIfCall(
160 @NotNull Call callForIf,
161 @NotNull DataFlowInfo thenInfo,
162 @NotNull DataFlowInfo elseInfo
163 ) {
164 Map<ValueArgument, DataFlowInfo> dataFlowInfoForArgumentsMap = Maps.newHashMap();
165 dataFlowInfoForArgumentsMap.put(callForIf.getValueArguments().get(0), thenInfo);
166 dataFlowInfoForArgumentsMap.put(callForIf.getValueArguments().get(1), elseInfo);
167 return createIndependentDataFlowInfoForArgumentsForCall(dataFlowInfoForArgumentsMap);
168 }
169
170 /*package*/ static Call createCallForSpecialConstruction(
171 @NotNull final JetExpression expression,
172 @NotNull List<? extends JetExpression> arguments
173 ) {
174 final List<ValueArgument> valueArguments = Lists.newArrayList();
175 for (JetExpression argument : arguments) {
176 valueArguments.add(CallMaker.makeValueArgument(argument, argument));
177 }
178 return new Call() {
179 @Nullable
180 @Override
181 public ASTNode getCallOperationNode() {
182 return expression.getNode();
183 }
184
185 @NotNull
186 @Override
187 public ReceiverValue getExplicitReceiver() {
188 return ReceiverValue.NO_RECEIVER;
189 }
190
191 @NotNull
192 @Override
193 public ReceiverValue getThisObject() {
194 return ReceiverValue.NO_RECEIVER;
195 }
196
197 @Nullable
198 @Override
199 public JetExpression getCalleeExpression() {
200 return expression;
201 }
202
203 @Nullable
204 @Override
205 public JetValueArgumentList getValueArgumentList() {
206 return null;
207 }
208
209 @NotNull
210 @Override
211 public List<? extends ValueArgument> getValueArguments() {
212 return valueArguments;
213 }
214
215 @NotNull
216 @Override
217 public List<JetExpression> getFunctionLiteralArguments() {
218 return Collections.emptyList();
219 }
220
221 @NotNull
222 @Override
223 public List<JetTypeProjection> getTypeArguments() {
224 return Collections.emptyList();
225 }
226
227 @Nullable
228 @Override
229 public JetTypeArgumentList getTypeArgumentList() {
230 return null;
231 }
232
233 @NotNull
234 @Override
235 public PsiElement getCallElement() {
236 return expression;
237 }
238
239 @NotNull
240 @Override
241 public CallType getCallType() {
242 return CallType.DEFAULT;
243 }
244 };
245 }
246
247 /*package*/ static TracingStrategy createTracingForSpecialConstruction(
248 final @NotNull Call call,
249 final @NotNull String constructionName
250 ) {
251 class CheckTypeContext {
252 public BindingTrace trace;
253 public JetType expectedType;
254
255 CheckTypeContext(@NotNull BindingTrace trace, @NotNull JetType expectedType) {
256 this.trace = trace;
257 this.expectedType = expectedType;
258 }
259
260 CheckTypeContext makeTypeNullable() {
261 if (TypeUtils.noExpectedType(expectedType)) return this;
262 return new CheckTypeContext(trace, TypeUtils.makeNullable(expectedType));
263 }
264 }
265
266 final JetVisitor<Void, CheckTypeContext> checkTypeVisitor = new JetVisitor<Void, CheckTypeContext>() {
267 private void checkExpressionType(@Nullable JetExpression expression, CheckTypeContext c) {
268 if (expression == null) return;
269 expression.accept(this, c);
270 }
271
272 @Override
273 public Void visitIfExpression(@NotNull JetIfExpression ifExpression, CheckTypeContext c) {
274 checkExpressionType(ifExpression.getThen(), c);
275 checkExpressionType(ifExpression.getElse(), c);
276 return null;
277 }
278
279 @Override
280 public Void visitBlockExpression(@NotNull JetBlockExpression expression, CheckTypeContext c) {
281 if (expression.getStatements().isEmpty()) {
282 visitExpression(expression, c);
283 return null;
284 }
285 JetElement lastStatement = JetPsiUtil.getLastStatementInABlock(expression);
286 if (lastStatement instanceof JetExpression) {
287 checkExpressionType((JetExpression) lastStatement, c);
288 }
289 return null;
290 }
291
292 @Override
293 public Void visitPostfixExpression(@NotNull JetPostfixExpression expression, CheckTypeContext c) {
294 if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.EXCLEXCL) {
295 checkExpressionType(expression.getBaseExpression(), c.makeTypeNullable());
296 return null;
297 }
298 return super.visitPostfixExpression(expression, c);
299 }
300
301 @Override
302 public Void visitBinaryExpression(@NotNull JetBinaryExpression expression, CheckTypeContext c) {
303 if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.ELVIS) {
304 checkExpressionType(expression.getLeft(), c.makeTypeNullable());
305 checkExpressionType(expression.getRight(), c);
306 return null;
307 }
308 return super.visitBinaryExpression(expression, c);
309 }
310
311 @Override
312 public Void visitExpression(@NotNull JetExpression expression, CheckTypeContext c) {
313 JetTypeInfo typeInfo = BindingContextUtils.getRecordedTypeInfo(expression, c.trace.getBindingContext());
314 if (typeInfo != null) {
315 DataFlowUtils.checkType(typeInfo.getType(), expression, c.expectedType, typeInfo.getDataFlowInfo(), c.trace);
316 }
317 return null;
318 }
319 };
320
321 return new ThrowingOnErrorTracingStrategy("resolve " + constructionName + " as a call") {
322 @Override
323 public <D extends CallableDescriptor> void bindReference(
324 @NotNull BindingTrace trace, @NotNull ResolvedCallWithTrace<D> resolvedCall
325 ) {
326 //do nothing
327 }
328
329 @Override
330 public <D extends CallableDescriptor> void bindResolvedCall(
331 @NotNull BindingTrace trace, @NotNull ResolvedCallWithTrace<D> resolvedCall
332 ) {
333 trace.record(RESOLVED_CALL, call.getCalleeExpression(), resolvedCall);
334 trace.record(CALL, call.getCalleeExpression(), call);
335
336 }
337
338 @Override
339 public void typeInferenceFailed(
340 @NotNull BindingTrace trace, @NotNull InferenceErrorData data
341 ) {
342 ConstraintSystem constraintSystem = data.constraintSystem;
343 ConstraintSystemStatus status = constraintSystem.getStatus();
344 assert !status.isSuccessful() : "Report error only for not successful constraint system";
345
346 if (status.hasErrorInConstrainingTypes()) {
347 return;
348 }
349 JetExpression expression = call.getCalleeExpression();
350 if (expression == null) return;
351 if (status.hasOnlyErrorsFromPosition(ConstraintPosition.EXPECTED_TYPE_POSITION) || status.hasConflictingConstraints()) {
352 expression.accept(checkTypeVisitor, new CheckTypeContext(trace, data.expectedType));
353 return;
354 }
355 throwError("Expression: " + expression.getText() + ".\nConstraint system status: \n" + ConstraintsUtil.getDebugMessageForStatus(status));
356 super.typeInferenceFailed(trace, data);
357 }
358 };
359 }
360
361 private abstract static class ThrowingOnErrorTracingStrategy implements TracingStrategy {
362 private final String debugName;
363
364 protected ThrowingOnErrorTracingStrategy(String debugName) {
365 this.debugName = debugName;
366 }
367
368 private void throwError() {
369 throwError(null);
370 }
371
372 protected void throwError(@Nullable String additionalInformation) {
373 String errorMessage = "Resolution error of this type shouldn't occur for " + debugName;
374 if (additionalInformation != null) {
375 errorMessage += ".\n" + additionalInformation;
376 }
377 throw new IllegalStateException(errorMessage);
378 }
379
380 @Override
381 public void unresolvedReference(@NotNull BindingTrace trace) {
382 throwError();
383 }
384
385 @Override
386 public <D extends CallableDescriptor> void unresolvedReferenceWrongReceiver(
387 @NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> candidates
388 ) {
389 throwError();
390 }
391
392 @Override
393 public <D extends CallableDescriptor> void recordAmbiguity(
394 @NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> candidates
395 ) {
396 throwError();
397 }
398
399 @Override
400 public void missingReceiver(
401 @NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor expectedReceiver
402 ) {
403 throwError();
404 }
405
406 @Override
407 public void wrongReceiverType(
408 @NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor receiverParameter, @NotNull ReceiverValue receiverArgument
409 ) {
410 throwError();
411 }
412
413 @Override
414 public void noReceiverAllowed(@NotNull BindingTrace trace) {
415 throwError();
416 }
417
418 @Override
419 public void noValueForParameter(
420 @NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter
421 ) {
422 throwError();
423 }
424
425 @Override
426 public void wrongNumberOfTypeArguments(@NotNull BindingTrace trace, int expectedTypeArgumentCount) {
427 throwError();
428 }
429
430 @Override
431 public <D extends CallableDescriptor> void ambiguity(
432 @NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> descriptors
433 ) {
434 throwError();
435 }
436
437 @Override
438 public <D extends CallableDescriptor> void noneApplicable(
439 @NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> descriptors
440 ) {
441 throwError();
442 }
443
444 @Override
445 public <D extends CallableDescriptor> void cannotCompleteResolve(
446 @NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> descriptors
447 ) {
448 throwError();
449 }
450
451 @Override
452 public void instantiationOfAbstractClass(@NotNull BindingTrace trace) {
453 throwError();
454 }
455
456 @Override
457 public void unsafeCall(
458 @NotNull BindingTrace trace, @NotNull JetType type, boolean isCallForImplicitInvoke
459 ) {
460 throwError();
461 }
462
463 @Override
464 public void unnecessarySafeCall(
465 @NotNull BindingTrace trace, @NotNull JetType type
466 ) {
467 throwError();
468 }
469
470 @Override
471 public void danglingFunctionLiteralArgumentSuspected(
472 @NotNull BindingTrace trace, @NotNull List<JetExpression> functionLiteralArguments
473 ) {
474 throwError();
475 }
476
477 @Override
478 public void invisibleMember(
479 @NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor
480 ) {
481 throwError();
482 }
483
484 @Override
485 public void typeInferenceFailed(
486 @NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData
487 ) {
488 throwError();
489 }
490 }
491 }