Skip to content

Commit 1887950

Browse files
committed
Sema: Remove inference of conditional Copyable conformance from generic parameters
1 parent 232798c commit 1887950

15 files changed

+127
-281
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7623,10 +7623,6 @@ NOTE(add_inverse,none,
76237623
NOTE(note_inverse_preventing_conformance,none,
76247624
"%0 has '~%1' constraint preventing implicit '%1' conformance",
76257625
(Type, StringRef))
7626-
NOTE(note_inverse_preventing_conformance_implicit,none,
7627-
"%kind0 has '~%1' constraint on a generic parameter, "
7628-
"making its '%1' conformance conditional",
7629-
(const ValueDecl *, StringRef))
76307626
NOTE(note_inverse_preventing_conformance_explicit,none,
76317627
"%kind0 has '~%1' constraint preventing '%1' conformance",
76327628
(const ValueDecl *, StringRef))

include/swift/AST/InverseMarking.h

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ namespace swift {
2424
struct InverseMarking {
2525
enum class Kind : uint8_t {
2626
None, // No inverse marking is present
27-
Inferred, // Inverse is inferred based on generic parameters.
2827
Explicit, // Inverse is explicitly present.
2928
LegacyExplicit, // An equivalent, explicit legacy annotation is present.
3029
};
@@ -84,25 +83,6 @@ struct InverseMarking {
8483
return Mark(k, loc);
8584
}
8685
};
87-
88-
private:
89-
Mark inverse;
90-
Mark positive;
91-
92-
public:
93-
94-
// Creates an empty marking.
95-
InverseMarking() {}
96-
97-
Mark const& getInverse() const { return inverse; }
98-
Mark const& getPositive() const { return positive; }
99-
100-
static InverseMarking forInverse(Kind kind, SourceLoc loc = SourceLoc()) {
101-
InverseMarking marking;
102-
marking.inverse.set(kind, loc);
103-
marking.positive.set(Kind::None);
104-
return marking;
105-
}
10686
};
10787

10888
}

lib/AST/ConformanceLookup.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,6 @@ getBuiltinInvertibleProtocolConformance(NominalTypeDecl *nominal,
421421
// An inverse ~Copyable prevents conformance.
422422
return ProtocolConformanceRef::forInvalid();
423423

424-
case InverseMarking::Kind::Inferred: // ignore "inferred" inverse marking
425424
case InverseMarking::Kind::None:
426425
break;
427426
}

lib/AST/Decl.cpp

Lines changed: 2 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -6694,9 +6694,9 @@ NominalTypeDecl::hasInverseMarking(InvertibleProtocolKind target) const {
66946694
if (!ctx.LangOpts.hasFeature(Feature::NoncopyableGenerics))
66956695
return InverseMarking::Mark(InverseMarking::Kind::None);
66966696

6697-
// Claim that the tuple decl has an inferred ~TARGET marking.
6697+
// Claim that the tuple decl has an explicit ~TARGET marking.
66986698
if (isa<BuiltinTupleDecl>(this))
6699-
return InverseMarking::Mark(InverseMarking::Kind::Inferred);
6699+
return InverseMarking::Mark(InverseMarking::Kind::Explicit);
67006700

67016701
if (auto P = dyn_cast<ProtocolDecl>(this))
67026702
return P->hasInverseMarking(target);
@@ -6705,57 +6705,6 @@ NominalTypeDecl::hasInverseMarking(InvertibleProtocolKind target) const {
67056705
if (auto inverse = findInverseInInheritance(getInherited(), target))
67066706
return inverse;
67076707

6708-
// Check the generic parameters for an explicit ~TARGET marking
6709-
// which would result in an Inferred ~TARGET marking for this context.
6710-
auto *gpList = getParsedGenericParams();
6711-
if (!gpList)
6712-
return InverseMarking::Mark();
6713-
6714-
llvm::SmallSet<GenericTypeParamDecl *, 4> params;
6715-
6716-
// Scan the inheritance clauses of generic parameters only for an inverse.
6717-
for (GenericTypeParamDecl *param : gpList->getParams()) {
6718-
auto inverse = findInverseInInheritance(param->getInherited(), target);
6719-
6720-
// Inverse is inferred from one of the generic parameters.
6721-
if (inverse)
6722-
return inverse.with(InverseMarking::Kind::Inferred);
6723-
6724-
params.insert(param);
6725-
}
6726-
6727-
// Next, scan the where clause and return the result.
6728-
auto whereClause = getTrailingWhereClause();
6729-
if (!whereClause)
6730-
return InverseMarking::Mark();
6731-
6732-
auto requirements = whereClause->getRequirements();
6733-
for (unsigned i : indices(requirements)) {
6734-
auto requirementRepr = requirements[i];
6735-
if (requirementRepr.getKind() != RequirementReprKind::TypeConstraint)
6736-
continue;
6737-
6738-
auto *subjectRepr =
6739-
dyn_cast<UnqualifiedIdentTypeRepr>(requirementRepr.getSubjectRepr());
6740-
6741-
if (!(subjectRepr && subjectRepr->isBound()))
6742-
continue;
6743-
6744-
auto *subjectGP =
6745-
dyn_cast<GenericTypeParamDecl>(subjectRepr->getBoundDecl());
6746-
if (!subjectGP || !params.contains(subjectGP))
6747-
continue;
6748-
6749-
auto *constraintRepr =
6750-
dyn_cast<InverseTypeRepr>(requirementRepr.getConstraintRepr());
6751-
if (!constraintRepr || constraintRepr->isInvalid())
6752-
continue;
6753-
6754-
if (constraintRepr->isInverseOf(target, getDeclContext()))
6755-
return InverseMarking::Mark(InverseMarking::Kind::Inferred,
6756-
constraintRepr->getLoc());
6757-
}
6758-
67596708
return InverseMarking::Mark();
67606709
}
67616710

lib/AST/FeatureSet.cpp

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -525,22 +525,23 @@ static bool usesFeatureRawLayout(Decl *decl) {
525525
UNINTERESTING_FEATURE(Embedded)
526526

527527
static bool usesFeatureNoncopyableGenerics(Decl *decl) {
528-
auto checkInverseMarking = [](auto &marking) -> bool {
529-
switch (marking.getKind()) {
530-
case InverseMarking::Kind::None:
531-
case InverseMarking::Kind::LegacyExplicit: // covered by other checks.
532-
return false;
533-
534-
case InverseMarking::Kind::Explicit:
535-
case InverseMarking::Kind::Inferred:
536-
return true;
528+
SmallVector<Requirement, 2> reqs;
529+
SmallVector<InverseRequirement, 2> inverseReqs;
530+
531+
if (auto *proto = dyn_cast<ProtocolDecl>(decl)) {
532+
proto->getRequirementSignature().getRequirementsWithInverses(
533+
proto, reqs, inverseReqs);
534+
} else if (auto *genCtx = decl->getAsGenericContext()) {
535+
if (auto *ext = dyn_cast<ExtensionDecl>(decl)) {
536+
if (auto *nominal = ext->getExtendedNominal())
537+
if (usesFeatureNoncopyableGenerics(nominal))
538+
return true;
537539
}
538-
};
540+
if (auto genericSig = genCtx->getGenericSignature())
541+
genericSig->getRequirementsWithInverses(reqs, inverseReqs);
542+
}
539543

540-
return hasInverse(decl, InvertibleProtocolKind::Copyable,
541-
checkInverseMarking) ||
542-
hasInverse(decl, InvertibleProtocolKind::Escapable,
543-
checkInverseMarking);
544+
return !inverseReqs.empty();
544545
}
545546

546547
static bool usesFeatureStructLetDestructuring(Decl *decl) {

lib/Sema/TypeCheckInvertible.cpp

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,7 @@ static void emitAdviceToApplyInverseAfter(InFlightDiagnostic &&diag,
7171
}
7272
}
7373

74-
auto &ctx = nominal->getASTContext();
75-
7674
switch (inverseMarking.getKind()) {
77-
case InverseMarking::Kind::Inferred:
78-
// Note that the enclosing type is conditionally conforming to KP first.
79-
ctx.Diags.diagnose(inverseMarking.getLoc(),
80-
diag::note_inverse_preventing_conformance_implicit,
81-
nominal, getProtocolName(kp));
82-
LLVM_FALLTHROUGH;
8375
case InverseMarking::Kind::None: {
8476
// Suggest adding ~KP to make it non-KP.
8577
auto diag = nominal->diagnose(diag::add_inverse,
@@ -144,12 +136,6 @@ static void tryEmitContainmentFixits(InFlightDiagnostic &&diag,
144136
case InverseMarking::Kind::None:
145137
assert(false && "how did it become noncopyable/nonescapable then?");
146138
break;
147-
case InverseMarking::Kind::Inferred:
148-
assert(loc);
149-
ctx.Diags.diagnose(loc,
150-
diag::note_inverse_preventing_conformance_implicit,
151-
nominal, getProtocolName(kp));
152-
break;
153139
case InverseMarking::Kind::LegacyExplicit:
154140
case InverseMarking::Kind::Explicit:
155141
assert(loc);
@@ -344,7 +330,6 @@ ProtocolConformance *deriveConformanceForInvertible(Evaluator &evaluator,
344330
llvm_unreachable("not an invertible protocol");
345331

346332
assert(!isa<ClassDecl>(nominal) && "classes aren't handled here");
347-
auto file = cast<FileUnit>(nominal->getModuleScopeContext());
348333

349334
// Generates a conformance for the nominal to the protocol.
350335
// The conformanceDC specifies THE decl context to use for the conformance.
@@ -362,58 +347,13 @@ ProtocolConformance *deriveConformanceForInvertible(Evaluator &evaluator,
362347
return conformance;
363348
};
364349

365-
auto generateConditionalConformance = [&]() -> ProtocolConformance * {
366-
// Generate an extension with a conditional conformance to IP that
367-
// requires all generic parameters to be IP.
368-
auto protoTy = proto->getDeclaredInterfaceType();
369-
auto dc = nominal->getDeclContext();
370-
371-
// extension Nominal: P { ... }
372-
SmallVector<InheritedEntry, 1> inherited;
373-
inherited.emplace_back(TypeLoc::withoutLoc(protoTy));
374-
auto *ext = ExtensionDecl::create(ctx, SourceLoc(), nullptr,
375-
ctx.AllocateCopy(inherited),
376-
dc, nullptr);
377-
ext->setImplicit();
378-
379-
// Build a generic signature for this extension that looks like this:
380-
// <T_1..., T_n where T_1: IP, ... T_n: IP>
381-
auto genericSig = nominal->getGenericSignature();
382-
auto params = genericSig.getGenericParams();
383-
SmallVector<Requirement, 2> reqs;
384-
385-
for (auto param : params)
386-
reqs.push_back({RequirementKind::Conformance, param, protoTy});
387-
388-
genericSig = buildGenericSignature(ctx, genericSig, {}, reqs,
389-
/*allowInverses=*/false);
390-
ext->setGenericSignature(genericSig);
391-
392-
// Bind the extension.
393-
evaluator.cacheOutput(ExtendedTypeRequest{ext},
394-
nominal->getDeclaredInterfaceType());
395-
ext->setExtendedNominal(nominal);
396-
nominal->addExtension(ext);
397-
398-
// Make it accessible to getTopLevelDecls() so it gets type-checked.
399-
file->getOrCreateSynthesizedFile().addTopLevelDecl(ext);
400-
401-
// Then create the conformance using the extension as the conformance's
402-
// DeclContext, which is how we register these conditional requirements
403-
// with the conformance.
404-
return generateConformance(ext);
405-
};
406-
407350
// Check what kind of inverse-marking we have to determine whether to generate
408351
// a conformance for IP.
409352
switch (nominal->hasInverseMarking(*ip).getKind()) {
410353
case InverseMarking::Kind::LegacyExplicit:
411354
case InverseMarking::Kind::Explicit:
412355
return nullptr; // No positive IP conformance will be inferred.
413356

414-
case InverseMarking::Kind::Inferred:
415-
return generateConditionalConformance();
416-
417357
case InverseMarking::Kind::None:
418358
// All types already start with conformances to the invertible protocols in
419359
// this case, within `NominalTypeDecl::prepareConformanceTable`.

test/Generics/inverse_extension_signatures.swift

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -44,32 +44,6 @@
4444

4545
// CHECK-LABEL: ExtensionDecl {{.*}} base=Outer.InnerVariation2
4646
// CHECK: Generic signature: <A, D where A : Escapable, D : Copyable>
47-
48-
// CHECK-LABEL: ExtensionDecl line=0 base=Outer<A>.InnerStruct<C>
49-
// CHECK-NEXT: (normal_conformance type="Outer<A>.InnerStruct<C>" protocol="Copyable"
50-
// CHECK-NEXT: (requirement "A" conforms_to "Copyable")
51-
// CHECK-NEXT: (requirement "C" conforms_to "Copyable"))
52-
53-
// CHECK-LABEL: ExtensionDecl line=0 base=Outer<A>.InnerVariation1<D>
54-
// CHECK-NEXT: (normal_conformance type="Outer<A>.InnerVariation1<D>" protocol="Copyable"
55-
// CHECK-NEXT: (requirement "A" conforms_to "Copyable")
56-
// CHECK-NEXT: (requirement "D" conforms_to "Copyable"))
57-
58-
// CHECK-LABEL: ExtensionDecl line=0 base=Outer<A>.InnerVariation2<D>
59-
// CHECK-NEXT: (normal_conformance type="Outer<A>.InnerVariation2<D>" protocol="Escapable"
60-
// CHECK-NEXT: (requirement "D" conforms_to "Escapable"))
61-
62-
// CHECK-LABEL: ExtensionDecl line=0 base=Outer<A>
63-
// CHECK-NEXT: (normal_conformance type="Outer<A>" protocol="Copyable"
64-
// CHECK-NEXT: (requirement "A" conforms_to "Copyable"))
65-
66-
// CHECK-LABEL: ExtensionDecl line=0 base=Freestanding<T>
67-
// CHECK-NEXT: (normal_conformance type="Freestanding<T>" protocol="Escapable"
68-
// CHECK-NEXT: (requirement "T" conforms_to "Escapable"))
69-
70-
// CHECK-LABEL: ExtensionDecl line=0 base=Freestanding<T>
71-
// CHECK-NEXT: (normal_conformance type="Freestanding<T>" protocol="Copyable"
72-
// CHECK-NEXT: (requirement "T" conforms_to "Copyable"))
7347

7448
public struct Outer<A: ~Copyable> {
7549
public func innerFn<B: ~Copyable>(_ b: borrowing B) {}

0 commit comments

Comments
 (0)