Skip to content

Commit 79bd38b

Browse files
authored
Merge pull request #24090 from AnthonyLatsis/synth-init-conflict-diag
Sema: Improve redeclaration error for synthesized inits
2 parents 1060d1a + e229fbd commit 79bd38b

File tree

3 files changed

+43
-3
lines changed

3 files changed

+43
-3
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,9 @@ ERROR(reserved_member_name,none,
658658
" 'foo.%1' expression", (DeclName, StringRef))
659659

660660
ERROR(invalid_redecl,none,"invalid redeclaration of %0", (DeclName))
661+
ERROR(invalid_redecl_init,none,
662+
"invalid redeclaration of synthesized %select{|memberwise }1%0",
663+
(DeclName, bool))
661664
WARNING(invalid_redecl_swift5_warning,none,
662665
"redeclaration of %0 is deprecated and will be an error in Swift 5",
663666
(DeclName))

lib/Sema/TypeCheckDecl.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -891,8 +891,21 @@ static void checkRedeclaration(TypeChecker &tc, ValueDecl *current) {
891891
current->getFullName());
892892
tc.diagnose(other, diag::invalid_redecl_prev, other->getFullName());
893893
} else {
894-
tc.diagnose(current, diag::invalid_redecl, current->getFullName());
895-
tc.diagnose(other, diag::invalid_redecl_prev, other->getFullName());
894+
const auto *otherInit = dyn_cast<ConstructorDecl>(other);
895+
// Provide a better description for implicit initializers.
896+
if (otherInit && otherInit->isImplicit()) {
897+
// Skip conflicts with inherited initializers, which only happen
898+
// when the current declaration is within an extension. The override
899+
// checker should have already taken care of emitting a more
900+
// productive diagnostic.
901+
if (!other->getOverriddenDecl())
902+
tc.diagnose(current, diag::invalid_redecl_init,
903+
current->getFullName(),
904+
otherInit->isMemberwiseInitializer());
905+
} else {
906+
tc.diagnose(current, diag::invalid_redecl, current->getFullName());
907+
tc.diagnose(other, diag::invalid_redecl_prev, other->getFullName());
908+
}
896909
markInvalid();
897910
}
898911

test/decl/init/basic_init.swift

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift
1+
// RUN: %target-typecheck-verify-swift -enable-objc-interop -disable-objc-attr-requires-foundation-module
22

33
class Foo {
44
func bar(_: bar) {} // expected-error{{use of undeclared type 'bar'}}
@@ -13,8 +13,32 @@ class C {
1313
typealias t = t // expected-error {{type alias 't' references itself}}
1414
// expected-note@-1{{type declared here}}
1515

16+
extension Foo {
17+
convenience init() {} // expected-error{{invalid redeclaration of synthesized 'init()'}}
18+
}
1619

20+
class InitClass {
21+
init(arg: Bool) {} // expected-note{{add '@objc' to make this declaration overridable}}
22+
@objc init(baz: Int) {} // expected-note{{overridden declaration is here}}
23+
@objc dynamic init(bar: Int) {}
24+
}
25+
class InitSubclass: InitClass {}
26+
// expected-note@-1 {{'init(bar:)' previously overridden here}}
27+
// expected-note@-2 {{'init(baz:)' previously overridden here}}
28+
extension InitSubclass {
29+
convenience init(arg: Bool) {} // expected-error{{overriding non-@objc declarations from extensions is not supported}}
30+
convenience override init(baz: Int) {}
31+
// expected-error@-1 {{cannot override a non-dynamic class declaration from an extension}}
32+
// expected-error@-2 {{'init(baz:)' has already been overridden}}
33+
convenience override init(bar: Int) {} // expected-error{{'init(bar:)' has already been overridden}}
34+
}
1735

36+
struct InitStruct {
37+
let foo: Int
38+
}
39+
extension InitStruct {
40+
init(foo: Int) {} // expected-error{{invalid redeclaration of synthesized memberwise 'init(foo:)'}}
41+
}
1842

1943
// <rdar://problem/17564699> QoI: Structs should get convenience initializers
2044
struct MyStruct {

0 commit comments

Comments
 (0)