Skip to content

Commit 6ddd1c9

Browse files
Merge pull request #82664 from swiftlang/jepa2-6.2
[6.2] Sema: Fix the insertion location for conformances attributes
2 parents d98ab48 + c1ed83e commit 6ddd1c9

18 files changed

+323
-89
lines changed

include/swift/AST/ASTContext.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,10 +1330,10 @@ class ASTContext final {
13301330
getNormalConformance(Type conformingType,
13311331
ProtocolDecl *protocol,
13321332
SourceLoc loc,
1333+
TypeRepr *inheritedTypeRepr,
13331334
DeclContext *dc,
13341335
ProtocolConformanceState state,
1335-
ProtocolConformanceOptions options,
1336-
SourceLoc preconcurrencyLoc = SourceLoc());
1336+
ProtocolConformanceOptions options);
13371337

13381338
/// Produce a self-conformance for the given protocol.
13391339
SelfProtocolConformance *

include/swift/AST/NameLookup.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,11 @@ void forEachPotentialAttachedMacro(
604604

605605
/// Describes an inherited nominal entry.
606606
struct InheritedNominalEntry : Located<NominalTypeDecl *> {
607+
/// The `TypeRepr` of the inheritance clause entry from which this nominal was
608+
/// sourced, if any. For example, if this is a conformance to `Y` declared as
609+
/// `struct S: X, Y & Z {}`, this is the `TypeRepr` for `Y & Z`.
610+
TypeRepr *inheritedTypeRepr;
611+
607612
ConformanceAttributes attributes;
608613

609614
/// Whether this inherited entry was suppressed via "~".
@@ -612,10 +617,10 @@ struct InheritedNominalEntry : Located<NominalTypeDecl *> {
612617
InheritedNominalEntry() { }
613618

614619
InheritedNominalEntry(NominalTypeDecl *item, SourceLoc loc,
615-
ConformanceAttributes attributes,
616-
bool isSuppressed)
617-
: Located(item, loc), attributes(attributes),
618-
isSuppressed(isSuppressed) {}
620+
TypeRepr *inheritedTypeRepr,
621+
ConformanceAttributes attributes, bool isSuppressed)
622+
: Located(item, loc), inheritedTypeRepr(inheritedTypeRepr),
623+
attributes(attributes), isSuppressed(isSuppressed) {}
619624
};
620625

621626
/// Retrieve the set of nominal type declarations that are directly

include/swift/AST/ProtocolConformance.h

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -586,10 +586,17 @@ class NormalProtocolConformance : public RootProtocolConformance,
586586
SourceLoc Loc;
587587

588588
/// The location of the protocol name within the conformance.
589+
///
590+
/// - Important: This is not a valid insertion location for an attribute.
591+
/// Use `applyConformanceAttribute` instead.
589592
SourceLoc ProtocolNameLoc;
590593

591-
/// The location of the `@preconcurrency` attribute, if any.
592-
SourceLoc PreconcurrencyLoc;
594+
/// The `TypeRepr` of the inheritance clause entry that declares this
595+
/// conformance, if any. For example, if this is a conformance to `Y`
596+
/// declared as `struct S: X, Y & Z {}`, this is the `TypeRepr` for `Y & Z`.
597+
///
598+
/// - Important: The value can be valid only for an explicit conformance.
599+
TypeRepr *inheritedTypeRepr;
593600

594601
/// The declaration context containing the ExtensionDecl or
595602
/// NominalTypeDecl that declared the conformance.
@@ -625,22 +632,26 @@ class NormalProtocolConformance : public RootProtocolConformance,
625632
// Record the explicitly-specified global actor isolation.
626633
void setExplicitGlobalActorIsolation(TypeExpr *typeExpr);
627634

635+
/// Return the `TypeRepr` of the inheritance clause entry that declares this
636+
/// conformance, if any. For example, if this is a conformance to `Y`
637+
/// declared as `struct S: X, Y & Z {}`, this is the `TypeRepr` for `Y & Z`.
638+
///
639+
/// - Important: The value can be valid only for an explicit conformance.
640+
TypeRepr *getInheritedTypeRepr() const { return inheritedTypeRepr; }
641+
628642
public:
629643
NormalProtocolConformance(Type conformingType, ProtocolDecl *protocol,
630-
SourceLoc loc, DeclContext *dc,
631-
ProtocolConformanceState state,
632-
ProtocolConformanceOptions options,
633-
SourceLoc preconcurrencyLoc)
644+
SourceLoc loc, TypeRepr *inheritedTypeRepr,
645+
DeclContext *dc, ProtocolConformanceState state,
646+
ProtocolConformanceOptions options)
634647
: RootProtocolConformance(ProtocolConformanceKind::Normal,
635648
conformingType),
636649
Protocol(protocol), Loc(extractNearestSourceLoc(dc)),
637-
ProtocolNameLoc(loc), PreconcurrencyLoc(preconcurrencyLoc),
650+
ProtocolNameLoc(loc), inheritedTypeRepr(inheritedTypeRepr),
638651
Context(dc) {
639652
assert(!conformingType->hasArchetype() &&
640653
"ProtocolConformances should store interface types");
641-
assert((preconcurrencyLoc.isInvalid() ||
642-
options.contains(ProtocolConformanceFlags::Preconcurrency)) &&
643-
"Cannot have a @preconcurrency location without isPreconcurrency");
654+
644655
setState(state);
645656
Bits.NormalProtocolConformance.IsInvalid = false;
646657
Bits.NormalProtocolConformance.IsPreconcurrencyEffectful = false;
@@ -650,6 +661,9 @@ class NormalProtocolConformance : public RootProtocolConformance,
650661
unsigned(ConformanceEntryKind::Explicit);
651662
Bits.NormalProtocolConformance.HasExplicitGlobalActor = false;
652663
setExplicitGlobalActorIsolation(options.getGlobalActorIsolationType());
664+
665+
assert((!getPreconcurrencyLoc() || isPreconcurrency()) &&
666+
"Cannot have a @preconcurrency location without isPreconcurrency");
653667
}
654668

655669
/// Get the protocol being conformed to.
@@ -659,6 +673,9 @@ class NormalProtocolConformance : public RootProtocolConformance,
659673
SourceLoc getLoc() const { return Loc; }
660674

661675
/// Retrieve the name of the protocol location.
676+
///
677+
/// - Important: This is not a valid insertion location for an attribute.
678+
/// Use `applyConformanceAttribute` instead.
662679
SourceLoc getProtocolNameLoc() const { return ProtocolNameLoc; }
663680

664681
/// Get the declaration context that contains the conforming extension or
@@ -729,7 +746,9 @@ class NormalProtocolConformance : public RootProtocolConformance,
729746

730747
/// Retrieve the location of `@preconcurrency`, if there is one and it is
731748
/// known.
732-
SourceLoc getPreconcurrencyLoc() const { return PreconcurrencyLoc; }
749+
///
750+
/// - Important: The value can be valid only for an explicit conformance.
751+
SourceLoc getPreconcurrencyLoc() const;
733752

734753
/// Query whether this conformance was explicitly declared to be safe or
735754
/// unsafe.
@@ -853,6 +872,15 @@ class NormalProtocolConformance : public RootProtocolConformance,
853872
/// Triggers a request that resolves all of the conformance's value witnesses.
854873
void resolveValueWitnesses() const;
855874

875+
/// If the necessary source location information is found, attaches a fix-it
876+
/// to the given diagnostic for applying the given attribute to the
877+
/// conformance.
878+
///
879+
/// \param attrStr A conformance attribute as a string, e.g. "@unsafe" or
880+
/// "nonisolated".
881+
void applyConformanceAttribute(InFlightDiagnostic &diag,
882+
std::string attrStr) const;
883+
856884
/// Determine whether the witness for the given type requirement
857885
/// is the default definition.
858886
bool usesDefaultDefinition(AssociatedTypeDecl *requirement) const {

lib/AST/ASTContext.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2911,10 +2911,10 @@ NormalProtocolConformance *
29112911
ASTContext::getNormalConformance(Type conformingType,
29122912
ProtocolDecl *protocol,
29132913
SourceLoc loc,
2914+
TypeRepr *inheritedTypeRepr,
29142915
DeclContext *dc,
29152916
ProtocolConformanceState state,
2916-
ProtocolConformanceOptions options,
2917-
SourceLoc preconcurrencyLoc) {
2917+
ProtocolConformanceOptions options) {
29182918
assert(dc->isTypeContext());
29192919

29202920
llvm::FoldingSetNodeID id;
@@ -2928,8 +2928,7 @@ ASTContext::getNormalConformance(Type conformingType,
29282928

29292929
// Build a new normal protocol conformance.
29302930
auto result = new (*this) NormalProtocolConformance(
2931-
conformingType, protocol, loc, dc, state,
2932-
options, preconcurrencyLoc);
2931+
conformingType, protocol, loc, inheritedTypeRepr, dc, state, options);
29332932
normalConformances.InsertNode(result, insertPos);
29342933

29352934
return result;

lib/AST/ConformanceLookupTable.cpp

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,20 @@ void ConformanceLookupTable::destroy() {
149149

150150
namespace {
151151
struct ConformanceConstructionInfo : public Located<ProtocolDecl *> {
152+
/// The `TypeRepr` of the inheritance clause entry from which this nominal
153+
/// was sourced, if any. For example, if this is a conformance to `Y`
154+
/// declared as `struct S: X, Y & Z {}`, this is the `TypeRepr` for `Y & Z`.
155+
TypeRepr *inheritedTypeRepr;
156+
152157
ConformanceAttributes attributes;
153158

154159
ConformanceConstructionInfo() { }
155160

156161
ConformanceConstructionInfo(ProtocolDecl *item, SourceLoc loc,
162+
TypeRepr *inheritedTypeRepr,
157163
ConformanceAttributes attributes)
158-
: Located(item, loc), attributes(attributes) {}
164+
: Located(item, loc), inheritedTypeRepr(inheritedTypeRepr),
165+
attributes(attributes) {}
159166
};
160167
}
161168

@@ -210,8 +217,9 @@ void ConformanceLookupTable::forEachInStage(ConformanceStage stage,
210217
loader.first->loadAllConformances(next, loader.second, conformances);
211218
registerProtocolConformances(next, conformances);
212219
for (auto conf : conformances) {
213-
protocols.push_back(
214-
{conf->getProtocol(), SourceLoc(), ConformanceAttributes()});
220+
protocols.push_back({conf->getProtocol(), SourceLoc(),
221+
/*inheritedTypeRepr=*/nullptr,
222+
ConformanceAttributes()});
215223
}
216224
} else if (next->getParentSourceFile() ||
217225
next->getParentModule()->isBuiltinModule()) {
@@ -220,7 +228,8 @@ void ConformanceLookupTable::forEachInStage(ConformanceStage stage,
220228
for (const auto &found :
221229
getDirectlyInheritedNominalTypeDecls(next, inverses, anyObject)) {
222230
if (auto proto = dyn_cast<ProtocolDecl>(found.Item))
223-
protocols.push_back({proto, found.Loc, found.attributes});
231+
protocols.push_back(
232+
{proto, found.Loc, found.inheritedTypeRepr, found.attributes});
224233
}
225234
}
226235

@@ -292,8 +301,6 @@ void ConformanceLookupTable::updateLookupTable(NominalTypeDecl *nominal,
292301
forEachInStage(
293302
stage, nominal,
294303
[&](NominalTypeDecl *nominal) {
295-
auto source = ConformanceSource::forExplicit(nominal);
296-
297304
// Get all of the protocols in the inheritance clause.
298305
InvertibleProtocolSet inverses;
299306
bool anyObject = false;
@@ -303,10 +310,12 @@ void ConformanceLookupTable::updateLookupTable(NominalTypeDecl *nominal,
303310
if (!proto)
304311
continue;
305312
auto kp = proto->getKnownProtocolKind();
306-
assert(!found.isSuppressed ||
307-
kp.has_value() &&
308-
"suppressed conformance for non-known protocol!?");
313+
assert(!found.isSuppressed ||
314+
kp.has_value() &&
315+
"suppressed conformance for non-known protocol!?");
309316
if (!found.isSuppressed) {
317+
auto source = ConformanceSource::forExplicit(
318+
nominal, found.inheritedTypeRepr);
310319
addProtocol(
311320
proto, found.Loc, source.withAttributes(found.attributes));
312321
}
@@ -318,11 +327,12 @@ void ConformanceLookupTable::updateLookupTable(NominalTypeDecl *nominal,
318327
[&](ExtensionDecl *ext, ArrayRef<ConformanceConstructionInfo> protos) {
319328
// The extension decl may not be validated, so we can't use
320329
// its inherited protocols directly.
321-
auto source = ConformanceSource::forExplicit(ext);
322-
for (auto locAndProto : protos)
323-
addProtocol(
324-
locAndProto.Item, locAndProto.Loc,
325-
source.withAttributes(locAndProto.attributes));
330+
for (auto locAndProto : protos) {
331+
auto source = ConformanceSource::forExplicit(
332+
ext, locAndProto.inheritedTypeRepr);
333+
addProtocol(locAndProto.Item, locAndProto.Loc,
334+
source.withAttributes(locAndProto.attributes));
335+
}
326336
});
327337
break;
328338

@@ -977,12 +987,17 @@ ConformanceLookupTable::getConformance(NominalTypeDecl *nominal,
977987
implyingConf = origImplyingConf->getRootNormalConformance();
978988
}
979989

990+
TypeRepr *inheritedTypeRepr = nullptr;
991+
if (entry->Source.getKind() == ConformanceEntryKind::Explicit) {
992+
inheritedTypeRepr = entry->Source.getInheritedTypeRepr();
993+
}
994+
980995
// Create or find the normal conformance.
981996
auto normalConf = ctx.getNormalConformance(
982-
conformingType, protocol, conformanceLoc, conformingDC,
983-
ProtocolConformanceState::Incomplete,
984-
entry->Source.getOptions(),
985-
entry->Source.getPreconcurrencyLoc());
997+
conformingType, protocol, conformanceLoc, inheritedTypeRepr,
998+
conformingDC, ProtocolConformanceState::Incomplete,
999+
entry->Source.getOptions());
1000+
9861001
// Invalid code may cause the getConformance call below to loop, so break
9871002
// the infinite recursion by setting this eagerly to shortcircuit with the
9881003
// early return at the start of this function.
@@ -1050,10 +1065,11 @@ void ConformanceLookupTable::registerProtocolConformance(
10501065

10511066
// Otherwise, add a new entry.
10521067
auto inherited = dyn_cast<InheritedProtocolConformance>(conformance);
1053-
ConformanceSource source
1054-
= inherited ? ConformanceSource::forInherited(cast<ClassDecl>(nominal)) :
1055-
synthesized ? ConformanceSource::forSynthesized(dc) :
1056-
ConformanceSource::forExplicit(dc);
1068+
ConformanceSource source =
1069+
inherited ? ConformanceSource::forInherited(cast<ClassDecl>(nominal))
1070+
: synthesized
1071+
? ConformanceSource::forSynthesized(dc)
1072+
: ConformanceSource::forExplicit(dc, /*inheritedEntry=*/nullptr);
10571073

10581074
ASTContext &ctx = nominal->getASTContext();
10591075
ConformanceEntry *entry = new (ctx) ConformanceEntry(SourceLoc(),

lib/AST/ConformanceLookupTable.h

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,20 @@ class ConformanceLookupTable : public ASTAllocated<ConformanceLookupTable> {
8888
class ConformanceSource {
8989
void *Storage;
9090

91+
/// The `TypeRepr` of the inheritance clause entry that declares this
92+
/// conformance, if any. For example, if this is a conformance to `Y`
93+
/// declared as `struct S: X, Y & Z {}`, this is the `TypeRepr` for `Y & Z`.
94+
///
95+
/// - Important: The value can be valid only for an explicit conformance.
96+
TypeRepr *inheritedTypeRepr;
97+
9198
ConformanceEntryKind Kind;
9299

93100
ConformanceAttributes attributes;
94101

95-
ConformanceSource(void *ptr, ConformanceEntryKind kind)
96-
: Storage(ptr), Kind(kind) { }
102+
ConformanceSource(void *ptr, ConformanceEntryKind kind,
103+
TypeRepr *inheritedTypeRepr = nullptr)
104+
: Storage(ptr), inheritedTypeRepr(inheritedTypeRepr), Kind(kind) {}
97105

98106
public:
99107
/// Create an inherited conformance.
@@ -109,8 +117,10 @@ class ConformanceLookupTable : public ASTAllocated<ConformanceLookupTable> {
109117
/// The given declaration context (nominal type declaration or
110118
/// extension thereof) explicitly specifies conformance to the
111119
/// protocol.
112-
static ConformanceSource forExplicit(DeclContext *dc) {
113-
return ConformanceSource(dc, ConformanceEntryKind::Explicit);
120+
static ConformanceSource forExplicit(DeclContext *dc,
121+
TypeRepr *inheritedEntry) {
122+
return ConformanceSource(dc, ConformanceEntryKind::Explicit,
123+
inheritedEntry);
114124
}
115125

116126
/// Create an implied conformance.
@@ -134,6 +144,13 @@ class ConformanceLookupTable : public ASTAllocated<ConformanceLookupTable> {
134144
return ConformanceSource(dc, ConformanceEntryKind::PreMacroExpansion);
135145
}
136146

147+
/// Return the `TypeRepr` of the inheritance clause entry that declares this
148+
/// conformance, if any. For example, if this is a conformance to `Y`
149+
/// declared as `struct S: X, Y & Z {}`, this is the `TypeRepr` for `Y & Z`.
150+
///
151+
/// - Important: The value can be valid only for an explicit conformance.
152+
TypeRepr *getInheritedTypeRepr() const { return inheritedTypeRepr; }
153+
137154
/// Return a new conformance source with the given conformance
138155
/// attributes.
139156
ConformanceSource withAttributes(ConformanceAttributes attributes) {

lib/AST/NameLookup.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4091,7 +4091,8 @@ void swift::getDirectlyInheritedNominalTypeDecls(
40914091

40924092
// Form the result.
40934093
for (auto nominal : nominalTypes) {
4094-
result.push_back({nominal, loc, attributes, isSuppressed});
4094+
result.push_back({nominal, loc, inheritedTypes.getTypeRepr(i), attributes,
4095+
isSuppressed});
40954096
}
40964097
}
40974098

@@ -4124,8 +4125,8 @@ swift::getDirectlyInheritedNominalTypeDecls(
41244125
ConformanceAttributes attributes;
41254126
if (attr->isUnchecked())
41264127
attributes.uncheckedLoc = loc;
4127-
result.push_back(
4128-
{attr->getProtocol(), loc, attributes, /*isSuppressed=*/false});
4128+
result.push_back({attr->getProtocol(), loc, /*inheritedTypeRepr=*/nullptr,
4129+
attributes, /*isSuppressed=*/false});
41294130
}
41304131

41314132
// Else we have access to this information on the where clause.
@@ -4136,7 +4137,8 @@ swift::getDirectlyInheritedNominalTypeDecls(
41364137
// FIXME: Refactor SelfBoundsFromWhereClauseRequest to dig out
41374138
// the source location.
41384139
for (auto inheritedNominal : selfBounds.decls)
4139-
result.emplace_back(inheritedNominal, SourceLoc(), ConformanceAttributes(),
4140+
result.emplace_back(inheritedNominal, SourceLoc(),
4141+
/*inheritedTypeRepr=*/nullptr, ConformanceAttributes(),
41404142
/*isSuppressed=*/false);
41414143

41424144
return result;

0 commit comments

Comments
 (0)