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