Skip to content

Commit 4f19ba2

Browse files
committed
[CSSimplify] Teach transitive conformance check about Unsafe{Mutable}RawPointer conversions
1 parent 49da89f commit 4f19ba2

File tree

2 files changed

+61
-13
lines changed

2 files changed

+61
-13
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6254,6 +6254,14 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyTransitivelyConformsTo(
62546254
[](Type type) { return type->is<ProtocolCompositionType>(); }))
62556255
return SolutionKind::Solved;
62566256

6257+
// All bets are off for pointers, there are multiple combinations
6258+
// to check and it doesn't see worth to do that upfront.
6259+
{
6260+
PointerTypeKind pointerKind;
6261+
if (resolvedTy->getAnyPointerElementType(pointerKind))
6262+
return SolutionKind::Solved;
6263+
}
6264+
62576265
auto *protocol = protocolTy->castTo<ProtocolType>()->getDecl();
62586266

62596267
auto *M = DC->getParentModule();
@@ -6277,29 +6285,51 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyTransitivelyConformsTo(
62776285
typesToCheck.push_back(anyHashable->getDeclaredInterfaceType());
62786286

62796287
// Rest of the implicit conversions depend on the resolved type.
6280-
if (auto *ptrDecl = ctx.getUnsafePointerDecl()) {
6288+
{
6289+
auto getPointerFor = [&ctx](PointerTypeKind ptrKind,
6290+
Optional<Type> elementTy = None) -> Type {
6291+
switch (ptrKind) {
6292+
case PTK_UnsafePointer:
6293+
assert(elementTy);
6294+
return BoundGenericType::get(ctx.getUnsafePointerDecl(),
6295+
/*parent=*/Type(), {*elementTy});
6296+
case PTK_UnsafeMutablePointer:
6297+
assert(elementTy);
6298+
return BoundGenericType::get(ctx.getUnsafeMutablePointerDecl(),
6299+
/*parent=*/Type(), {*elementTy});
6300+
6301+
case PTK_UnsafeRawPointer:
6302+
return ctx.getUnsafeRawPointerDecl()->getDeclaredInterfaceType();
6303+
6304+
case PTK_UnsafeMutableRawPointer:
6305+
return ctx.getUnsafeMutableRawPointerDecl()->getDeclaredInterfaceType();
6306+
6307+
case PTK_AutoreleasingUnsafeMutablePointer:
6308+
llvm_unreachable("no implicit conversion");
6309+
}
6310+
};
6311+
62816312
// String -> UnsafePointer<Void>
62826313
if (auto *string = ctx.getStringDecl()) {
62836314
if (resolvedTy->isEqual(string->getDeclaredInterfaceType())) {
6284-
typesToCheck.push_back(BoundGenericType::get(ptrDecl, /*parent=*/Type(),
6285-
{ctx.TheEmptyTupleType}));
6315+
typesToCheck.push_back(
6316+
getPointerFor(PTK_UnsafePointer, ctx.TheEmptyTupleType));
62866317
}
62876318
}
62886319

6289-
// Array<T> -> UnsafePointer<T>
6320+
// Array<T> -> Unsafe{Raw}Pointer<T>
62906321
if (auto elt = isArrayType(resolvedTy)) {
6291-
typesToCheck.push_back(
6292-
BoundGenericType::get(ptrDecl, /*parent=*/Type(), {*elt}));
6322+
typesToCheck.push_back(getPointerFor(PTK_UnsafePointer, *elt));
6323+
typesToCheck.push_back(getPointerFor(PTK_UnsafeRawPointer, *elt));
62936324
}
62946325

6295-
// inout argument -> UnsafePointer<T>, UnsafeMutablePointer<T>
6326+
// inout argument -> UnsafePointer<T>, UnsafeMutablePointer<T>,
6327+
// UnsafeRawPointer, UnsafeMutableRawPointer.
62966328
if (type->is<InOutType>()) {
6297-
typesToCheck.push_back(
6298-
BoundGenericType::get(ptrDecl, /*parent=*/Type(), {resolvedTy}));
6299-
6300-
if (auto *mutablePtr = ctx.getUnsafeMutablePointerDecl())
6301-
typesToCheck.push_back(
6302-
BoundGenericType::get(mutablePtr, /*parent=*/Type(), {resolvedTy}));
6329+
typesToCheck.push_back(getPointerFor(PTK_UnsafePointer, resolvedTy));
6330+
typesToCheck.push_back(getPointerFor(PTK_UnsafeMutablePointer, resolvedTy));
6331+
typesToCheck.push_back(getPointerFor(PTK_UnsafeRawPointer));
6332+
typesToCheck.push_back(getPointerFor(PTK_UnsafeMutableRawPointer));
63036333
}
63046334
}
63056335

test/Constraints/protocols.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,13 +445,31 @@ extension AnyHashable : Trivial {
445445
typealias T = Int
446446
}
447447

448+
extension UnsafeRawPointer : Trivial {
449+
typealias T = Int
450+
}
451+
452+
extension UnsafeMutableRawPointer : Trivial {
453+
typealias T = Int
454+
}
455+
448456
func test_inference_through_implicit_conversion() {
449457
struct C : Hashable {}
450458

451459
func test<T: Trivial>(_: T) -> T {}
452460

461+
var arr: [C] = []
462+
let ptr: UnsafeMutablePointer<C> = UnsafeMutablePointer(bitPattern: 0)!
463+
let rawPtr: UnsafeMutableRawPointer = UnsafeMutableRawPointer(bitPattern: 0)!
464+
453465
let _: C? = test(C()) // Ok -> argument is implicitly promoted into an optional
454466
let _: UnsafePointer<C> = test([C()]) // Ok - argument is implicitly converted to a pointer
467+
let _: UnsafeRawPointer = test([C()]) // Ok - argument is implicitly converted to a raw pointer
468+
let _: UnsafeMutableRawPointer = test(&arr) // Ok - inout Array<T> -> UnsafeMutableRawPointer
469+
let _: UnsafePointer<C> = test(ptr) // Ok - UnsafeMutablePointer<T> -> UnsafePointer<T>
470+
let _: UnsafeRawPointer = test(ptr) // Ok - UnsafeMutablePointer<T> -> UnsafeRawPointer
471+
let _: UnsafeRawPointer = test(rawPtr) // Ok - UnsafeMutableRawPointer -> UnsafeRawPointer
472+
let _: UnsafeMutableRawPointer = test(ptr) // Ok - UnsafeMutablePointer<T> -> UnsafeMutableRawPointer
455473
let _: AnyHashable = test(C()) // Ok - argument is implicitly converted to `AnyHashable` because it's Hashable
456474
}
457475

0 commit comments

Comments
 (0)