Skip to content

Commit ab13088

Browse files
committed
Initial ban of move-only types from being used generically
Since values of generic type are currently assumed to always support copying, we need to prevent move-only types from being substituted for generic type parameters. This approach leans on a `_Copyable` marker protocol to which all generic type parameters implicitly must conform. A few other changes in this initial implementation: - Now every concrete type that can conform to Copyable will do so. This fixes issues with conforming to a protocol that requires Copyable. - Narrowly ban writing a concrete type `[T]` when `T` is move-only.
1 parent 882e105 commit ab13088

17 files changed

+397
-14
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6653,6 +6653,7 @@ ERROR(noimplicitcopy_attr_valid_only_on_local_let_params,
66536653
none, "'@_noImplicitCopy' attribute can only be applied to local lets and params", ())
66546654
ERROR(noimplicitcopy_attr_invalid_in_generic_context,
66556655
none, "'@_noImplicitCopy' attribute cannot be applied to entities in generic contexts", ())
6656+
ERROR(moveonly_generics, none, "move-only type %0 cannot be used with generics yet", (Type))
66566657
ERROR(noimplicitcopy_attr_not_allowed_on_moveonlytype,none,
66576658
"'@_noImplicitCopy' has no effect when applied to a move only type", ())
66586659

@@ -6972,4 +6973,3 @@ NOTE(opt_out_from_missing_reflection_metadata_attr,none,
69726973

69736974
#define UNDEFINE_DIAGNOSTIC_MACROS
69746975
#include "DefineDiagnosticMacros.h"
6975-

include/swift/AST/KnownProtocols.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ PROTOCOL(AsyncIteratorProtocol)
117117

118118
PROTOCOL(FloatingPoint)
119119

120+
PROTOCOL_(Copyable)
121+
120122
EXPRESSIBLE_BY_LITERAL_PROTOCOL(ExpressibleByArrayLiteral, "Array", false)
121123
EXPRESSIBLE_BY_LITERAL_PROTOCOL(ExpressibleByBooleanLiteral, "BooleanLiteralType", true)
122124
EXPRESSIBLE_BY_LITERAL_PROTOCOL(ExpressibleByDictionaryLiteral, "Dictionary", false)

include/swift/Sema/CSFix.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,9 @@ enum class FixKind : uint8_t {
422422
/// Allow function type actor mismatch e.g. `@MainActor () -> Void`
423423
/// vs.`@OtherActor () -> Void`
424424
AllowGlobalActorMismatch,
425+
426+
/// Produce an error about a type that must be Copyable
427+
MustBeCopyable,
425428
};
426429

427430
class ConstraintFix {
@@ -2027,6 +2030,29 @@ class NotCompileTimeConst final : public ContextualMismatch {
20272030
}
20282031
};
20292032

2033+
class MustBeCopyable final : public ConstraintFix {
2034+
Type noncopyableTy;
2035+
2036+
MustBeCopyable(ConstraintSystem &cs, Type noncopyableTy, ConstraintLocator *locator);
2037+
2038+
public:
2039+
std::string getName() const override { return "remove move-only from type"; }
2040+
2041+
bool diagnose(const Solution &solution, bool asNote = false) const override;
2042+
2043+
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
2044+
return diagnose(*commonFixes.front().first);
2045+
}
2046+
2047+
static MustBeCopyable *create(ConstraintSystem &cs,
2048+
Type noncopyableTy,
2049+
ConstraintLocator *locator);
2050+
2051+
static bool classof(ConstraintFix *fix) {
2052+
return fix->getKind() == FixKind::MustBeCopyable;
2053+
}
2054+
};
2055+
20302056
class CollectionElementContextualMismatch final
20312057
: public ContextualMismatch,
20322058
private llvm::TrailingObjects<CollectionElementContextualMismatch,

lib/AST/Module.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1527,6 +1527,11 @@ LookupConformanceInModuleRequest::evaluate(
15271527
// constraint and the superclass conforms to the protocol.
15281528
if (auto archetype = type->getAs<ArchetypeType>()) {
15291529

1530+
// All archetypes conform to Copyable since they represent a generic.
1531+
// FIXME: can't tell whether this is a hack.
1532+
if (protocol->isSpecificProtocol(KnownProtocolKind::Copyable))
1533+
return ProtocolConformanceRef(protocol);
1534+
15301535
// The generic signature builder drops conformance requirements that are made
15311536
// redundant by a superclass requirement, so check for a concrete
15321537
// conformance first, since an abstract conformance might not be

lib/AST/ProtocolConformance.cpp

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,6 +1097,11 @@ void NominalTypeDecl::prepareConformanceTable() const {
10971097
if (mutableThis->getAttrs().hasAttribute<GlobalActorAttr>()) {
10981098
addSynthesized(ctx.getProtocol(KnownProtocolKind::GlobalActor));
10991099
}
1100+
1101+
// All nominal types that are not move-only conform to Copyable.
1102+
if (!mutableThis->isMoveOnly()) {
1103+
addSynthesized(ctx.getProtocol(KnownProtocolKind::Copyable));
1104+
}
11001105
}
11011106

11021107
bool NominalTypeDecl::lookupConformance(
@@ -1224,24 +1229,24 @@ static SmallVector<ProtocolConformance *, 2> findSynthesizedConformances(
12241229
// Try to find specific conformances
12251230
SmallVector<ProtocolConformance *, 2> result;
12261231

1227-
// Sendable may be synthesized for concrete types
1228-
if (!isa<ProtocolDecl>(nominal)) {
1229-
if (auto sendable =
1230-
findSynthesizedConformance(dc, KnownProtocolKind::Sendable)) {
1231-
result.push_back(sendable);
1232+
auto trySynthesize = [&](KnownProtocolKind knownProto) {
1233+
if (auto conformance =
1234+
findSynthesizedConformance(dc, knownProto)) {
1235+
result.push_back(conformance);
12321236
}
1237+
};
1238+
1239+
// Concrete types may synthesize some conformances
1240+
if (!isa<ProtocolDecl>(nominal)) {
1241+
trySynthesize(KnownProtocolKind::Sendable);
1242+
trySynthesize(KnownProtocolKind::Copyable); // FIXME: we do it when the conformance table is generaetd
1243+
// so this is actually useless now.
12331244
}
12341245

12351246
/// Distributed actors can synthesize Encodable/Decodable, so look for those
12361247
if (nominal->isDistributedActor()) {
1237-
if (auto conformance =
1238-
findSynthesizedConformance(dc, KnownProtocolKind::Encodable)) {
1239-
result.push_back(conformance);
1240-
}
1241-
if (auto conformance =
1242-
findSynthesizedConformance(dc, KnownProtocolKind::Decodable)) {
1243-
result.push_back(conformance);
1244-
}
1248+
trySynthesize(KnownProtocolKind::Encodable);
1249+
trySynthesize(KnownProtocolKind::Decodable);
12451250
}
12461251

12471252
return result;

lib/IRGen/GenMeta.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5885,6 +5885,7 @@ SpecialProtocol irgen::getSpecialProtocolID(ProtocolDecl *P) {
58855885
case KnownProtocolKind::UnsafeSendable:
58865886
case KnownProtocolKind::RangeReplaceableCollection:
58875887
case KnownProtocolKind::GlobalActor:
5888+
case KnownProtocolKind::Copyable:
58885889
return SpecialProtocol::None;
58895890
}
58905891

lib/Sema/CSDiagnostics.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5822,6 +5822,11 @@ bool NotCompileTimeConstFailure::diagnoseAsError() {
58225822
return true;
58235823
}
58245824

5825+
bool NotCopyableFailure::diagnoseAsError() {
5826+
emitDiagnostic(diag::moveonly_generics, noncopyableTy);
5827+
return true;
5828+
}
5829+
58255830
bool CollectionElementContextualFailure::diagnoseAsError() {
58265831
auto anchor = getRawAnchor();
58275832
auto *locator = getLocator();

lib/Sema/CSDiagnostics.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1823,6 +1823,15 @@ class NotCompileTimeConstFailure final : public FailureDiagnostic {
18231823
bool diagnoseAsError() override;
18241824
};
18251825

1826+
class NotCopyableFailure final : public FailureDiagnostic {
1827+
Type noncopyableTy;
1828+
public:
1829+
NotCopyableFailure(const Solution &solution, Type noncopyableTy, ConstraintLocator *locator)
1830+
: FailureDiagnostic(solution, locator), noncopyableTy(noncopyableTy) {}
1831+
1832+
bool diagnoseAsError() override;
1833+
};
1834+
18261835
/// Diagnose a contextual mismatch between expected collection element type
18271836
/// and the one provided (e.g. source of the assignment or argument to a call)
18281837
/// e.g.:

lib/Sema/CSFix.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,6 +1328,21 @@ bool NotCompileTimeConst::diagnose(const Solution &solution, bool asNote) const
13281328
return failure.diagnose(asNote);
13291329
}
13301330

1331+
MustBeCopyable::MustBeCopyable(ConstraintSystem &cs, Type noncopyableTy, ConstraintLocator *locator)
1332+
: ConstraintFix(cs, FixKind::MustBeCopyable, locator, FixBehavior::Error),
1333+
noncopyableTy(noncopyableTy) {}
1334+
1335+
bool MustBeCopyable::diagnose(const Solution &solution, bool asNote) const {
1336+
NotCopyableFailure failure(solution, noncopyableTy, getLocator());
1337+
return failure.diagnose(asNote);
1338+
}
1339+
1340+
MustBeCopyable* MustBeCopyable::create(ConstraintSystem &cs,
1341+
Type noncopyableTy,
1342+
ConstraintLocator *locator) {
1343+
return new (cs.getAllocator()) MustBeCopyable(cs, noncopyableTy, locator);
1344+
}
1345+
13311346
bool CollectionElementContextualMismatch::diagnose(const Solution &solution,
13321347
bool asNote) const {
13331348
CollectionElementContextualFailure failure(

lib/Sema/CSSimplify.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8129,6 +8129,14 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
81298129
return SolutionKind::Solved;
81308130
}
81318131
}
8132+
8133+
// If this is a failure to conform to Copyable, tailor the error message.
8134+
if (protocol->isSpecificProtocol(KnownProtocolKind::Copyable)) {
8135+
auto *fix =
8136+
MustBeCopyable::create(*this, type, getConstraintLocator(locator));
8137+
if (!recordFix(fix))
8138+
return SolutionKind::Solved;
8139+
}
81328140
}
81338141

81348142
// There's nothing more we can do; fail.
@@ -13943,6 +13951,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1394313951
case FixKind::IgnoreKeyPathContextualMismatch:
1394413952
case FixKind::NotCompileTimeConst:
1394513953
case FixKind::RenameConflictingPatternVariables:
13954+
case FixKind::MustBeCopyable:
1394613955
case FixKind::MacroMissingPound:
1394713956
case FixKind::AllowGlobalActorMismatch: {
1394813957
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;

0 commit comments

Comments
 (0)