Skip to content

[Amendment] SE-0296: Allow overloads that differ only in async #38107

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,9 @@ struct OverloadSignature {
/// Whether this is a function.
unsigned IsFunction : 1;

/// Whether this is an async function.
unsigned IsAsyncFunction : 1;

/// Whether this is a enum element.
unsigned IsEnumElement : 1;

Expand All @@ -249,8 +252,9 @@ struct OverloadSignature {

OverloadSignature()
: UnaryOperator(UnaryOperatorKind::None), IsInstanceMember(false),
IsVariable(false), IsFunction(false), InProtocolExtension(false),
InExtensionOfGenericType(false), HasOpaqueReturnType(false) { }
IsVariable(false), IsFunction(false), IsAsyncFunction(false),
InProtocolExtension(false), InExtensionOfGenericType(false),
HasOpaqueReturnType(false) { }
};

/// Determine whether two overload signatures conflict.
Expand Down
12 changes: 11 additions & 1 deletion lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2483,6 +2483,10 @@ bool swift::conflicting(const OverloadSignature& sig1,
if (sig1.IsInstanceMember != sig2.IsInstanceMember)
return false;

// If one is an async function and the other is not, they can't conflict.
if (sig1.IsAsyncFunction != sig2.IsAsyncFunction)
return false;

// If one is a compound name and the other is not, they do not conflict
// if one is a property and the other is a non-nullary function.
if (sig1.Name.isCompoundName() != sig2.Name.isCompoundName()) {
Expand Down Expand Up @@ -2709,7 +2713,6 @@ OverloadSignature ValueDecl::getOverloadSignature() const {
= static_cast<bool>(getDeclContext()->getExtendedProtocolDecl());
signature.IsInstanceMember = isInstanceMember();
signature.IsVariable = isa<VarDecl>(this);
signature.IsFunction = isa<AbstractFunctionDecl>(this);
signature.IsEnumElement = isa<EnumElementDecl>(this);
signature.IsNominal = isa<NominalTypeDecl>(this);
signature.IsTypeAlias = isa<TypeAliasDecl>(this);
Expand All @@ -2723,6 +2726,13 @@ OverloadSignature ValueDecl::getOverloadSignature() const {
}
}

// Functions include async/not-async.
if (auto func = dyn_cast<AbstractFunctionDecl>(this)) {
signature.IsFunction = true;
if (func->hasAsync())
signature.IsAsyncFunction = true;
}

if (auto *extension = dyn_cast<ExtensionDecl>(getDeclContext()))
if (extension->isGeneric())
signature.InExtensionOfGenericType = true;
Expand Down
7 changes: 3 additions & 4 deletions test/ClangImporter/objc_async_conformance.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,11 @@ extension C2 {
}

// a version of C2 that requires both sync and async methods (differing only by
// completion handler) in ObjC, is not possible to conform to with 'async' in
// a Swift protocol
// completion handler) in ObjC.
class C3 : NSObject, RequiredObserver {}
extension C3 {
func hello() -> Bool { true } // expected-note {{'hello()' previously declared here}}
func hello() async -> Bool { true } // expected-error {{invalid redeclaration of 'hello()'}}
func hello() -> Bool { true }
func hello() async -> Bool { true }
}

// the only way to conform to 'RequiredObserver' in Swift is to not use 'async'
Expand Down
4 changes: 2 additions & 2 deletions test/decl/func/async.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
func redecl1() async { } // expected-note{{previously declared here}}
func redecl1() async throws { } // expected-error{{invalid redeclaration of 'redecl1()'}}

func redecl2() -> String { "" } // expected-note{{previously declared here}}
func redecl2() async -> String { "" } // expected-error{{invalid redeclaration of 'redecl2()'}}
func redecl2() -> String { "" } // okay
func redecl2() async -> String { "" } // okay

// Override checking

Expand Down