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