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