Skip to content

Commit 7159111

Browse files
committed
Improve diagnosis of generic types in @abi
A same-type constraint in an enclosing `where` clause will eliminate a generic parameter’s ABI impact. Teach `ABIDeclChecker::checkType()` about this so it can handle a known-unsupported case for `Swift.Result.init(catching:)`.
1 parent 446dc9d commit 7159111

File tree

2 files changed

+53
-20
lines changed

2 files changed

+53
-20
lines changed

lib/Sema/TypeCheckAttrABI.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,13 @@ SourceLoc getTypeLoc(AbstractStorageDecl *storage, Decl *owner = nullptr) {
222222
return loc;
223223
}
224224

225+
/// Get a decl's generic signature, if it has one.
226+
GenericSignature getGenericSignature(Decl *decl) {
227+
if (auto genericCtx = decl->getAsGenericContext())
228+
return genericCtx->getGenericSignature();
229+
return GenericSignature();
230+
}
231+
225232
class ABIDeclChecker : public ASTComparisonVisitor<ABIDeclChecker> {
226233
ASTContext &ctx;
227234
Decl *diagnoseOnDecl;
@@ -371,6 +378,8 @@ class ABIDeclChecker : public ASTComparisonVisitor<ABIDeclChecker> {
371378

372379
didDiagnose |= checkType(apiNorm.getPlainType(), abiNorm.getPlainType(),
373380
apiTypeLoc, abiTypeLoc,
381+
getGenericSignature(apiDecl),
382+
getGenericSignature(abiDecl),
374383
TypeOrigin::forParameter(abi));
375384

376385
didDiagnose |= checkParameterFlags(apiNorm.getParameterFlags(),
@@ -471,6 +480,8 @@ class ABIDeclChecker : public ASTComparisonVisitor<ABIDeclChecker> {
471480

472481
didDiagnose |= checkType(apiThrowType, abiThrowType,
473482
api.throwsLoc, abi.throwsLoc,
483+
getGenericSignature(apiDecl),
484+
getGenericSignature(abiDecl),
474485
TypeOrigin::forThrowsEffect());
475486
}
476487

@@ -621,10 +632,9 @@ class ABIDeclChecker : public ASTComparisonVisitor<ABIDeclChecker> {
621632
bool visitDecl(Decl *api, Decl *abi) {
622633
bool didDiagnose = checkAttrs(api->getAttrs(), abi->getAttrs(), api, abi);
623634

624-
if (auto apiGenericCtx = api->getAsGenericContext()) {
625-
auto abiGenericCtx = abi->getAsGenericContext();
626-
didDiagnose |= checkGenericSignature(apiGenericCtx->getGenericSignature(),
627-
abiGenericCtx->getGenericSignature(),
635+
if (api->getAsGenericContext()) {
636+
didDiagnose |= checkGenericSignature(getGenericSignature(api),
637+
getGenericSignature(abi),
628638
api, abi);
629639
}
630640

@@ -706,6 +716,7 @@ class ABIDeclChecker : public ASTComparisonVisitor<ABIDeclChecker> {
706716
abi->getResultInterfaceType(),
707717
api->getResultTypeSourceRange().Start,
708718
abi->getResultTypeSourceRange().Start,
719+
getGenericSignature(api), getGenericSignature(abi),
709720
TypeOrigin::forResult());
710721
}
711722

@@ -723,6 +734,7 @@ class ABIDeclChecker : public ASTComparisonVisitor<ABIDeclChecker> {
723734

724735
if (checkType(api->getValueInterfaceType(), abi->getValueInterfaceType(),
725736
getTypeLoc(api), getTypeLoc(abi),
737+
getGenericSignature(api), getGenericSignature(abi),
726738
TypeOrigin::forUnspecified()))
727739
return true;
728740

@@ -934,10 +946,11 @@ class ABIDeclChecker : public ASTComparisonVisitor<ABIDeclChecker> {
934946
// MARK: @abi checking - types
935947

936948
bool checkType(Type api, Type abi, SourceLoc apiLoc, SourceLoc abiLoc,
949+
GenericSignature apiSig, GenericSignature abiSig,
937950
TypeOrigin origin) {
938951
if (!api.isNull() && !abi.isNull()) {
939-
Type apiNorm = normalizeType(api);
940-
Type abiNorm = normalizeType(abi);
952+
Type apiNorm = normalizeType(api->getReducedType(apiSig));
953+
Type abiNorm = normalizeType(abi->getReducedType(abiSig));
941954
if (apiNorm->isEqual(abiNorm)) {
942955
return false;
943956
}

test/attr/attr_abi.swift

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,40 @@ var throws00Var: Int { get { fatalError() } }
220220
@abi(var throws11Var: Int)
221221
var throws11Var: Int { get throws { fatalError() } }
222222
223+
enum ErsatzResult<Success, Failure: Error> {}
224+
225+
extension ErsatzResult where Failure == Swift.Error {
226+
// The `where` clause makes `throws(Failure)` equivalent to `throws`.
227+
228+
// Similar to Swift.Result.init(__untyped_throws_catching:)
229+
@abi(
230+
init(
231+
catching body: () throws -> Success
232+
)
233+
)
234+
init(
235+
__untyped_throws_catching body: () throws(Failure) -> Success
236+
) {}
237+
238+
@abi(func get() throws -> Success)
239+
func __untyped_throws_get() throws(Failure) -> Success { fatalError() }
240+
}
241+
242+
extension ErsatzResult {
243+
// Should not be allowed, as `Failure` is still generic
244+
@abi(
245+
init(
246+
unconstrainedCatching body: () throws -> Success // expected-error {{parameter 'body' type '() throws -> Success' in '@abi' should match '() throws(Failure) -> Success'}}
247+
)
248+
)
249+
init(
250+
__untyped_throws_catching_bad body: () throws(Failure) -> Success // expected-note {{should match type here}}
251+
) {}
252+
253+
@abi(func unconstrainedGet() throws -> Success) // expected-error @:32 {{thrown type 'any Error' in '@abi' should match 'Failure'}}
254+
func __untyped_throws_get_bad() throws(Failure) -> Success { fatalError() } // expected-note {{should match type here}}
255+
}
256+
223257
//
224258
// Async effect checking
225259
//
@@ -999,20 +1033,6 @@ func testNormalProtocolsGeneric<A: CustomStringConvertible, B>( // expected-note
9991033
_: A, _: B
10001034
) {}
10011035
1002-
enum ErsatzResult<Success, Failure: Error> {}
1003-
extension ErsatzResult where Failure == Swift.Error {
1004-
// Similar to Swift.Result.init(__untyped_throws_catching:)
1005-
// FIXME: The where clause makes this ABI-compatible, but we can't tell that.
1006-
@abi(
1007-
init(
1008-
catching body: () throws -> Success // expected-error {{parameter 'body' type '() throws -> Success' in '@abi' should match '() throws(Failure) -> Success'}}
1009-
)
1010-
)
1011-
init(
1012-
__untyped_throws_catching body: () throws(Failure) -> Success // expected-note {{should match type here}}
1013-
) {}
1014-
}
1015-
10161036
//
10171037
// Static/Instance and interactions with `final`
10181038
//

0 commit comments

Comments
 (0)