Skip to content

Commit 064c8c5

Browse files
authored
Merge pull request #71995 from slavapestov/ncgenerics-fixes-6
Non-copyable generics fixes
2 parents 2f6e9b3 + 5c46e06 commit 064c8c5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+192
-227
lines changed

include/swift/AST/RequirementSignature.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ class RequirementSignature final {
8383
const PrintOptions &Options = PrintOptions()) const;
8484
void print(ProtocolDecl *owner, ASTPrinter &Printer,
8585
const PrintOptions &Opts = PrintOptions()) const;
86+
87+
static RequirementSignature getPlaceholderRequirementSignature(
88+
const ProtocolDecl *proto, GenericSignatureErrors errors);
8689
};
8790

8891
} // end namespace swift

lib/AST/Decl.cpp

Lines changed: 3 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -6858,63 +6858,12 @@ ProtocolDecl::getProtocolDependencies() const {
68586858
std::nullopt);
68596859
}
68606860

6861-
/// If we hit a request cycle, give the protocol a requirement signature that
6862-
/// still has inherited protocol requirements on Self, and also conformances
6863-
/// to Copyable and Escapable for all associated types. Otherwise, we'll see
6864-
/// invariant violations from the inheritance clause mismatch, as well as
6865-
/// spurious downstream diagnostics concerning move-only types.
6866-
static RequirementSignature getPlaceholderRequirementSignature(
6867-
const ProtocolDecl *proto) {
6868-
auto &ctx = proto->getASTContext();
6869-
6870-
SmallVector<ProtocolDecl *, 2> inheritedProtos;
6871-
for (auto *inheritedProto : proto->getInheritedProtocols()) {
6872-
inheritedProtos.push_back(inheritedProto);
6873-
}
6874-
6875-
if (ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
6876-
for (auto ip : InvertibleProtocolSet::full()) {
6877-
auto *otherProto = ctx.getProtocol(getKnownProtocolKind(ip));
6878-
inheritedProtos.push_back(otherProto);
6879-
}
6880-
}
6881-
6882-
ProtocolType::canonicalizeProtocols(inheritedProtos);
6883-
6884-
SmallVector<Requirement, 2> requirements;
6885-
6886-
for (auto *inheritedProto : inheritedProtos) {
6887-
requirements.emplace_back(RequirementKind::Conformance,
6888-
proto->getSelfInterfaceType(),
6889-
inheritedProto->getDeclaredInterfaceType());
6890-
}
6891-
6892-
if (ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
6893-
for (auto *assocTypeDecl : proto->getAssociatedTypeMembers()) {
6894-
for (auto ip : InvertibleProtocolSet::full()) {
6895-
auto *otherProto = ctx.getProtocol(getKnownProtocolKind(ip));
6896-
requirements.emplace_back(RequirementKind::Conformance,
6897-
assocTypeDecl->getDeclaredInterfaceType(),
6898-
otherProto->getDeclaredInterfaceType());
6899-
}
6900-
}
6901-
}
6902-
6903-
// Maintain invariants.
6904-
llvm::array_pod_sort(requirements.begin(), requirements.end(),
6905-
[](const Requirement *lhs, const Requirement *rhs) -> int {
6906-
return lhs->compare(*rhs);
6907-
});
6908-
6909-
return RequirementSignature(ctx.AllocateCopy(requirements),
6910-
ArrayRef<ProtocolTypeAlias>());
6911-
}
6912-
69136861
RequirementSignature ProtocolDecl::getRequirementSignature() const {
69146862
return getASTContext().evaluator(
6915-
RequirementSignatureRequest { const_cast<ProtocolDecl *>(this) },
6863+
RequirementSignatureRequest{const_cast<ProtocolDecl *>(this)},
69166864
[this]() {
6917-
return getPlaceholderRequirementSignature(this);
6865+
return RequirementSignature::getPlaceholderRequirementSignature(
6866+
this, GenericSignatureErrors());
69186867
});
69196868
}
69206869

lib/AST/GenericEnvironment.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ GenericEnvironment::maybeApplyOuterContextSubstitutions(Type type) const {
404404

405405
Type GenericEnvironment::mapTypeIntoContext(GenericEnvironment *env,
406406
Type type) {
407-
assert((!type->hasArchetype() || type->hasOpenedExistential()) &&
407+
assert((!type->hasArchetype() || type->hasLocalArchetype()) &&
408408
"already have a contextual type");
409409
assert((env || !type->hasTypeParameter()) &&
410410
"no generic environment provided for type with type parameters");

lib/AST/GenericSignature.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,6 +1291,59 @@ void GenericSignatureImpl::getRequirementsWithInverses(
12911291
}
12921292
}
12931293

1294+
/// If we we can't build a requirement signature because of a request cycle or
1295+
/// failure in Knuth-Bendix completion, we give the protocol a requirement
1296+
/// signature that still has inherited protocol requirements on Self, and also
1297+
/// conformances to Copyable and Escapable for all associated types. Otherwise,
1298+
/// we'll see invariant violations from the inheritance clause mismatch, as
1299+
/// well as spurious downstream diagnostics concerning move-only types.
1300+
RequirementSignature RequirementSignature::getPlaceholderRequirementSignature(
1301+
const ProtocolDecl *proto, GenericSignatureErrors errors) {
1302+
auto &ctx = proto->getASTContext();
1303+
1304+
SmallVector<ProtocolDecl *, 2> inheritedProtos;
1305+
for (auto *inheritedProto : proto->getInheritedProtocols()) {
1306+
inheritedProtos.push_back(inheritedProto);
1307+
}
1308+
1309+
if (ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
1310+
for (auto ip : InvertibleProtocolSet::full()) {
1311+
auto *otherProto = ctx.getProtocol(getKnownProtocolKind(ip));
1312+
inheritedProtos.push_back(otherProto);
1313+
}
1314+
}
1315+
1316+
ProtocolType::canonicalizeProtocols(inheritedProtos);
1317+
1318+
SmallVector<Requirement, 2> requirements;
1319+
1320+
for (auto *inheritedProto : inheritedProtos) {
1321+
requirements.emplace_back(RequirementKind::Conformance,
1322+
proto->getSelfInterfaceType(),
1323+
inheritedProto->getDeclaredInterfaceType());
1324+
}
1325+
1326+
if (ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics)) {
1327+
for (auto *assocTypeDecl : proto->getAssociatedTypeMembers()) {
1328+
for (auto ip : InvertibleProtocolSet::full()) {
1329+
auto *otherProto = ctx.getProtocol(getKnownProtocolKind(ip));
1330+
requirements.emplace_back(RequirementKind::Conformance,
1331+
assocTypeDecl->getDeclaredInterfaceType(),
1332+
otherProto->getDeclaredInterfaceType());
1333+
}
1334+
}
1335+
}
1336+
1337+
// Maintain invariants.
1338+
llvm::array_pod_sort(requirements.begin(), requirements.end(),
1339+
[](const Requirement *lhs, const Requirement *rhs) -> int {
1340+
return lhs->compare(*rhs);
1341+
});
1342+
1343+
return RequirementSignature(ctx.AllocateCopy(requirements),
1344+
ArrayRef<ProtocolTypeAlias>());
1345+
}
1346+
12941347
void RequirementSignature::getRequirementsWithInverses(
12951348
ProtocolDecl *owner,
12961349
SmallVector<Requirement, 2> &reqs,

lib/AST/RequirementMachine/GenericSignatureQueries.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ RequirementMachine::getLocalRequirements(
7575
for (const auto *proto : props->getConformsTo())
7676
result.protos.push_back(const_cast<ProtocolDecl *>(proto));
7777

78+
ProtocolType::canonicalizeProtocols(result.protos);
79+
7880
result.layout = props->getLayoutConstraint();
7981

8082
return result;

lib/AST/RequirementMachine/PropertyUnification.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,9 @@ void RewriteSystem::recordConflict(unsigned existingRuleID,
156156
// conflicting rules of the same kind, so we rule that out by
157157
// marking the shorter rule as the conflict. Otherwise, we just
158158
// leave both rules in place.
159-
if (existingRule.getRHS().size() > newRule.getRHS().size()) {
159+
if (existingRule.getRHS().size() > newRule.getRHS().size() ||
160+
(existingRule.getRHS().size() == newRule.getRHS().size() &&
161+
existingRuleID < newRuleID)) {
160162
existingRule.markConflicting();
161163
} else {
162164
newRule.markConflicting();
@@ -192,6 +194,12 @@ void PropertyMap::addLayoutProperty(
192194
// If the intersection is invalid, we have a conflict.
193195
if (!mergedLayout->isKnownLayout()) {
194196
System.recordConflict(*props->LayoutRule, ruleID);
197+
198+
// Replace the old layout. Since recordConflict() marks the older rule,
199+
// this ensures that if we process multiple conflicting layout
200+
// requirements, all but the final one will be marked conflicting.
201+
props->Layout = newLayout;
202+
props->LayoutRule = ruleID;
195203
return;
196204
}
197205

lib/AST/RequirementMachine/RequirementBuilder.cpp

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -192,50 +192,31 @@ void RequirementBuilder::addRequirementRules(ArrayRef<unsigned> rules) {
192192
prop->getLayoutConstraint());
193193
return;
194194

195-
case Symbol::Kind::Superclass: {
196-
// Requirements containing unresolved name symbols originate from
197-
// invalid code and should not appear in the generic signature.
198-
for (auto term : prop->getSubstitutions()) {
199-
if (term.containsUnresolvedSymbols())
200-
return;
201-
}
202-
203-
Type superclassType = Map.getTypeFromSubstitutionSchema(
204-
prop->getConcreteType(),
205-
prop->getSubstitutions(),
206-
GenericParams, MutableTerm());
207-
if (rule.isRecursive())
208-
superclassType = replaceTypeParametersWithErrorTypes(superclassType);
209-
210-
if (ReconstituteSugar)
211-
superclassType = superclassType->reconstituteSugar(/*recursive=*/true);
212-
213-
Reqs.emplace_back(RequirementKind::Superclass,
214-
subjectType, superclassType);
215-
return;
216-
}
217-
195+
case Symbol::Kind::Superclass:
218196
case Symbol::Kind::ConcreteType: {
219-
// Requirements containing unresolved name symbols originate from
220-
// invalid code and should not appear in the generic signature.
197+
bool containsUnresolvedSymbols = false;
221198
for (auto term : prop->getSubstitutions()) {
222-
if (term.containsUnresolvedSymbols())
223-
return;
199+
containsUnresolvedSymbols |= term.containsUnresolvedSymbols();
224200
}
225201

226202
Type concreteType = Map.getTypeFromSubstitutionSchema(
227203
prop->getConcreteType(),
228204
prop->getSubstitutions(),
229205
GenericParams, MutableTerm());
230-
if (rule.isRecursive())
206+
if (containsUnresolvedSymbols || rule.isRecursive())
231207
concreteType = replaceTypeParametersWithErrorTypes(concreteType);
232208

233209
if (ReconstituteSugar)
234210
concreteType = concreteType->reconstituteSugar(/*recursive=*/true);
235211

236-
auto &component = Components[rule.getRHS()];
237-
assert(!component.ConcreteType);
238-
component.ConcreteType = concreteType;
212+
if (prop->getKind() == Symbol::Kind::Superclass) {
213+
Reqs.emplace_back(RequirementKind::Superclass,
214+
subjectType, concreteType);
215+
} else {
216+
auto &component = Components[rule.getRHS()];
217+
assert(!component.ConcreteType);
218+
component.ConcreteType = concreteType;
219+
}
239220
return;
240221
}
241222

lib/AST/RequirementMachine/RequirementMachineRequests.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -342,8 +342,8 @@ RequirementSignatureRequest::evaluate(Evaluator &evaluator,
342342

343343
unsigned attempt = 0;
344344
for (;;) {
345-
for (const auto *proto : component) {
346-
auto &requirements = protos[proto];
345+
for (const auto *otherProto : component) {
346+
auto &requirements = protos[otherProto];
347347

348348
// Preprocess requirements to eliminate conformances on type parameters
349349
// which are made concrete.
@@ -384,11 +384,13 @@ RequirementSignatureRequest::evaluate(Evaluator &evaluator,
384384
if (otherProto != proto) {
385385
ctx.evaluator.cacheOutput(
386386
RequirementSignatureRequest{const_cast<ProtocolDecl *>(otherProto)},
387-
RequirementSignature(GenericSignatureErrorFlags::CompletionFailed));
387+
RequirementSignature::getPlaceholderRequirementSignature(
388+
otherProto, GenericSignatureErrorFlags::CompletionFailed));
388389
}
389390
}
390391

391-
return RequirementSignature(GenericSignatureErrorFlags::CompletionFailed);
392+
return RequirementSignature::getPlaceholderRequirementSignature(
393+
proto, GenericSignatureErrorFlags::CompletionFailed);
392394
}
393395

394396
auto minimalRequirements = machine->computeMinimalProtocolRequirements();

lib/AST/Type.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,20 +1118,6 @@ bool TypeBase::isAnyObject() {
11181118
return canTy.getExistentialLayout().isAnyObject();
11191119
}
11201120

1121-
// Distinguish between class-bound types that might be AnyObject vs other
1122-
// class-bound types. Only types that are potentially AnyObject might have a
1123-
// transparent runtime type wrapper like __SwiftValue. This must look through
1124-
// all optional types because dynamic casting sees through them.
1125-
bool TypeBase::isPotentiallyAnyObject() {
1126-
Type unwrappedTy = lookThroughAllOptionalTypes();
1127-
if (auto archetype = unwrappedTy->getAs<ArchetypeType>()) {
1128-
// Does archetype have any requirements that contradict AnyObject?
1129-
// 'T : AnyObject' requires a layout constraint, not a conformance.
1130-
return archetype->getConformsTo().empty() && !archetype->getSuperclass();
1131-
}
1132-
return unwrappedTy->isAnyObject();
1133-
}
1134-
11351121
bool ExistentialLayout::isErrorExistential() const {
11361122
auto protocols = getProtocols();
11371123
return (!hasExplicitAnyObject &&

lib/SIL/Utils/DynamicCasts.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,22 @@ static CanType getHashableExistentialType(ModuleDecl *M) {
225225
return hashable->getDeclaredInterfaceType()->getCanonicalType();
226226
}
227227

228+
// Distinguish between class-bound types that might be AnyObject vs other
229+
// class-bound types. Only types that are potentially AnyObject might have a
230+
// transparent runtime type wrapper like __SwiftValue. This must look through
231+
// all optional types because dynamic casting sees through them.
232+
static bool isPotentiallyAnyObject(Type type) {
233+
Type unwrappedTy = type->lookThroughAllOptionalTypes();
234+
if (auto archetype = unwrappedTy->getAs<ArchetypeType>()) {
235+
for (auto *proto : archetype->getConformsTo()) {
236+
if (!proto->getInvertibleProtocolKind())
237+
return false;
238+
}
239+
return !archetype->getSuperclass();
240+
}
241+
return unwrappedTy->isAnyObject();
242+
}
243+
228244
// Returns true if casting \p sourceFormalType to \p targetFormalType preserves
229245
// ownership.
230246
//
@@ -321,11 +337,11 @@ bool swift::doesCastPreserveOwnershipForTypes(SILModule &module,
321337
return false;
322338

323339
// (B2) unwrapping
324-
if (sourceType->isPotentiallyAnyObject())
340+
if (isPotentiallyAnyObject(sourceType))
325341
return false;
326342

327343
// (B1) wrapping
328-
if (targetType->isPotentiallyAnyObject()) {
344+
if (isPotentiallyAnyObject(targetType)) {
329345
// A class type cannot be wrapped in __SwiftValue, so casting
330346
// from a class to AnyObject preserves ownership.
331347
return

lib/Sema/CodeSynthesisDistributedActor.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -878,9 +878,6 @@ static bool canSynthesizeDistributedThunk(AbstractFunctionDecl *distributedTarge
878878
return true;
879879
}
880880

881-
auto &C = distributedTarget->getASTContext();
882-
ProtocolDecl *DistributedActor = C.getDistributedActorDecl();
883-
884881
SmallPtrSet<ProtocolDecl *, 2> requirementProtos;
885882
if (getSerializationRequirementTypesForMember(distributedTarget,
886883
requirementProtos)) {

lib/Sema/PlaygroundTransform.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -799,11 +799,15 @@ class Instrumenter : InstrumenterBase {
799799

800800
bool shouldLog(ASTNode node) {
801801
// Don't try to log ~Copyable types, as we can't pass them to the generic logging functions yet.
802-
if (auto *VD = dyn_cast_or_null<ValueDecl>(node.dyn_cast<Decl *>()))
803-
return VD->hasInterfaceType() ? !VD->getInterfaceType()->isNoncopyable() : true;
804-
if (auto *E = node.dyn_cast<Expr *>())
802+
if (auto *VD = dyn_cast_or_null<ValueDecl>(node.dyn_cast<Decl *>())) {
803+
auto interfaceTy = VD->getInterfaceType();
804+
auto contextualTy = VD->getInnermostDeclContext()->mapTypeIntoContext(interfaceTy);
805+
return !contextualTy->isNoncopyable();
806+
} else if (auto *E = node.dyn_cast<Expr *>()) {
805807
return !E->getType()->isNoncopyable();
806-
return true;
808+
} else {
809+
return true;
810+
}
807811
}
808812

809813
Added<Stmt *> buildLoggerCall(Added<Expr *> E, SourceRange SR,

0 commit comments

Comments
 (0)