Skip to content

Commit 0d36a1f

Browse files
committed
[SIL] The Self type of a protocol can conform to multiple protocols.
Through a same-type constraint on an associated type, the Self type of a protocol can conform to multiple protocols that are not related by direct inheritance. There were two places that incorrectly assumed that this didn't happen: 1) The SIL verifier checked that the archetype for Self conformed to only a single protocol. This only tripped up +Asserts builds, and had no effect on code generation. Change it to ensure that the archetype for Self conforms to the expected protocol. 2) SILFunctionType's getDefaultWitnessMethodProtocol() asserted that the Self type of a protocol only conformed to a single protocol, and then returned the first protocol in the list. This could end up returning the wrong protocol, in turn producing an incorrect substitution list in IRGen. Change it to return the protocol from the constraint in the generic signature. Fixes SR-9848 / rdar://problem/47767506.
1 parent 1b4b739 commit 0d36a1f

File tree

3 files changed

+34
-7
lines changed

3 files changed

+34
-7
lines changed

lib/SIL/SILFunctionType.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,14 @@ SILFunctionType::getDefaultWitnessMethodProtocol() const {
107107
auto superclass = GenericSig->getSuperclassBound(paramTy);
108108
if (superclass)
109109
return nullptr;
110-
auto protos = GenericSig->getConformsTo(paramTy);
111-
assert(protos.size() == 1);
112-
return protos[0];
110+
111+
assert(!GenericSig->getRequirements().empty());
112+
assert(GenericSig->getRequirements().front().getKind() ==
113+
RequirementKind::Conformance);
114+
assert(GenericSig->getRequirements().front().getFirstType()
115+
->isEqual(paramTy));
116+
return GenericSig->getRequirements().front().getSecondType()
117+
->castTo<ProtocolType>()->getDecl();
113118
}
114119

115120
return nullptr;

lib/SIL/SILVerifier.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2542,10 +2542,9 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
25422542
selfRequirement->getKind() == RequirementKind::Conformance,
25432543
"first non-same-typerequirement should be conformance requirement");
25442544
auto conformsTo = genericSig->getConformsTo(selfGenericParam);
2545-
require(conformsTo.size() == 1,
2546-
"requirement Self parameter must conform to exactly one protocol");
2547-
require(conformsTo[0] == protocol,
2548-
"requirement Self parameter should be constrained by protocol");
2545+
require(std::find(conformsTo.begin(), conformsTo.end(), protocol)
2546+
!= conformsTo.end(),
2547+
"requirement Self parameter must conform to called protocol");
25492548

25502549
auto lookupType = AMI->getLookupType();
25512550
if (getOpenedArchetypeOf(lookupType)) {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %target-swift-frontend %s -emit-ir | %FileCheck --check-prefix=CHECK %s -DINT=i%target-ptrsize
2+
3+
public protocol DummyProtocol { }
4+
5+
public protocol SIMDStorageStub {
6+
associatedtype Scalar : DummyProtocol
7+
}
8+
9+
public protocol SIMDScalarStub {
10+
associatedtype SIMD2Storage : SIMDStorageStub
11+
where SIMD2Storage.Scalar == Self
12+
13+
func abs() -> Self
14+
}
15+
16+
// CHECK: define swiftcc void @"$s22witness_method_default7callAbs1sxx_tAA14SIMDScalarStubRzlF
17+
public func callAbs<T: SIMDScalarStub>(s: T) -> T {
18+
// CHECK: [[ABS_PTR:%[0-9]+]] = getelementptr inbounds i8*, i8** %T.SIMDScalarStub, i32 3
19+
// CHECK-NEXT: [[ABS_VALUE:%[0-9]+]] = load i8*, i8** [[ABS_PTR]]
20+
// CHECK-NEXT: [[ABS:%[0-9]+]] = bitcast i8* [[ABS_VALUE]]
21+
// CHECK-NEXT: call swiftcc void [[ABS]]
22+
return s.abs()
23+
}

0 commit comments

Comments
 (0)