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    }