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