Skip to content

Commit b1182eb

Browse files
committed
Sema: Improved check for failure to bind an extension
Calling computeExtendedNominal() won't catch the case where the extended type did not exist at extension binding time but then appeared later, like an inferred associated type witness for example.
1 parent 2338c43 commit b1182eb

File tree

5 files changed

+42
-17
lines changed

5 files changed

+42
-17
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1919,7 +1919,7 @@ NOTE(extension_stored_property_fixit,none,
19191919
"Remove '=' to make %0 a computed property", (Identifier))
19201920
ERROR(extension_nongeneric_trailing_where,none,
19211921
"trailing 'where' clause for extension of non-generic type %0",
1922-
(Identifier))
1922+
(Type))
19231923
ERROR(extension_protocol_inheritance,none,
19241924
"extension of protocol %0 cannot have an inheritance clause",
19251925
(Identifier))
@@ -1935,6 +1935,8 @@ ERROR(invalid_nominal_extension,none,
19351935
(Type, Type))
19361936
NOTE(invalid_nominal_extension_rewrite,none,
19371937
"did you mean to extend %0 instead?", (Type))
1938+
ERROR(synthesized_nominal_extension,none,
1939+
"cannot extend synthesized type %0", (Type))
19381940

19391941
// Protocols
19401942
ERROR(type_does_not_conform,none,

lib/AST/ASTVerifier.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2842,6 +2842,11 @@ class Verifier : public ASTWalker {
28422842
verifyConformance(ext, conformance);
28432843
}
28442844

2845+
// Make sure extension binding succeeded.
2846+
if (!ext->hasBeenBound()) {
2847+
Out << "ExtensionDecl was not bound\n";
2848+
abort();
2849+
}
28452850
verifyCheckedBase(ext);
28462851
}
28472852

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3037,11 +3037,11 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
30373037
// Produce any diagnostics for the extended type.
30383038
auto extType = ED->getExtendedType();
30393039

3040-
auto nominal = ED->computeExtendedNominal();
3040+
auto *nominal = ED->getExtendedNominal();
30413041
if (nominal == nullptr) {
30423042
const bool wasAlreadyInvalid = ED->isInvalid();
30433043
ED->setInvalid();
3044-
if (extType && !extType->hasError() && extType->getAnyNominal()) {
3044+
if (!extType->hasError() && extType->getAnyNominal()) {
30453045
// If we've got here, then we have some kind of extension of a prima
30463046
// fascie non-nominal type. This can come up when we're projecting
30473047
// typealiases out of bound generic types.
@@ -3051,22 +3051,30 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
30513051
//
30523052
// Offer to rewrite it to the underlying nominal type.
30533053
auto canExtType = extType->getCanonicalType();
3054-
ED->diagnose(diag::invalid_nominal_extension, extType, canExtType)
3055-
.highlight(ED->getExtendedTypeRepr()->getSourceRange());
3056-
ED->diagnose(diag::invalid_nominal_extension_rewrite, canExtType)
3057-
.fixItReplace(ED->getExtendedTypeRepr()->getSourceRange(),
3058-
canExtType->getString());
3059-
} else if (!wasAlreadyInvalid) {
3054+
if (canExtType.getPointer() != extType.getPointer()) {
3055+
ED->diagnose(diag::invalid_nominal_extension, extType, canExtType)
3056+
.highlight(ED->getExtendedTypeRepr()->getSourceRange());
3057+
ED->diagnose(diag::invalid_nominal_extension_rewrite, canExtType)
3058+
.fixItReplace(ED->getExtendedTypeRepr()->getSourceRange(),
3059+
canExtType->getString());
3060+
return;
3061+
}
3062+
}
3063+
3064+
if (!wasAlreadyInvalid) {
30603065
// If nothing else applies, fall back to a generic diagnostic.
30613066
ED->diagnose(diag::non_nominal_extension, extType);
30623067
}
3068+
30633069
return;
30643070
}
30653071

3066-
// Produce any diagnostics for the generic signature.
3067-
(void) ED->getGenericSignature();
3072+
// Record a dependency from TypeCheckSourceFileRequest to
3073+
// ExtendedNominalRequest, since the call to getExtendedNominal()
3074+
// above doesn't record a dependency when reading a cached value.
3075+
ED->computeExtendedNominal();
30683076

3069-
if (extType && !extType->hasError()) {
3077+
if (!extType->hasError()) {
30703078
// The first condition catches syntactic forms like
30713079
// protocol A & B { ... } // may be protocols or typealiases
30723080
// The second condition also looks through typealiases and catches
@@ -3082,9 +3090,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
30823090
extTypeNominal && extTypeNominal != nominal;
30833091
if (isa<CompositionTypeRepr>(extTypeRepr)
30843092
|| firstNominalIsNotMostSpecific) {
3085-
auto firstNominalType = nominal->getDeclaredType();
30863093
auto diag = ED->diagnose(diag::composition_in_extended_type,
3087-
firstNominalType);
3094+
nominal->getDeclaredType());
30883095
diag.highlight(extTypeRepr->getSourceRange());
30893096
if (firstNominalIsNotMostSpecific) {
30903097
diag.flush();
@@ -3095,19 +3102,22 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
30953102
mostSpecificProtocol->getString());
30963103
} else {
30973104
diag.fixItReplace(extTypeRepr->getSourceRange(),
3098-
firstNominalType->getString());
3105+
nominal->getDeclaredType()->getString());
30993106
}
31003107
}
31013108
}
31023109

3110+
// Produce any diagnostics for the generic signature.
3111+
(void) ED->getGenericSignature();
3112+
31033113
checkInheritanceClause(ED);
31043114

31053115
// Only generic and protocol types are permitted to have
31063116
// trailing where clauses.
31073117
if (auto trailingWhereClause = ED->getTrailingWhereClause()) {
31083118
if (!ED->getGenericParams() && !ED->isInvalid()) {
31093119
ED->diagnose(diag::extension_nongeneric_trailing_where,
3110-
nominal->getName())
3120+
nominal->getDeclaredType())
31113121
.highlight(trailingWhereClause->getSourceRange());
31123122
}
31133123
}

test/AutoDiff/Sema/DerivedConformances/struct_differentiable_member_types.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,9 @@ protocol Protocol {
1212
struct Struct: Differentiable {
1313
var weight: Float
1414
}
15+
16+
// Extending a synthesized type doesn't actually work because of circularity issues.
17+
// It just wasn't diagnosed before.
18+
1519
extension Struct.TangentVector: Protocol {}
20+
// expected-error@-1 {{non-nominal type 'Struct.TangentVector' cannot be extended}}

test/decl/ext/extensions.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ var c = C()
104104
var x = c.p1
105105
c.p1 = 1
106106

107+
// Reject extension of nominal type via inferred associated type
107108
protocol P3 {
108109
associatedtype Assoc
109110
func foo() -> Assoc
@@ -113,6 +114,8 @@ struct X3 : P3 {
113114
}
114115

115116
extension X3.Assoc {
117+
// expected-error@-1 {{extension of type 'X3.Assoc' (aka 'Int') must be declared as an extension of 'Int'}}
118+
// expected-note@-2 {{did you mean to extend 'Int' instead?}}
116119
}
117120

118121
extension X3 {
@@ -331,7 +334,7 @@ extension ImposeClassReq2 {
331334
}
332335
}
333336

334-
// Reject extension of nominal type via parameterized typealias
337+
// Reject extension of nominal type via typealias with dependent underlying type
335338

336339
struct Nest<Egg> { typealias Contents = Egg }
337340
struct Tree {

0 commit comments

Comments
 (0)