Skip to content

[5.1] [Typechecker] Allow static functions to overload enum cases #25099

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 8 commits into from
Jun 24, 2019
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
9 changes: 9 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,15 @@ struct OverloadSignature {
/// Whether this is a function.
unsigned IsFunction : 1;

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

/// Whether this is a nominal type.
unsigned IsNominal : 1;

/// Whether this is a type alias.
unsigned IsTypeAlias : 1;

/// Whether this signature is part of a protocol extension.
unsigned InProtocolExtension : 1;

Expand Down
36 changes: 36 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2138,6 +2138,32 @@ bool swift::conflicting(ASTContext &ctx,
if (!conflicting(sig1, sig2, skipProtocolExtensionCheck))
return false;

// Functions and enum elements do not conflict with each other if their types
// are different.
if (((sig1.IsFunction && sig2.IsEnumElement) ||
(sig1.IsEnumElement && sig2.IsFunction)) &&
sig1Type != sig2Type) {
return false;
}

// Nominal types and enum elements always conflict with each other.
if ((sig1.IsNominal && sig2.IsEnumElement) ||
(sig1.IsEnumElement && sig2.IsNominal)) {
return true;
}

// Typealiases and enum elements always conflict with each other.
if ((sig1.IsTypeAlias && sig2.IsEnumElement) ||
(sig1.IsEnumElement && sig2.IsTypeAlias)) {
return true;
}

// Enum elements always conflict with each other. At this point, they
// have the same base name but different types.
if (sig1.IsEnumElement && sig2.IsEnumElement) {
return true;
}

// Functions always conflict with non-functions with the same signature.
// In practice, this only applies for zero argument functions.
if (sig1.IsFunction != sig2.IsFunction)
Expand Down Expand Up @@ -2309,6 +2335,9 @@ OverloadSignature ValueDecl::getOverloadSignature() const {
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);
signature.HasOpaqueReturnType =
!signature.IsVariable && (bool)getOpaqueResultTypeDecl();

Expand Down Expand Up @@ -2361,6 +2390,13 @@ CanType ValueDecl::getOverloadSignatureType() const {
->getCanonicalType();
}

if (isa<EnumElementDecl>(this)) {
auto mappedType = mapSignatureFunctionType(
getASTContext(), getInterfaceType(), /*topLevelFunction=*/false,
/*isMethod=*/false, /*isInitializer=*/false, /*curryLevels=*/0);
return mappedType->getCanonicalType();
}

// Note: If you add more cases to this function, you should update the
// implementation of the swift::conflicting overload that deals with
// overload types, in order to account for cases where the overload types
Expand Down
117 changes: 117 additions & 0 deletions test/decl/overload.swift
Original file line number Diff line number Diff line change
Expand Up @@ -486,5 +486,122 @@ extension SR7250 where T : P3 {
subscript(i: Int) -> String { return "" }
}

// SR-10084

struct SR_10084_S {
let name: String
}

enum SR_10084_E {
case foo(SR_10084_S) // expected-note {{'foo' previously declared here}}

static func foo(_ name: String) -> SR_10084_E { // Okay
return .foo(SR_10084_S(name: name))
}

func foo(_ name: Bool) -> SR_10084_E { // Okay
return .foo(SR_10084_S(name: "Test"))
}

static func foo(_ value: SR_10084_S) -> SR_10084_E { // expected-error {{invalid redeclaration of 'foo'}}
return .foo(value)
}
}

enum SR_10084_E_1 {
static func foo(_ name: String) -> SR_10084_E_1 { // Okay
return .foo(SR_10084_S(name: name))
}

static func foo(_ value: SR_10084_S) -> SR_10084_E_1 { // expected-note {{'foo' previously declared here}}
return .foo(value)
}

case foo(SR_10084_S) // expected-error {{invalid redeclaration of 'foo'}}
}

enum SR_10084_E_2 {
case fn(() -> Void) // expected-note {{'fn' previously declared here}}

static func fn(_ x: @escaping () -> Void) -> SR_10084_E_2 { // expected-error {{invalid redeclaration of 'fn'}}
fatalError()
}

static func fn(_ x: @escaping () -> Int) -> SR_10084_E_2 { // Okay
fatalError()
}

static func fn(_ x: @escaping () -> Bool) -> SR_10084_E_2 { // Okay
fatalError()
}
}

enum SR_10084_E_3 {
protocol A {} //expected-error {{protocol 'A' cannot be nested inside another declaration}} // expected-note {{'A' previously declared here}}
case A // expected-error {{invalid redeclaration of 'A'}}
}

enum SR_10084_E_4 {
class B {} // expected-note {{'B' previously declared here}}
case B // expected-error {{invalid redeclaration of 'B'}}
}

enum SR_10084_E_5 {
struct C {} // expected-note {{'C' previously declared here}}
case C // expected-error {{invalid redeclaration of 'C'}}
}

enum SR_10084_E_6 {
case D // expected-note {{'D' previously declared here}}
protocol D {} //expected-error {{protocol 'D' cannot be nested inside another declaration}} // expected-error {{invalid redeclaration of 'D'}}
}

enum SR_10084_E_7 {
case E // expected-note {{'E' previously declared here}}
class E {} // expected-error {{invalid redeclaration of 'E'}}
}

enum SR_10084_E_8 {
case F // expected-note {{'F' previously declared here}}
struct F {} // expected-error {{invalid redeclaration of 'F'}}
}

enum SR_10084_E_9 {
case A // expected-note {{found this candidate}} // expected-note {{'A' previously declared here}}
static let A: SR_10084_E_9 = .A // expected-note {{found this candidate}} // expected-error {{invalid redeclaration of 'A'}} // expected-error {{ambiguous use of 'A'}}
}

enum SR_10084_E_10 {
static let A: SR_10084_E_10 = .A // expected-note {{found this candidate}} // expected-note {{'A' previously declared here}} // expected-error {{ambiguous use of 'A'}}
case A // expected-note {{found this candidate}} // expected-error {{invalid redeclaration of 'A'}}
}

enum SR_10084_E_11 {
case A // expected-note {{found this candidate}} // expected-note {{'A' previously declared here}}
static var A: SR_10084_E_11 = .A // expected-note {{found this candidate}} // expected-error {{invalid redeclaration of 'A'}} // expected-error {{ambiguous use of 'A'}}
}

enum SR_10084_E_12 {
static var A: SR_10084_E_12 = .A // expected-note {{found this candidate}} // expected-note {{'A' previously declared here}} // expected-error {{ambiguous use of 'A'}}
case A // expected-note {{found this candidate}} // expected-error {{invalid redeclaration of 'A'}}
}

enum SR_10084_E_13 {
case X // expected-note {{'X' previously declared here}}
struct X<T> {} // expected-error {{invalid redeclaration of 'X'}}
}

enum SR_10084_E_14 {
struct X<T> {} // expected-note {{'X' previously declared here}}
case X // expected-error {{invalid redeclaration of 'X'}}
}

enum SR_10084_E_15 {
case Y // expected-note {{'Y' previously declared here}}
typealias Y = Int // expected-error {{invalid redeclaration of 'Y'}}
}

enum SR_10084_E_16 {
typealias Z = Int // expected-note {{'Z' previously declared here}}
case Z // expected-error {{invalid redeclaration of 'Z'}}
}