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.inference;
018
019 import com.google.common.base.Function;
020 import com.google.common.base.Functions;
021 import com.google.common.collect.Lists;
022 import com.google.common.collect.Maps;
023 import com.google.common.collect.Sets;
024 import org.jetbrains.annotations.NotNull;
025 import org.jetbrains.annotations.Nullable;
026 import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
027 import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
028 import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
029 import org.jetbrains.jet.lang.types.*;
030 import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure;
031 import org.jetbrains.jet.lang.types.checker.TypingConstraints;
032 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
033
034 import java.util.List;
035 import java.util.Map;
036 import java.util.Set;
037
038 import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.*;
039 import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.EQUAL;
040 import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.SUB_TYPE;
041 import static org.jetbrains.jet.lang.resolve.calls.inference.TypeConstraintsImpl.BoundKind;
042 import static org.jetbrains.jet.lang.resolve.calls.inference.TypeConstraintsImpl.BoundKind.*;
043
044 public class ConstraintSystemImpl implements ConstraintSystem {
045
046 public enum ConstraintKind {
047 SUB_TYPE, EQUAL
048 }
049
050 private final Map<TypeParameterDescriptor, TypeConstraintsImpl> typeParameterConstraints = Maps.newLinkedHashMap();
051 private final Set<ConstraintPosition> errorConstraintPositions = Sets.newHashSet();
052 private final TypeSubstitutor resultingSubstitutor;
053 private final TypeSubstitutor currentSubstitutor;
054 private boolean hasErrorInConstrainingTypes;
055
056 @Nullable
057 private ConstraintSystem systemWithoutExpectedTypeConstraint;
058
059 public ConstraintSystemImpl() {
060 this.resultingSubstitutor = createTypeSubstitutorWithDefaultForUnknownTypeParameter(new TypeProjection(CANT_INFER_TYPE_PARAMETER));
061 this.currentSubstitutor = createTypeSubstitutorWithDefaultForUnknownTypeParameter(new TypeProjection(DONT_CARE));
062 }
063
064 private TypeSubstitutor createTypeSubstitutorWithDefaultForUnknownTypeParameter(@Nullable final TypeProjection defaultTypeProjection) {
065 return TypeSubstitutor.create(new TypeSubstitution() {
066 @Override
067 public TypeProjection get(TypeConstructor key) {
068 DeclarationDescriptor declarationDescriptor = key.getDeclarationDescriptor();
069 if (declarationDescriptor instanceof TypeParameterDescriptor) {
070 TypeParameterDescriptor descriptor = (TypeParameterDescriptor) declarationDescriptor;
071
072 JetType value = ConstraintsUtil.getValue(getTypeConstraints(descriptor));
073 if (value != null && !TypeUtils.equalsOrContainsAsArgument(value, DONT_CARE)) {
074 return new TypeProjection(value);
075 }
076 if (typeParameterConstraints.containsKey(descriptor)) {
077 return defaultTypeProjection;
078 }
079 }
080 return null;
081 }
082
083 @Override
084 public boolean isEmpty() {
085 return false;
086 }
087
088 @Override
089 public String toString() {
090 return typeParameterConstraints.toString();
091 }
092 });
093 }
094
095 @Override
096 public boolean hasTypeConstructorMismatch() {
097 return !errorConstraintPositions.isEmpty();
098 }
099
100 @Override
101 public boolean hasTypeConstructorMismatchAt(@NotNull ConstraintPosition constraintPosition) {
102 return errorConstraintPositions.contains(constraintPosition);
103 }
104
105 @Override
106 public boolean hasOnlyExpectedTypeMismatch() {
107 if (systemWithoutExpectedTypeConstraint == null) {
108 // the expected type constraint isn't added, there can't be an error with it
109 return false;
110 }
111 if (!isSuccessful() && systemWithoutExpectedTypeConstraint.isSuccessful()) {
112 return true;
113 }
114 if (errorConstraintPositions.size() == 1 && errorConstraintPositions.contains(ConstraintPosition.EXPECTED_TYPE_POSITION)) {
115 // if systemWithoutExpectedTypeConstraint has unknown type parameters, it's not successful,
116 // but there can be expected type mismatch after expected type is added
117 return true;
118 }
119 return false;
120 }
121
122 @Override
123 public boolean hasErrorInConstrainingTypes() {
124 return hasErrorInConstrainingTypes;
125 }
126
127 @Override
128 public void registerTypeVariable(@NotNull TypeParameterDescriptor typeVariable, @NotNull Variance positionVariance) {
129 typeParameterConstraints.put(typeVariable, new TypeConstraintsImpl(positionVariance));
130 }
131
132 @Override
133 @NotNull
134 public ConstraintSystem copy() {
135 return replaceTypeVariables(Functions.<TypeParameterDescriptor>identity(), true);
136 }
137
138 @NotNull
139 public ConstraintSystem replaceTypeVariables(@NotNull Function<TypeParameterDescriptor, TypeParameterDescriptor> typeVariablesMap) {
140 return replaceTypeVariables(typeVariablesMap, false);
141 }
142
143 @NotNull
144 private ConstraintSystem replaceTypeVariables(
145 @NotNull Function<TypeParameterDescriptor, TypeParameterDescriptor> typeVariablesMap,
146 boolean recreateTypeConstraints
147 ) {
148 ConstraintSystemImpl newConstraintSystem = new ConstraintSystemImpl();
149 for (Map.Entry<TypeParameterDescriptor, TypeConstraintsImpl> entry : typeParameterConstraints.entrySet()) {
150 TypeParameterDescriptor typeParameter = entry.getKey();
151 TypeConstraintsImpl typeConstraints = entry.getValue();
152
153 TypeParameterDescriptor newTypeParameter = typeVariablesMap.apply(typeParameter);
154 assert newTypeParameter != null;
155 newConstraintSystem.typeParameterConstraints.put(newTypeParameter, recreateTypeConstraints ? typeConstraints.copy() : typeConstraints);
156 }
157 newConstraintSystem.errorConstraintPositions.addAll(errorConstraintPositions);
158 newConstraintSystem.hasErrorInConstrainingTypes = hasErrorInConstrainingTypes;
159 return newConstraintSystem;
160 }
161
162 @Override
163 public void addSupertypeConstraint(
164 @Nullable JetType constrainingType,
165 @NotNull JetType subjectType,
166 @NotNull ConstraintPosition constraintPosition
167 ) {
168 if (constrainingType == TypeUtils.NO_EXPECTED_TYPE) return;
169
170 if (constraintPosition == ConstraintPosition.EXPECTED_TYPE_POSITION) {
171 systemWithoutExpectedTypeConstraint = copy();
172 }
173 addConstraint(SUB_TYPE, subjectType, constrainingType, constraintPosition);
174 }
175
176 @Override
177 public void addSubtypeConstraint(
178 @Nullable JetType constrainingType,
179 @NotNull JetType subjectType,
180 @NotNull ConstraintPosition constraintPosition
181 ) {
182 addConstraint(SUB_TYPE, constrainingType, subjectType, constraintPosition);
183 }
184
185 private void addConstraint(
186 @NotNull ConstraintKind constraintKind,
187 @Nullable JetType subType,
188 @Nullable JetType superType,
189 @NotNull final ConstraintPosition constraintPosition
190 ) {
191 TypeCheckingProcedure typeCheckingProcedure = new TypeCheckingProcedure(new TypingConstraints() {
192 @Override
193 public boolean assertEqualTypes(
194 @NotNull JetType a, @NotNull JetType b, @NotNull TypeCheckingProcedure typeCheckingProcedure
195 ) {
196 doAddConstraint(EQUAL, a, b, constraintPosition, typeCheckingProcedure);
197 return true;
198
199 }
200
201 @Override
202 public boolean assertEqualTypeConstructors(
203 @NotNull TypeConstructor a, @NotNull TypeConstructor b
204 ) {
205 throw new IllegalStateException("'assertEqualTypeConstructors' shouldn't be invoked inside 'isSubtypeOf'");
206 }
207
208 @Override
209 public boolean assertSubtype(
210 @NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeCheckingProcedure typeCheckingProcedure
211 ) {
212 doAddConstraint(SUB_TYPE, subtype, supertype, constraintPosition, typeCheckingProcedure);
213 return true;
214 }
215
216 @Override
217 public boolean noCorrespondingSupertype(
218 @NotNull JetType subtype, @NotNull JetType supertype
219 ) {
220 errorConstraintPositions.add(constraintPosition);
221 return true;
222 }
223 });
224 doAddConstraint(constraintKind, subType, superType, constraintPosition, typeCheckingProcedure);
225 }
226
227 private boolean isErrorOrSpecialType(@Nullable JetType type) {
228 if (type == DONT_CARE || type == CANT_INFER_TYPE_PARAMETER) {
229 return true;
230 }
231
232 if (type == null || ((ErrorUtils.isErrorType(type) && type != PLACEHOLDER_FUNCTION_TYPE))) {
233 hasErrorInConstrainingTypes = true;
234 return true;
235 }
236 return false;
237 }
238
239 private void doAddConstraint(
240 @NotNull ConstraintKind constraintKind,
241 @Nullable JetType subType,
242 @Nullable JetType superType,
243 @NotNull ConstraintPosition constraintPosition,
244 @NotNull TypeCheckingProcedure typeCheckingProcedure
245 ) {
246
247 if (isErrorOrSpecialType(subType) || isErrorOrSpecialType(superType)) return;
248 assert subType != null && superType != null;
249
250 assert superType != PLACEHOLDER_FUNCTION_TYPE : "The type for " + constraintPosition + " shouldn't be a placeholder for function type";
251
252 KotlinBuiltIns kotlinBuiltIns = KotlinBuiltIns.getInstance();
253 if (subType == PLACEHOLDER_FUNCTION_TYPE) {
254 if (!kotlinBuiltIns.isFunctionOrExtensionFunctionType(superType)) {
255 if (isMyTypeVariable(superType)) {
256 // a constraint binds type parameter and any function type, so there is no new info and no error
257 return;
258 }
259 errorConstraintPositions.add(constraintPosition);
260 }
261 return;
262 }
263
264 // todo temporary hack
265 // function literal without declaring receiver type { x -> ... }
266 // can be considered as extension function if one is expected
267 // (special type constructor for function/ extension function should be introduced like PLACEHOLDER_FUNCTION_TYPE)
268 if (constraintKind == SUB_TYPE && kotlinBuiltIns.isFunctionType(subType) && kotlinBuiltIns.isExtensionFunctionType(superType)) {
269 subType = createCorrespondingExtensionFunctionType(subType, DONT_CARE);
270 }
271
272 // can be equal for the recursive invocations:
273 // fun <T> foo(i: Int) : T { ... return foo(i); } => T <: T
274 if (subType.equals(superType)) return;
275
276 assert !isMyTypeVariable(subType) || !isMyTypeVariable(superType) :
277 "The constraint shouldn't contain different type variables on both sides: " + subType + " <: " + superType;
278
279
280 if (isMyTypeVariable(subType)) {
281 generateTypeParameterConstraint(subType, superType, constraintKind == SUB_TYPE ? UPPER_BOUND : EXACT_BOUND);
282 return;
283 }
284 if (isMyTypeVariable(superType)) {
285 generateTypeParameterConstraint(superType, subType, constraintKind == SUB_TYPE ? LOWER_BOUND : EXACT_BOUND);
286 return;
287 }
288 // if superType is nullable and subType is not nullable, unsafe call error will be generated later,
289 // but constraint system should be solved anyway
290 typeCheckingProcedure.isSubtypeOf(TypeUtils.makeNotNullable(subType), TypeUtils.makeNotNullable(superType));
291 }
292
293 private void generateTypeParameterConstraint(
294 @NotNull JetType parameterType,
295 @NotNull JetType constrainingType,
296 @NotNull BoundKind boundKind
297 ) {
298 TypeConstraintsImpl typeConstraints = getTypeConstraints(parameterType);
299 assert typeConstraints != null : "constraint should be generated only for type variables";
300
301 if (parameterType.isNullable()) {
302 // For parameter type T constraint T? <: Int? should transform to T <: Int
303 constrainingType = TypeUtils.makeNotNullable(constrainingType);
304 }
305 typeConstraints.addBound(boundKind, constrainingType);
306 }
307
308 public void processDeclaredBoundConstraints() {
309 for (Map.Entry<TypeParameterDescriptor, TypeConstraintsImpl> entry : typeParameterConstraints.entrySet()) {
310 TypeParameterDescriptor typeParameterDescriptor = entry.getKey();
311 TypeConstraintsImpl typeConstraints = entry.getValue();
312 for (JetType declaredUpperBound : typeParameterDescriptor.getUpperBounds()) {
313 //todo order matters here
314 for (JetType lowerOrExactBound : Sets.union(typeConstraints.getLowerBounds(), typeConstraints.getExactBounds())) {
315 addSubtypeConstraint(lowerOrExactBound, declaredUpperBound, ConstraintPosition.BOUND_CONSTRAINT_POSITION);
316 }
317 }
318 }
319 }
320
321 @NotNull
322 @Override
323 public Set<TypeParameterDescriptor> getTypeVariables() {
324 return typeParameterConstraints.keySet();
325 }
326
327 @Override
328 @Nullable
329 public TypeConstraints getTypeConstraints(@NotNull TypeParameterDescriptor typeVariable) {
330 return typeParameterConstraints.get(typeVariable);
331 }
332
333 @Nullable
334 private TypeConstraintsImpl getTypeConstraints(@NotNull JetType type) {
335 ClassifierDescriptor parameterDescriptor = type.getConstructor().getDeclarationDescriptor();
336 if (parameterDescriptor instanceof TypeParameterDescriptor) {
337 return typeParameterConstraints.get(parameterDescriptor);
338 }
339 return null;
340 }
341
342 private boolean isMyTypeVariable(@NotNull JetType type) {
343 ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
344 return descriptor instanceof TypeParameterDescriptor && typeParameterConstraints.get(descriptor) != null;
345 }
346
347 @Override
348 public boolean isSuccessful() {
349 return !hasContradiction() && !hasUnknownParameters();
350 }
351
352 @Override
353 public boolean hasContradiction() {
354 return hasTypeConstructorMismatch() || hasConflictingConstraints();
355 }
356
357 @Override
358 public boolean hasConflictingConstraints() {
359 for (TypeParameterDescriptor typeParameter : typeParameterConstraints.keySet()) {
360 TypeConstraints typeConstraints = getTypeConstraints(typeParameter);
361 if (typeConstraints != null && ConstraintsUtil.getValues(typeConstraints).size() > 1) return true;
362 }
363 return false;
364 }
365
366 @Override
367 public boolean hasUnknownParameters() {
368 for (TypeConstraintsImpl constraints : typeParameterConstraints.values()) {
369 if (constraints.isEmpty()) {
370 return true;
371 }
372 }
373 return false;
374 }
375
376 @NotNull
377 @Override
378 public TypeSubstitutor getResultingSubstitutor() {
379 if (hasOnlyExpectedTypeMismatch()) {
380 assert systemWithoutExpectedTypeConstraint != null;
381 return systemWithoutExpectedTypeConstraint.getResultingSubstitutor();
382 }
383 return resultingSubstitutor;
384 }
385
386 @NotNull
387 @Override
388 public TypeSubstitutor getCurrentSubstitutor() {
389 return currentSubstitutor;
390 }
391
392 @NotNull
393 public static JetType createCorrespondingExtensionFunctionType(@NotNull JetType functionType, @NotNull JetType receiverType) {
394 assert KotlinBuiltIns.getInstance().isFunctionType(functionType);
395
396 List<TypeProjection> typeArguments = functionType.getArguments();
397 assert !typeArguments.isEmpty();
398
399 List<JetType> arguments = Lists.newArrayList();
400 // excluding the last type argument of the function type, which is the return type
401 int index = 0;
402 int lastIndex = typeArguments.size() - 1;
403 for (TypeProjection typeArgument : typeArguments) {
404 if (index < lastIndex) {
405 arguments.add(typeArgument.getType());
406 }
407 index++;
408 }
409 JetType returnType = typeArguments.get(lastIndex).getType();
410 return KotlinBuiltIns.getInstance().getFunctionType(functionType.getAnnotations(), receiverType, arguments, returnType);
411 }
412 }