diff --git a/include/swift/AST/ConformanceAttributes.h b/include/swift/AST/ConformanceAttributes.h new file mode 100644 index 00000000000..4f9242c6b39 --- /dev/null +++ b/include/swift/AST/ConformanceAttributes.h @@ -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 diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h index ae78c967644..d678f9a7c32 100644 --- a/include/swift/AST/NameLookup.h +++ b/include/swift/AST/NameLookup.h @@ -19,6 +19,7 @@ #include "swift/AST/ASTVisitor.h" #include "swift/AST/CatchNode.h" +#include "swift/AST/ConformanceAttributes.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/Identifier.h" #include "swift/AST/Module.h" @@ -603,14 +604,7 @@ void forEachPotentialAttachedMacro( /// Describes an inherited nominal entry. struct InheritedNominalEntry : Located { - /// 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; + ConformanceAttributes attributes; /// Whether this inherited entry was suppressed via "~". bool isSuppressed; @@ -618,10 +612,9 @@ struct InheritedNominalEntry : Located { InheritedNominalEntry() { } InheritedNominalEntry(NominalTypeDecl *item, SourceLoc loc, - SourceLoc uncheckedLoc, SourceLoc preconcurrencyLoc, - SourceLoc unsafeLoc, bool isSuppressed) - : Located(item, loc), uncheckedLoc(uncheckedLoc), - preconcurrencyLoc(preconcurrencyLoc), unsafeLoc(unsafeLoc), + ConformanceAttributes attributes, + bool isSuppressed) + : Located(item, loc), attributes(attributes), isSuppressed(isSuppressed) {} }; diff --git a/lib/AST/ConformanceLookupTable.cpp b/lib/AST/ConformanceLookupTable.cpp index 6af43b1e753..46872a0c10e 100644 --- a/lib/AST/ConformanceLookupTable.cpp +++ b/lib/AST/ConformanceLookupTable.cpp @@ -16,6 +16,7 @@ #include "ConformanceLookupTable.h" #include "swift/AST/ASTContext.h" +#include "swift/AST/ConformanceAttributes.h" #include "swift/AST/ConformanceLookup.h" #include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" @@ -148,23 +149,13 @@ void ConformanceLookupTable::destroy() { namespace { struct ConformanceConstructionInfo : public Located { - /// The location of the "unchecked" attribute, if present. - 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; + ConformanceAttributes attributes; ConformanceConstructionInfo() { } ConformanceConstructionInfo(ProtocolDecl *item, SourceLoc loc, - SourceLoc uncheckedLoc, - SourceLoc preconcurrencyLoc, - SourceLoc unsafeLoc) - : Located(item, loc), uncheckedLoc(uncheckedLoc), - preconcurrencyLoc(preconcurrencyLoc), unsafeLoc(unsafeLoc) {} + ConformanceAttributes attributes) + : Located(item, loc), attributes(attributes) {} }; } @@ -220,7 +211,7 @@ void ConformanceLookupTable::forEachInStage(ConformanceStage stage, registerProtocolConformances(next, conformances); for (auto conf : conformances) { protocols.push_back( - {conf->getProtocol(), SourceLoc(), SourceLoc(), SourceLoc(), SourceLoc()}); + {conf->getProtocol(), SourceLoc(), ConformanceAttributes()}); } } else if (next->getParentSourceFile() || next->getParentModule()->isBuiltinModule()) { @@ -229,9 +220,7 @@ void ConformanceLookupTable::forEachInStage(ConformanceStage stage, for (const auto &found : getDirectlyInheritedNominalTypeDecls(next, inverses, anyObject)) { if (auto proto = dyn_cast(found.Item)) - protocols.push_back( - {proto, found.Loc, found.uncheckedLoc, - found.preconcurrencyLoc, found.unsafeLoc}); + protocols.push_back({proto, found.Loc, found.attributes}); } } @@ -318,10 +307,8 @@ void ConformanceLookupTable::updateLookupTable(NominalTypeDecl *nominal, kp.has_value() && "suppressed conformance for non-known protocol!?"); if (!found.isSuppressed) { - addProtocol(proto, found.Loc, - source.withUncheckedLoc(found.uncheckedLoc) - .withPreconcurrencyLoc(found.preconcurrencyLoc) - .withUnsafeLoc(found.unsafeLoc)); + addProtocol( + proto, found.Loc, source.withAttributes(found.attributes)); } } @@ -335,9 +322,7 @@ void ConformanceLookupTable::updateLookupTable(NominalTypeDecl *nominal, for (auto locAndProto : protos) addProtocol( locAndProto.Item, locAndProto.Loc, - source.withUncheckedLoc(locAndProto.uncheckedLoc) - .withPreconcurrencyLoc(locAndProto.preconcurrencyLoc) - .withUnsafeLoc(locAndProto.unsafeLoc)); + source.withAttributes(locAndProto.attributes)); }); break; diff --git a/lib/AST/ConformanceLookupTable.h b/lib/AST/ConformanceLookupTable.h index 3164fc0abfa..92ed8be8c8e 100644 --- a/lib/AST/ConformanceLookupTable.h +++ b/lib/AST/ConformanceLookupTable.h @@ -21,6 +21,7 @@ #define SWIFT_AST_CONFORMANCE_LOOKUP_TABLE_H #include "swift/AST/DeclContext.h" +#include "swift/AST/ConformanceAttributes.h" #include "swift/AST/ProtocolConformanceOptions.h" #include "swift/Basic/Debug.h" #include "swift/Basic/LLVM.h" @@ -89,14 +90,7 @@ class ConformanceLookupTable : public ASTAllocated { ConformanceEntryKind Kind; - /// The location of the "unchecked" attribute, if there is one. - 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; + ConformanceAttributes attributes; ConformanceSource(void *ptr, ConformanceEntryKind kind) : Storage(ptr), Kind(kind) { } @@ -140,29 +134,16 @@ class ConformanceLookupTable : public ASTAllocated { return ConformanceSource(dc, ConformanceEntryKind::PreMacroExpansion); } - /// Return a new conformance source with the given location of "@unchecked". - ConformanceSource withUncheckedLoc(SourceLoc uncheckedLoc) { + /// Return a new conformance source with the given conformance + /// attributes. + ConformanceSource withAttributes(ConformanceAttributes attributes) { ConformanceSource result(*this); - if (uncheckedLoc.isValid()) - result.uncheckedLoc = uncheckedLoc; + result.attributes |= attributes; return result; } - /// Return a new conformance source with the given location of - /// "@preconcurrency". - 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; + ConformanceAttributes getAttributes() const { + return attributes; } ProtocolConformanceOptions getOptions() const { @@ -216,16 +197,16 @@ class ConformanceLookupTable : public ASTAllocated { /// The location of the @unchecked attribute, if any. SourceLoc getUncheckedLoc() const { - return uncheckedLoc; + return attributes.uncheckedLoc; } SourceLoc getPreconcurrencyLoc() const { - return preconcurrencyLoc; + return attributes.preconcurrencyLoc; } /// The location of the @unsafe attribute, if any. SourceLoc getUnsafeLoc() const { - return unsafeLoc; + return attributes.unsafeLoc; } /// For an inherited conformance, retrieve the class declaration diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 4d99bdcc2f4..cfc1a963737 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -19,6 +19,7 @@ #include "swift/AST/ASTVisitor.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/ClangModuleLoader.h" +#include "swift/AST/ConformanceAttributes.h" #include "swift/AST/DebuggerClient.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/GenericParamList.h" @@ -3962,23 +3963,19 @@ void swift::getDirectlyInheritedNominalTypeDecls( // FIXME: This is a hack. We need cooperation from // InheritedDeclsReferencedRequest to make this work. SourceLoc loc; - SourceLoc uncheckedLoc; - SourceLoc preconcurrencyLoc; - SourceLoc unsafeLoc; + ConformanceAttributes attributes; auto inheritedTypes = InheritedTypes(decl); bool isSuppressed = inheritedTypes.getEntry(i).isSuppressed(); if (TypeRepr *typeRepr = inheritedTypes.getTypeRepr(i)) { loc = typeRepr->getLoc(); - uncheckedLoc = typeRepr->findAttrLoc(TypeAttrKind::Unchecked); - preconcurrencyLoc = typeRepr->findAttrLoc(TypeAttrKind::Preconcurrency); - unsafeLoc = typeRepr->findAttrLoc(TypeAttrKind::Unsafe); + attributes.uncheckedLoc = typeRepr->findAttrLoc(TypeAttrKind::Unchecked); + attributes.preconcurrencyLoc = typeRepr->findAttrLoc(TypeAttrKind::Preconcurrency); + attributes.unsafeLoc = typeRepr->findAttrLoc(TypeAttrKind::Unsafe); } // Form the result. for (auto nominal : nominalTypes) { - result.push_back( - {nominal, loc, uncheckedLoc, preconcurrencyLoc, unsafeLoc, - isSuppressed}); + result.push_back({nominal, loc, attributes, isSuppressed}); } } @@ -4008,10 +4005,11 @@ swift::getDirectlyInheritedNominalTypeDecls( for (auto attr : protoDecl->getAttrs().getAttributes()) { auto loc = attr->getLocation(); + ConformanceAttributes attributes; + if (attr->isUnchecked()) + attributes.uncheckedLoc = loc; result.push_back( - {attr->getProtocol(), loc, attr->isUnchecked() ? loc : SourceLoc(), - /*preconcurrencyLoc=*/SourceLoc(), SourceLoc(), - /*isSuppressed=*/false}); + {attr->getProtocol(), loc, attributes, /*isSuppressed=*/false}); } // Else we have access to this information on the where clause. @@ -4022,8 +4020,8 @@ swift::getDirectlyInheritedNominalTypeDecls( // FIXME: Refactor SelfBoundsFromWhereClauseRequest to dig out // the source location. for (auto inheritedNominal : selfBounds.decls) - result.emplace_back(inheritedNominal, SourceLoc(), SourceLoc(), - SourceLoc(), SourceLoc(), /*isSuppressed=*/false); + result.emplace_back(inheritedNominal, SourceLoc(), ConformanceAttributes(), + /*isSuppressed=*/false); return result; }