Skip to content

[Name lookup] Introduce a request for "extended nominal type decl" #18425

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 6, 2018
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
36 changes: 34 additions & 2 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1640,7 +1640,10 @@ class ExtensionDecl final : public GenericContext, public Decl,

/// The type being extended.
TypeLoc ExtendedType;


/// The nominal type being extended.
NominalTypeDecl *ExtendedNominal = nullptr;

MutableArrayRef<TypeLoc> Inherited;

/// \brief The next extension in the linked list of extensions.
Expand Down Expand Up @@ -1677,6 +1680,7 @@ class ExtensionDecl final : public GenericContext, public Decl,
/// Slow path for \c takeConformanceLoader().
std::pair<LazyMemberLoader *, uint64_t> takeConformanceLoaderSlow();

friend class ExtendedNominalRequest;
public:
using Decl::getASTContext;

Expand All @@ -1698,8 +1702,19 @@ class ExtensionDecl final : public GenericContext, public Decl,
void setBraces(SourceRange braces) { Braces = braces; }

/// Retrieve the type being extended.
///
/// Only use this entry point when the complete type, as spelled in the source,
/// is required. For most clients, \c getExtendedNominal(), which provides
/// only the \c NominalTypeDecl, will suffice.
Type getExtendedType() const { return ExtendedType.getType(); }

/// Retrieve the nominal type declaration that is being extended.
NominalTypeDecl *getExtendedNominal() const;

/// Determine whether this extension has already been bound to a nominal
/// type declaration.
bool alreadyBoundToNominal() const { return NextExtension.getInt(); }

/// Retrieve the extended type location.
TypeLoc &getExtendedTypeLoc() { return ExtendedType; }

Expand Down Expand Up @@ -3615,6 +3630,23 @@ class ClassDecl final : public NominalTypeDecl {
/// might have implicitly @objc members, but will never itself be @objc.
ObjCClassKind checkObjCAncestry() const;

/// \brief Whether this class or its superclasses has some form of generic
/// context.
///
/// For example, given
///
/// class A<X> {}
/// class B : A<Int> {}
/// struct C<T> {
/// struct Inner {}
/// }
/// class D {}
/// class E: D {}
///
/// Calling hasGenericAncestry() on `B` returns `A<Int>`, on `C<T>.Inner`
/// returns `C<T>.Inner`, but on `E` it returns null.
ClassDecl *getGenericAncestor() const;

/// The type of metaclass to use for a class.
enum class MetaclassKind : uint8_t {
ObjC,
Expand Down Expand Up @@ -3679,7 +3711,7 @@ class ClassDecl final : public NominalTypeDecl {
///
/// This is true of imported Objective-C classes.
bool usesObjCGenericsModel() const {
return isObjC() && hasClangNode() && isGenericContext();
return hasClangNode() && isGenericContext() && isObjC();
}

/// True if the class is known to be implemented in Swift.
Expand Down
3 changes: 2 additions & 1 deletion include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -1490,7 +1490,8 @@ ERROR(extension_specialization,none,
ERROR(extension_stored_property,none,
"extensions must not contain stored properties", ())
ERROR(extension_nongeneric_trailing_where,none,
"trailing 'where' clause for extension of non-generic type %0", (Type))
"trailing 'where' clause for extension of non-generic type %0",
(DeclName))
ERROR(extension_protocol_inheritance,none,
"extension of protocol %0 cannot have an inheritance clause", (Type))
ERROR(objc_generic_extension_using_type_parameter,none,
Expand Down
27 changes: 27 additions & 0 deletions include/swift/AST/NameLookupRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,33 @@ class SuperclassDeclRequest :
void noteCycleStep(DiagnosticEngine &diags) const;
};

/// Request the nominal declaration extended by a given extension declaration.
class ExtendedNominalRequest :
public SimpleRequest<ExtendedNominalRequest,
CacheKind::SeparatelyCached,
NominalTypeDecl *,
ExtensionDecl *> {
public:
using SimpleRequest::SimpleRequest;

private:
friend class SimpleRequest;

// Evaluation.
NominalTypeDecl *evaluate(Evaluator &evaluator, ExtensionDecl *ext) const;

public:
// Separate caching.
bool isCached() const { return true; }
Optional<NominalTypeDecl *> getCachedResult() const;
void cacheResult(NominalTypeDecl *value) const;

// Cycle handling
NominalTypeDecl *breakCycle() const { return nullptr; }
void diagnoseCycle(DiagnosticEngine &diags) const;
void noteCycleStep(DiagnosticEngine &diags) const;
};

/// The zone number for name-lookup requests.
#define SWIFT_NAME_LOOKUP_REQUESTS_TYPEID_ZONE 9

Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/NameLookupTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@
SWIFT_TYPEID(InheritedDeclsReferencedRequest)
SWIFT_TYPEID(UnderlyingTypeDeclsReferencedRequest)
SWIFT_TYPEID(SuperclassDeclRequest)
SWIFT_TYPEID(ExtendedNominalRequest)
17 changes: 0 additions & 17 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -806,23 +806,6 @@ class alignas(1 << TypeAlignInBits) TypeBase {
Type getSuperclassForDecl(const ClassDecl *classDecl,
bool useArchetypes = true);

/// \brief Whether this type or its superclasses has some form of generic
/// context.
///
/// For example, given
///
/// class A<X> {}
/// class B : A<Int> {}
/// struct C<T> {
/// struct Inner {}
/// }
/// class D {}
/// class E: D {}
///
/// Calling hasGenericAncestry() on `B` returns `A<Int>`, on `C<T>.Inner`
/// returns `C<T>.Inner`, but on `E` it returns null.
Type getGenericAncestor();

/// \brief True if this type is the superclass of another type, or a generic
/// type that could be bound to the superclass.
///
Expand Down
7 changes: 2 additions & 5 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1295,11 +1295,8 @@ void swift::printContext(raw_ostream &os, DeclContext *dc) {
break;

case DeclContextKind::ExtensionDecl:
if (auto extendedTy = cast<ExtensionDecl>(dc)->getExtendedType()) {
if (auto nominal = extendedTy->getAnyNominal()) {
printName(os, nominal->getName());
break;
}
if (auto extendedNominal = cast<ExtensionDecl>(dc)->getExtendedNominal()) {
printName(os, extendedNominal->getName());
}
os << " extension";
break;
Expand Down
6 changes: 2 additions & 4 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1402,13 +1402,11 @@ void ASTMangler::appendContext(const DeclContext *ctx) {

case DeclContextKind::ExtensionDecl: {
auto ExtD = cast<ExtensionDecl>(ctx);
auto ExtTy = ExtD->getExtendedType();
auto decl = ExtD->getExtendedNominal();
// Recover from erroneous extension.
if (ExtTy.isNull() || ExtTy->hasError())
if (!decl)
return appendContext(ExtD->getDeclContext());

auto decl = ExtTy->getAnyNominal();
assert(decl && "extension of non-nominal type?");
if (!ExtD->isEquivalentToExtendedContext()) {
// Mangle the extension if:
// - the extension is defined in a different module from the original
Expand Down
3 changes: 1 addition & 2 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1817,8 +1817,7 @@ void PrintAST::printExtension(ExtensionDecl *decl) {
recordDeclLoc(decl, [&]{
// We cannot extend sugared types.
Type extendedType = decl->getExtendedType();
NominalTypeDecl *nominal = extendedType ? extendedType->getAnyNominal() : nullptr;
if (!nominal) {
if (!extendedType || !extendedType->getAnyNominal()) {
// Fallback to TypeRepr.
printTypeLoc(decl->getExtendedTypeLoc());
return;
Expand Down
9 changes: 2 additions & 7 deletions lib/AST/ASTScope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1760,11 +1760,6 @@ SmallVector<ValueDecl *, 4> ASTScope::getLocalBindings() const {
if (range.Start == range.End)
break;

// Bind this extension, if we haven't done so already.
if (!extension->getExtendedType())
if (auto resolver = extension->getASTContext().getLazyResolver())
resolver->bindExtension(extension);

// If there are generic parameters, add them.
for (auto genericParams = extension->getGenericParams();
genericParams;
Expand Down Expand Up @@ -1915,8 +1910,8 @@ void ASTScope::print(llvm::raw_ostream &out, unsigned level,
out << " extension of '";
if (auto typeRepr = extension->getExtendedTypeLoc().getTypeRepr())
typeRepr->print(out);
else
extension->getExtendedType()->print(out);
else if (auto nominal = extension->getExtendedNominal())
out << nominal->getName();
out << "'";
printRange();
break;
Expand Down
14 changes: 10 additions & 4 deletions lib/AST/ASTVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2471,7 +2471,7 @@ class Verifier : public ASTWalker {
} else {
auto ext = cast<ExtensionDecl>(decl);
conformingDC = ext;
nominal = ext->getExtendedType()->getAnyNominal();
nominal = ext->getExtendedNominal();
}

auto proto = conformance->getProtocol();
Expand Down Expand Up @@ -2619,8 +2619,14 @@ class Verifier : public ASTWalker {
verifyProtocolList(nominal, nominal->getLocalProtocols());

// Make sure that the protocol conformances are complete.
for (auto conformance : nominal->getLocalConformances()) {
verifyConformance(nominal, conformance);
// Only do so within the source file of the nominal type,
// because anywhere else this can trigger new type-check requests.
if (auto sf = M.dyn_cast<SourceFile *>()) {
if (nominal->getParentSourceFile() == sf) {
for (auto conformance : nominal->getLocalConformances()) {
verifyConformance(nominal, conformance);
}
}
}

verifyCheckedBase(nominal);
Expand Down Expand Up @@ -3491,7 +3497,7 @@ void swift::verify(SourceFile &SF) {
bool swift::shouldVerify(const Decl *D, const ASTContext &Context) {
#if !(defined(NDEBUG) || defined(SWIFT_DISABLE_AST_VERIFIER))
if (const auto *ED = dyn_cast<ExtensionDecl>(D)) {
return shouldVerify(ED->getExtendedType()->getAnyNominal(), Context);
return shouldVerify(ED->getExtendedNominal(), Context);
}

const auto *VD = dyn_cast<ValueDecl>(D);
Expand Down
9 changes: 3 additions & 6 deletions lib/AST/AccessRequests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,12 +206,9 @@ DefaultAndMaxAccessLevelRequest::evaluate(Evaluator &evaluator,

AccessLevel maxAccess = AccessLevel::Public;

if (!ED->getExtendedType().isNull() &&
!ED->getExtendedType()->hasError()) {
if (NominalTypeDecl *nominal = ED->getExtendedType()->getAnyNominal()) {
maxAccess = std::max(nominal->getFormalAccess(),
AccessLevel::FilePrivate);
}
if (NominalTypeDecl *nominal = ED->getExtendedNominal()) {
maxAccess = std::max(nominal->getFormalAccess(),
AccessLevel::FilePrivate);
}

if (const GenericParamList *genericParams = ED->getGenericParams()) {
Expand Down
5 changes: 5 additions & 0 deletions lib/AST/ConformanceLookupTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,11 @@ ConformanceLookupTable::getConformance(NominalTypeDecl *nominal,
ctx.getInheritedConformance(type, inheritedConformance->getConcrete());
} else {
// Create or find the normal conformance.
if (auto ext = dyn_cast<ExtensionDecl>(conformingDC)) {
if (auto resolver = ctx.getLazyResolver())
resolver->bindExtension(ext);
}

Type conformingType = conformingDC->getDeclaredInterfaceType();
SourceLoc conformanceLoc
= conformingNominal == conformingDC
Expand Down
44 changes: 29 additions & 15 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,12 @@ ExtensionDecl::takeConformanceLoaderSlow() {
return { contextInfo->loader, contextInfo->allConformancesData };
}

NominalTypeDecl *ExtensionDecl::getExtendedNominal() const {
ASTContext &ctx = getASTContext();
return ctx.evaluator(
ExtendedNominalRequest{const_cast<ExtensionDecl *>(this)});;
}

Type ExtensionDecl::getInheritedType(unsigned index) const {
ASTContext &ctx = getASTContext();
return ctx.evaluator(InheritedTypeRequest{const_cast<ExtensionDecl *>(this),
Expand All @@ -992,7 +998,7 @@ bool ExtensionDecl::isConstrainedExtension() const {
if (!getGenericSignature())
return false;

auto nominal = getExtendedType()->getAnyNominal();
auto nominal = getExtendedNominal();
assert(nominal);

// If the generic signature differs from that of the nominal type, it's a
Expand All @@ -1002,7 +1008,7 @@ bool ExtensionDecl::isConstrainedExtension() const {
}

bool ExtensionDecl::isEquivalentToExtendedContext() const {
auto decl = getExtendedType()->getAnyNominal();
auto decl = getExtendedNominal();
return getParentModule() == decl->getParentModule()
&& !isConstrainedExtension()
&& !getDeclaredInterfaceType()->isExistentialType();
Expand Down Expand Up @@ -2373,11 +2379,9 @@ AccessLevel ValueDecl::getEffectiveAccess() const {
} else if (auto enclosingExt = dyn_cast<ExtensionDecl>(getDeclContext())) {
// Just check the base type. If it's a constrained extension, Sema should
// have already enforced access more strictly.
if (auto extendedTy = enclosingExt->getExtendedType()) {
if (auto nominal = extendedTy->getAnyNominal()) {
effectiveAccess =
restrictToEnclosing(effectiveAccess, nominal->getEffectiveAccess());
}
if (auto nominal = enclosingExt->getExtendedNominal()) {
effectiveAccess =
restrictToEnclosing(effectiveAccess, nominal->getEffectiveAccess());
}

} else if (getDeclContext()->isLocalContext()) {
Expand Down Expand Up @@ -2430,13 +2434,11 @@ getAccessScopeForFormalAccess(const ValueDecl *VD,
} else if (auto enclosingExt = dyn_cast<ExtensionDecl>(resultDC)) {
// Just check the base type. If it's a constrained extension, Sema should
// have already enforced access more strictly.
if (auto extendedTy = enclosingExt->getExtendedType()) {
if (auto nominal = extendedTy->getAnyNominal()) {
auto nominalAccess =
getAdjustedFormalAccess(nominal, useDC,
treatUsableFromInlineAsPublic);
access = std::min(access, nominalAccess);
}
if (auto nominal = enclosingExt->getExtendedNominal()) {
auto nominalAccess =
getAdjustedFormalAccess(nominal, useDC,
treatUsableFromInlineAsPublic);
access = std::min(access, nominalAccess);
}

} else {
Expand Down Expand Up @@ -2881,7 +2883,7 @@ ExtensionRange NominalTypeDecl::getExtensions() {
}

void NominalTypeDecl::addExtension(ExtensionDecl *extension) {
assert(!extension->NextExtension.getInt() && "Already added extension");
assert(!extension->alreadyBoundToNominal() && "Already added extension");
extension->NextExtension.setInt(true);

// First extension; set both first and last.
Expand Down Expand Up @@ -3374,6 +3376,18 @@ ClassDecl::findImplementingMethod(const AbstractFunctionDecl *Method) const {
return nullptr;
}

ClassDecl *ClassDecl::getGenericAncestor() const {
ClassDecl *current = const_cast<ClassDecl *>(this);

while (current) {
if (current->isGenericContext())
return current;

current = current->getSuperclassDecl();
}

return nullptr;
}

EnumCaseDecl *EnumCaseDecl::create(SourceLoc CaseLoc,
ArrayRef<EnumElementDecl *> Elements,
Expand Down
Loading