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 final JetExpression calleeExpression,
162 @NotNull List<? extends JetExpression> arguments
163 ) {
164 final List<ValueArgument> valueArguments = Lists.newArrayList();
165 for (JetExpression argument : arguments) {
166 valueArguments.add(CallMaker.makeValueArgument(argument, argument));
167 }
168 return new Call() {
169 @Nullable
170 @Override
171 public ASTNode getCallOperationNode() {
172 return expression.getNode();
173 }
174
175 @NotNull
176 @Override
177 public ReceiverValue getExplicitReceiver() {
178 return ReceiverValue.NO_RECEIVER;
179 }
180
181 @NotNull
182 @Override
183 public ReceiverValue getThisObject() {
184 return ReceiverValue.NO_RECEIVER;
185 }
186
187 @Nullable
188 @Override
189 public JetExpression getCalleeExpression() {
190 return calleeExpression;
191 }
192
193 @Nullable
194 @Override
195 public JetValueArgumentList getValueArgumentList() {
196 return null;
197 }
198
199 @NotNull
200 @Override
201 public List<? extends ValueArgument> getValueArguments() {
202 return valueArguments;
203 }
204
205 @NotNull
206 @Override
207 public List<JetExpression> getFunctionLiteralArguments() {
208 return Collections.emptyList();
209 }
210
211 @NotNull
212 @Override
213 public List<JetTypeProjection> getTypeArguments() {
214 return Collections.emptyList();
215 }
216
217 @Nullable
218 @Override
219 public JetTypeArgumentList getTypeArgumentList() {
220 return null;
221 }
222
223 @NotNull
224 @Override
225 public JetElement getCallElement() {
226 return expression;
227 }
228
229 @NotNull
230 @Override
231 public CallType getCallType() {
232 return CallType.DEFAULT;
233 }
234 };
235 }
236
237 @NotNull
238 /*package*/ static TracingStrategy createTracingForSpecialConstruction(
239 final @NotNull Call call,
240 final @NotNull String constructionName
241 ) {
242 class CheckTypeContext {
243 public BindingTrace trace;
244 public JetType expectedType;
245
246 CheckTypeContext(@NotNull BindingTrace trace, @NotNull JetType expectedType) {
247 this.trace = trace;
248 this.expectedType = expectedType;
249 }
250
251 CheckTypeContext makeTypeNullable() {
252 if (TypeUtils.noExpectedType(expectedType)) return this;
253 return new CheckTypeContext(trace, TypeUtils.makeNullable(expectedType));
254 }
255 }
256
257 final JetVisitor<Void, CheckTypeContext> checkTypeVisitor = new JetVisitor<Void, CheckTypeContext>() {
258 private void checkExpressionType(@Nullable JetExpression expression, CheckTypeContext c) {
259 if (expression == null) return;
260 expression.accept(this, c);
261 }
262
263 @Override
264 public Void visitIfExpression(@NotNull JetIfExpression ifExpression, CheckTypeContext c) {
265 JetExpression thenBranch = ifExpression.getThen();
266 JetExpression elseBranch = ifExpression.getElse();
267 if (thenBranch == null || elseBranch == null) {
268 visitExpression(ifExpression, c);
269 return null;
270 }
271 checkExpressionType(thenBranch, c);
272 checkExpressionType(elseBranch, c);
273 return null;
274 }
275
276 @Override
277 public Void visitBlockExpression(@NotNull JetBlockExpression expression, CheckTypeContext c) {
278 if (expression.getStatements().isEmpty()) {
279 visitExpression(expression, c);
280 return null;
281 }
282 JetElement lastStatement = JetPsiUtil.getLastStatementInABlock(expression);
283 if (lastStatement instanceof JetExpression) {
284 checkExpressionType((JetExpression) lastStatement, c);
285 }
286 return null;
287 }
288
289 @Override
290 public Void visitPostfixExpression(@NotNull JetPostfixExpression expression, CheckTypeContext c) {
291 if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.EXCLEXCL) {
292 checkExpressionType(expression.getBaseExpression(), c.makeTypeNullable());
293 return null;
294 }
295 return super.visitPostfixExpression(expression, c);
296 }
297
298 @Override
299 public Void visitBinaryExpression(@NotNull JetBinaryExpression expression, CheckTypeContext c) {
300 if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.ELVIS) {
301 checkExpressionType(expression.getLeft(), c.makeTypeNullable());
302 checkExpressionType(expression.getRight(), c);
303 return null;
304 }
305 return super.visitBinaryExpression(expression, c);
306 }
307
308 @Override
309 public Void visitExpression(@NotNull JetExpression expression, CheckTypeContext c) {
310 JetTypeInfo typeInfo = BindingContextUtils.getRecordedTypeInfo(expression, c.trace.getBindingContext());
311 if (typeInfo != null) {
312 DataFlowUtils.checkType(typeInfo.getType(), expression, c.expectedType, typeInfo.getDataFlowInfo(), c.trace);
313 }
314 return null;
315 }
316 };
317
318 return new ThrowingOnErrorTracingStrategy("resolve " + constructionName + " as a call") {
319 @Override
320 public <D extends CallableDescriptor> void bindReference(
321 @NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall
322 ) {
323 //do nothing
324 }
325
326 @Override
327 public void bindCall(@NotNull BindingTrace trace, @NotNull Call call) {
328 trace.record(CALL, call.getCalleeExpression(), call);
329 }
330
331 @Override
332 public <D extends CallableDescriptor> void bindResolvedCall(
333 @NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall
334 ) {
335 trace.record(RESOLVED_CALL, call.getCalleeExpression(), resolvedCall);
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 = (JetExpression) call.getCallElement();
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<? extends ResolvedCall<D>> candidates
387 ) {
388 throwError();
389 }
390
391 @Override
392 public <D extends CallableDescriptor> void recordAmbiguity(
393 @NotNull BindingTrace trace, @NotNull Collection<? extends ResolvedCall<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<? extends ResolvedCall<D>> descriptors
432 ) {
433 throwError();
434 }
435
436 @Override
437 public <D extends CallableDescriptor> void noneApplicable(
438 @NotNull BindingTrace trace, @NotNull Collection<? extends ResolvedCall<D>> descriptors
439 ) {
440 throwError();
441 }
442
443 @Override
444 public <D extends CallableDescriptor> void cannotCompleteResolve(
445 @NotNull BindingTrace trace, @NotNull Collection<? extends ResolvedCall<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 }