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