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 kotlin.Function1;
020 import kotlin.KotlinPackage;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
024 import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
025 import org.jetbrains.jet.lang.types.*;
026 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
027 import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure;
028 import org.jetbrains.jet.lang.types.checker.TypingConstraints;
029 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
030 import org.jetbrains.jet.utils.UtilsPackage;
031
032 import java.util.*;
033
034 import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.EQUAL;
035 import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.SUB_TYPE;
036 import static org.jetbrains.jet.lang.resolve.calls.inference.TypeBounds.Bound;
037 import static org.jetbrains.jet.lang.resolve.calls.inference.TypeBounds.BoundKind.*;
038 import static org.jetbrains.jet.lang.types.TypeUtils.DONT_CARE;
039
040 public class ConstraintSystemImpl implements ConstraintSystem {
041
042 public enum ConstraintKind {
043 SUB_TYPE, EQUAL
044 }
045
046 private final Map<TypeParameterDescriptor, TypeBoundsImpl> typeParameterBounds =
047 new LinkedHashMap<TypeParameterDescriptor, TypeBoundsImpl>();
048 private final Set<ConstraintPosition> errorConstraintPositions = new HashSet<ConstraintPosition>();
049 private boolean hasErrorInConstrainingTypes;
050
051 private final ConstraintSystemStatus constraintSystemStatus = new ConstraintSystemStatus() {
052 // for debug ConstraintsUtil.getDebugMessageForStatus might be used
053
054 @Override
055 public boolean isSuccessful() {
056 return !hasContradiction() && !hasUnknownParameters();
057 }
058
059 @Override
060 public boolean hasContradiction() {
061 return hasTypeConstructorMismatch() || hasConflictingConstraints();
062 }
063
064 @Override
065 public boolean hasViolatedUpperBound() {
066 if (isSuccessful()) return false;
067 return getSystemWithoutWeakConstraints().getStatus().isSuccessful();
068 }
069
070 @Override
071 public boolean hasConflictingConstraints() {
072 for (TypeBoundsImpl typeBounds : typeParameterBounds.values()) {
073 if (typeBounds.getValues().size() > 1) return true;
074 }
075 return false;
076 }
077
078 @Override
079 public boolean hasUnknownParameters() {
080 for (TypeBoundsImpl typeBounds : typeParameterBounds.values()) {
081 if (typeBounds.isEmpty()) {
082 return true;
083 }
084 }
085 return false;
086 }
087
088 @Override
089 public boolean hasTypeConstructorMismatch() {
090 return !errorConstraintPositions.isEmpty();
091 }
092
093 @Override
094 public boolean hasTypeConstructorMismatchAt(@NotNull ConstraintPosition constraintPosition) {
095 return errorConstraintPositions.contains(constraintPosition);
096 }
097
098 @Override
099 public boolean hasOnlyErrorsFromPosition(ConstraintPosition constraintPosition) {
100 if (isSuccessful()) return false;
101 ConstraintSystem systemWithoutConstraintsFromPosition = filterConstraintsOut(constraintPosition);
102 if (systemWithoutConstraintsFromPosition.getStatus().isSuccessful()) {
103 return true;
104 }
105 if (errorConstraintPositions.size() == 1 && errorConstraintPositions.contains(constraintPosition)) {
106 // e.g. if systemWithoutConstraintsFromPosition has unknown type parameters, it's not successful
107 return true;
108 }
109 return false;
110 }
111
112 @Override
113 public boolean hasErrorInConstrainingTypes() {
114 return hasErrorInConstrainingTypes;
115 }
116 };
117
118 @NotNull
119 private static Map<TypeParameterDescriptor, TypeProjection> getParameterToInferredValueMap(
120 @NotNull Map<TypeParameterDescriptor, TypeBoundsImpl> typeParameterBounds,
121 @NotNull Function1<TypeParameterDescriptor, TypeProjection> getDefaultTypeProjection
122 ) {
123 Map<TypeParameterDescriptor, TypeProjection> substitutionContext =
124 UtilsPackage.newHashMapWithExpectedSize(typeParameterBounds.size());
125 for (Map.Entry<TypeParameterDescriptor, TypeBoundsImpl> entry : typeParameterBounds.entrySet()) {
126 TypeParameterDescriptor typeParameter = entry.getKey();
127 TypeBounds typeBounds = entry.getValue();
128
129 TypeProjection typeProjection;
130 JetType value = typeBounds.getValue();
131 if (value != null && !TypeUtils.containsSpecialType(value, TypeUtils.DONT_CARE)) {
132 typeProjection = new TypeProjectionImpl(value);
133 }
134 else {
135 typeProjection = getDefaultTypeProjection.invoke(typeParameter);
136 }
137 substitutionContext.put(typeParameter, typeProjection);
138 }
139 return substitutionContext;
140 }
141
142 private TypeSubstitutor replaceUninferredBy(@NotNull Function1<TypeParameterDescriptor, TypeProjection> getDefaultValue) {
143 return TypeUtils.makeSubstitutorForTypeParametersMap(getParameterToInferredValueMap(typeParameterBounds, getDefaultValue));
144 }
145
146 private TypeSubstitutor replaceUninferredBy(@NotNull final JetType defaultValue) {
147 return replaceUninferredBy(
148 new Function1<TypeParameterDescriptor, TypeProjection>() {
149 @Override
150 public TypeProjection invoke(TypeParameterDescriptor descriptor) {
151 return new TypeProjectionImpl(defaultValue);
152 }
153 }
154 );
155 }
156
157 private TypeSubstitutor replaceUninferredBySpecialErrorType() {
158 return replaceUninferredBy(
159 new Function1<TypeParameterDescriptor, TypeProjection>() {
160 @Override
161 public TypeProjection invoke(TypeParameterDescriptor descriptor) {
162 return new TypeProjectionImpl(ErrorUtils.createUninferredParameterType(descriptor));
163 }
164 }
165 );
166 }
167
168 @NotNull
169 @Override
170 public ConstraintSystemStatus getStatus() {
171 return constraintSystemStatus;
172 }
173
174 @Override
175 public void registerTypeVariables(@NotNull Map<TypeParameterDescriptor, Variance> typeVariables) {
176 for (Map.Entry<TypeParameterDescriptor, Variance> entry : typeVariables.entrySet()) {
177 TypeParameterDescriptor typeVariable = entry.getKey();
178 Variance positionVariance = entry.getValue();
179 typeParameterBounds.put(typeVariable, new TypeBoundsImpl(typeVariable, positionVariance));
180 }
181 TypeSubstitutor constantSubstitutor = TypeUtils.makeConstantSubstitutor(typeParameterBounds.keySet(), DONT_CARE);
182 for (Map.Entry<TypeParameterDescriptor, TypeBoundsImpl> entry : typeParameterBounds.entrySet()) {
183 TypeParameterDescriptor typeVariable = entry.getKey();
184 TypeBoundsImpl typeBounds = entry.getValue();
185
186 for (JetType declaredUpperBound : typeVariable.getUpperBounds()) {
187 if (KotlinBuiltIns.getInstance().getNullableAnyType().equals(declaredUpperBound)) continue; //todo remove this line (?)
188 JetType substitutedBound = constantSubstitutor.substitute(declaredUpperBound, Variance.INVARIANT);
189 if (substitutedBound != null) {
190 typeBounds.addBound(UPPER_BOUND, substitutedBound, ConstraintPosition.getTypeBoundPosition(typeVariable.getIndex()));
191 }
192 }
193 }
194 }
195
196 @Override
197 @NotNull
198 public ConstraintSystem copy() {
199 return createNewConstraintSystemFromThis(
200 UtilsPackage.<TypeParameterDescriptor>identity(),
201 new Function1<TypeBoundsImpl, TypeBoundsImpl>() {
202 @Override
203 public TypeBoundsImpl invoke(TypeBoundsImpl typeBounds) {
204 return typeBounds.copy();
205 }
206 },
207 UtilsPackage.<ConstraintPosition>alwaysTrue()
208 );
209 }
210
211 @NotNull
212 public ConstraintSystem substituteTypeVariables(@NotNull Function1<TypeParameterDescriptor, TypeParameterDescriptor> typeVariablesMap) {
213 return createNewConstraintSystemFromThis(
214 typeVariablesMap,
215 // type bounds are proper types and don't contain other variables
216 UtilsPackage.<TypeBoundsImpl>identity(),
217 UtilsPackage.<ConstraintPosition>alwaysTrue()
218 );
219 }
220
221 @NotNull
222 public ConstraintSystem filterConstraintsOut(@NotNull final ConstraintPosition excludePosition) {
223 return filterConstraints(new Function1<ConstraintPosition, Boolean>() {
224 @Override
225 public Boolean invoke(ConstraintPosition constraintPosition) {
226 return !excludePosition.equals(constraintPosition);
227 }
228 });
229 }
230
231 @NotNull
232 private ConstraintSystem filterConstraints(@NotNull final Function1<ConstraintPosition, Boolean> condition) {
233 return createNewConstraintSystemFromThis(
234 UtilsPackage.<TypeParameterDescriptor>identity(),
235 new Function1<TypeBoundsImpl, TypeBoundsImpl>() {
236 @Override
237 public TypeBoundsImpl invoke(TypeBoundsImpl typeBounds) {
238 return typeBounds.filter(condition);
239 }
240 },
241 condition
242 );
243 }
244
245 @NotNull
246 public ConstraintSystem getSystemWithoutWeakConstraints() {
247 return filterConstraints(new Function1<ConstraintPosition, Boolean>() {
248 @Override
249 public Boolean invoke(ConstraintPosition constraintPosition) {
250 // 'isStrong' for compound means 'has some strong constraints'
251 // but for testing absence of weak constraints we need 'has only strong constraints' here
252 if (constraintPosition instanceof ConstraintPosition.CompoundConstraintPosition) {
253 ConstraintPosition.CompoundConstraintPosition position =
254 (ConstraintPosition.CompoundConstraintPosition) constraintPosition;
255 return position.consistsOfOnlyStrongConstraints();
256 }
257 return constraintPosition.isStrong();
258 }
259 });
260 }
261
262 @NotNull
263 private ConstraintSystem createNewConstraintSystemFromThis(
264 @NotNull Function1<TypeParameterDescriptor, TypeParameterDescriptor> substituteTypeVariable,
265 @NotNull Function1<TypeBoundsImpl, TypeBoundsImpl> replaceTypeBounds,
266 @NotNull Function1<ConstraintPosition, Boolean> filterConstraintPosition
267 ) {
268 ConstraintSystemImpl newSystem = new ConstraintSystemImpl();
269 for (Map.Entry<TypeParameterDescriptor, TypeBoundsImpl> entry : typeParameterBounds.entrySet()) {
270 TypeParameterDescriptor typeParameter = entry.getKey();
271 TypeBoundsImpl typeBounds = entry.getValue();
272
273 TypeParameterDescriptor newTypeParameter = substituteTypeVariable.invoke(typeParameter);
274 assert newTypeParameter != null;
275 newSystem.typeParameterBounds.put(newTypeParameter, replaceTypeBounds.invoke(typeBounds));
276 }
277 newSystem.errorConstraintPositions.addAll(KotlinPackage.filter(errorConstraintPositions, filterConstraintPosition));
278 //todo if 'filterConstraintPosition' is not trivial, it's incorrect to just copy 'hasErrorInConstrainingTypes'
279 newSystem.hasErrorInConstrainingTypes = hasErrorInConstrainingTypes;
280 return newSystem;
281 }
282
283 @Override
284 public void addSupertypeConstraint(
285 @Nullable JetType constrainingType,
286 @NotNull JetType subjectType,
287 @NotNull ConstraintPosition constraintPosition
288 ) {
289 if (constrainingType != null && TypeUtils.noExpectedType(constrainingType)) return;
290
291 addConstraint(SUB_TYPE, subjectType, constrainingType, constraintPosition);
292 }
293
294 @Override
295 public void addSubtypeConstraint(
296 @Nullable JetType constrainingType,
297 @NotNull JetType subjectType,
298 @NotNull ConstraintPosition constraintPosition
299 ) {
300 addConstraint(SUB_TYPE, constrainingType, subjectType, constraintPosition);
301 }
302
303 private void addConstraint(
304 @NotNull ConstraintKind constraintKind,
305 @Nullable JetType subType,
306 @Nullable JetType superType,
307 @NotNull final ConstraintPosition constraintPosition
308 ) {
309 TypeCheckingProcedure typeCheckingProcedure = new TypeCheckingProcedure(new TypingConstraints() {
310 @Override
311 public boolean assertEqualTypes(
312 @NotNull JetType a, @NotNull JetType b, @NotNull TypeCheckingProcedure typeCheckingProcedure
313 ) {
314 doAddConstraint(EQUAL, a, b, constraintPosition, typeCheckingProcedure);
315 return true;
316
317 }
318
319 @Override
320 public boolean assertEqualTypeConstructors(
321 @NotNull TypeConstructor a, @NotNull TypeConstructor b
322 ) {
323 return a.equals(b);
324 }
325
326 @Override
327 public boolean assertSubtype(
328 @NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeCheckingProcedure typeCheckingProcedure
329 ) {
330 doAddConstraint(SUB_TYPE, subtype, supertype, constraintPosition, typeCheckingProcedure);
331 return true;
332 }
333
334 @Override
335 public boolean noCorrespondingSupertype(
336 @NotNull JetType subtype, @NotNull JetType supertype
337 ) {
338 errorConstraintPositions.add(constraintPosition);
339 return true;
340 }
341 });
342 doAddConstraint(constraintKind, subType, superType, constraintPosition, typeCheckingProcedure);
343 }
344
345 private boolean isErrorOrSpecialType(@Nullable JetType type) {
346 if (type == DONT_CARE || ErrorUtils.isUninferredParameter(type)) {
347 return true;
348 }
349
350 if (type == null || (type.isError() && type != TypeUtils.PLACEHOLDER_FUNCTION_TYPE)) {
351 hasErrorInConstrainingTypes = true;
352 return true;
353 }
354 return false;
355 }
356
357 private void doAddConstraint(
358 @NotNull ConstraintKind constraintKind,
359 @Nullable JetType subType,
360 @Nullable JetType superType,
361 @NotNull ConstraintPosition constraintPosition,
362 @NotNull TypeCheckingProcedure typeCheckingProcedure
363 ) {
364
365 if (isErrorOrSpecialType(subType) || isErrorOrSpecialType(superType)) return;
366 assert subType != null && superType != null;
367
368 assert superType != TypeUtils.PLACEHOLDER_FUNCTION_TYPE : "The type for " + constraintPosition + " shouldn't be a placeholder for function type";
369
370 KotlinBuiltIns kotlinBuiltIns = KotlinBuiltIns.getInstance();
371 if (subType == TypeUtils.PLACEHOLDER_FUNCTION_TYPE) {
372 if (!kotlinBuiltIns.isFunctionOrExtensionFunctionType(superType)) {
373 if (isMyTypeVariable(superType)) {
374 // a constraint binds type parameter and any function type, so there is no new info and no error
375 return;
376 }
377 errorConstraintPositions.add(constraintPosition);
378 }
379 return;
380 }
381
382 // todo temporary hack
383 // function literal without declaring receiver type { x -> ... }
384 // can be considered as extension function if one is expected
385 // (special type constructor for function/ extension function should be introduced like PLACEHOLDER_FUNCTION_TYPE)
386 if (constraintKind == SUB_TYPE && kotlinBuiltIns.isFunctionType(subType) && kotlinBuiltIns.isExtensionFunctionType(superType)) {
387 subType = createCorrespondingExtensionFunctionType(subType, DONT_CARE);
388 }
389
390 // can be equal for the recursive invocations:
391 // fun <T> foo(i: Int) : T { ... return foo(i); } => T <: T
392 if (JetTypeChecker.DEFAULT.equalTypes(subType, superType)) return;
393
394 assert !isMyTypeVariable(subType) || !isMyTypeVariable(superType) :
395 "The constraint shouldn't contain different type variables on both sides: " + subType + " <: " + superType;
396
397
398 if (isMyTypeVariable(subType)) {
399 generateTypeParameterConstraint(subType, superType, constraintKind == SUB_TYPE ? UPPER_BOUND : EXACT_BOUND, constraintPosition);
400 return;
401 }
402 if (isMyTypeVariable(superType)) {
403 generateTypeParameterConstraint(superType, subType, constraintKind == SUB_TYPE ? LOWER_BOUND : EXACT_BOUND, constraintPosition);
404 return;
405 }
406 // if superType is nullable and subType is not nullable, unsafe call error will be generated later,
407 // but constraint system should be solved anyway
408 typeCheckingProcedure.isSubtypeOf(TypeUtils.makeNotNullable(subType), TypeUtils.makeNotNullable(superType));
409 }
410
411 private void generateTypeParameterConstraint(
412 @NotNull JetType parameterType,
413 @NotNull JetType constrainingType,
414 @NotNull TypeBoundsImpl.BoundKind boundKind,
415 @NotNull ConstraintPosition constraintPosition
416 ) {
417 // Here we are handling the case when T! gets a bound Foo (or Foo?)
418 // In this case, type parameter T is supposed to get the bound Foo!
419 // Example:
420 // val c: Collection<Foo> = Collections.singleton(null : Foo?)
421 // Constraints for T are:
422 // Foo? <: T!
423 // Foo >: T!
424 // both Foo and Foo? transform to Foo! here
425 if (TypesPackage.isFlexible(parameterType)) {
426 CustomTypeVariable typeVariable = TypesPackage.getCustomTypeVariable(parameterType);
427 if (typeVariable != null) {
428 constrainingType = typeVariable.substitutionResult(constrainingType);
429 }
430 }
431
432 TypeBoundsImpl typeBounds = getTypeBounds(parameterType);
433 assert typeBounds != null : "constraint should be generated only for type variables";
434
435 if (!parameterType.isNullable() || !constrainingType.isNullable()) {
436 typeBounds.addBound(boundKind, constrainingType, constraintPosition);
437 return;
438 }
439 // For parameter type T:
440 // constraint T? = Int? should transform to T >: Int and T <: Int?
441 // constraint T? >: Int? should transform to T >: Int
442 JetType notNullConstrainingType = TypeUtils.makeNotNullable(constrainingType);
443 if (boundKind == EXACT_BOUND || boundKind == LOWER_BOUND) {
444 typeBounds.addBound(LOWER_BOUND, notNullConstrainingType, constraintPosition);
445 }
446 // constraint T? <: Int? should transform to T <: Int?
447 if (boundKind == EXACT_BOUND || boundKind == UPPER_BOUND) {
448 typeBounds.addBound(UPPER_BOUND, constrainingType, constraintPosition);
449 }
450 }
451
452 public void processDeclaredBoundConstraints() {
453 for (Map.Entry<TypeParameterDescriptor, TypeBoundsImpl> entry : typeParameterBounds.entrySet()) {
454 TypeParameterDescriptor typeParameterDescriptor = entry.getKey();
455 TypeBoundsImpl typeBounds = entry.getValue();
456 for (JetType declaredUpperBound : typeParameterDescriptor.getUpperBounds()) {
457 //todo order matters here
458 Collection<Bound> bounds = new ArrayList<Bound>(typeBounds.getBounds());
459 for (Bound bound : bounds) {
460 if (bound.kind == LOWER_BOUND || bound.kind == EXACT_BOUND) {
461 ConstraintPosition position = ConstraintPosition.getCompoundConstraintPosition(
462 ConstraintPosition.getTypeBoundPosition(typeParameterDescriptor.getIndex()), bound.position);
463 addSubtypeConstraint(bound.type, declaredUpperBound, position);
464 }
465 }
466 ClassifierDescriptor declarationDescriptor = declaredUpperBound.getConstructor().getDeclarationDescriptor();
467 if (declarationDescriptor instanceof TypeParameterDescriptor && typeParameterBounds.containsKey(declarationDescriptor)) {
468 TypeBoundsImpl typeBoundsForUpperBound = typeParameterBounds.get(declarationDescriptor);
469 for (Bound bound : typeBoundsForUpperBound.getBounds()) {
470 if (bound.kind == UPPER_BOUND || bound.kind == EXACT_BOUND) {
471 ConstraintPosition position = ConstraintPosition.getCompoundConstraintPosition(
472 ConstraintPosition.getTypeBoundPosition(typeParameterDescriptor.getIndex()), bound.position);
473 typeBounds.addBound(UPPER_BOUND, bound.type, position);
474 }
475 }
476 }
477 }
478 }
479 }
480
481 @NotNull
482 @Override
483 public Set<TypeParameterDescriptor> getTypeVariables() {
484 return typeParameterBounds.keySet();
485 }
486
487 @Override
488 @NotNull
489 public TypeBounds getTypeBounds(@NotNull TypeParameterDescriptor typeVariable) {
490 TypeBoundsImpl typeBounds = typeParameterBounds.get(typeVariable);
491 assert typeBounds != null : "TypeParameterDescriptor is not a type variable for constraint system: " + typeVariable;
492 return typeBounds;
493 }
494
495 @Nullable
496 private TypeBoundsImpl getTypeBounds(@NotNull JetType type) {
497 ClassifierDescriptor parameterDescriptor = type.getConstructor().getDeclarationDescriptor();
498 if (parameterDescriptor instanceof TypeParameterDescriptor) {
499 return typeParameterBounds.get(parameterDescriptor);
500 }
501 return null;
502 }
503
504 private boolean isMyTypeVariable(@NotNull JetType type) {
505 ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
506 return descriptor instanceof TypeParameterDescriptor && typeParameterBounds.get(descriptor) != null;
507 }
508
509 @NotNull
510 @Override
511 public TypeSubstitutor getResultingSubstitutor() {
512 return replaceUninferredBySpecialErrorType();
513 }
514
515 @NotNull
516 @Override
517 public TypeSubstitutor getCurrentSubstitutor() {
518 return replaceUninferredBy(TypeUtils.DONT_CARE);
519 }
520
521 @NotNull
522 public static JetType createCorrespondingExtensionFunctionType(@NotNull JetType functionType, @NotNull JetType receiverType) {
523 assert KotlinBuiltIns.getInstance().isFunctionType(functionType);
524
525 List<TypeProjection> typeArguments = functionType.getArguments();
526 assert !typeArguments.isEmpty();
527
528 // excluding the last type argument of the function type, which is the return type
529 int index = 0;
530 int lastIndex = typeArguments.size() - 1;
531 List<JetType> arguments = new ArrayList<JetType>(lastIndex);
532 for (TypeProjection typeArgument : typeArguments) {
533 if (index < lastIndex) {
534 arguments.add(typeArgument.getType());
535 }
536 index++;
537 }
538 JetType returnType = typeArguments.get(lastIndex).getType();
539 return KotlinBuiltIns.getInstance().getFunctionType(functionType.getAnnotations(), receiverType, arguments, returnType);
540 }
541 }