Merge pull request #79614 from DougGregor/conformance-attributes

Factor conformance attributes into their own separate structure.
This commit is contained in:
Doug Gregor
2025-02-25 17:07:59 -08:00
committed by GitHub
5 changed files with 83 additions and 80 deletions

View File

@@ -0,0 +1,46 @@
//===--- ConformanceLookup.h - Global conformance lookup --------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_AST_CONFORMANCEATTRIBUTES_H
#define SWIFT_AST_CONFORMANCEATTRIBUTES_H
#include "swift/Basic/SourceLoc.h"
namespace swift {
/// Describes all of the attributes that can occur on a conformance.
struct ConformanceAttributes {
/// The location of the "unchecked" attribute, if present.
SourceLoc uncheckedLoc;
/// The location of the "preconcurrency" attribute if present.
SourceLoc preconcurrencyLoc;
/// The location of the "unsafe" attribute if present.
SourceLoc unsafeLoc;
/// Merge other conformance attributes into this set.
ConformanceAttributes &
operator |=(const ConformanceAttributes &other) {
if (other.uncheckedLoc.isValid())
uncheckedLoc = other.uncheckedLoc;
if (other.preconcurrencyLoc.isValid())
preconcurrencyLoc = other.preconcurrencyLoc;
if (other.unsafeLoc.isValid())
unsafeLoc = other.unsafeLoc;
return *this;
}
};
}
#endif

View File

@@ -19,6 +19,7 @@
#include "swift/AST/ASTVisitor.h" #include "swift/AST/ASTVisitor.h"
#include "swift/AST/CatchNode.h" #include "swift/AST/CatchNode.h"
#include "swift/AST/ConformanceAttributes.h"
#include "swift/AST/GenericSignature.h" #include "swift/AST/GenericSignature.h"
#include "swift/AST/Identifier.h" #include "swift/AST/Identifier.h"
#include "swift/AST/Module.h" #include "swift/AST/Module.h"
@@ -603,14 +604,7 @@ void forEachPotentialAttachedMacro(
/// Describes an inherited nominal entry. /// Describes an inherited nominal entry.
struct InheritedNominalEntry : Located<NominalTypeDecl *> { struct InheritedNominalEntry : Located<NominalTypeDecl *> {
/// The location of the "unchecked" attribute, if present. ConformanceAttributes attributes;
SourceLoc uncheckedLoc;
/// The location of the "preconcurrency" attribute if present.
SourceLoc preconcurrencyLoc;
/// The location of the "unsafe" attribute if present.
SourceLoc unsafeLoc;
/// Whether this inherited entry was suppressed via "~". /// Whether this inherited entry was suppressed via "~".
bool isSuppressed; bool isSuppressed;
@@ -618,10 +612,9 @@ struct InheritedNominalEntry : Located<NominalTypeDecl *> {
InheritedNominalEntry() { } InheritedNominalEntry() { }
InheritedNominalEntry(NominalTypeDecl *item, SourceLoc loc, InheritedNominalEntry(NominalTypeDecl *item, SourceLoc loc,
SourceLoc uncheckedLoc, SourceLoc preconcurrencyLoc, ConformanceAttributes attributes,
SourceLoc unsafeLoc, bool isSuppressed) bool isSuppressed)
: Located(item, loc), uncheckedLoc(uncheckedLoc), : Located(item, loc), attributes(attributes),
preconcurrencyLoc(preconcurrencyLoc), unsafeLoc(unsafeLoc),
isSuppressed(isSuppressed) {} isSuppressed(isSuppressed) {}
}; };

View File

@@ -16,6 +16,7 @@
#include "ConformanceLookupTable.h" #include "ConformanceLookupTable.h"
#include "swift/AST/ASTContext.h" #include "swift/AST/ASTContext.h"
#include "swift/AST/ConformanceAttributes.h"
#include "swift/AST/ConformanceLookup.h" #include "swift/AST/ConformanceLookup.h"
#include "swift/AST/Decl.h" #include "swift/AST/Decl.h"
#include "swift/AST/ExistentialLayout.h" #include "swift/AST/ExistentialLayout.h"
@@ -148,23 +149,13 @@ void ConformanceLookupTable::destroy() {
namespace { namespace {
struct ConformanceConstructionInfo : public Located<ProtocolDecl *> { struct ConformanceConstructionInfo : public Located<ProtocolDecl *> {
/// The location of the "unchecked" attribute, if present. ConformanceAttributes attributes;
const SourceLoc uncheckedLoc;
/// The location of the "preconcurrency" attribute if present.
const SourceLoc preconcurrencyLoc;
/// The location of the "unsafe" attribute if present.
const SourceLoc unsafeLoc;
ConformanceConstructionInfo() { } ConformanceConstructionInfo() { }
ConformanceConstructionInfo(ProtocolDecl *item, SourceLoc loc, ConformanceConstructionInfo(ProtocolDecl *item, SourceLoc loc,
SourceLoc uncheckedLoc, ConformanceAttributes attributes)
SourceLoc preconcurrencyLoc, : Located(item, loc), attributes(attributes) {}
SourceLoc unsafeLoc)
: Located(item, loc), uncheckedLoc(uncheckedLoc),
preconcurrencyLoc(preconcurrencyLoc), unsafeLoc(unsafeLoc) {}
}; };
} }
@@ -220,7 +211,7 @@ void ConformanceLookupTable::forEachInStage(ConformanceStage stage,
registerProtocolConformances(next, conformances); registerProtocolConformances(next, conformances);
for (auto conf : conformances) { for (auto conf : conformances) {
protocols.push_back( protocols.push_back(
{conf->getProtocol(), SourceLoc(), SourceLoc(), SourceLoc(), SourceLoc()}); {conf->getProtocol(), SourceLoc(), ConformanceAttributes()});
} }
} else if (next->getParentSourceFile() || } else if (next->getParentSourceFile() ||
next->getParentModule()->isBuiltinModule()) { next->getParentModule()->isBuiltinModule()) {
@@ -229,9 +220,7 @@ void ConformanceLookupTable::forEachInStage(ConformanceStage stage,
for (const auto &found : for (const auto &found :
getDirectlyInheritedNominalTypeDecls(next, inverses, anyObject)) { getDirectlyInheritedNominalTypeDecls(next, inverses, anyObject)) {
if (auto proto = dyn_cast<ProtocolDecl>(found.Item)) if (auto proto = dyn_cast<ProtocolDecl>(found.Item))
protocols.push_back( protocols.push_back({proto, found.Loc, found.attributes});
{proto, found.Loc, found.uncheckedLoc,
found.preconcurrencyLoc, found.unsafeLoc});
} }
} }
@@ -318,10 +307,8 @@ void ConformanceLookupTable::updateLookupTable(NominalTypeDecl *nominal,
kp.has_value() && kp.has_value() &&
"suppressed conformance for non-known protocol!?"); "suppressed conformance for non-known protocol!?");
if (!found.isSuppressed) { if (!found.isSuppressed) {
addProtocol(proto, found.Loc, addProtocol(
source.withUncheckedLoc(found.uncheckedLoc) proto, found.Loc, source.withAttributes(found.attributes));
.withPreconcurrencyLoc(found.preconcurrencyLoc)
.withUnsafeLoc(found.unsafeLoc));
} }
} }
@@ -335,9 +322,7 @@ void ConformanceLookupTable::updateLookupTable(NominalTypeDecl *nominal,
for (auto locAndProto : protos) for (auto locAndProto : protos)
addProtocol( addProtocol(
locAndProto.Item, locAndProto.Loc, locAndProto.Item, locAndProto.Loc,
source.withUncheckedLoc(locAndProto.uncheckedLoc) source.withAttributes(locAndProto.attributes));
.withPreconcurrencyLoc(locAndProto.preconcurrencyLoc)
.withUnsafeLoc(locAndProto.unsafeLoc));
}); });
break; break;

View File

@@ -21,6 +21,7 @@
#define SWIFT_AST_CONFORMANCE_LOOKUP_TABLE_H #define SWIFT_AST_CONFORMANCE_LOOKUP_TABLE_H
#include "swift/AST/DeclContext.h" #include "swift/AST/DeclContext.h"
#include "swift/AST/ConformanceAttributes.h"
#include "swift/AST/ProtocolConformanceOptions.h" #include "swift/AST/ProtocolConformanceOptions.h"
#include "swift/Basic/Debug.h" #include "swift/Basic/Debug.h"
#include "swift/Basic/LLVM.h" #include "swift/Basic/LLVM.h"
@@ -89,14 +90,7 @@ class ConformanceLookupTable : public ASTAllocated<ConformanceLookupTable> {
ConformanceEntryKind Kind; ConformanceEntryKind Kind;
/// The location of the "unchecked" attribute, if there is one. ConformanceAttributes attributes;
SourceLoc uncheckedLoc;
/// The location of the "preconcurrency" attribute, if there is one.
SourceLoc preconcurrencyLoc;
/// The location of the "unsafe" attribute, if there is one.
SourceLoc unsafeLoc;
ConformanceSource(void *ptr, ConformanceEntryKind kind) ConformanceSource(void *ptr, ConformanceEntryKind kind)
: Storage(ptr), Kind(kind) { } : Storage(ptr), Kind(kind) { }
@@ -140,29 +134,16 @@ class ConformanceLookupTable : public ASTAllocated<ConformanceLookupTable> {
return ConformanceSource(dc, ConformanceEntryKind::PreMacroExpansion); return ConformanceSource(dc, ConformanceEntryKind::PreMacroExpansion);
} }
/// Return a new conformance source with the given location of "@unchecked". /// Return a new conformance source with the given conformance
ConformanceSource withUncheckedLoc(SourceLoc uncheckedLoc) { /// attributes.
ConformanceSource withAttributes(ConformanceAttributes attributes) {
ConformanceSource result(*this); ConformanceSource result(*this);
if (uncheckedLoc.isValid()) result.attributes |= attributes;
result.uncheckedLoc = uncheckedLoc;
return result; return result;
} }
/// Return a new conformance source with the given location of ConformanceAttributes getAttributes() const {
/// "@preconcurrency". return attributes;
ConformanceSource withPreconcurrencyLoc(SourceLoc preconcurrencyLoc) {
ConformanceSource result(*this);
if (preconcurrencyLoc.isValid())
result.preconcurrencyLoc = preconcurrencyLoc;
return result;
}
/// Return a new conformance source with the given location of "@unsafe".
ConformanceSource withUnsafeLoc(SourceLoc unsafeLoc) {
ConformanceSource result(*this);
if (unsafeLoc.isValid())
result.unsafeLoc = unsafeLoc;
return result;
} }
ProtocolConformanceOptions getOptions() const { ProtocolConformanceOptions getOptions() const {
@@ -216,16 +197,16 @@ class ConformanceLookupTable : public ASTAllocated<ConformanceLookupTable> {
/// The location of the @unchecked attribute, if any. /// The location of the @unchecked attribute, if any.
SourceLoc getUncheckedLoc() const { SourceLoc getUncheckedLoc() const {
return uncheckedLoc; return attributes.uncheckedLoc;
} }
SourceLoc getPreconcurrencyLoc() const { SourceLoc getPreconcurrencyLoc() const {
return preconcurrencyLoc; return attributes.preconcurrencyLoc;
} }
/// The location of the @unsafe attribute, if any. /// The location of the @unsafe attribute, if any.
SourceLoc getUnsafeLoc() const { SourceLoc getUnsafeLoc() const {
return unsafeLoc; return attributes.unsafeLoc;
} }
/// For an inherited conformance, retrieve the class declaration /// For an inherited conformance, retrieve the class declaration

View File

@@ -19,6 +19,7 @@
#include "swift/AST/ASTVisitor.h" #include "swift/AST/ASTVisitor.h"
#include "swift/AST/ASTWalker.h" #include "swift/AST/ASTWalker.h"
#include "swift/AST/ClangModuleLoader.h" #include "swift/AST/ClangModuleLoader.h"
#include "swift/AST/ConformanceAttributes.h"
#include "swift/AST/DebuggerClient.h" #include "swift/AST/DebuggerClient.h"
#include "swift/AST/ExistentialLayout.h" #include "swift/AST/ExistentialLayout.h"
#include "swift/AST/GenericParamList.h" #include "swift/AST/GenericParamList.h"
@@ -3962,23 +3963,19 @@ void swift::getDirectlyInheritedNominalTypeDecls(
// FIXME: This is a hack. We need cooperation from // FIXME: This is a hack. We need cooperation from
// InheritedDeclsReferencedRequest to make this work. // InheritedDeclsReferencedRequest to make this work.
SourceLoc loc; SourceLoc loc;
SourceLoc uncheckedLoc; ConformanceAttributes attributes;
SourceLoc preconcurrencyLoc;
SourceLoc unsafeLoc;
auto inheritedTypes = InheritedTypes(decl); auto inheritedTypes = InheritedTypes(decl);
bool isSuppressed = inheritedTypes.getEntry(i).isSuppressed(); bool isSuppressed = inheritedTypes.getEntry(i).isSuppressed();
if (TypeRepr *typeRepr = inheritedTypes.getTypeRepr(i)) { if (TypeRepr *typeRepr = inheritedTypes.getTypeRepr(i)) {
loc = typeRepr->getLoc(); loc = typeRepr->getLoc();
uncheckedLoc = typeRepr->findAttrLoc(TypeAttrKind::Unchecked); attributes.uncheckedLoc = typeRepr->findAttrLoc(TypeAttrKind::Unchecked);
preconcurrencyLoc = typeRepr->findAttrLoc(TypeAttrKind::Preconcurrency); attributes.preconcurrencyLoc = typeRepr->findAttrLoc(TypeAttrKind::Preconcurrency);
unsafeLoc = typeRepr->findAttrLoc(TypeAttrKind::Unsafe); attributes.unsafeLoc = typeRepr->findAttrLoc(TypeAttrKind::Unsafe);
} }
// Form the result. // Form the result.
for (auto nominal : nominalTypes) { for (auto nominal : nominalTypes) {
result.push_back( result.push_back({nominal, loc, attributes, isSuppressed});
{nominal, loc, uncheckedLoc, preconcurrencyLoc, unsafeLoc,
isSuppressed});
} }
} }
@@ -4008,10 +4005,11 @@ swift::getDirectlyInheritedNominalTypeDecls(
for (auto attr : for (auto attr :
protoDecl->getAttrs().getAttributes<SynthesizedProtocolAttr>()) { protoDecl->getAttrs().getAttributes<SynthesizedProtocolAttr>()) {
auto loc = attr->getLocation(); auto loc = attr->getLocation();
ConformanceAttributes attributes;
if (attr->isUnchecked())
attributes.uncheckedLoc = loc;
result.push_back( result.push_back(
{attr->getProtocol(), loc, attr->isUnchecked() ? loc : SourceLoc(), {attr->getProtocol(), loc, attributes, /*isSuppressed=*/false});
/*preconcurrencyLoc=*/SourceLoc(), SourceLoc(),
/*isSuppressed=*/false});
} }
// Else we have access to this information on the where clause. // Else we have access to this information on the where clause.
@@ -4022,8 +4020,8 @@ swift::getDirectlyInheritedNominalTypeDecls(
// FIXME: Refactor SelfBoundsFromWhereClauseRequest to dig out // FIXME: Refactor SelfBoundsFromWhereClauseRequest to dig out
// the source location. // the source location.
for (auto inheritedNominal : selfBounds.decls) for (auto inheritedNominal : selfBounds.decls)
result.emplace_back(inheritedNominal, SourceLoc(), SourceLoc(), result.emplace_back(inheritedNominal, SourceLoc(), ConformanceAttributes(),
SourceLoc(), SourceLoc(), /*isSuppressed=*/false); /*isSuppressed=*/false);
return result; return result;
} }