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