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 org.jetbrains.annotations.NotNull;
025 import org.jetbrains.annotations.Nullable;
026 import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
027 import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
028 import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
029 import org.jetbrains.jet.lang.types.*;
030 import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure;
031 import org.jetbrains.jet.lang.types.checker.TypingConstraints;
032 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
033
034 import java.util.List;
035 import java.util.Map;
036 import java.util.Set;
037
038 import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.*;
039 import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.EQUAL;
040 import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.SUB_TYPE;
041 import static org.jetbrains.jet.lang.resolve.calls.inference.TypeConstraintsImpl.BoundKind;
042 import static org.jetbrains.jet.lang.resolve.calls.inference.TypeConstraintsImpl.BoundKind.*;
043 import static org.jetbrains.jet.lang.types.TypeUtils.noExpectedType;
044
045 public class ConstraintSystemImpl implements ConstraintSystem {
046
047 public enum ConstraintKind {
048 SUB_TYPE, EQUAL
049 }
050
051 private final Map<TypeParameterDescriptor, TypeConstraintsImpl> typeParameterConstraints = Maps.newLinkedHashMap();
052 private final Set<ConstraintPosition> errorConstraintPositions = Sets.newHashSet();
053 private final TypeSubstitutor resultingSubstitutor;
054 private final TypeSubstitutor currentSubstitutor;
055 private boolean hasErrorInConstrainingTypes;
056
057 @Nullable
058 private ConstraintSystem systemWithoutExpectedTypeConstraint;
059
060 public ConstraintSystemImpl() {
061 this.resultingSubstitutor = createTypeSubstitutorWithDefaultForUnknownTypeParameter(new TypeProjection(CANT_INFER_TYPE_PARAMETER));
062 this.currentSubstitutor = createTypeSubstitutorWithDefaultForUnknownTypeParameter(new TypeProjection(DONT_CARE));
063 }
064
065 private TypeSubstitutor createTypeSubstitutorWithDefaultForUnknownTypeParameter(@Nullable final TypeProjection defaultTypeProjection) {
066 return TypeSubstitutor.create(new TypeSubstitution() {
067 @Override
068 public TypeProjection get(TypeConstructor key) {
069 DeclarationDescriptor declarationDescriptor = key.getDeclarationDescriptor();
070 if (declarationDescriptor instanceof TypeParameterDescriptor) {
071 TypeParameterDescriptor descriptor = (TypeParameterDescriptor) declarationDescriptor;
072
073 JetType value = ConstraintsUtil.getValue(getTypeConstraints(descriptor));
074 if (value != null && !TypeUtils.equalsOrContainsAsArgument(value, DONT_CARE)) {
075 return new TypeProjection(value);
076 }
077 if (typeParameterConstraints.containsKey(descriptor)) {
078 return defaultTypeProjection;
079 }
080 }
081 return null;
082 }
083
084 @Override
085 public boolean isEmpty() {
086 return false;
087 }
088
089 @Override
090 public String toString() {
091 return typeParameterConstraints.toString();
092 }
093 });
094 }
095
096 @Override
097 public boolean hasTypeConstructorMismatch() {
098 return !errorConstraintPositions.isEmpty();
099 }
100
101 @Override
102 public boolean hasTypeConstructorMismatchAt(@NotNull ConstraintPosition constraintPosition) {
103 return errorConstraintPositions.contains(constraintPosition);
104 }
105
106 @Override
107 public boolean hasOnlyExpectedTypeMismatch() {
108 if (systemWithoutExpectedTypeConstraint == null) {
109 // the expected type constraint isn't added, there can't be an error with it
110 return false;
111 }
112 if (!isSuccessful() && systemWithoutExpectedTypeConstraint.isSuccessful()) {
113 return true;
114 }
115 if (errorConstraintPositions.size() == 1 && errorConstraintPositions.contains(ConstraintPosition.EXPECTED_TYPE_POSITION)) {
116 // if systemWithoutExpectedTypeConstraint has unknown type parameters, it's not successful,
117 // but there can be expected type mismatch after expected type is added
118 return true;
119 }
120 return false;
121 }
122
123 @Override
124 public boolean hasErrorInConstrainingTypes() {
125 return hasErrorInConstrainingTypes;
126 }
127
128 @Override
129 public void registerTypeVariable(@NotNull TypeParameterDescriptor typeVariable, @NotNull Variance positionVariance) {
130 typeParameterConstraints.put(typeVariable, new TypeConstraintsImpl(positionVariance));
131 }
132
133 @Override
134 @NotNull
135 public ConstraintSystem copy() {
136 return replaceTypeVariables(Functions.<TypeParameterDescriptor>identity(), true);
137 }
138
139 @NotNull
140 public ConstraintSystem replaceTypeVariables(@NotNull Function<TypeParameterDescriptor, TypeParameterDescriptor> typeVariablesMap) {
141 return replaceTypeVariables(typeVariablesMap, false);
142 }
143
144 @NotNull
145 private ConstraintSystem replaceTypeVariables(
146 @NotNull Function<TypeParameterDescriptor, TypeParameterDescriptor> typeVariablesMap,
147 boolean recreateTypeConstraints
148 ) {
149 ConstraintSystemImpl newConstraintSystem = new ConstraintSystemImpl();
150 for (Map.Entry<TypeParameterDescriptor, TypeConstraintsImpl> entry : typeParameterConstraints.entrySet()) {
151 TypeParameterDescriptor typeParameter = entry.getKey();
152 TypeConstraintsImpl typeConstraints = entry.getValue();
153
154 TypeParameterDescriptor newTypeParameter = typeVariablesMap.apply(typeParameter);
155 assert newTypeParameter != null;
156 newConstraintSystem.typeParameterConstraints.put(newTypeParameter, recreateTypeConstraints ? typeConstraints.copy() : typeConstraints);
157 }
158 newConstraintSystem.errorConstraintPositions.addAll(errorConstraintPositions);
159 newConstraintSystem.hasErrorInConstrainingTypes = hasErrorInConstrainingTypes;
160 return newConstraintSystem;
161 }
162
163 @Override
164 public void addSupertypeConstraint(
165 @Nullable JetType constrainingType,
166 @NotNull JetType subjectType,
167 @NotNull ConstraintPosition constraintPosition
168 ) {
169 if (constrainingType != null && noExpectedType(constrainingType)) return;
170
171 if (constraintPosition == ConstraintPosition.EXPECTED_TYPE_POSITION) {
172 systemWithoutExpectedTypeConstraint = copy();
173 }
174 addConstraint(SUB_TYPE, subjectType, constrainingType, constraintPosition);
175 }
176
177 @Override
178 public void addSubtypeConstraint(
179 @Nullable JetType constrainingType,
180 @NotNull JetType subjectType,
181 @NotNull ConstraintPosition constraintPosition
182 ) {
183 addConstraint(SUB_TYPE, constrainingType, subjectType, constraintPosition);
184 }
185
186 private void addConstraint(
187 @NotNull ConstraintKind constraintKind,
188 @Nullable JetType subType,
189 @Nullable JetType superType,
190 @NotNull final ConstraintPosition constraintPosition
191 ) {
192 TypeCheckingProcedure typeCheckingProcedure = new TypeCheckingProcedure(new TypingConstraints() {
193 @Override
194 public boolean assertEqualTypes(
195 @NotNull JetType a, @NotNull JetType b, @NotNull TypeCheckingProcedure typeCheckingProcedure
196 ) {
197 doAddConstraint(EQUAL, a, b, constraintPosition, typeCheckingProcedure);
198 return true;
199
200 }
201
202 @Override
203 public boolean assertEqualTypeConstructors(
204 @NotNull TypeConstructor a, @NotNull TypeConstructor b
205 ) {
206 throw new IllegalStateException("'assertEqualTypeConstructors' shouldn't be invoked inside 'isSubtypeOf'");
207 }
208
209 @Override
210 public boolean assertSubtype(
211 @NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeCheckingProcedure typeCheckingProcedure
212 ) {
213 doAddConstraint(SUB_TYPE, subtype, supertype, constraintPosition, typeCheckingProcedure);
214 return true;
215 }
216
217 @Override
218 public boolean noCorrespondingSupertype(
219 @NotNull JetType subtype, @NotNull JetType supertype
220 ) {
221 errorConstraintPositions.add(constraintPosition);
222 return true;
223 }
224 });
225 doAddConstraint(constraintKind, subType, superType, constraintPosition, typeCheckingProcedure);
226 }
227
228 private boolean isErrorOrSpecialType(@Nullable JetType type) {
229 if (type == DONT_CARE || type == CANT_INFER_TYPE_PARAMETER) {
230 return true;
231 }
232
233 if (type == null || ((ErrorUtils.isErrorType(type) && type != PLACEHOLDER_FUNCTION_TYPE))) {
234 hasErrorInConstrainingTypes = true;
235 return true;
236 }
237 return false;
238 }
239
240 private void doAddConstraint(
241 @NotNull ConstraintKind constraintKind,
242 @Nullable JetType subType,
243 @Nullable JetType superType,
244 @NotNull ConstraintPosition constraintPosition,
245 @NotNull TypeCheckingProcedure typeCheckingProcedure
246 ) {
247
248 if (isErrorOrSpecialType(subType) || isErrorOrSpecialType(superType)) return;
249 assert subType != null && superType != null;
250
251 assert superType != PLACEHOLDER_FUNCTION_TYPE : "The type for " + constraintPosition + " shouldn't be a placeholder for function type";
252
253 KotlinBuiltIns kotlinBuiltIns = KotlinBuiltIns.getInstance();
254 if (subType == PLACEHOLDER_FUNCTION_TYPE) {
255 if (!kotlinBuiltIns.isFunctionOrExtensionFunctionType(superType)) {
256 if (isMyTypeVariable(superType)) {
257 // a constraint binds type parameter and any function type, so there is no new info and no error
258 return;
259 }
260 errorConstraintPositions.add(constraintPosition);
261 }
262 return;
263 }
264
265 // todo temporary hack
266 // function literal without declaring receiver type { x -> ... }
267 // can be considered as extension function if one is expected
268 // (special type constructor for function/ extension function should be introduced like PLACEHOLDER_FUNCTION_TYPE)
269 if (constraintKind == SUB_TYPE && kotlinBuiltIns.isFunctionType(subType) && kotlinBuiltIns.isExtensionFunctionType(superType)) {
270 subType = createCorrespondingExtensionFunctionType(subType, DONT_CARE);
271 }
272
273 // can be equal for the recursive invocations:
274 // fun <T> foo(i: Int) : T { ... return foo(i); } => T <: T
275 if (subType.equals(superType)) return;
276
277 assert !isMyTypeVariable(subType) || !isMyTypeVariable(superType) :
278 "The constraint shouldn't contain different type variables on both sides: " + subType + " <: " + superType;
279
280
281 if (isMyTypeVariable(subType)) {
282 generateTypeParameterConstraint(subType, superType, constraintKind == SUB_TYPE ? UPPER_BOUND : EXACT_BOUND);
283 return;
284 }
285 if (isMyTypeVariable(superType)) {
286 generateTypeParameterConstraint(superType, subType, constraintKind == SUB_TYPE ? LOWER_BOUND : EXACT_BOUND);
287 return;
288 }
289 // if superType is nullable and subType is not nullable, unsafe call error will be generated later,
290 // but constraint system should be solved anyway
291 typeCheckingProcedure.isSubtypeOf(TypeUtils.makeNotNullable(subType), TypeUtils.makeNotNullable(superType));
292 }
293
294 private void generateTypeParameterConstraint(
295 @NotNull JetType parameterType,
296 @NotNull JetType constrainingType,
297 @NotNull BoundKind boundKind
298 ) {
299 TypeConstraintsImpl typeConstraints = getTypeConstraints(parameterType);
300 assert typeConstraints != null : "constraint should be generated only for type variables";
301
302 if (parameterType.isNullable()) {
303 // For parameter type T constraint T? <: Int? should transform to T <: Int
304 constrainingType = TypeUtils.makeNotNullable(constrainingType);
305 }
306 typeConstraints.addBound(boundKind, constrainingType);
307 }
308
309 public void processDeclaredBoundConstraints() {
310 for (Map.Entry<TypeParameterDescriptor, TypeConstraintsImpl> entry : typeParameterConstraints.entrySet()) {
311 TypeParameterDescriptor typeParameterDescriptor = entry.getKey();
312 TypeConstraintsImpl typeConstraints = entry.getValue();
313 for (JetType declaredUpperBound : typeParameterDescriptor.getUpperBounds()) {
314 //todo order matters here
315 for (JetType lowerOrExactBound : Sets.union(typeConstraints.getLowerBounds(), typeConstraints.getExactBounds())) {
316 addSubtypeConstraint(lowerOrExactBound, declaredUpperBound, ConstraintPosition.BOUND_CONSTRAINT_POSITION);
317 }
318 }
319 }
320 }
321
322 @NotNull
323 @Override
324 public Set<TypeParameterDescriptor> getTypeVariables() {
325 return typeParameterConstraints.keySet();
326 }
327
328 @Override
329 @Nullable
330 public TypeConstraints getTypeConstraints(@NotNull TypeParameterDescriptor typeVariable) {
331 return typeParameterConstraints.get(typeVariable);
332 }
333
334 @Nullable
335 private TypeConstraintsImpl getTypeConstraints(@NotNull JetType type) {
336 ClassifierDescriptor parameterDescriptor = type.getConstructor().getDeclarationDescriptor();
337 if (parameterDescriptor instanceof TypeParameterDescriptor) {
338 return typeParameterConstraints.get(parameterDescriptor);
339 }
340 return null;
341 }
342
343 private boolean isMyTypeVariable(@NotNull JetType type) {
344 ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
345 return descriptor instanceof TypeParameterDescriptor && typeParameterConstraints.get(descriptor) != null;
346 }
347
348 @Override
349 public boolean isSuccessful() {
350 return !hasContradiction() && !hasUnknownParameters();
351 }
352
353 @Override
354 public boolean hasContradiction() {
355 return hasTypeConstructorMismatch() || hasConflictingConstraints();
356 }
357
358 @Override
359 public boolean hasConflictingConstraints() {
360 for (TypeParameterDescriptor typeParameter : typeParameterConstraints.keySet()) {
361 TypeConstraints typeConstraints = getTypeConstraints(typeParameter);
362 if (typeConstraints != null && ConstraintsUtil.getValues(typeConstraints).size() > 1) return true;
363 }
364 return false;
365 }
366
367 @Override
368 public boolean hasUnknownParameters() {
369 for (TypeConstraintsImpl constraints : typeParameterConstraints.values()) {
370 if (constraints.isEmpty()) {
371 return true;
372 }
373 }
374 return false;
375 }
376
377 @NotNull
378 @Override
379 public TypeSubstitutor getResultingSubstitutor() {
380 if (hasOnlyExpectedTypeMismatch()) {
381 assert systemWithoutExpectedTypeConstraint != null;
382 return systemWithoutExpectedTypeConstraint.getResultingSubstitutor();
383 }
384 return resultingSubstitutor;
385 }
386
387 @NotNull
388 @Override
389 public TypeSubstitutor getCurrentSubstitutor() {
390 return currentSubstitutor;
391 }
392
393 @NotNull
394 public static JetType createCorrespondingExtensionFunctionType(@NotNull JetType functionType, @NotNull JetType receiverType) {
395 assert KotlinBuiltIns.getInstance().isFunctionType(functionType);
396
397 List<TypeProjection> typeArguments = functionType.getArguments();
398 assert !typeArguments.isEmpty();
399
400 List<JetType> arguments = Lists.newArrayList();
401 // excluding the last type argument of the function type, which is the return type
402 int index = 0;
403 int lastIndex = typeArguments.size() - 1;
404 for (TypeProjection typeArgument : typeArguments) {
405 if (index < lastIndex) {
406 arguments.add(typeArgument.getType());
407 }
408 index++;
409 }
410 JetType returnType = typeArguments.get(lastIndex).getType();
411 return KotlinBuiltIns.getInstance().getFunctionType(functionType.getAnnotations(), receiverType, arguments, returnType);
412 }
413 }