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.Annotations;
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.*;
036 import org.jetbrains.jet.lang.resolve.calls.model.MutableDataFlowInfoForArguments;
037 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
038 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
039 import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
040 import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate;
041 import org.jetbrains.jet.lang.resolve.calls.tasks.TracingStrategy;
042 import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
043 import org.jetbrains.jet.lang.resolve.name.Name;
044 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
045 import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
046 import org.jetbrains.jet.lang.types.*;
047 import org.jetbrains.jet.lexer.JetTokens;
048
049 import java.util.Collection;
050 import java.util.Collections;
051 import java.util.List;
052 import java.util.Map;
053
054 import static org.jetbrains.jet.lang.resolve.BindingContext.CALL;
055 import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL;
056
057 public class ControlStructureTypingUtils {
058
059 private final ExpressionTypingServices expressionTypingServices;
060
061 public ControlStructureTypingUtils(@NotNull ExpressionTypingServices expressionTypingServices) {
062 this.expressionTypingServices = expressionTypingServices;
063 }
064
065 /*package*/ ResolvedCall<FunctionDescriptor> resolveSpecialConstructionAsCall(
066 @NotNull Call call,
067 @NotNull String constructionName,
068 @NotNull List<String> argumentNames,
069 @NotNull List<Boolean> isArgumentNullable,
070 @NotNull ExpressionTypingContext context,
071 @Nullable MutableDataFlowInfoForArguments dataFlowInfoForArguments
072 ) {
073 SimpleFunctionDescriptorImpl function = createFunctionDescriptorForSpecialConstruction(
074 constructionName.toUpperCase(), argumentNames, isArgumentNullable);
075 TracingStrategy tracing = createTracingForSpecialConstruction(call, constructionName);
076 ResolutionCandidate<CallableDescriptor> resolutionCandidate = ResolutionCandidate.<CallableDescriptor>create(call, function, null);
077 CallResolver callResolver = expressionTypingServices.getCallResolver();
078 OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallWithKnownCandidate(
079 call, tracing, context, resolutionCandidate, dataFlowInfoForArguments);
080 assert results.isSingleResult() : "Not single result after resolving one known candidate";
081 return results.getResultingCall();
082 }
083
084 private static SimpleFunctionDescriptorImpl createFunctionDescriptorForSpecialConstruction(
085 @NotNull String constructionName,
086 @NotNull List<String> argumentNames,
087 @NotNull List<Boolean> isArgumentNullable
088 ) {
089 assert argumentNames.size() == isArgumentNullable.size();
090
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 Annotations.EMPTY, specialFunctionName, CallableMemberDescriptor.Kind.DECLARATION);
096
097 TypeParameterDescriptor typeParameter = TypeParameterDescriptorImpl.createWithDefaultBound(
098 function, Annotations.EMPTY, 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 Annotations.EMPTY, 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, Annotations.EMPTY, 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 );
121 return function;
122 }
123
124 /*package*/ static MutableDataFlowInfoForArguments createIndependentDataFlowInfoForArgumentsForCall(
125 final Map<ValueArgument, DataFlowInfo> dataFlowInfoForArgumentsMap
126 ) {
127 return new MutableDataFlowInfoForArguments() {
128 private DataFlowInfo initialDataFlowInfo;
129
130 @Override
131 public void setInitialDataFlowInfo(@NotNull DataFlowInfo dataFlowInfo) {
132 this.initialDataFlowInfo = dataFlowInfo;
133 }
134
135 @Override
136 public void updateInfo(@NotNull ValueArgument valueArgument, @NotNull DataFlowInfo dataFlowInfo) {
137 //todo
138 }
139
140 @NotNull
141 @Override
142 public DataFlowInfo getInfo(@NotNull ValueArgument valueArgument) {
143 return dataFlowInfoForArgumentsMap.get(valueArgument);
144 }
145
146 @NotNull
147 @Override
148 public DataFlowInfo getResultInfo() {
149 //todo merge and use
150 return initialDataFlowInfo;
151 }
152 };
153 }
154
155 public static MutableDataFlowInfoForArguments createDataFlowInfoForArgumentsForIfCall(
156 @NotNull Call callForIf,
157 @NotNull DataFlowInfo thenInfo,
158 @NotNull DataFlowInfo elseInfo
159 ) {
160 Map<ValueArgument, DataFlowInfo> dataFlowInfoForArgumentsMap = Maps.newHashMap();
161 dataFlowInfoForArgumentsMap.put(callForIf.getValueArguments().get(0), thenInfo);
162 dataFlowInfoForArgumentsMap.put(callForIf.getValueArguments().get(1), elseInfo);
163 return createIndependentDataFlowInfoForArgumentsForCall(dataFlowInfoForArgumentsMap);
164 }
165
166 /*package*/ static Call createCallForSpecialConstruction(
167 @NotNull final JetExpression expression,
168 @NotNull List<? extends JetExpression> arguments
169 ) {
170 final List<ValueArgument> valueArguments = Lists.newArrayList();
171 for (JetExpression argument : arguments) {
172 valueArguments.add(CallMaker.makeValueArgument(argument, argument));
173 }
174 return new Call() {
175 @Nullable
176 @Override
177 public ASTNode getCallOperationNode() {
178 return expression.getNode();
179 }
180
181 @NotNull
182 @Override
183 public ReceiverValue getExplicitReceiver() {
184 return ReceiverValue.NO_RECEIVER;
185 }
186
187 @NotNull
188 @Override
189 public ReceiverValue getThisObject() {
190 return ReceiverValue.NO_RECEIVER;
191 }
192
193 @Nullable
194 @Override
195 public JetExpression getCalleeExpression() {
196 return expression;
197 }
198
199 @Nullable
200 @Override
201 public JetValueArgumentList getValueArgumentList() {
202 return null;
203 }
204
205 @NotNull
206 @Override
207 public List<? extends ValueArgument> getValueArguments() {
208 return valueArguments;
209 }
210
211 @NotNull
212 @Override
213 public List<JetExpression> getFunctionLiteralArguments() {
214 return Collections.emptyList();
215 }
216
217 @NotNull
218 @Override
219 public List<JetTypeProjection> getTypeArguments() {
220 return Collections.emptyList();
221 }
222
223 @Nullable
224 @Override
225 public JetTypeArgumentList getTypeArgumentList() {
226 return null;
227 }
228
229 @NotNull
230 @Override
231 public PsiElement getCallElement() {
232 return expression;
233 }
234
235 @NotNull
236 @Override
237 public CallType getCallType() {
238 return CallType.DEFAULT;
239 }
240 };
241 }
242
243 @NotNull
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(@NotNull JetIfExpression ifExpression, CheckTypeContext c) {
271 JetExpression thenBranch = ifExpression.getThen();
272 JetExpression elseBranch = ifExpression.getElse();
273 if (thenBranch == null || elseBranch == null) {
274 visitExpression(ifExpression, c);
275 return null;
276 }
277 checkExpressionType(thenBranch, c);
278 checkExpressionType(elseBranch, c);
279 return null;
280 }
281
282 @Override
283 public Void visitBlockExpression(@NotNull JetBlockExpression expression, CheckTypeContext c) {
284 if (expression.getStatements().isEmpty()) {
285 visitExpression(expression, c);
286 return null;
287 }
288 JetElement lastStatement = JetPsiUtil.getLastStatementInABlock(expression);
289 if (lastStatement instanceof JetExpression) {
290 checkExpressionType((JetExpression) lastStatement, c);
291 }
292 return null;
293 }
294
295 @Override
296 public Void visitPostfixExpression(@NotNull JetPostfixExpression expression, CheckTypeContext c) {
297 if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.EXCLEXCL) {
298 checkExpressionType(expression.getBaseExpression(), c.makeTypeNullable());
299 return null;
300 }
301 return super.visitPostfixExpression(expression, c);
302 }
303
304 @Override
305 public Void visitBinaryExpression(@NotNull JetBinaryExpression expression, CheckTypeContext c) {
306 if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.ELVIS) {
307 checkExpressionType(expression.getLeft(), c.makeTypeNullable());
308 checkExpressionType(expression.getRight(), c);
309 return null;
310 }
311 return super.visitBinaryExpression(expression, c);
312 }
313
314 @Override
315 public Void visitExpression(@NotNull JetExpression expression, CheckTypeContext c) {
316 JetTypeInfo typeInfo = BindingContextUtils.getRecordedTypeInfo(expression, c.trace.getBindingContext());
317 if (typeInfo != null) {
318 DataFlowUtils.checkType(typeInfo.getType(), expression, c.expectedType, typeInfo.getDataFlowInfo(), c.trace);
319 }
320 return null;
321 }
322 };
323
324 return new ThrowingOnErrorTracingStrategy("resolve " + constructionName + " as a call") {
325 @Override
326 public <D extends CallableDescriptor> void bindReference(
327 @NotNull BindingTrace trace, @NotNull ResolvedCallWithTrace<D> resolvedCall
328 ) {
329 //do nothing
330 }
331
332 @Override
333 public <D extends CallableDescriptor> void bindResolvedCall(
334 @NotNull BindingTrace trace, @NotNull ResolvedCallWithTrace<D> resolvedCall
335 ) {
336 trace.record(RESOLVED_CALL, call.getCalleeExpression(), resolvedCall);
337 trace.record(CALL, call.getCalleeExpression(), call);
338
339 }
340
341 @Override
342 public void typeInferenceFailed(
343 @NotNull BindingTrace trace, @NotNull InferenceErrorData data
344 ) {
345 ConstraintSystem constraintSystem = data.constraintSystem;
346 ConstraintSystemStatus status = constraintSystem.getStatus();
347 assert !status.isSuccessful() : "Report error only for not successful constraint system";
348
349 if (status.hasErrorInConstrainingTypes()) {
350 return;
351 }
352 JetExpression expression = call.getCalleeExpression();
353 if (expression == null) return;
354 if (status.hasOnlyErrorsFromPosition(ConstraintPosition.EXPECTED_TYPE_POSITION) || status.hasConflictingConstraints()) {
355 expression.accept(checkTypeVisitor, new CheckTypeContext(trace, data.expectedType));
356 return;
357 }
358 throwError("Expression: " + expression.getText() + ".\nConstraint system status: \n" + ConstraintsUtil.getDebugMessageForStatus(status));
359 super.typeInferenceFailed(trace, data);
360 }
361 };
362 }
363
364 private abstract static class ThrowingOnErrorTracingStrategy implements TracingStrategy {
365 private final String debugName;
366
367 protected ThrowingOnErrorTracingStrategy(String debugName) {
368 this.debugName = debugName;
369 }
370
371 private void throwError() {
372 throwError(null);
373 }
374
375 protected void throwError(@Nullable String additionalInformation) {
376 String errorMessage = "Resolution error of this type shouldn't occur for " + debugName;
377 if (additionalInformation != null) {
378 errorMessage += ".\n" + additionalInformation;
379 }
380 throw new IllegalStateException(errorMessage);
381 }
382
383 @Override
384 public void unresolvedReference(@NotNull BindingTrace trace) {
385 throwError();
386 }
387
388 @Override
389 public <D extends CallableDescriptor> void unresolvedReferenceWrongReceiver(
390 @NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> candidates
391 ) {
392 throwError();
393 }
394
395 @Override
396 public <D extends CallableDescriptor> void recordAmbiguity(
397 @NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> candidates
398 ) {
399 throwError();
400 }
401
402 @Override
403 public void missingReceiver(
404 @NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor expectedReceiver
405 ) {
406 throwError();
407 }
408
409 @Override
410 public void wrongReceiverType(
411 @NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor receiverParameter, @NotNull ReceiverValue receiverArgument
412 ) {
413 throwError();
414 }
415
416 @Override
417 public void noReceiverAllowed(@NotNull BindingTrace trace) {
418 throwError();
419 }
420
421 @Override
422 public void noValueForParameter(
423 @NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter
424 ) {
425 throwError();
426 }
427
428 @Override
429 public void wrongNumberOfTypeArguments(@NotNull BindingTrace trace, int expectedTypeArgumentCount) {
430 throwError();
431 }
432
433 @Override
434 public <D extends CallableDescriptor> void ambiguity(
435 @NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> descriptors
436 ) {
437 throwError();
438 }
439
440 @Override
441 public <D extends CallableDescriptor> void noneApplicable(
442 @NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> descriptors
443 ) {
444 throwError();
445 }
446
447 @Override
448 public <D extends CallableDescriptor> void cannotCompleteResolve(
449 @NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> descriptors
450 ) {
451 throwError();
452 }
453
454 @Override
455 public void instantiationOfAbstractClass(@NotNull BindingTrace trace) {
456 throwError();
457 }
458
459 @Override
460 public void unsafeCall(
461 @NotNull BindingTrace trace, @NotNull JetType type, boolean isCallForImplicitInvoke
462 ) {
463 throwError();
464 }
465
466 @Override
467 public void unnecessarySafeCall(
468 @NotNull BindingTrace trace, @NotNull JetType type
469 ) {
470 throwError();
471 }
472
473 @Override
474 public void danglingFunctionLiteralArgumentSuspected(
475 @NotNull BindingTrace trace, @NotNull List<JetExpression> functionLiteralArguments
476 ) {
477 throwError();
478 }
479
480 @Override
481 public void invisibleMember(
482 @NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor
483 ) {
484 throwError();
485 }
486
487 @Override
488 public void typeInferenceFailed(
489 @NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData
490 ) {
491 throwError();
492 }
493 }
494 }