Skip to content

Commit dc1bf91

Browse files
committed
[wip] Copyable as a Requirement Against the Machine
1 parent 7c72e7d commit dc1bf91

File tree

6 files changed

+75
-6
lines changed

6 files changed

+75
-6
lines changed

include/swift/Basic/Features.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,9 @@ EXPERIMENTAL_FEATURE(RawLayout, true)
235235
/// Enables the "embedded" swift mode (no runtime).
236236
EXPERIMENTAL_FEATURE(Embedded, true)
237237

238+
/// Enables noncopyable generics
239+
EXPERIMENTAL_FEATURE(NoncopyableGenerics, false)
240+
238241
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
239242
#undef EXPERIMENTAL_FEATURE
240243
#undef UPCOMING_FEATURE

lib/AST/ASTPrinter.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3366,6 +3366,12 @@ static bool usesFeatureMoveOnlyPartialConsumption(Decl *decl) {
33663366
return false;
33673367
}
33683368

3369+
static bool usesFeatureNoncopyableGenerics(Decl *decl) {
3370+
// FIXME: need to look for suppressed entries on generic parameters or
3371+
// inheritance clauses!
3372+
llvm_unreachable("todo: implement usesFeatureNoncopyableGenerics")
3373+
}
3374+
33693375
static bool usesFeatureOneWayClosureParameters(Decl *decl) {
33703376
return false;
33713377
}

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,22 @@ void swift::rewriting::realizeInheritedRequirements(
756756

757757
realizeTypeRequirement(dc, type, inheritedType, loc, result, errors);
758758
}
759+
760+
auto &ctx = dc->getASTContext();
761+
if (ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
762+
// All associated types or generic type params are Copyable by default.
763+
// TODO: if we saw ~Copyable in the inherited types list earlier, skip this!
764+
765+
if (auto *copyable = ctx.getProtocol(KnownProtocolKind::Copyable)) {
766+
SourceLoc loc = decl->getLoc();
767+
Type copyableType = copyable->getDeclaredInterfaceType();
768+
769+
// Add Copyable as an "inferred" requirement.
770+
SmallVector<Requirement, 2> reqs;
771+
Requirement req(RequirementKind::Conformance, type, copyableType);
772+
result.push_back({req, loc, /*wasInferred=*/true});
773+
}
774+
}
759775
}
760776

761777
/// StructuralRequirementsRequest realizes all the user-written requirements

lib/Sema/CSDiagnostics.cpp

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,20 @@ bool MissingConformanceFailure::diagnoseAsError() {
616616
if (diagnoseAsAmbiguousOperatorRef())
617617
return true;
618618

619+
// Use tailored diagnostics for failure to conform to Copyable.
620+
if (auto asProtoType = protocolType->getAs<ProtocolType>()) {
621+
if (auto *protoDecl = asProtoType->getDecl()) {
622+
if (protoDecl->isSpecificProtocol(KnownProtocolKind::Copyable)) {
623+
NotCopyableFailure failure(getSolution(),
624+
nonConformingType,
625+
NoncopyableMatchFailure::forCopyableConstraint(),
626+
getLocator());
627+
if (failure.diagnoseAsError())
628+
return true;
629+
}
630+
}
631+
}
632+
619633
if (nonConformingType->isObjCExistentialType()) {
620634
emitDiagnostic(diag::protocol_does_not_conform_static, nonConformingType,
621635
protocolType);
@@ -6167,6 +6181,7 @@ bool NotCopyableFailure::diagnoseAsError() {
61676181

61686182
case NoncopyableMatchFailure::CopyableConstraint: {
61696183
auto *loc = getLocator();
6184+
auto path = loc->getPath();
61706185

61716186
if (loc->isLastElement<LocatorPathElt::AnyTupleElement>()) {
61726187
assert(!noncopyableTy->is<TupleType>() && "will use poor wording");
@@ -6180,9 +6195,11 @@ bool NotCopyableFailure::diagnoseAsError() {
61806195
return true;
61816196
}
61826197

6183-
// a bit paranoid of nulls and such...
6184-
if (auto *genericParam = loc->getGenericParameter()) {
6185-
if (auto *paramDecl = genericParam->getDecl()) {
6198+
auto diagnoseGenericTypeParamType = [&](GenericTypeParamType *typeParam) {
6199+
if (!typeParam)
6200+
return false;
6201+
6202+
if (auto *paramDecl = typeParam->getDecl()) {
61866203
if (auto *owningDecl =
61876204
dyn_cast_or_null<ValueDecl>(paramDecl->getDeclContext()->getAsDecl())) {
61886205

@@ -6191,27 +6208,45 @@ bool NotCopyableFailure::diagnoseAsError() {
61916208
emitDiagnostic(diag::noncopyable_generics_generic_param_metatype,
61926209
noncopyableTy->getMetatypeInstanceType(),
61936210
paramDecl->getDescriptiveKind(),
6194-
genericParam,
6211+
typeParam,
61956212
owningDecl->getName(),
61966213
noncopyableTy);
61976214
else
61986215
emitDiagnostic(diag::noncopyable_generics_generic_param,
61996216
noncopyableTy,
62006217
paramDecl->getDescriptiveKind(),
6201-
genericParam,
6218+
typeParam,
62026219
owningDecl->getName());
62036220

62046221
// If we have a location for the parameter, point it out in a note.
62056222
if (auto loc = paramDecl->getNameLoc()) {
62066223
emitDiagnosticAt(loc,
62076224
diag::noncopyable_generics_implicit_copyable,
62086225
paramDecl->getDescriptiveKind(),
6209-
genericParam);
6226+
typeParam);
62106227
}
62116228

62126229
return true;
62136230
}
62146231
}
6232+
return false;
6233+
};
6234+
6235+
// NOTE: a non-requirement constraint locator might now be impossible after
6236+
// having made Copyable be added as a Requirement.
6237+
if (diagnoseGenericTypeParamType(loc->getGenericParameter()))
6238+
return true;
6239+
6240+
if (auto tpr =
6241+
loc->getLastElementAs<LocatorPathElt::TypeParameterRequirement>()) {
6242+
auto signature = path[path.size() - 2]
6243+
.castTo<LocatorPathElt::OpenedGeneric>()
6244+
.getSignature();
6245+
auto requirement = signature.getRequirements()[tpr->getIndex()];
6246+
auto subject = requirement.getFirstType();
6247+
6248+
if (diagnoseGenericTypeParamType(subject->getAs<GenericTypeParamType>()))
6249+
return true;
62156250
}
62166251
break;
62176252
}

lib/Sema/ConstraintSystem.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1928,6 +1928,10 @@ TypeVariableType *ConstraintSystem::openGenericParameter(
19281928
assert(result.second);
19291929
(void)result;
19301930

1931+
if (Context.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
1932+
return typeVar;
1933+
}
1934+
19311935
// Add a constraint that generic parameters conform to Copyable.
19321936
// This lookup only can fail if the stdlib (i.e. the Swift module) has not
19331937
// been loaded because you've passed `-parse-stdlib` and are not building the

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1817,6 +1817,11 @@ static void checkProtocolRefinementRequirements(ProtocolDecl *proto) {
18171817
if (otherProto == proto)
18181818
continue;
18191819

1820+
// For any protocol 'P', there is an implied requirement 'Self: Copyable',
1821+
// unless it was suppressed via `Self: ~Copyable`; so skip if present.
1822+
if (otherProto->isSpecificProtocol(KnownProtocolKind::Copyable))
1823+
continue;
1824+
18201825
// GenericSignature::getRequiredProtocols() canonicalizes the protocol
18211826
// list by dropping protocols that are inherited by other protocols in
18221827
// the list. Any protocols that remain in the list other than 'proto'

0 commit comments

Comments
 (0)