Skip to content

Commit 0d8b67e

Browse files
committed
Fix substitutions for generic requirements
1 parent a2b20f9 commit 0d8b67e

File tree

4 files changed

+38
-4
lines changed

4 files changed

+38
-4
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2582,10 +2582,7 @@ checkIndividualConformance(NormalProtocolConformance *conformance) {
25822582
// unsafe, then the conformance must be unsafe.
25832583
if (auto witness = conformance->getWitnessUncached(valueRequirement)) {
25842584
if (isUnsafe(witness.getDeclRef()) &&
2585-
!isUnsafe(
2586-
ConcreteDeclRef(
2587-
valueRequirement,
2588-
witness.getRequirementToWitnessThunkSubs()))) {
2585+
!isUnsafeInConformance(valueRequirement, witness, conformance)) {
25892586
unsafeUses.push_back(
25902587
UnsafeUse::forWitness(
25912588
witness.getDecl(), requirement, conformance));

lib/Sema/TypeCheckUnsafe.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,3 +300,21 @@ bool swift::isUnsafe(ConcreteDeclRef declRef) {
300300

301301
return false;
302302
}
303+
304+
bool swift::isUnsafeInConformance(const ValueDecl *requirement,
305+
const Witness &witness,
306+
NormalProtocolConformance *conformance) {
307+
if (requirement->isUnsafe())
308+
return true;
309+
310+
Type requirementType = requirement->getInterfaceType();
311+
Type requirementTypeInContext;
312+
auto requirementSubs = witness.getRequirementToWitnessThunkSubs();
313+
if (auto genericFnType = requirementType->getAs<GenericFunctionType>()) {
314+
requirementTypeInContext =
315+
genericFnType->substGenericArgs(requirementSubs);
316+
} else {
317+
requirementTypeInContext = requirementType.subst(requirementSubs);
318+
}
319+
return requirementTypeInContext->isUnsafe();
320+
}

lib/Sema/TypeCheckUnsafe.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
namespace swift {
1919

20+
class Witness;
21+
2022
/// Diagnose the given unsafe use right now.
2123
void diagnoseUnsafeUse(const UnsafeUse &use, bool asNote = false);
2224

@@ -28,6 +30,11 @@ void diagnoseUnsafeUsesIn(const Decl *decl);
2830
/// either explicitly (@unsafe) or because it references an unsafe type.
2931
bool isUnsafe(ConcreteDeclRef declRef);
3032

33+
/// Whether the given requirement should be considered unsafe for the given
34+
/// conformance.
35+
bool isUnsafeInConformance(const ValueDecl *requirement,
36+
const Witness &witness,
37+
NormalProtocolConformance *conformance);
3138
}
3239

3340
#endif // SWIFT_SEMA_TYPE_CHECK_UNSAFE_H

test/Unsafe/unsafe.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,18 @@ extension ConformsToMultiP: MultiP {
5353
@unsafe func f() -> UnsafeSuper { .init() }
5454
}
5555

56+
protocol GenericP {
57+
associatedtype Ptr
58+
59+
func f<T>(_: T, _: Ptr)
60+
}
61+
62+
// expected-warning@+1{{conformance of 'ConformsToGenericP' to protocol 'GenericP' involves unsafe code; use '@unsafe' to indicate that the conformance is not memory-safe}}
63+
struct ConformsToGenericP: GenericP {
64+
typealias Ptr = Int
65+
@unsafe func f<T>(_: T, _: Ptr) { } // expected-note{{unsafe instance method 'f' cannot satisfy safe requirement}}
66+
}
67+
5668
// -----------------------------------------------------------------------
5769
// Overrides
5870
// -----------------------------------------------------------------------

0 commit comments

Comments
 (0)