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