Skip to content

Commit ee2450f

Browse files
authored
Merge pull request #79724 from DougGregor/isolated-conformances-constraint-system
Prohibit isolated conformances with Sendable(Metatype) constraints
2 parents 143d683 + 6a4d1a4 commit ee2450f

26 files changed

+431
-94
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2722,23 +2722,8 @@ 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))
27282725
NOTE(add_preconcurrency_to_conformance,none,
27292726
"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'", ())
2736-
ERROR(nonisolated_conformance_depends_on_isolated_conformance,none,
2737-
"conformance of %0 to %1 depends on %2 conformance of %3 to %4; mark it as 'isolated'",
2738-
(Type, DeclName, ActorIsolation, Type, DeclName))
2739-
ERROR(isolated_conformance_mismatch_with_associated_isolation,none,
2740-
"%0 conformance of %1 to %2 cannot depend on %3 conformance of %4 to %5",
2741-
(ActorIsolation, Type, DeclName, ActorIsolation, Type, DeclName))
27422727
WARNING(remove_public_import,none,
27432728
"public import of %0 was not used in public declarations or inlinable code",
27442729
(Identifier))
@@ -8309,6 +8294,33 @@ ERROR(attr_abi_incompatible_with_silgen_name,none,
83098294
"the same purpose",
83108295
(DescriptiveDeclKind))
83118296

8297+
//===----------------------------------------------------------------------===//
8298+
// MARK: Isolated conformances
8299+
//===----------------------------------------------------------------------===//
8300+
ERROR(isolated_conformance_not_global_actor_isolated,none,
8301+
"isolated conformance is only permitted on global-actor-isolated types",
8302+
())
8303+
ERROR(isolated_conformance_experimental_feature,none,
8304+
"isolated conformances require experimental feature "
8305+
" 'IsolatedConformances'", ())
8306+
ERROR(nonisolated_conformance_depends_on_isolated_conformance,none,
8307+
"conformance of %0 to %1 depends on %2 conformance of %3 to %4; mark it as 'isolated'",
8308+
(Type, DeclName, ActorIsolation, Type, DeclName))
8309+
ERROR(isolated_conformance_mismatch_with_associated_isolation,none,
8310+
"%0 conformance of %1 to %2 cannot depend on %3 conformance of %4 to %5",
8311+
(ActorIsolation, Type, DeclName, ActorIsolation, Type, DeclName))
8312+
NOTE(add_isolated_to_conformance,none,
8313+
"add 'isolated' to the %0 conformance to restrict it to %1 code",
8314+
(DeclName, ActorIsolation))
8315+
ERROR(isolated_conformance_with_sendable,none,
8316+
"isolated conformance of %0 to %1 cannot be used to satisfy conformance "
8317+
"requirement for a %select{`Sendable`|`SendableMetatype`}2 type "
8318+
"parameter %3", (Type, DeclName, bool, Type))
8319+
ERROR(isolated_conformance_with_sendable_simple,none,
8320+
"isolated conformance of %0 to %1 cannot be used to satisfy conformance "
8321+
"requirement for a `Sendable` type parameter ",
8322+
(Type, DeclName))
8323+
83128324
//===----------------------------------------------------------------------===//
83138325
// MARK: @execution Attribute
83148326
//===----------------------------------------------------------------------===//

include/swift/AST/ProtocolConformanceRef.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,14 @@ class ProtocolConformanceRef {
140140
bool forEachMissingConformance(
141141
llvm::function_ref<bool(BuiltinProtocolConformance *missing)> fn) const;
142142

143+
/// Enumerate all of the isolated conformances in the given conformance.
144+
///
145+
/// The given `body` will be called on each isolated conformance. If it ever
146+
/// returns `true`, this function will abort the search and return `true`.
147+
bool forEachIsolatedConformance(
148+
llvm::function_ref<bool(ProtocolConformance*)> body
149+
) const;
150+
143151
using OpaqueValue = void*;
144152
OpaqueValue getOpaqueValue() const { return Union.getOpaqueValue(); }
145153
static ProtocolConformanceRef getFromOpaqueValue(OpaqueValue value) {

include/swift/AST/Requirement.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,13 @@ class Requirement {
187187
/// \param subReqs An out parameter initialized to a list of simpler
188188
/// requirements which the caller must check to ensure this
189189
/// requirement is completely satisfied.
190+
/// \param isolatedConformances If non-NULL, will be provided with all of the
191+
/// isolated conformances that
190192
CheckRequirementResult checkRequirement(
191193
SmallVectorImpl<Requirement> &subReqs,
192-
bool allowMissing = false) const;
194+
bool allowMissing = false,
195+
SmallVectorImpl<ProtocolConformance *> *isolatedConformances = nullptr
196+
) const;
193197

194198
/// Determines if this substituted requirement can ever be satisfied,
195199
/// possibly with additional substitutions.

include/swift/Sema/CSFix.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,9 @@ enum class FixKind : uint8_t {
487487
/// Ignore when an 'InlineArray' literal has mismatched number of elements to
488488
/// the type it's attempting to bind to.
489489
AllowInlineArrayLiteralCountMismatch,
490+
491+
/// Ignore that a conformance is isolated but is not allowed to be.
492+
IgnoreIsolatedConformance,
490493
};
491494

492495
class ConstraintFix {
@@ -3865,6 +3868,35 @@ class AllowInlineArrayLiteralCountMismatch final : public ConstraintFix {
38653868
}
38663869
};
38673870

3871+
class IgnoreIsolatedConformance : public ConstraintFix {
3872+
ProtocolConformance *conformance;
3873+
3874+
IgnoreIsolatedConformance(ConstraintSystem &cs,
3875+
ConstraintLocator *locator,
3876+
ProtocolConformance *conformance)
3877+
: ConstraintFix(cs, FixKind::IgnoreIsolatedConformance, locator),
3878+
conformance(conformance) { }
3879+
3880+
public:
3881+
std::string getName() const override {
3882+
return "ignore isolated conformance";
3883+
}
3884+
3885+
bool diagnose(const Solution &solution, bool asNote = false) const override;
3886+
3887+
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
3888+
return diagnose(*commonFixes.front().first);
3889+
}
3890+
3891+
static IgnoreIsolatedConformance *create(ConstraintSystem &cs,
3892+
ConstraintLocator *locator,
3893+
ProtocolConformance *conformance);
3894+
3895+
static bool classof(const ConstraintFix *fix) {
3896+
return fix->getKind() == FixKind::IgnoreIsolatedConformance;
3897+
}
3898+
};
3899+
38683900
} // end namespace constraints
38693901
} // end namespace swift
38703902

include/swift/Sema/Constraint.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ enum class ConstraintKind : char {
8585
/// class type).
8686
SubclassOf,
8787
/// The first type must conform to the second type (which is a
88+
/// protocol type) and the conformance must not be an isolated conformance.
89+
NonisolatedConformsTo,
90+
/// The first type must conform to the second type (which is a
8891
/// protocol type).
8992
ConformsTo,
9093
/// The first type describes a literal that conforms to the second
@@ -689,6 +692,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
689692
case ConstraintKind::OperatorArgumentConversion:
690693
case ConstraintKind::SubclassOf:
691694
case ConstraintKind::ConformsTo:
695+
case ConstraintKind::NonisolatedConformsTo:
692696
case ConstraintKind::LiteralConformsTo:
693697
case ConstraintKind::TransitivelyConformsTo:
694698
case ConstraintKind::CheckedCast:

include/swift/Sema/ConstraintSystem.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3666,7 +3666,8 @@ class ConstraintSystem {
36663666

36673667
/// Add a requirement as a constraint to the constraint system.
36683668
void addConstraint(Requirement req, ConstraintLocatorBuilder locator,
3669-
bool isFavored = false);
3669+
bool isFavored,
3670+
bool prohibitNonisolatedConformance);
36703671

36713672
void addApplicationConstraint(
36723673
FunctionType *appliedFn, Type calleeType,
@@ -4363,6 +4364,7 @@ class ConstraintSystem {
43634364

43644365
// Record the given requirement in the constraint system.
43654366
void openGenericRequirement(DeclContext *outerDC,
4367+
GenericSignature signature,
43664368
unsigned index,
43674369
const Requirement &requirement,
43684370
bool skipProtocolSelfConstraint,

lib/AST/ProtocolConformanceRef.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,42 @@ bool ProtocolConformanceRef::forEachMissingConformance(
386386
return false;
387387
}
388388

389+
bool ProtocolConformanceRef::forEachIsolatedConformance(
390+
llvm::function_ref<bool(ProtocolConformance*)> body
391+
) const {
392+
if (isInvalid() || isAbstract())
393+
return false;
394+
395+
if (isPack()) {
396+
auto pack = getPack()->getPatternConformances();
397+
for (auto conformance : pack) {
398+
if (conformance.forEachIsolatedConformance(body))
399+
return true;
400+
}
401+
402+
return false;
403+
}
404+
405+
// Is this an isolated conformance?
406+
auto concrete = getConcrete();
407+
if (auto normal =
408+
dyn_cast<NormalProtocolConformance>(concrete->getRootConformance())) {
409+
if (normal->isIsolated()) {
410+
if (body(concrete))
411+
return true;
412+
}
413+
}
414+
415+
// Check conformances that are part of this conformance.
416+
auto subMap = concrete->getSubstitutionMap();
417+
for (auto conformance : subMap.getConformances()) {
418+
if (conformance.forEachIsolatedConformance(body))
419+
return true;
420+
}
421+
422+
return false;
423+
}
424+
389425
void swift::simple_display(llvm::raw_ostream &out, ProtocolConformanceRef conformanceRef) {
390426
if (conformanceRef.isAbstract()) {
391427
simple_display(out, conformanceRef.getAbstract());

lib/AST/Requirement.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ ProtocolDecl *Requirement::getProtocolDecl() const {
8282

8383
CheckRequirementResult Requirement::checkRequirement(
8484
SmallVectorImpl<Requirement> &subReqs,
85-
bool allowMissing) const {
85+
bool allowMissing,
86+
SmallVectorImpl<ProtocolConformance *> *isolatedConformances
87+
) const {
8688
if (hasError())
8789
return CheckRequirementResult::SubstitutionFailure;
8890

@@ -122,6 +124,15 @@ CheckRequirementResult Requirement::checkRequirement(
122124
if (!conformance)
123125
return CheckRequirementResult::RequirementFailure;
124126

127+
// Collect isolated conformances.
128+
if (isolatedConformances) {
129+
conformance.forEachIsolatedConformance(
130+
[&](ProtocolConformance *isolatedConformance) {
131+
isolatedConformances->push_back(isolatedConformance);
132+
return false;
133+
});
134+
}
135+
125136
auto condReqs = conformance.getConditionalRequirements();
126137
if (condReqs.empty())
127138
return CheckRequirementResult::Success;

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ static void desugarSuperclassRequirement(
300300

301301
SmallVector<Requirement, 2> subReqs;
302302

303-
switch (req.checkRequirement(subReqs)) {
303+
switch (req.checkRequirement(subReqs, /*allowMissing=*/false)) {
304304
case CheckRequirementResult::Success:
305305
case CheckRequirementResult::PackRequirement:
306306
break;
@@ -333,7 +333,7 @@ static void desugarLayoutRequirement(
333333

334334
SmallVector<Requirement, 2> subReqs;
335335

336-
switch (req.checkRequirement(subReqs)) {
336+
switch (req.checkRequirement(subReqs, /*allowMissing=*/false)) {
337337
case CheckRequirementResult::Success:
338338
case CheckRequirementResult::PackRequirement:
339339
break;

lib/IDE/IDETypeChecking.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ struct SynthesizedExtensionAnalyzer::Implementation {
363363

364364
while (!subReqs.empty()) {
365365
auto req = subReqs.pop_back_val();
366-
switch (req.checkRequirement(subReqs)) {
366+
switch (req.checkRequirement(subReqs, /*allowMissing=*/false)) {
367367
case CheckRequirementResult::Success:
368368
case CheckRequirementResult::PackRequirement:
369369
case CheckRequirementResult::ConditionalConformance:

lib/Sema/CSBindings.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ BindingSet::BindingSet(ConstraintSystem &CS, TypeVariableType *TypeVar,
5151

5252
for (auto *constraint : info.Constraints) {
5353
switch (constraint->getKind()) {
54+
case ConstraintKind::NonisolatedConformsTo:
5455
case ConstraintKind::ConformsTo:
5556
if (constraint->getSecondType()->is<ProtocolType>())
5657
Protocols.push_back(constraint);
@@ -256,7 +257,8 @@ bool BindingSet::isPotentiallyIncomplete() const {
256257
// that's done as a last resort effort at resolving first member.
257258
if (auto *constraint = binding.getSource()) {
258259
if (binding.BindingType->is<ProtocolType>() &&
259-
constraint->getKind() == ConstraintKind::ConformsTo)
260+
(constraint->getKind() == ConstraintKind::ConformsTo ||
261+
constraint->getKind() == ConstraintKind::NonisolatedConformsTo))
260262
return true;
261263
}
262264
}
@@ -1941,6 +1943,7 @@ void PotentialBindings::infer(ConstraintSystem &CS,
19411943
case ConstraintKind::PackElementOf:
19421944
case ConstraintKind::SameShape:
19431945
case ConstraintKind::MaterializePackExpansion:
1946+
case ConstraintKind::NonisolatedConformsTo:
19441947
case ConstraintKind::ConformsTo:
19451948
case ConstraintKind::LiteralConformsTo:
19461949
case ConstraintKind::Defaultable:

lib/Sema/CSDiagnostics.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9562,3 +9562,19 @@ bool IncorrectInlineArrayLiteralCount::diagnoseAsError() {
95629562
emitDiagnostic(diag::inlinearray_literal_incorrect_count, lhsCount, rhsCount);
95639563
return true;
95649564
}
9565+
9566+
bool DisallowedIsolatedConformance::diagnoseAsError() {
9567+
emitDiagnostic(diag::isolated_conformance_with_sendable_simple,
9568+
conformance->getType(),
9569+
conformance->getProtocol()->getName());
9570+
9571+
auto selectedOverload = getCalleeOverloadChoiceIfAvailable(getLocator());
9572+
if (!selectedOverload)
9573+
return true;
9574+
9575+
if (auto *decl = selectedOverload->choice.getDeclOrNull()) {
9576+
emitDiagnosticAt(decl, diag::decl_declared_here, decl);
9577+
}
9578+
9579+
return true;
9580+
}

lib/Sema/CSDiagnostics.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3252,6 +3252,21 @@ class IncorrectInlineArrayLiteralCount final : public FailureDiagnostic {
32523252
bool diagnoseAsError() override;
32533253
};
32543254

3255+
/// Diagnose when an isolated conformance is used in a place where one cannot
3256+
/// be, e.g., due to a Sendable or SendableMetatype requirement on the
3257+
/// corresponding type parameter.
3258+
class DisallowedIsolatedConformance final : public FailureDiagnostic {
3259+
ProtocolConformance *conformance;
3260+
3261+
public:
3262+
DisallowedIsolatedConformance(const Solution &solution,
3263+
ProtocolConformance *conformance,
3264+
ConstraintLocator *locator)
3265+
: FailureDiagnostic(solution, locator), conformance(conformance) {}
3266+
3267+
bool diagnoseAsError() override;
3268+
};
3269+
32553270
} // end namespace constraints
32563271
} // end namespace swift
32573272

lib/Sema/CSFix.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2740,3 +2740,18 @@ bool AllowInlineArrayLiteralCountMismatch::diagnose(const Solution &solution,
27402740
getLocator());
27412741
return failure.diagnose(asNote);
27422742
}
2743+
2744+
IgnoreIsolatedConformance *
2745+
IgnoreIsolatedConformance::create(ConstraintSystem &cs,
2746+
ConstraintLocator *locator,
2747+
ProtocolConformance *conformance) {
2748+
assert(conformance && "Must have an isolated conformance");
2749+
return new (cs.getAllocator())
2750+
IgnoreIsolatedConformance(cs, locator, conformance);
2751+
}
2752+
2753+
bool IgnoreIsolatedConformance::diagnose(const Solution &solution,
2754+
bool asNote) const {
2755+
DisallowedIsolatedConformance failure(solution, conformance, getLocator());
2756+
return failure.diagnose(asNote);
2757+
}

0 commit comments

Comments
 (0)