Skip to content

Commit de29302

Browse files
committed
Parsing and type checking for the definition of isolated conformances
Allow a conformance to be "isolated", meaning that it stays in the same isolation domain as the conforming type. Only allow this for global-actor-isolated types. When a conformance is isolated, a nonisolated requirement can be witnessed by a declaration with the same global actor isolation as the enclosing type.
1 parent 556bfd2 commit de29302

15 files changed

+175
-24
lines changed

include/swift/AST/ConformanceAttributes.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ struct ConformanceAttributes {
2727

2828
/// The location of the "unsafe" attribute if present.
2929
SourceLoc unsafeLoc;
30+
31+
/// The location of the "@isolated" attribute if present.
32+
SourceLoc isolatedLoc;
3033

3134
/// Merge other conformance attributes into this set.
3235
ConformanceAttributes &
@@ -37,6 +40,8 @@ struct ConformanceAttributes {
3740
preconcurrencyLoc = other.preconcurrencyLoc;
3841
if (other.unsafeLoc.isValid())
3942
unsafeLoc = other.unsafeLoc;
43+
if (other.isolatedLoc.isValid())
44+
isolatedLoc = other.isolatedLoc;
4045
return *this;
4146
}
4247
};

include/swift/AST/Decl.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1836,12 +1836,13 @@ struct InheritedEntry : public TypeLoc {
18361836
bool isPreconcurrency() const {
18371837
return getOptions().contains(ProtocolConformanceFlags::Preconcurrency);
18381838
}
1839+
bool isIsolated() const {
1840+
return getOptions().contains(ProtocolConformanceFlags::Isolated);
1841+
}
18391842

18401843
ExplicitSafety getExplicitSafety() const {
18411844
if (getOptions().contains(ProtocolConformanceFlags::Unsafe))
18421845
return ExplicitSafety::Unsafe;
1843-
if (getOptions().contains(ProtocolConformanceFlags::Safe))
1844-
return ExplicitSafety::Safe;
18451846
return ExplicitSafety::Unspecified;
18461847
}
18471848

@@ -1852,13 +1853,10 @@ struct InheritedEntry : public TypeLoc {
18521853
}
18531854

18541855
void setOption(ExplicitSafety safety) {
1855-
RawOptions = (getOptions() - ProtocolConformanceFlags::Unsafe
1856-
- ProtocolConformanceFlags::Safe).toRaw();
1856+
RawOptions = (getOptions() - ProtocolConformanceFlags::Unsafe).toRaw();
18571857
switch (safety) {
18581858
case ExplicitSafety::Unspecified:
1859-
break;
18601859
case ExplicitSafety::Safe:
1861-
RawOptions = (getOptions() | ProtocolConformanceFlags::Safe).toRaw();
18621860
break;
18631861
case ExplicitSafety::Unsafe:
18641862
RawOptions = (getOptions() | ProtocolConformanceFlags::Unsafe).toRaw();

include/swift/AST/DiagnosticsSema.def

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2722,8 +2722,17 @@ WARNING(add_predates_concurrency_import,none,
27222722
GROUPED_WARNING(remove_predates_concurrency_import,PreconcurrencyImport,
27232723
DefaultIgnore,
27242724
"'@preconcurrency' attribute on module %0 has no effect", (Identifier))
2725+
NOTE(add_isolated_to_conformance,none,
2726+
"add 'isolated' to the %0 conformance to restrict it to %1 code",
2727+
(DeclName, ActorIsolation))
27252728
NOTE(add_preconcurrency_to_conformance,none,
27262729
"add '@preconcurrency' to the %0 conformance to defer isolation checking to run time", (DeclName))
2730+
ERROR(isolated_conformance_not_global_actor_isolated,none,
2731+
"isolated conformance is only permitted on global-actor-isolated types",
2732+
())
2733+
ERROR(isolated_conformance_experimental_feature,none,
2734+
"isolated conformances require experimental feature "
2735+
" 'IsolatedConformances'", ())
27272736
WARNING(remove_public_import,none,
27282737
"public import of %0 was not used in public declarations or inlinable code",
27292738
(Identifier))

include/swift/AST/ProtocolConformance.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,11 @@ class NormalProtocolConformance : public RootProtocolConformance,
669669
return getOptions().contains(ProtocolConformanceFlags::Preconcurrency);
670670
}
671671

672+
/// Whether this is an isolated conformance.
673+
bool isIsolated() const {
674+
return getOptions().contains(ProtocolConformanceFlags::Isolated);
675+
}
676+
672677
/// Retrieve the location of `@preconcurrency`, if there is one and it is
673678
/// known.
674679
SourceLoc getPreconcurrencyLoc() const { return PreconcurrencyLoc; }
@@ -678,8 +683,6 @@ class NormalProtocolConformance : public RootProtocolConformance,
678683
ExplicitSafety getExplicitSafety() const {
679684
if (getOptions().contains(ProtocolConformanceFlags::Unsafe))
680685
return ExplicitSafety::Unsafe;
681-
if (getOptions().contains(ProtocolConformanceFlags::Safe))
682-
return ExplicitSafety::Safe;
683686
return ExplicitSafety::Unspecified;
684687
}
685688

include/swift/AST/ProtocolConformanceOptions.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ enum class ProtocolConformanceFlags {
3434
/// @retroactive conformance
3535
Retroactive = 0x08,
3636

37-
/// @safe conformance
38-
Safe = 0x10,
37+
/// @isolated conformance
38+
Isolated = 0x10,
3939

4040
// Note: whenever you add a bit here, update
4141
// NumProtocolConformanceOptions below.

include/swift/Basic/Features.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,11 +450,15 @@ SUPPRESSIBLE_EXPERIMENTAL_FEATURE(CustomAvailability, true)
450450
/// Be strict about the Sendable conformance of metatypes.
451451
EXPERIMENTAL_FEATURE(StrictSendableMetatypes, true)
452452

453+
453454
/// Allow public enumerations to be extensible by default
454455
/// regardless of whether the module they are declared in
455456
/// is resilient or not.
456457
EXPERIMENTAL_FEATURE(ExtensibleEnums, true)
457458

459+
/// Allow isolated conformances.
460+
EXPERIMENTAL_FEATURE(IsolatedConformances, true)
461+
458462
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
459463
#undef EXPERIMENTAL_FEATURE
460464
#undef UPCOMING_FEATURE

lib/AST/ConformanceLookupTable.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ class ConformanceLookupTable : public ASTAllocated<ConformanceLookupTable> {
154154
options |= ProtocolConformanceFlags::Preconcurrency;
155155
if (getUnsafeLoc().isValid())
156156
options |= ProtocolConformanceFlags::Unsafe;
157+
if (getIsolatedLoc().isValid())
158+
options |= ProtocolConformanceFlags::Isolated;
157159
return options;
158160
}
159161

@@ -209,6 +211,11 @@ class ConformanceLookupTable : public ASTAllocated<ConformanceLookupTable> {
209211
return attributes.unsafeLoc;
210212
}
211213

214+
/// The location of the @isolated attribute, if any.
215+
SourceLoc getIsolatedLoc() const {
216+
return attributes.isolatedLoc;
217+
}
218+
212219
/// For an inherited conformance, retrieve the class declaration
213220
/// for the inheriting class.
214221
ClassDecl *getInheritingClass() const {

lib/AST/Decl.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1780,6 +1780,8 @@ InheritedEntry::InheritedEntry(const TypeLoc &typeLoc)
17801780
setOption(ProtocolConformanceFlags::Unsafe);
17811781
if (typeRepr->findAttrLoc(TypeAttrKind::Preconcurrency).isValid())
17821782
setOption(ProtocolConformanceFlags::Preconcurrency);
1783+
if (typeRepr->findAttrLoc(TypeAttrKind::Isolated).isValid())
1784+
setOption(ProtocolConformanceFlags::Isolated);
17831785
}
17841786
}
17851787

lib/AST/FeatureSet.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,11 @@ static bool usesFeatureABIAttribute(Decl *decl) {
348348
return getABIAttr(decl) != nullptr;
349349
}
350350

351+
static bool usesFeatureIsolatedConformances(Decl *decl) {
352+
// FIXME: Check conformances associated with this decl?
353+
return false;
354+
}
355+
351356
UNINTERESTING_FEATURE(WarnUnsafe)
352357
UNINTERESTING_FEATURE(SafeInteropWrappers)
353358
UNINTERESTING_FEATURE(AssumeResilientCxxTypes)

lib/AST/NameLookup.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3144,6 +3144,12 @@ directReferencesForTypeRepr(Evaluator &evaluator, ASTContext &ctx,
31443144
attributed->getTypeRepr(), dc, options);
31453145
}
31463146

3147+
case TypeReprKind::Isolated: {
3148+
auto isolated = cast<IsolatedTypeRepr>(typeRepr);
3149+
return directReferencesForTypeRepr(evaluator, ctx,
3150+
isolated->getBase(), dc, options);
3151+
}
3152+
31473153
case TypeReprKind::Composition: {
31483154
auto composition = cast<CompositionTypeRepr>(typeRepr);
31493155
for (auto component : composition->getTypes()) {
@@ -3217,7 +3223,6 @@ directReferencesForTypeRepr(Evaluator &evaluator, ASTContext &ctx,
32173223
case TypeReprKind::Error:
32183224
case TypeReprKind::Function:
32193225
case TypeReprKind::Ownership:
3220-
case TypeReprKind::Isolated:
32213226
case TypeReprKind::CompileTimeConst:
32223227
case TypeReprKind::Metatype:
32233228
case TypeReprKind::Protocol:
@@ -3933,6 +3938,21 @@ CustomAttrNominalRequest::evaluate(Evaluator &evaluator,
39333938
return nullptr;
39343939
}
39353940

3941+
/// Find the location of 'isolated' within this type representation.
3942+
static SourceLoc findIsolatedLoc(TypeRepr *typeRepr) {
3943+
do {
3944+
if (auto isolatedTypeRepr = dyn_cast<IsolatedTypeRepr>(typeRepr))
3945+
return isolatedTypeRepr->getLoc();
3946+
3947+
if (auto attrTypeRepr = dyn_cast<AttributedTypeRepr>(typeRepr)) {
3948+
typeRepr = attrTypeRepr->getTypeRepr();
3949+
continue;
3950+
}
3951+
3952+
return SourceLoc();
3953+
} while (true);
3954+
}
3955+
39363956
/// Decompose the ith inheritance clause entry to a list of type declarations,
39373957
/// inverses, and optional AnyObject member.
39383958
void swift::getDirectlyInheritedNominalTypeDecls(
@@ -3971,6 +3991,9 @@ void swift::getDirectlyInheritedNominalTypeDecls(
39713991
attributes.uncheckedLoc = typeRepr->findAttrLoc(TypeAttrKind::Unchecked);
39723992
attributes.preconcurrencyLoc = typeRepr->findAttrLoc(TypeAttrKind::Preconcurrency);
39733993
attributes.unsafeLoc = typeRepr->findAttrLoc(TypeAttrKind::Unsafe);
3994+
3995+
// Look for an IsolatedTypeRepr.
3996+
attributes.isolatedLoc = findIsolatedLoc(typeRepr);
39743997
}
39753998

39763999
// Form the result.

0 commit comments

Comments
 (0)