Skip to content
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
4 changes: 3 additions & 1 deletion include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -1919,7 +1919,7 @@ NOTE(extension_stored_property_fixit,none,
"Remove '=' to make %0 a computed property", (Identifier))
ERROR(extension_nongeneric_trailing_where,none,
"trailing 'where' clause for extension of non-generic type %0",
(Identifier))
(Type))
ERROR(extension_protocol_inheritance,none,
"extension of protocol %0 cannot have an inheritance clause",
(Identifier))
Expand All @@ -1935,6 +1935,8 @@ ERROR(invalid_nominal_extension,none,
(Type, Type))
NOTE(invalid_nominal_extension_rewrite,none,
"did you mean to extend %0 instead?", (Type))
ERROR(synthesized_nominal_extension,none,
"cannot extend synthesized type %0", (Type))

// Protocols
ERROR(type_does_not_conform,none,
Expand Down
5 changes: 5 additions & 0 deletions lib/AST/ASTVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2842,6 +2842,11 @@ class Verifier : public ASTWalker {
verifyConformance(ext, conformance);
}

// Make sure extension binding succeeded.
if (!ext->hasBeenBound()) {
Out << "ExtensionDecl was not bound\n";
abort();
}
verifyCheckedBase(ext);
}

Expand Down
40 changes: 28 additions & 12 deletions lib/AST/NameLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1044,7 +1044,8 @@ namespace {
/// the given parsed type representation.
static DirectlyReferencedTypeDecls
directReferencesForTypeRepr(Evaluator &evaluator, ASTContext &ctx,
TypeRepr *typeRepr, DeclContext *dc);
TypeRepr *typeRepr, DeclContext *dc,
bool allowUsableFromInline=false);

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

if (allowUsableFromInline)
options |= UnqualifiedLookupFlags::IncludeUsableFromInline;

auto &ctx = dc->getASTContext();
auto descriptor = UnqualifiedLookupDescriptor(name, dc, loc, options);
auto lookup = evaluateOrDefault(ctx.evaluator,
Expand Down Expand Up @@ -2388,7 +2393,8 @@ directReferencesForQualifiedTypeLookup(Evaluator &evaluator,
ASTContext &ctx,
ArrayRef<TypeDecl *> baseTypes,
DeclNameRef name,
DeclContext *dc) {
DeclContext *dc,
bool allowUsableFromInline=false) {
DirectlyReferencedTypeDecls result;
auto addResults = [&result](ArrayRef<ValueDecl *> found){
for (auto decl : found){
Expand All @@ -2403,6 +2409,9 @@ directReferencesForQualifiedTypeLookup(Evaluator &evaluator,
SmallVector<ValueDecl *, 4> members;
auto options = NL_RemoveNonVisible | NL_OnlyTypes;

if (allowUsableFromInline)
options |= NL_IncludeUsableFromInline;

// Look through the type declarations we were given, resolving them down
// to nominal type declarations, module declarations, and
SmallVector<ModuleDecl *, 2> moduleDecls;
Expand Down Expand Up @@ -2433,7 +2442,7 @@ directReferencesForQualifiedTypeLookup(Evaluator &evaluator,
static DirectlyReferencedTypeDecls
directReferencesForIdentTypeRepr(Evaluator &evaluator,
ASTContext &ctx, IdentTypeRepr *ident,
DeclContext *dc) {
DeclContext *dc, bool allowUsableFromInline) {
DirectlyReferencedTypeDecls current;

for (const auto &component : ident->getComponentRange()) {
Expand All @@ -2449,7 +2458,8 @@ directReferencesForIdentTypeRepr(Evaluator &evaluator,
directReferencesForUnqualifiedTypeLookup(component->getNameRef(),
component->getLoc(),
dc,
LookupOuterResults::Excluded);
LookupOuterResults::Excluded,
allowUsableFromInline);

// If we didn't find anything, fail now.
if (current.empty())
Expand All @@ -2461,7 +2471,8 @@ directReferencesForIdentTypeRepr(Evaluator &evaluator,
// For subsequent components, perform qualified name lookup.
current =
directReferencesForQualifiedTypeLookup(evaluator, ctx, current,
component->getNameRef(), dc);
component->getNameRef(), dc,
allowUsableFromInline);
if (current.empty())
return current;
}
Expand All @@ -2472,23 +2483,25 @@ directReferencesForIdentTypeRepr(Evaluator &evaluator,
static DirectlyReferencedTypeDecls
directReferencesForTypeRepr(Evaluator &evaluator,
ASTContext &ctx, TypeRepr *typeRepr,
DeclContext *dc) {
DeclContext *dc, bool allowUsableFromInline) {
switch (typeRepr->getKind()) {
case TypeReprKind::Array:
return {1, ctx.getArrayDecl()};

case TypeReprKind::Attributed: {
auto attributed = cast<AttributedTypeRepr>(typeRepr);
return directReferencesForTypeRepr(evaluator, ctx,
attributed->getTypeRepr(), dc);
attributed->getTypeRepr(), dc,
allowUsableFromInline);
}

case TypeReprKind::Composition: {
DirectlyReferencedTypeDecls result;
auto composition = cast<CompositionTypeRepr>(typeRepr);
for (auto component : composition->getTypes()) {
auto componentResult =
directReferencesForTypeRepr(evaluator, ctx, component, dc);
directReferencesForTypeRepr(evaluator, ctx, component, dc,
allowUsableFromInline);
result.insert(result.end(),
componentResult.begin(),
componentResult.end());
Expand All @@ -2500,7 +2513,8 @@ directReferencesForTypeRepr(Evaluator &evaluator,
case TypeReprKind::GenericIdent:
case TypeReprKind::SimpleIdent:
return directReferencesForIdentTypeRepr(evaluator, ctx,
cast<IdentTypeRepr>(typeRepr), dc);
cast<IdentTypeRepr>(typeRepr), dc,
allowUsableFromInline);

case TypeReprKind::Dictionary:
return { 1, ctx.getDictionaryDecl()};
Expand All @@ -2509,7 +2523,8 @@ directReferencesForTypeRepr(Evaluator &evaluator,
auto tupleRepr = cast<TupleTypeRepr>(typeRepr);
if (tupleRepr->isParenType()) {
return directReferencesForTypeRepr(evaluator, ctx,
tupleRepr->getElementType(0), dc);
tupleRepr->getElementType(0), dc,
allowUsableFromInline);
}
return { };
}
Expand Down Expand Up @@ -2715,7 +2730,8 @@ ExtendedNominalRequest::evaluate(Evaluator &evaluator,

ASTContext &ctx = ext->getASTContext();
DirectlyReferencedTypeDecls referenced =
directReferencesForTypeRepr(evaluator, ctx, typeRepr, ext->getParent());
directReferencesForTypeRepr(evaluator, ctx, typeRepr, ext->getParent(),
ext->isInSpecializeExtensionContext());

// Resolve those type declarations to nominal type declarations.
SmallVector<ModuleDecl *, 2> modulesFound;
Expand Down
40 changes: 25 additions & 15 deletions lib/Sema/TypeCheckDeclPrimary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3037,11 +3037,11 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
// Produce any diagnostics for the extended type.
auto extType = ED->getExtendedType();

auto nominal = ED->computeExtendedNominal();
auto *nominal = ED->getExtendedNominal();
if (nominal == nullptr) {
const bool wasAlreadyInvalid = ED->isInvalid();
ED->setInvalid();
if (extType && !extType->hasError() && extType->getAnyNominal()) {
if (!extType->hasError() && extType->getAnyNominal()) {
// If we've got here, then we have some kind of extension of a prima
// fascie non-nominal type. This can come up when we're projecting
// typealiases out of bound generic types.
Expand All @@ -3051,22 +3051,30 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
//
// Offer to rewrite it to the underlying nominal type.
auto canExtType = extType->getCanonicalType();
ED->diagnose(diag::invalid_nominal_extension, extType, canExtType)
.highlight(ED->getExtendedTypeRepr()->getSourceRange());
ED->diagnose(diag::invalid_nominal_extension_rewrite, canExtType)
.fixItReplace(ED->getExtendedTypeRepr()->getSourceRange(),
canExtType->getString());
} else if (!wasAlreadyInvalid) {
if (canExtType.getPointer() != extType.getPointer()) {
ED->diagnose(diag::invalid_nominal_extension, extType, canExtType)
.highlight(ED->getExtendedTypeRepr()->getSourceRange());
ED->diagnose(diag::invalid_nominal_extension_rewrite, canExtType)
.fixItReplace(ED->getExtendedTypeRepr()->getSourceRange(),
canExtType->getString());
return;
}
}

if (!wasAlreadyInvalid) {
// If nothing else applies, fall back to a generic diagnostic.
ED->diagnose(diag::non_nominal_extension, extType);
}

return;
}

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

if (extType && !extType->hasError()) {
if (!extType->hasError()) {
// The first condition catches syntactic forms like
// protocol A & B { ... } // may be protocols or typealiases
// The second condition also looks through typealiases and catches
Expand All @@ -3082,9 +3090,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
extTypeNominal && extTypeNominal != nominal;
if (isa<CompositionTypeRepr>(extTypeRepr)
|| firstNominalIsNotMostSpecific) {
auto firstNominalType = nominal->getDeclaredType();
auto diag = ED->diagnose(diag::composition_in_extended_type,
firstNominalType);
nominal->getDeclaredType());
diag.highlight(extTypeRepr->getSourceRange());
if (firstNominalIsNotMostSpecific) {
diag.flush();
Expand All @@ -3095,19 +3102,22 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
mostSpecificProtocol->getString());
} else {
diag.fixItReplace(extTypeRepr->getSourceRange(),
firstNominalType->getString());
nominal->getDeclaredType()->getString());
}
}
}

// Produce any diagnostics for the generic signature.
(void) ED->getGenericSignature();

checkInheritanceClause(ED);

// Only generic and protocol types are permitted to have
// trailing where clauses.
if (auto trailingWhereClause = ED->getTrailingWhereClause()) {
if (!ED->getGenericParams() && !ED->isInvalid()) {
ED->diagnose(diag::extension_nongeneric_trailing_where,
nominal->getName())
nominal->getDeclaredType())
.highlight(trailingWhereClause->getSourceRange());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,9 @@ protocol Protocol {
struct Struct: Differentiable {
var weight: Float
}

// Extending a synthesized type doesn't actually work because of circularity issues.
// It just wasn't diagnosed before.

extension Struct.TangentVector: Protocol {}
// expected-error@-1 {{non-nominal type 'Struct.TangentVector' cannot be extended}}
5 changes: 4 additions & 1 deletion test/decl/ext/extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ var c = C()
var x = c.p1
c.p1 = 1

// Reject extension of nominal type via inferred associated type
protocol P3 {
associatedtype Assoc
func foo() -> Assoc
Expand All @@ -113,6 +114,8 @@ struct X3 : P3 {
}

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

extension X3 {
Expand Down Expand Up @@ -331,7 +334,7 @@ extension ImposeClassReq2 {
}
}

// Reject extension of nominal type via parameterized typealias
// Reject extension of nominal type via typealias with dependent underlying type

struct Nest<Egg> { typealias Contents = Egg }
struct Tree {
Expand Down