|
16 | 16 | //===----------------------------------------------------------------------===//
|
17 | 17 |
|
18 | 18 | #include "CSDiagnostics.h"
|
| 19 | +#include "swift/AST/Decl.h" |
19 | 20 | #include "swift/AST/ExistentialLayout.h"
|
20 | 21 | #include "swift/AST/GenericEnvironment.h"
|
21 | 22 | #include "swift/AST/GenericSignature.h"
|
@@ -1433,6 +1434,34 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
|
1433 | 1434 | assert(!argsWithLabels[argIdx].isAutoClosure() ||
|
1434 | 1435 | isSynthesizedArgument(argument));
|
1435 | 1436 |
|
| 1437 | + // If parameter is a generic parameter, let's copy its |
| 1438 | + // conformance requirements (if any), to the argument |
| 1439 | + // be able to filter mismatching choices earlier. |
| 1440 | + if (auto *typeVar = paramTy->getAs<TypeVariableType>()) { |
| 1441 | + auto *locator = typeVar->getImpl().getLocator(); |
| 1442 | + if (locator->isForGenericParameter()) { |
| 1443 | + auto &CG = cs.getConstraintGraph(); |
| 1444 | + |
| 1445 | + auto isTransferableConformance = [&typeVar](Constraint *constraint) { |
| 1446 | + if (constraint->getKind() != ConstraintKind::ConformsTo) |
| 1447 | + return false; |
| 1448 | + |
| 1449 | + auto requirementTy = constraint->getFirstType(); |
| 1450 | + if (!requirementTy->isEqual(typeVar)) |
| 1451 | + return false; |
| 1452 | + |
| 1453 | + return constraint->getSecondType()->is<ProtocolType>(); |
| 1454 | + }; |
| 1455 | + |
| 1456 | + for (auto *constraint : CG[typeVar].getConstraints()) { |
| 1457 | + if (isTransferableConformance(constraint)) |
| 1458 | + cs.addConstraint(ConstraintKind::TransitivelyConformsTo, argTy, |
| 1459 | + constraint->getSecondType(), |
| 1460 | + constraint->getLocator()); |
| 1461 | + } |
| 1462 | + } |
| 1463 | + } |
| 1464 | + |
1436 | 1465 | cs.addConstraint(
|
1437 | 1466 | subKind, argTy, paramTy,
|
1438 | 1467 | matchingAutoClosureResult
|
@@ -1542,6 +1571,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
|
1542 | 1571 | case ConstraintKind::BindOverload:
|
1543 | 1572 | case ConstraintKind::CheckedCast:
|
1544 | 1573 | case ConstraintKind::ConformsTo:
|
| 1574 | + case ConstraintKind::TransitivelyConformsTo: |
1545 | 1575 | case ConstraintKind::Defaultable:
|
1546 | 1576 | case ConstraintKind::Disjunction:
|
1547 | 1577 | case ConstraintKind::DynamicTypeOf:
|
@@ -1682,6 +1712,7 @@ static bool matchFunctionRepresentations(FunctionType::ExtInfo einfo1,
|
1682 | 1712 | case ConstraintKind::BindOverload:
|
1683 | 1713 | case ConstraintKind::CheckedCast:
|
1684 | 1714 | case ConstraintKind::ConformsTo:
|
| 1715 | + case ConstraintKind::TransitivelyConformsTo: |
1685 | 1716 | case ConstraintKind::Defaultable:
|
1686 | 1717 | case ConstraintKind::Disjunction:
|
1687 | 1718 | case ConstraintKind::DynamicTypeOf:
|
@@ -2072,6 +2103,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
|
2072 | 2103 | case ConstraintKind::BindOverload:
|
2073 | 2104 | case ConstraintKind::CheckedCast:
|
2074 | 2105 | case ConstraintKind::ConformsTo:
|
| 2106 | + case ConstraintKind::TransitivelyConformsTo: |
2075 | 2107 | case ConstraintKind::Defaultable:
|
2076 | 2108 | case ConstraintKind::Disjunction:
|
2077 | 2109 | case ConstraintKind::DynamicTypeOf:
|
@@ -4983,6 +5015,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
|
4983 | 5015 | case ConstraintKind::BridgingConversion:
|
4984 | 5016 | case ConstraintKind::CheckedCast:
|
4985 | 5017 | case ConstraintKind::ConformsTo:
|
| 5018 | + case ConstraintKind::TransitivelyConformsTo: |
4986 | 5019 | case ConstraintKind::Defaultable:
|
4987 | 5020 | case ConstraintKind::Disjunction:
|
4988 | 5021 | case ConstraintKind::DynamicTypeOf:
|
@@ -6208,6 +6241,128 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
|
6208 | 6241 | return SolutionKind::Error;
|
6209 | 6242 | }
|
6210 | 6243 |
|
| 6244 | +ConstraintSystem::SolutionKind ConstraintSystem::simplifyTransitivelyConformsTo( |
| 6245 | + Type type, Type protocolTy, ConstraintLocatorBuilder locator, |
| 6246 | + TypeMatchOptions flags) { |
| 6247 | + auto &ctx = getASTContext(); |
| 6248 | + |
| 6249 | + // Since this is a performance optimization, let's ignore it |
| 6250 | + // in diagnostic mode. |
| 6251 | + if (shouldAttemptFixes()) |
| 6252 | + return SolutionKind::Solved; |
| 6253 | + |
| 6254 | + auto formUnsolved = [&]() { |
| 6255 | + // If we're supposed to generate constraints, do so. |
| 6256 | + if (flags.contains(TMF_GenerateConstraints)) { |
| 6257 | + auto *conformance = |
| 6258 | + Constraint::create(*this, ConstraintKind::TransitivelyConformsTo, |
| 6259 | + type, protocolTy, getConstraintLocator(locator)); |
| 6260 | + |
| 6261 | + addUnsolvedConstraint(conformance); |
| 6262 | + return SolutionKind::Solved; |
| 6263 | + } |
| 6264 | + |
| 6265 | + return SolutionKind::Unsolved; |
| 6266 | + }; |
| 6267 | + |
| 6268 | + auto resolvedTy = getFixedTypeRecursive(type, /*wantRValue=*/true); |
| 6269 | + if (resolvedTy->isTypeVariableOrMember()) |
| 6270 | + return formUnsolved(); |
| 6271 | + |
| 6272 | + // If the composition consists of a class + protocol, |
| 6273 | + // we can't check conformance of the argument because |
| 6274 | + // parameter could pick one of the components. |
| 6275 | + if (resolvedTy.findIf( |
| 6276 | + [](Type type) { return type->is<ProtocolCompositionType>(); })) |
| 6277 | + return SolutionKind::Solved; |
| 6278 | + |
| 6279 | + // All bets are off for pointers, there are multiple combinations |
| 6280 | + // to check and it doesn't see worth to do that upfront. |
| 6281 | + { |
| 6282 | + PointerTypeKind pointerKind; |
| 6283 | + if (resolvedTy->getAnyPointerElementType(pointerKind)) |
| 6284 | + return SolutionKind::Solved; |
| 6285 | + } |
| 6286 | + |
| 6287 | + auto *protocol = protocolTy->castTo<ProtocolType>()->getDecl(); |
| 6288 | + |
| 6289 | + auto *M = DC->getParentModule(); |
| 6290 | + |
| 6291 | + // First, let's check whether the type itself conforms, |
| 6292 | + // if it does - we are done. |
| 6293 | + if (M->lookupConformance(resolvedTy, protocol)) |
| 6294 | + return SolutionKind::Solved; |
| 6295 | + |
| 6296 | + // If the type doesn't conform, let's check whether |
| 6297 | + // an Optional or Unsafe{Mutable}Pointer from it would. |
| 6298 | + |
| 6299 | + SmallVector<Type, 4> typesToCheck; |
| 6300 | + |
| 6301 | + // T -> Optional<T> |
| 6302 | + if (!resolvedTy->getOptionalObjectType()) |
| 6303 | + typesToCheck.push_back(OptionalType::get(resolvedTy)); |
| 6304 | + |
| 6305 | + // AnyHashable |
| 6306 | + if (auto *anyHashable = ctx.getAnyHashableDecl()) |
| 6307 | + typesToCheck.push_back(anyHashable->getDeclaredInterfaceType()); |
| 6308 | + |
| 6309 | + // Rest of the implicit conversions depend on the resolved type. |
| 6310 | + { |
| 6311 | + auto getPointerFor = [&ctx](PointerTypeKind ptrKind, |
| 6312 | + Optional<Type> elementTy = None) -> Type { |
| 6313 | + switch (ptrKind) { |
| 6314 | + case PTK_UnsafePointer: |
| 6315 | + assert(elementTy); |
| 6316 | + return BoundGenericType::get(ctx.getUnsafePointerDecl(), |
| 6317 | + /*parent=*/Type(), {*elementTy}); |
| 6318 | + case PTK_UnsafeMutablePointer: |
| 6319 | + assert(elementTy); |
| 6320 | + return BoundGenericType::get(ctx.getUnsafeMutablePointerDecl(), |
| 6321 | + /*parent=*/Type(), {*elementTy}); |
| 6322 | + |
| 6323 | + case PTK_UnsafeRawPointer: |
| 6324 | + return ctx.getUnsafeRawPointerDecl()->getDeclaredInterfaceType(); |
| 6325 | + |
| 6326 | + case PTK_UnsafeMutableRawPointer: |
| 6327 | + return ctx.getUnsafeMutableRawPointerDecl()->getDeclaredInterfaceType(); |
| 6328 | + |
| 6329 | + case PTK_AutoreleasingUnsafeMutablePointer: |
| 6330 | + llvm_unreachable("no implicit conversion"); |
| 6331 | + } |
| 6332 | + }; |
| 6333 | + |
| 6334 | + // String -> UnsafePointer<Void> |
| 6335 | + if (auto *string = ctx.getStringDecl()) { |
| 6336 | + if (resolvedTy->isEqual(string->getDeclaredInterfaceType())) { |
| 6337 | + typesToCheck.push_back( |
| 6338 | + getPointerFor(PTK_UnsafePointer, ctx.TheEmptyTupleType)); |
| 6339 | + } |
| 6340 | + } |
| 6341 | + |
| 6342 | + // Array<T> -> Unsafe{Raw}Pointer<T> |
| 6343 | + if (auto elt = isArrayType(resolvedTy)) { |
| 6344 | + typesToCheck.push_back(getPointerFor(PTK_UnsafePointer, *elt)); |
| 6345 | + typesToCheck.push_back(getPointerFor(PTK_UnsafeRawPointer, *elt)); |
| 6346 | + } |
| 6347 | + |
| 6348 | + // inout argument -> UnsafePointer<T>, UnsafeMutablePointer<T>, |
| 6349 | + // UnsafeRawPointer, UnsafeMutableRawPointer. |
| 6350 | + if (type->is<InOutType>()) { |
| 6351 | + typesToCheck.push_back(getPointerFor(PTK_UnsafePointer, resolvedTy)); |
| 6352 | + typesToCheck.push_back(getPointerFor(PTK_UnsafeMutablePointer, resolvedTy)); |
| 6353 | + typesToCheck.push_back(getPointerFor(PTK_UnsafeRawPointer)); |
| 6354 | + typesToCheck.push_back(getPointerFor(PTK_UnsafeMutableRawPointer)); |
| 6355 | + } |
| 6356 | + } |
| 6357 | + |
| 6358 | + return llvm::any_of(typesToCheck, |
| 6359 | + [&](Type type) { |
| 6360 | + return bool(M->lookupConformance(type, protocol)); |
| 6361 | + }) |
| 6362 | + ? SolutionKind::Solved |
| 6363 | + : SolutionKind::Error; |
| 6364 | +} |
| 6365 | + |
6211 | 6366 | /// Determine the kind of checked cast to perform from the given type to
|
6212 | 6367 | /// the given type.
|
6213 | 6368 | ///
|
@@ -11284,6 +11439,10 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first,
|
11284 | 11439 | return simplifyConformsToConstraint(first, second, kind, locator,
|
11285 | 11440 | subflags);
|
11286 | 11441 |
|
| 11442 | + case ConstraintKind::TransitivelyConformsTo: |
| 11443 | + return simplifyTransitivelyConformsTo(first, second, locator, |
| 11444 | + subflags); |
| 11445 | + |
11287 | 11446 | case ConstraintKind::CheckedCast:
|
11288 | 11447 | return simplifyCheckedCastConstraint(first, second, subflags, locator);
|
11289 | 11448 |
|
@@ -11752,6 +11911,13 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
|
11752 | 11911 | constraint.getLocator(),
|
11753 | 11912 | None);
|
11754 | 11913 |
|
| 11914 | + case ConstraintKind::TransitivelyConformsTo: |
| 11915 | + return simplifyTransitivelyConformsTo( |
| 11916 | + constraint.getFirstType(), |
| 11917 | + constraint.getSecondType(), |
| 11918 | + constraint.getLocator(), |
| 11919 | + None); |
| 11920 | + |
11755 | 11921 | case ConstraintKind::CheckedCast: {
|
11756 | 11922 | auto result = simplifyCheckedCastConstraint(constraint.getFirstType(),
|
11757 | 11923 | constraint.getSecondType(),
|
|
0 commit comments