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