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.JetScope;
043 import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
044 import org.jetbrains.jet.lang.types.*;
045 import org.jetbrains.jet.lexer.JetTokens;
046
047 import java.util.Collection;
048 import java.util.Collections;
049 import java.util.List;
050 import java.util.Map;
051
052 import static org.jetbrains.jet.lang.resolve.BindingContext.CALL;
053 import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL;
054
055 public class ControlStructureTypingUtils {
056
057 private final ExpressionTypingServices expressionTypingServices;
058
059 public ControlStructureTypingUtils(@NotNull ExpressionTypingServices expressionTypingServices) {
060 this.expressionTypingServices = expressionTypingServices;
061 }
062
063 /*package*/ ResolvedCall<FunctionDescriptor> resolveSpecialConstructionAsCall(
064 @NotNull Call call,
065 @NotNull String constructionName,
066 @NotNull List<String> argumentNames,
067 @NotNull List<Boolean> isArgumentNullable,
068 @NotNull ExpressionTypingContext context,
069 @Nullable MutableDataFlowInfoForArguments dataFlowInfoForArguments
070 ) {
071 SimpleFunctionDescriptorImpl function = createFunctionDescriptorForSpecialConstruction(
072 constructionName.toUpperCase(), argumentNames, isArgumentNullable);
073 TracingStrategy tracing = createTracingForSpecialConstruction(call, constructionName);
074 ResolutionCandidate<CallableDescriptor> resolutionCandidate = ResolutionCandidate.<CallableDescriptor>create(call, function, null);
075 CallResolver callResolver = expressionTypingServices.getCallResolver();
076 OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallWithKnownCandidate(
077 call, tracing, context, resolutionCandidate, dataFlowInfoForArguments);
078 assert results.isSingleResult() : "Not single result after resolving one known candidate";
079 return results.getResultingCall();
080 }
081
082 private static SimpleFunctionDescriptorImpl createFunctionDescriptorForSpecialConstruction(
083 @NotNull String constructionName,
084 @NotNull List<String> argumentNames,
085 @NotNull List<Boolean> isArgumentNullable
086 ) {
087 assert argumentNames.size() == isArgumentNullable.size();
088
089 Name specialFunctionName = Name.identifierNoValidate("<SPECIAL-FUNCTION-FOR-" + constructionName + "-RESOLVE>");
090
091 SimpleFunctionDescriptorImpl function = SimpleFunctionDescriptorImpl.create(
092 ErrorUtils.getErrorModule(),//todo hack to avoid returning true in 'isError(DeclarationDescriptor)'
093 Annotations.EMPTY, specialFunctionName, CallableMemberDescriptor.Kind.DECLARATION);
094
095 TypeParameterDescriptor typeParameter = TypeParameterDescriptorImpl.createWithDefaultBound(
096 function, Annotations.EMPTY, false, Variance.INVARIANT,
097 Name.identifierNoValidate("<TYPE-PARAMETER-FOR-" + constructionName + "-RESOLVE>"), 0);
098
099 JetType type = new JetTypeImpl(typeParameter.getTypeConstructor(), JetScope.EMPTY);
100 JetType nullableType = new JetTypeImpl(
101 Annotations.EMPTY, typeParameter.getTypeConstructor(), true, Collections.<TypeProjection>emptyList(), JetScope.EMPTY);
102
103 List<ValueParameterDescriptor> valueParameters = Lists.newArrayList();
104 for (int i = 0; i < argumentNames.size(); i++) {
105 JetType argumentType = isArgumentNullable.get(i) ? nullableType : type;
106 ValueParameterDescriptorImpl valueParameter = new ValueParameterDescriptorImpl(
107 function, null, i, Annotations.EMPTY, Name.identifier(argumentNames.get(i)), argumentType, false, null);
108 valueParameters.add(valueParameter);
109 }
110 function.initialize(
111 null,
112 ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER,
113 Lists.newArrayList(typeParameter),
114 valueParameters,
115 type,
116 Modality.FINAL,
117 Visibilities.PUBLIC
118 );
119 return function;
120 }
121
122 /*package*/ static MutableDataFlowInfoForArguments createIndependentDataFlowInfoForArgumentsForCall(
123 final Map<ValueArgument, DataFlowInfo> dataFlowInfoForArgumentsMap
124 ) {
125 return new MutableDataFlowInfoForArguments() {
126 private DataFlowInfo initialDataFlowInfo;
127
128 @Override
129 public void setInitialDataFlowInfo(@NotNull DataFlowInfo dataFlowInfo) {
130 this.initialDataFlowInfo = dataFlowInfo;
131 }
132
133 @Override
134 public void updateInfo(@NotNull ValueArgument valueArgument, @NotNull DataFlowInfo dataFlowInfo) {
135 //todo
136 }
137
138 @NotNull
139 @Override
140 public DataFlowInfo getInfo(@NotNull ValueArgument valueArgument) {
141 return dataFlowInfoForArgumentsMap.get(valueArgument);
142 }
143
144 @NotNull
145 @Override
146 public DataFlowInfo getResultInfo() {
147 //todo merge and use
148 return initialDataFlowInfo;
149 }
150 };
151 }
152
153 public static MutableDataFlowInfoForArguments createDataFlowInfoForArgumentsForIfCall(
154 @NotNull Call callForIf,
155 @NotNull DataFlowInfo thenInfo,
156 @NotNull DataFlowInfo elseInfo
157 ) {
158 Map<ValueArgument, DataFlowInfo> dataFlowInfoForArgumentsMap = Maps.newHashMap();
159 dataFlowInfoForArgumentsMap.put(callForIf.getValueArguments().get(0), thenInfo);
160 dataFlowInfoForArgumentsMap.put(callForIf.getValueArguments().get(1), elseInfo);
161 return createIndependentDataFlowInfoForArgumentsForCall(dataFlowInfoForArgumentsMap);
162 }
163
164 /*package*/ static Call createCallForSpecialConstruction(
165 @NotNull final JetExpression expression,
166 @NotNull List<? extends JetExpression> arguments
167 ) {
168 final List<ValueArgument> valueArguments = Lists.newArrayList();
169 for (JetExpression argument : arguments) {
170 valueArguments.add(CallMaker.makeValueArgument(argument, argument));
171 }
172 return new Call() {
173 @Nullable
174 @Override
175 public ASTNode getCallOperationNode() {
176 return expression.getNode();
177 }
178
179 @NotNull
180 @Override
181 public ReceiverValue getExplicitReceiver() {
182 return ReceiverValue.NO_RECEIVER;
183 }
184
185 @NotNull
186 @Override
187 public ReceiverValue getThisObject() {
188 return ReceiverValue.NO_RECEIVER;
189 }
190
191 @Nullable
192 @Override
193 public JetExpression getCalleeExpression() {
194 return expression;
195 }
196
197 @Nullable
198 @Override
199 public JetValueArgumentList getValueArgumentList() {
200 return null;
201 }
202
203 @NotNull
204 @Override
205 public List<? extends ValueArgument> getValueArguments() {
206 return valueArguments;
207 }
208
209 @NotNull
210 @Override
211 public List<JetExpression> getFunctionLiteralArguments() {
212 return Collections.emptyList();
213 }
214
215 @NotNull
216 @Override
217 public List<JetTypeProjection> getTypeArguments() {
218 return Collections.emptyList();
219 }
220
221 @Nullable
222 @Override
223 public JetTypeArgumentList getTypeArgumentList() {
224 return null;
225 }
226
227 @NotNull
228 @Override
229 public JetElement getCallElement() {
230 return expression;
231 }
232
233 @NotNull
234 @Override
235 public CallType getCallType() {
236 return CallType.DEFAULT;
237 }
238 };
239 }
240
241 @NotNull
242 /*package*/ static TracingStrategy createTracingForSpecialConstruction(
243 final @NotNull Call call,
244 final @NotNull String constructionName
245 ) {
246 class CheckTypeContext {
247 public BindingTrace trace;
248 public JetType expectedType;
249
250 CheckTypeContext(@NotNull BindingTrace trace, @NotNull JetType expectedType) {
251 this.trace = trace;
252 this.expectedType = expectedType;
253 }
254
255 CheckTypeContext makeTypeNullable() {
256 if (TypeUtils.noExpectedType(expectedType)) return this;
257 return new CheckTypeContext(trace, TypeUtils.makeNullable(expectedType));
258 }
259 }
260
261 final JetVisitor<Void, CheckTypeContext> checkTypeVisitor = new JetVisitor<Void, CheckTypeContext>() {
262 private void checkExpressionType(@Nullable JetExpression expression, CheckTypeContext c) {
263 if (expression == null) return;
264 expression.accept(this, c);
265 }
266
267 @Override
268 public Void visitIfExpression(@NotNull JetIfExpression ifExpression, CheckTypeContext c) {
269 JetExpression thenBranch = ifExpression.getThen();
270 JetExpression elseBranch = ifExpression.getElse();
271 if (thenBranch == null || elseBranch == null) {
272 visitExpression(ifExpression, c);
273 return null;
274 }
275 checkExpressionType(thenBranch, c);
276 checkExpressionType(elseBranch, c);
277 return null;
278 }
279
280 @Override
281 public Void visitBlockExpression(@NotNull JetBlockExpression expression, CheckTypeContext c) {
282 if (expression.getStatements().isEmpty()) {
283 visitExpression(expression, c);
284 return null;
285 }
286 JetElement lastStatement = JetPsiUtil.getLastStatementInABlock(expression);
287 if (lastStatement instanceof JetExpression) {
288 checkExpressionType((JetExpression) lastStatement, c);
289 }
290 return null;
291 }
292
293 @Override
294 public Void visitPostfixExpression(@NotNull JetPostfixExpression expression, CheckTypeContext c) {
295 if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.EXCLEXCL) {
296 checkExpressionType(expression.getBaseExpression(), c.makeTypeNullable());
297 return null;
298 }
299 return super.visitPostfixExpression(expression, c);
300 }
301
302 @Override
303 public Void visitBinaryExpression(@NotNull JetBinaryExpression expression, CheckTypeContext c) {
304 if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.ELVIS) {
305 checkExpressionType(expression.getLeft(), c.makeTypeNullable());
306 checkExpressionType(expression.getRight(), c);
307 return null;
308 }
309 return super.visitBinaryExpression(expression, c);
310 }
311
312 @Override
313 public Void visitExpression(@NotNull JetExpression expression, CheckTypeContext c) {
314 JetTypeInfo typeInfo = BindingContextUtils.getRecordedTypeInfo(expression, c.trace.getBindingContext());
315 if (typeInfo != null) {
316 DataFlowUtils.checkType(typeInfo.getType(), expression, c.expectedType, typeInfo.getDataFlowInfo(), c.trace);
317 }
318 return null;
319 }
320 };
321
322 return new ThrowingOnErrorTracingStrategy("resolve " + constructionName + " as a call") {
323 @Override
324 public <D extends CallableDescriptor> void bindReference(
325 @NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall
326 ) {
327 //do nothing
328 }
329
330 @Override
331 public <D extends CallableDescriptor> void bindResolvedCall(
332 @NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall
333 ) {
334 trace.record(RESOLVED_CALL, call.getCalleeExpression(), resolvedCall);
335 trace.record(CALL, call.getCalleeExpression(), call);
336
337 }
338
339 @Override
340 public void typeInferenceFailed(
341 @NotNull BindingTrace trace, @NotNull InferenceErrorData data
342 ) {
343 ConstraintSystem constraintSystem = data.constraintSystem;
344 ConstraintSystemStatus status = constraintSystem.getStatus();
345 assert !status.isSuccessful() : "Report error only for not successful constraint system";
346
347 if (status.hasErrorInConstrainingTypes()) {
348 return;
349 }
350 JetExpression expression = call.getCalleeExpression();
351 if (expression == null) return;
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<JetExpression> 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 }