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.resolve.calls.autocasts;
018
019 import com.google.common.collect.Lists;
020 import com.google.common.collect.Sets;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.jet.lang.psi.JetExpression;
024 import org.jetbrains.jet.lang.resolve.BindingContext;
025 import org.jetbrains.jet.lang.resolve.BindingTrace;
026 import org.jetbrains.jet.lang.resolve.calls.ArgumentTypeResolver;
027 import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext;
028 import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
029 import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
030 import org.jetbrains.jet.lang.resolve.scopes.receivers.ThisReceiver;
031 import org.jetbrains.jet.lang.types.JetType;
032 import org.jetbrains.jet.lang.types.TypeUtils;
033 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
034
035 import java.util.Collections;
036 import java.util.List;
037 import java.util.Set;
038
039 import static org.jetbrains.jet.lang.diagnostics.Errors.AUTOCAST_IMPOSSIBLE;
040 import static org.jetbrains.jet.lang.resolve.BindingContext.AUTOCAST;
041 import static org.jetbrains.jet.lang.resolve.BindingContext.EXPRESSION_TYPE;
042
043 public class AutoCastUtils {
044
045 private AutoCastUtils() {}
046
047 public static List<JetType> getAutoCastVariants(
048 @NotNull ReceiverValue receiverToCast,
049 @NotNull ResolutionContext context
050 ) {
051 return getAutoCastVariants(receiverToCast, context.trace.getBindingContext(), context.dataFlowInfo);
052 }
053
054 public static List<JetType> getAutoCastVariants(
055 @NotNull ReceiverValue receiverToCast,
056 @NotNull BindingContext bindingContext,
057 @NotNull DataFlowInfo dataFlowInfo
058 ) {
059 List<JetType> variants = Lists.newArrayList();
060 variants.add(receiverToCast.getType());
061 variants.addAll(getAutoCastVariantsExcludingReceiver(bindingContext, dataFlowInfo, receiverToCast));
062 return variants;
063 }
064
065 /**
066 * @return variants @param receiverToCast may be cast to according to @param dataFlowInfo, @param receiverToCast itself is NOT included
067 */
068 @NotNull
069 public static List<JetType> getAutoCastVariantsExcludingReceiver(
070 @NotNull BindingContext bindingContext,
071 @NotNull DataFlowInfo dataFlowInfo,
072 @NotNull ReceiverValue receiverToCast
073 ) {
074 if (receiverToCast instanceof ThisReceiver) {
075 ThisReceiver receiver = (ThisReceiver) receiverToCast;
076 assert receiver.exists();
077 DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiver);
078 return collectAutoCastReceiverValues(dataFlowInfo, dataFlowValue);
079 }
080 else if (receiverToCast instanceof ExpressionReceiver) {
081 ExpressionReceiver receiver = (ExpressionReceiver) receiverToCast;
082 DataFlowValue dataFlowValue =
083 DataFlowValueFactory.createDataFlowValue(receiver.getExpression(), receiver.getType(), bindingContext);
084 return collectAutoCastReceiverValues(dataFlowInfo, dataFlowValue);
085 }
086 return Collections.emptyList();
087 }
088
089 @NotNull
090 private static List<JetType> collectAutoCastReceiverValues(
091 @NotNull DataFlowInfo dataFlowInfo,
092 @NotNull DataFlowValue dataFlowValue
093 ) {
094 return Lists.newArrayList(dataFlowInfo.getPossibleTypes(dataFlowValue));
095 }
096
097 public static boolean isSubTypeByAutoCastIgnoringNullability(
098 @NotNull ReceiverValue receiverArgument,
099 @NotNull JetType receiverParameterType,
100 @NotNull ResolutionContext context
101 ) {
102 List<JetType> autoCastTypes = getAutoCastVariants(receiverArgument, context);
103 return getAutoCastSubType(TypeUtils.makeNullable(receiverParameterType), autoCastTypes) != null;
104 }
105
106 @Nullable
107 private static JetType getAutoCastSubType(
108 @NotNull JetType receiverParameterType,
109 @NotNull List<JetType> autoCastTypes
110 ) {
111 Set<JetType> subTypes = Sets.newHashSet();
112 for (JetType autoCastType : autoCastTypes) {
113 if (ArgumentTypeResolver.isSubtypeOfForArgumentType(autoCastType, receiverParameterType)) {
114 subTypes.add(autoCastType);
115 }
116 }
117 if (subTypes.isEmpty()) return null;
118
119 JetType intersection = TypeUtils.intersect(JetTypeChecker.DEFAULT, subTypes);
120 if (intersection == null || !intersection.getConstructor().isDenotable()) {
121 return receiverParameterType;
122 }
123 return intersection;
124 }
125
126 public static boolean recordAutoCastIfNecessary(
127 @NotNull ReceiverValue receiver,
128 @NotNull JetType receiverParameterType,
129 @NotNull ResolutionContext context,
130 boolean safeAccess
131 ) {
132 if (!(receiver instanceof ExpressionReceiver)) return false;
133
134 receiverParameterType = safeAccess ? TypeUtils.makeNullable(receiverParameterType) : receiverParameterType;
135 if (ArgumentTypeResolver.isSubtypeOfForArgumentType(receiver.getType(), receiverParameterType)) {
136 return false;
137 }
138
139 List<JetType> autoCastTypesExcludingReceiver = getAutoCastVariantsExcludingReceiver(
140 context.trace.getBindingContext(), context.dataFlowInfo, receiver);
141 JetType autoCastSubType = getAutoCastSubType(receiverParameterType, autoCastTypesExcludingReceiver);
142 if (autoCastSubType == null) return false;
143
144 JetExpression expression = ((ExpressionReceiver) receiver).getExpression();
145 DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiver, context.trace.getBindingContext());
146
147 recordCastOrError(expression, autoCastSubType, context.trace, dataFlowValue.isStableIdentifier(), true);
148 return true;
149 }
150
151 public static void recordCastOrError(
152 @NotNull JetExpression expression,
153 @NotNull JetType type,
154 @NotNull BindingTrace trace,
155 boolean canBeCasted,
156 boolean recordExpressionType
157 ) {
158 if (canBeCasted) {
159 trace.record(AUTOCAST, expression, type);
160 if (recordExpressionType) {
161 //TODO
162 //Why the expression type is rewritten for receivers and is not rewritten for arguments? Is it necessary?
163 trace.record(EXPRESSION_TYPE, expression, type);
164 }
165 }
166 else {
167 trace.report(AUTOCAST_IMPOSSIBLE.on(expression, type, expression.getText()));
168 }
169 }
170
171 public static boolean isNotNull(
172 @NotNull ReceiverValue receiver,
173 @NotNull BindingContext bindingContext,
174 @NotNull DataFlowInfo dataFlowInfo
175 ) {
176 if (!receiver.getType().isNullable()) return true;
177
178 List<JetType> autoCastVariants = getAutoCastVariants(receiver, bindingContext, dataFlowInfo);
179 for (JetType autoCastVariant : autoCastVariants) {
180 if (!autoCastVariant.isNullable()) return true;
181 }
182 return false;
183 }
184 }