Skip to content

Commit 4e445a8

Browse files
committed
Improve diagnostics when trying to extend existential type
1 parent a159636 commit 4e445a8

File tree

3 files changed

+47
-25
lines changed

3 files changed

+47
-25
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1933,6 +1933,10 @@ NOTE(objc_generic_extension_using_type_parameter_here,none,
19331933
"generic parameter used here", ())
19341934
NOTE(objc_generic_extension_using_type_parameter_try_objc,none,
19351935
"add '@objc' to allow uses of 'self' within the function body", ())
1936+
ERROR(unsupported_existential_extension,none,
1937+
"extension of type %0 is not supported", (Type))
1938+
NOTE(unsupported_existential_extension_rewrite,none,
1939+
"did you mean to extend %0 instead?", (Type))
19361940
ERROR(invalid_nominal_extension,none,
19371941
"extension of type %0 must be declared as an extension of %1",
19381942
(Type, Type))

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3042,15 +3042,24 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
30423042
const bool wasAlreadyInvalid = ED->isInvalid();
30433043
ED->setInvalid();
30443044
if (!extType->hasError() && extType->getAnyNominal()) {
3045+
auto canExtType = extType->getCanonicalType();
3046+
if (auto existential = canExtType->getAs<ExistentialType>()) {
3047+
ED->diagnose(diag::unsupported_existential_extension, existential)
3048+
.highlight(ED->getExtendedTypeRepr()->getSourceRange());
3049+
ED->diagnose(diag::unsupported_existential_extension_rewrite, existential->getConstraintType())
3050+
.fixItReplace(ED->getExtendedTypeRepr()->getSourceRange(),
3051+
canExtType->getString());
3052+
return;
3053+
}
3054+
30453055
// If we've got here, then we have some kind of extension of a prima
3046-
// fascie non-nominal type. This can come up when we're projecting
3056+
// facie non-nominal type. This can come up when we're projecting
30473057
// typealiases out of bound generic types.
30483058
//
30493059
// struct Array<T> { typealias Indices = Range<Int> }
30503060
// extension Array.Indices.Bound {}
30513061
//
30523062
// Offer to rewrite it to the underlying nominal type.
3053-
auto canExtType = extType->getCanonicalType();
30543063
if (canExtType.getPointer() != extType.getPointer()) {
30553064
ED->diagnose(diag::invalid_nominal_extension, extType, canExtType)
30563065
.highlight(ED->getExtendedTypeRepr()->getSourceRange());

test/decl/ext/extensions.swift

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -104,24 +104,51 @@ var c = C()
104104
var x = c.p1
105105
c.p1 = 1
106106

107+
// Reject extension of existential type
108+
109+
protocol P3 {}
110+
111+
extension any P3 {
112+
// expected-error@-1 {{extension of type 'any P3' is not supported}}
113+
// expected-note@-2 {{did you mean to extend 'P3' instead?}}
114+
}
115+
107116
// Reject extension of nominal type via inferred associated type
108-
protocol P3 {
117+
protocol P4 {
109118
associatedtype Assoc
110119
func foo() -> Assoc
111120
}
112121

113-
struct X3 : P3 {
122+
struct X4 : P4 {
114123
}
115124

116-
extension X3.Assoc {
117-
// expected-error@-1 {{extension of type 'X3.Assoc' (aka 'Int') must be declared as an extension of 'Int'}}
125+
extension X4.Assoc {
126+
// expected-error@-1 {{extension of type 'X4.Assoc' (aka 'Int') must be declared as an extension of 'Int'}}
118127
// expected-note@-2 {{did you mean to extend 'Int' instead?}}
119128
}
120129

121-
extension X3 {
130+
extension X4 {
122131
func foo() -> Int { return 0 }
123132
}
124133

134+
// Reject extension of nominal type via typealias with dependent underlying type
135+
136+
struct Nest<Egg> { typealias Contents = Egg }
137+
struct Tree {
138+
typealias LimbContent = Nest<Int>
139+
typealias BoughPayload = Nest<Nest<Int>>
140+
}
141+
142+
extension Tree.LimbContent.Contents {
143+
// expected-error@-1 {{extension of type 'Tree.LimbContent.Contents' (aka 'Int') must be declared as an extension of 'Int'}}
144+
// expected-note@-2 {{did you mean to extend 'Int' instead?}} {{11-36=Int}}
145+
}
146+
147+
extension Tree.BoughPayload.Contents {
148+
// expected-error@-1 {{extension of type 'Tree.BoughPayload.Contents' (aka 'Nest<Int>') must be declared as an extension of 'Nest<Int>'}}
149+
// expected-note@-2 {{did you mean to extend 'Nest<Int>' instead?}} {{11-37=Nest<Int>}}
150+
}
151+
125152
// Make sure the test case from https://bugs.swift.org/browse/SR-3847 doesn't
126153
// cause problems when the later extension is incorrectly nested inside another
127154
// declaration.
@@ -334,24 +361,6 @@ extension ImposeClassReq2 {
334361
}
335362
}
336363

337-
// Reject extension of nominal type via typealias with dependent underlying type
338-
339-
struct Nest<Egg> { typealias Contents = Egg }
340-
struct Tree {
341-
typealias LimbContent = Nest<Int>
342-
typealias BoughPayload = Nest<Nest<Int>>
343-
}
344-
345-
extension Tree.LimbContent.Contents {
346-
// expected-error@-1 {{extension of type 'Tree.LimbContent.Contents' (aka 'Int') must be declared as an extension of 'Int'}}
347-
// expected-note@-2 {{did you mean to extend 'Int' instead?}} {{11-36=Int}}
348-
}
349-
350-
extension Tree.BoughPayload.Contents {
351-
// expected-error@-1 {{extension of type 'Tree.BoughPayload.Contents' (aka 'Nest<Int>') must be declared as an extension of 'Nest<Int>'}}
352-
// expected-note@-2 {{did you mean to extend 'Nest<Int>' instead?}}
353-
}
354-
355364
// SR-10466 Check 'where' clause when referencing type defined inside extension
356365
struct SR_10466<T> {
357366
var a : A // expected-error {{'SR_10466<T>.A' (aka 'Int') requires the types 'T' and 'Never' be equivalent}}

0 commit comments

Comments
 (0)