Skip to content

Commit 2944374

Browse files
authored
Merge pull request swiftlang#60364 from slavapestov/extension-of-inferred-type-alias
Sema: Improved check for failure to bind an extension
2 parents 7384ee2 + b1182eb commit 2944374

File tree

6 files changed

+70
-29
lines changed

6 files changed

+70
-29
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1922,7 +1922,7 @@ NOTE(extension_stored_property_fixit,none,
19221922
"Remove '=' to make %0 a computed property", (Identifier))
19231923
ERROR(extension_nongeneric_trailing_where,none,
19241924
"trailing 'where' clause for extension of non-generic type %0",
1925-
(Identifier))
1925+
(Type))
19261926
ERROR(extension_protocol_inheritance,none,
19271927
"extension of protocol %0 cannot have an inheritance clause",
19281928
(Identifier))
@@ -1938,6 +1938,8 @@ ERROR(invalid_nominal_extension,none,
19381938
(Type, Type))
19391939
NOTE(invalid_nominal_extension_rewrite,none,
19401940
"did you mean to extend %0 instead?", (Type))
1941+
ERROR(synthesized_nominal_extension,none,
1942+
"cannot extend synthesized type %0", (Type))
19411943

19421944
// Protocols
19431945
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/AST/NameLookup.cpp

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,7 +1044,8 @@ namespace {
10441044
/// the given parsed type representation.
10451045
static DirectlyReferencedTypeDecls
10461046
directReferencesForTypeRepr(Evaluator &evaluator, ASTContext &ctx,
1047-
TypeRepr *typeRepr, DeclContext *dc);
1047+
TypeRepr *typeRepr, DeclContext *dc,
1048+
bool allowUsableFromInline=false);
10481049

10491050
/// Retrieve the set of type declarations that are directly referenced from
10501051
/// the given type.
@@ -2325,7 +2326,8 @@ resolveTypeDeclsToNominal(Evaluator &evaluator,
23252326
static DirectlyReferencedTypeDecls
23262327
directReferencesForUnqualifiedTypeLookup(DeclNameRef name,
23272328
SourceLoc loc, DeclContext *dc,
2328-
LookupOuterResults lookupOuter) {
2329+
LookupOuterResults lookupOuter,
2330+
bool allowUsableFromInline=false) {
23292331
// In a protocol or protocol extension, the 'where' clause can refer to
23302332
// associated types without 'Self' qualification:
23312333
//
@@ -2359,6 +2361,9 @@ directReferencesForUnqualifiedTypeLookup(DeclNameRef name,
23592361
if (lookupOuter == LookupOuterResults::Included)
23602362
options |= UnqualifiedLookupFlags::IncludeOuterResults;
23612363

2364+
if (allowUsableFromInline)
2365+
options |= UnqualifiedLookupFlags::IncludeUsableFromInline;
2366+
23622367
auto &ctx = dc->getASTContext();
23632368
auto descriptor = UnqualifiedLookupDescriptor(name, dc, loc, options);
23642369
auto lookup = evaluateOrDefault(ctx.evaluator,
@@ -2388,7 +2393,8 @@ directReferencesForQualifiedTypeLookup(Evaluator &evaluator,
23882393
ASTContext &ctx,
23892394
ArrayRef<TypeDecl *> baseTypes,
23902395
DeclNameRef name,
2391-
DeclContext *dc) {
2396+
DeclContext *dc,
2397+
bool allowUsableFromInline=false) {
23922398
DirectlyReferencedTypeDecls result;
23932399
auto addResults = [&result](ArrayRef<ValueDecl *> found){
23942400
for (auto decl : found){
@@ -2403,6 +2409,9 @@ directReferencesForQualifiedTypeLookup(Evaluator &evaluator,
24032409
SmallVector<ValueDecl *, 4> members;
24042410
auto options = NL_RemoveNonVisible | NL_OnlyTypes;
24052411

2412+
if (allowUsableFromInline)
2413+
options |= NL_IncludeUsableFromInline;
2414+
24062415
// Look through the type declarations we were given, resolving them down
24072416
// to nominal type declarations, module declarations, and
24082417
SmallVector<ModuleDecl *, 2> moduleDecls;
@@ -2433,7 +2442,7 @@ directReferencesForQualifiedTypeLookup(Evaluator &evaluator,
24332442
static DirectlyReferencedTypeDecls
24342443
directReferencesForIdentTypeRepr(Evaluator &evaluator,
24352444
ASTContext &ctx, IdentTypeRepr *ident,
2436-
DeclContext *dc) {
2445+
DeclContext *dc, bool allowUsableFromInline) {
24372446
DirectlyReferencedTypeDecls current;
24382447

24392448
for (const auto &component : ident->getComponentRange()) {
@@ -2449,7 +2458,8 @@ directReferencesForIdentTypeRepr(Evaluator &evaluator,
24492458
directReferencesForUnqualifiedTypeLookup(component->getNameRef(),
24502459
component->getLoc(),
24512460
dc,
2452-
LookupOuterResults::Excluded);
2461+
LookupOuterResults::Excluded,
2462+
allowUsableFromInline);
24532463

24542464
// If we didn't find anything, fail now.
24552465
if (current.empty())
@@ -2461,7 +2471,8 @@ directReferencesForIdentTypeRepr(Evaluator &evaluator,
24612471
// For subsequent components, perform qualified name lookup.
24622472
current =
24632473
directReferencesForQualifiedTypeLookup(evaluator, ctx, current,
2464-
component->getNameRef(), dc);
2474+
component->getNameRef(), dc,
2475+
allowUsableFromInline);
24652476
if (current.empty())
24662477
return current;
24672478
}
@@ -2472,23 +2483,25 @@ directReferencesForIdentTypeRepr(Evaluator &evaluator,
24722483
static DirectlyReferencedTypeDecls
24732484
directReferencesForTypeRepr(Evaluator &evaluator,
24742485
ASTContext &ctx, TypeRepr *typeRepr,
2475-
DeclContext *dc) {
2486+
DeclContext *dc, bool allowUsableFromInline) {
24762487
switch (typeRepr->getKind()) {
24772488
case TypeReprKind::Array:
24782489
return {1, ctx.getArrayDecl()};
24792490

24802491
case TypeReprKind::Attributed: {
24812492
auto attributed = cast<AttributedTypeRepr>(typeRepr);
24822493
return directReferencesForTypeRepr(evaluator, ctx,
2483-
attributed->getTypeRepr(), dc);
2494+
attributed->getTypeRepr(), dc,
2495+
allowUsableFromInline);
24842496
}
24852497

24862498
case TypeReprKind::Composition: {
24872499
DirectlyReferencedTypeDecls result;
24882500
auto composition = cast<CompositionTypeRepr>(typeRepr);
24892501
for (auto component : composition->getTypes()) {
24902502
auto componentResult =
2491-
directReferencesForTypeRepr(evaluator, ctx, component, dc);
2503+
directReferencesForTypeRepr(evaluator, ctx, component, dc,
2504+
allowUsableFromInline);
24922505
result.insert(result.end(),
24932506
componentResult.begin(),
24942507
componentResult.end());
@@ -2500,7 +2513,8 @@ directReferencesForTypeRepr(Evaluator &evaluator,
25002513
case TypeReprKind::GenericIdent:
25012514
case TypeReprKind::SimpleIdent:
25022515
return directReferencesForIdentTypeRepr(evaluator, ctx,
2503-
cast<IdentTypeRepr>(typeRepr), dc);
2516+
cast<IdentTypeRepr>(typeRepr), dc,
2517+
allowUsableFromInline);
25042518

25052519
case TypeReprKind::Dictionary:
25062520
return { 1, ctx.getDictionaryDecl()};
@@ -2509,7 +2523,8 @@ directReferencesForTypeRepr(Evaluator &evaluator,
25092523
auto tupleRepr = cast<TupleTypeRepr>(typeRepr);
25102524
if (tupleRepr->isParenType()) {
25112525
return directReferencesForTypeRepr(evaluator, ctx,
2512-
tupleRepr->getElementType(0), dc);
2526+
tupleRepr->getElementType(0), dc,
2527+
allowUsableFromInline);
25132528
}
25142529
return { };
25152530
}
@@ -2715,7 +2730,8 @@ ExtendedNominalRequest::evaluate(Evaluator &evaluator,
27152730

27162731
ASTContext &ctx = ext->getASTContext();
27172732
DirectlyReferencedTypeDecls referenced =
2718-
directReferencesForTypeRepr(evaluator, ctx, typeRepr, ext->getParent());
2733+
directReferencesForTypeRepr(evaluator, ctx, typeRepr, ext->getParent(),
2734+
ext->isInSpecializeExtensionContext());
27192735

27202736
// Resolve those type declarations to nominal type declarations.
27212737
SmallVector<ModuleDecl *, 2> modulesFound;

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)