Skip to content

Commit 6a4d1a4

Browse files
committed
Prohibit isolated conformances with Sendable(Metatype) constraints
Within the constraint system, introduce a new kind of conformance constraint, a "nonisolated conforms-to" constraint, which can only be satisfied by nonisolated conformances. Introduce this constraint instead of the normal conforms-to constraint whenever the subject type is a type parameter that has either a `Sendable` or `SendableMetatype` constraint, i.e., when the type or its values can escape the current isolation domain.
1 parent ffca696 commit 6a4d1a4

16 files changed

+238
-39
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8316,6 +8316,10 @@ ERROR(isolated_conformance_with_sendable,none,
83168316
"isolated conformance of %0 to %1 cannot be used to satisfy conformance "
83178317
"requirement for a %select{`Sendable`|`SendableMetatype`}2 type "
83188318
"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))
83198323

83208324
//===----------------------------------------------------------------------===//
83218325
// MARK: @execution Attribute

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/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+
}

lib/Sema/CSSimplify.cpp

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1877,7 +1877,8 @@ static ConstraintSystem::TypeMatchResult matchCallArguments(
18771877
auto &CG = cs.getConstraintGraph();
18781878

18791879
auto isTransferableConformance = [&typeVar](Constraint *constraint) {
1880-
if (constraint->getKind() != ConstraintKind::ConformsTo)
1880+
if (constraint->getKind() != ConstraintKind::ConformsTo &&
1881+
constraint->getKind() != ConstraintKind::NonisolatedConformsTo)
18811882
return false;
18821883

18831884
auto requirementTy = constraint->getFirstType();
@@ -2167,6 +2168,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
21672168
case ConstraintKind::BindOverload:
21682169
case ConstraintKind::CheckedCast:
21692170
case ConstraintKind::SubclassOf:
2171+
case ConstraintKind::NonisolatedConformsTo:
21702172
case ConstraintKind::ConformsTo:
21712173
case ConstraintKind::TransitivelyConformsTo:
21722174
case ConstraintKind::Defaultable:
@@ -2530,6 +2532,7 @@ static bool matchFunctionRepresentations(FunctionType::ExtInfo einfo1,
25302532
case ConstraintKind::BindOverload:
25312533
case ConstraintKind::CheckedCast:
25322534
case ConstraintKind::SubclassOf:
2535+
case ConstraintKind::NonisolatedConformsTo:
25332536
case ConstraintKind::ConformsTo:
25342537
case ConstraintKind::TransitivelyConformsTo:
25352538
case ConstraintKind::Defaultable:
@@ -3220,6 +3223,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
32203223
case ConstraintKind::BindOverload:
32213224
case ConstraintKind::CheckedCast:
32223225
case ConstraintKind::SubclassOf:
3226+
case ConstraintKind::NonisolatedConformsTo:
32233227
case ConstraintKind::ConformsTo:
32243228
case ConstraintKind::TransitivelyConformsTo:
32253229
case ConstraintKind::Defaultable:
@@ -4100,7 +4104,8 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
41004104

41014105
if (auto layoutConstraint = layout.getLayoutConstraint()) {
41024106
if (layoutConstraint->isClass()) {
4103-
if (kind == ConstraintKind::ConformsTo) {
4107+
if (kind == ConstraintKind::ConformsTo ||
4108+
kind == ConstraintKind::NonisolatedConformsTo) {
41044109
if (!type1->satisfiesClassConstraint()) {
41054110
if (shouldAttemptFixes()) {
41064111
if (auto last = locator.last()) {
@@ -7170,6 +7175,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
71707175
case ConstraintKind::BridgingConversion:
71717176
case ConstraintKind::CheckedCast:
71727177
case ConstraintKind::SubclassOf:
7178+
case ConstraintKind::NonisolatedConformsTo:
71737179
case ConstraintKind::ConformsTo:
71747180
case ConstraintKind::TransitivelyConformsTo:
71757181
case ConstraintKind::Defaultable:
@@ -8525,6 +8531,10 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
85258531
locator, flags);
85268532
}
85278533

8534+
auto conformsToSubKind = (kind == ConstraintKind::NonisolatedConformsTo)
8535+
? kind
8536+
: ConstraintKind::ConformsTo;
8537+
85288538
// Dig out the fixed type to which this type refers.
85298539
type = getFixedTypeRecursive(type, flags, /*wantRValue=*/true);
85308540

@@ -8538,11 +8548,11 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
85388548
if (auto *packExpansionType = eltType->getAs<PackExpansionType>()) {
85398549
auto patternLoc =
85408550
locator.withPathElement(ConstraintLocator::PackExpansionPattern);
8541-
addConstraint(ConstraintKind::ConformsTo,
8551+
addConstraint(conformsToSubKind,
85428552
packExpansionType->getPatternType(), protocol,
85438553
patternLoc);
85448554
} else {
8545-
addConstraint(ConstraintKind::ConformsTo, eltType, protocol,
8555+
addConstraint(conformsToSubKind, eltType, protocol,
85468556
locator.withPathElement(LocatorPathElt::PackElement(i)));
85478557
}
85488558
}
@@ -8607,6 +8617,10 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
86078617
if (type->isTypeVariableOrMember())
86088618
return formUnsolved();
86098619

8620+
auto conformsToSubKind = kind;
8621+
if (kind != ConstraintKind::NonisolatedConformsTo)
8622+
conformsToSubKind = ConstraintKind::ConformsTo;
8623+
86108624
// ConformsTo constraints are generated when opening a generic
86118625
// signature with a RequirementKind::Conformance requirement, so
86128626
// we must handle pack types on the left by splitting up into
@@ -8617,12 +8631,12 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
86178631
if (auto *packExpansionType = eltType->getAs<PackExpansionType>()) {
86188632
auto patternLoc =
86198633
locator.withPathElement(ConstraintLocator::PackExpansionPattern);
8620-
addConstraint(ConstraintKind::ConformsTo,
8634+
addConstraint(conformsToSubKind,
86218635
packExpansionType->getPatternType(),
86228636
protocol->getDeclaredInterfaceType(),
86238637
patternLoc);
86248638
} else {
8625-
addConstraint(ConstraintKind::ConformsTo, eltType,
8639+
addConstraint(conformsToSubKind, eltType,
86268640
protocol->getDeclaredInterfaceType(),
86278641
locator.withPathElement(LocatorPathElt::PackElement(i)));
86288642
}
@@ -8634,7 +8648,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
86348648
// We sometimes get a pack expansion type here.
86358649
if (auto *expansionType = type->getAs<PackExpansionType>()) {
86368650
addConstraint(
8637-
ConstraintKind::ConformsTo, expansionType->getPatternType(),
8651+
conformsToSubKind, expansionType->getPatternType(),
86388652
protocol->getDeclaredInterfaceType(),
86398653
locator.withPathElement(LocatorPathElt::PackExpansionPattern()));
86408654

@@ -8658,6 +8672,27 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
86588672
if (numMissing > 0)
86598673
increaseScore(SK_MissingSynthesizableConformance, locator, numMissing);
86608674

8675+
// If we aren't allowed to have an isolated conformance, check for any
8676+
// isolated conformances here.
8677+
if (kind == ConstraintKind::NonisolatedConformsTo &&
8678+
!conformance.getRequirement()->isMarkerProtocol()) {
8679+
// Grab the first isolated conformance, if there is one.
8680+
ProtocolConformance *isolatedConformance = nullptr;
8681+
conformance.forEachIsolatedConformance([&](ProtocolConformance *conf) {
8682+
if (!isolatedConformance)
8683+
isolatedConformance = conf;
8684+
return true;
8685+
});
8686+
8687+
if (isolatedConformance) {
8688+
auto fix = IgnoreIsolatedConformance::create(
8689+
*this, getConstraintLocator(locator), isolatedConformance);
8690+
if (recordFix(fix)) {
8691+
return SolutionKind::Error;
8692+
}
8693+
}
8694+
}
8695+
86618696
// This conformance may be conditional, in which case we need to consider
86628697
// those requirements as constraints too.
86638698
if (conformance.isConcrete()) {
@@ -8670,7 +8705,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
86708705
addConstraint(
86718706
req, getConstraintLocator(conformanceLoc,
86728707
LocatorPathElt::ConditionalRequirement(
8673-
index++, req.getKind())));
8708+
index++, req.getKind())),
8709+
/*isFavored=*/false, kind == ConstraintKind::NonisolatedConformsTo);
86748710
}
86758711
}
86768712

@@ -8688,6 +8724,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
86888724
return recordConformance(conformance);
86898725
}
86908726
} break;
8727+
case ConstraintKind::NonisolatedConformsTo:
86918728
case ConstraintKind::ConformsTo:
86928729
case ConstraintKind::LiteralConformsTo: {
86938730
// If existential type is used as a for-in sequence, let's open it
@@ -8996,7 +9033,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
89969033

89979034
// Conformance constraint that is introduced by an implicit conversion
89989035
// for example to `AnyHashable`.
8999-
if (kind == ConstraintKind::ConformsTo &&
9036+
if ((kind == ConstraintKind::ConformsTo ||
9037+
kind == ConstraintKind::NonisolatedConformsTo) &&
90009038
loc->isLastElement<LocatorPathElt::ApplyArgToParam>()) {
90019039
auto *fix = AllowArgumentMismatch::create(*this, type, protocolTy, loc);
90029040
return recordFix(fix, /*impact=*/2) ? SolutionKind::Error
@@ -15731,6 +15769,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1573115769
case FixKind::IgnoreOutOfPlaceThenStmt:
1573215770
case FixKind::IgnoreMissingEachKeyword:
1573315771
case FixKind::AllowInlineArrayLiteralCountMismatch:
15772+
case FixKind::IgnoreIsolatedConformance:
1573415773
llvm_unreachable("handled elsewhere");
1573515774
}
1573615775

@@ -15780,6 +15819,7 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first,
1578015819
case ConstraintKind::SubclassOf:
1578115820
return simplifySubclassOfConstraint(first, second, locator, subflags);
1578215821

15822+
case ConstraintKind::NonisolatedConformsTo:
1578315823
case ConstraintKind::ConformsTo:
1578415824
case ConstraintKind::LiteralConformsTo:
1578515825
return simplifyConformsToConstraint(first, second, kind, locator,
@@ -15992,7 +16032,8 @@ ConstraintSystem::addKeyPathConstraint(
1599216032

1599316033
void ConstraintSystem::addConstraint(Requirement req,
1599416034
ConstraintLocatorBuilder locator,
15995-
bool isFavored) {
16035+
bool isFavored,
16036+
bool prohibitNonisolatedConformance) {
1599616037
bool conformsToAnyObject = false;
1599716038
std::optional<ConstraintKind> kind;
1599816039
switch (req.getKind()) {
@@ -16005,7 +16046,9 @@ void ConstraintSystem::addConstraint(Requirement req,
1600516046
}
1600616047

1600716048
case RequirementKind::Conformance:
16008-
kind = ConstraintKind::ConformsTo;
16049+
kind = prohibitNonisolatedConformance
16050+
? ConstraintKind::NonisolatedConformsTo
16051+
: ConstraintKind::ConformsTo;
1600916052
break;
1601016053
case RequirementKind::Superclass: {
1601116054
// FIXME: Should always use ConstraintKind::SubclassOf, but that breaks
@@ -16348,6 +16391,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
1634816391
constraint.getLocator(),
1634916392
/*flags*/ std::nullopt);
1635016393

16394+
case ConstraintKind::NonisolatedConformsTo:
1635116395
case ConstraintKind::ConformsTo:
1635216396
case ConstraintKind::LiteralConformsTo:
1635316397
return simplifyConformsToConstraint(

0 commit comments

Comments
 (0)