Skip to content

Commit 99d49f0

Browse files
committed
GSB: When rebuilding a signature, use the as-written requirements instead of the minimized ones
We rebuild a signature after dropping redundant conformance requirements, since conformance requirements change the canonical type and conformance access path computation. When doing this, instead of using the canonical requirements from the signature, use the original as-written requirements. This fixes some weirdness around concrete same-type requirements. There's a philosophical benefit here too -- since we rebuild the signature without ever having built the old signature, we never create an invalid GenericSignature in the ASTContext. Fixes rdar://problem/75690903.
1 parent 7d3a891 commit 99d49f0

File tree

5 files changed

+147
-33
lines changed

5 files changed

+147
-33
lines changed

include/swift/AST/GenericSignatureBuilder.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,10 @@ class GenericSignatureBuilder {
614614
/// because the type \c Dictionary<K,V> cannot be formed without it.
615615
void inferRequirements(ModuleDecl &module, ParameterList *params);
616616

617+
GenericSignature rebuildSignatureWithoutRedundantRequirements(
618+
bool allowConcreteGenericParams,
619+
bool buildingRequirementSignature) &&;
620+
617621
/// Finalize the set of requirements and compute the generic
618622
/// signature.
619623
///

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 94 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8366,19 +8366,97 @@ static Requirement stripBoundDependentMemberTypes(Requirement req) {
83668366
llvm_unreachable("Bad requirement kind");
83678367
}
83688368

8369+
GenericSignature GenericSignatureBuilder::rebuildSignatureWithoutRedundantRequirements(
8370+
bool allowConcreteGenericParams,
8371+
bool buildingRequirementSignature) && {
8372+
NumSignaturesRebuiltWithoutRedundantRequirements++;
8373+
8374+
GenericSignatureBuilder newBuilder(Context);
8375+
8376+
for (auto param : getGenericParams())
8377+
newBuilder.addGenericParameter(param);
8378+
8379+
auto newSource = FloatingRequirementSource::forAbstract();
8380+
8381+
for (const auto &req : Impl->ExplicitRequirements) {
8382+
assert(req.getKind() != RequirementKind::SameType &&
8383+
"Should not see same-type requirement here");
8384+
8385+
if (isRedundantExplicitRequirement(req))
8386+
continue;
8387+
8388+
auto subjectType = req.getSource()->getStoredType();
8389+
subjectType = stripBoundDependentMemberTypes(subjectType);
8390+
subjectType =
8391+
resolveDependentMemberTypes(*this, subjectType,
8392+
ArchetypeResolutionKind::WellFormed);
8393+
8394+
if (auto optReq = createRequirement(req.getKind(), subjectType, req.getRHS(),
8395+
getGenericParams())) {
8396+
auto newReq = stripBoundDependentMemberTypes(*optReq);
8397+
newBuilder.addRequirement(newReq, newSource, nullptr);
8398+
}
8399+
}
8400+
8401+
for (const auto &req : Impl->ExplicitSameTypeRequirements) {
8402+
auto resolveType = [this](Type t) -> Type {
8403+
t = stripBoundDependentMemberTypes(t);
8404+
if (t->is<GenericTypeParamType>()) {
8405+
return t;
8406+
} else if (auto *depMemTy = t->getAs<DependentMemberType>()) {
8407+
auto resolvedBaseTy =
8408+
resolveDependentMemberTypes(*this, depMemTy->getBase(),
8409+
ArchetypeResolutionKind::WellFormed);
8410+
8411+
8412+
if (resolvedBaseTy->isTypeParameter()) {
8413+
return DependentMemberType::get(resolvedBaseTy, depMemTy->getName());
8414+
} else {
8415+
return resolveDependentMemberTypes(*this, t,
8416+
ArchetypeResolutionKind::WellFormed);
8417+
}
8418+
} else {
8419+
return t;
8420+
}
8421+
};
8422+
8423+
auto subjectType = resolveType(req.getFirstType());
8424+
auto constraintType = resolveType(req.getSecondType());
8425+
8426+
auto newReq = stripBoundDependentMemberTypes(
8427+
Requirement(RequirementKind::SameType,
8428+
subjectType, constraintType));
8429+
8430+
newBuilder.addRequirement(newReq, newSource, nullptr);
8431+
}
8432+
8433+
// Wipe out the internal state of the old builder, since we don't need it anymore.
8434+
Impl.reset();
8435+
8436+
// Build a new signature using the new builder.
8437+
return std::move(newBuilder).computeGenericSignature(
8438+
allowConcreteGenericParams,
8439+
buildingRequirementSignature,
8440+
/*rebuildingWithoutRedundantConformances=*/true);
8441+
}
8442+
83698443
GenericSignature GenericSignatureBuilder::computeGenericSignature(
83708444
bool allowConcreteGenericParams,
83718445
bool buildingRequirementSignature,
83728446
bool rebuildingWithoutRedundantConformances) && {
83738447
// Finalize the builder, producing any necessary diagnostics.
83748448
finalize(getGenericParams(), allowConcreteGenericParams);
83758449

8376-
// Collect the requirements placed on the generic parameter types.
8377-
SmallVector<Requirement, 4> requirements;
8378-
enumerateRequirements(getGenericParams(), requirements);
8450+
if (rebuildingWithoutRedundantConformances) {
8451+
assert(!buildingRequirementSignature &&
8452+
"Rebuilding a requirement signature?");
83798453

8380-
// Form the generic signature.
8381-
auto sig = GenericSignature::get(getGenericParams(), requirements);
8454+
assert(!Impl->HadAnyError &&
8455+
"Rebuilt signature had errors");
8456+
8457+
assert(!hasExplicitConformancesImpliedByConcrete() &&
8458+
"Rebuilt signature still had redundant conformance requirements");
8459+
}
83828460

83838461
// If any of our explicit conformance requirements were implied by
83848462
// superclass or concrete same-type requirements, we have to build the
@@ -8389,34 +8467,22 @@ GenericSignature GenericSignatureBuilder::computeGenericSignature(
83898467
// we might end up emitting duplicate diagnostics.
83908468
//
83918469
// Also, don't do this when building a requirement signature.
8392-
if (!buildingRequirementSignature &&
8470+
if (!rebuildingWithoutRedundantConformances &&
8471+
!buildingRequirementSignature &&
83938472
!Impl->HadAnyError &&
83948473
hasExplicitConformancesImpliedByConcrete()) {
8395-
NumSignaturesRebuiltWithoutRedundantRequirements++;
8396-
8397-
if (rebuildingWithoutRedundantConformances) {
8398-
llvm::errs() << "Rebuilt signature still has "
8399-
<< "redundant conformance requirements: ";
8400-
llvm::errs() << sig << "\n";
8401-
abort();
8402-
}
8403-
8404-
GenericSignatureBuilder newBuilder(Context);
8405-
8406-
for (auto param : sig->getGenericParams())
8407-
newBuilder.addGenericParameter(param);
8408-
8409-
for (auto &req : sig->getRequirements()) {
8410-
newBuilder.addRequirement(stripBoundDependentMemberTypes(req),
8411-
FloatingRequirementSource::forAbstract(), nullptr);
8412-
}
8413-
8414-
return std::move(newBuilder).computeGenericSignature(
8474+
return std::move(*this).rebuildSignatureWithoutRedundantRequirements(
84158475
allowConcreteGenericParams,
8416-
buildingRequirementSignature,
8417-
/*rebuildingWithoutRedundantConformances=*/true);
8476+
buildingRequirementSignature);
84188477
}
84198478

8479+
// Collect the requirements placed on the generic parameter types.
8480+
SmallVector<Requirement, 4> requirements;
8481+
enumerateRequirements(getGenericParams(), requirements);
8482+
8483+
// Form the generic signature.
8484+
auto sig = GenericSignature::get(getGenericParams(), requirements);
8485+
84208486
#ifndef NDEBUG
84218487
if (!Impl->HadAnyError) {
84228488
checkGenericSignature(sig.getCanonicalSignature(), *this);
@@ -8526,9 +8592,6 @@ void GenericSignatureBuilder::verifyGenericSignature(ASTContext &context,
85268592
context.Diags.diagnose(SourceLoc(), diag::generic_signature_not_minimal,
85278593
reqString, sig->getAsString());
85288594
}
8529-
8530-
// Canonicalize the signature to check that it is canonical.
8531-
(void)newSig.getCanonicalSignature();
85328595
}
85338596
}
85348597

test/Generics/rdar75656022.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,48 @@ struct UnresolvedWithConcreteBase<A, B> {
3636
D == C.T,
3737
E == D.T { }
3838
}
39+
40+
// Make sure that we drop the conformance requirement
41+
// 'A : P2' and rebuild the generic signature with the
42+
// correct same-type requirements.
43+
//
44+
// The original test case in the bug report (correctly)
45+
// produces two warnings about redundant requirements.
46+
struct OriginalExampleWithWarning<A, B> where A : P2, B : P2, A.T == B.T {
47+
// CHECK-LABEL: Generic signature: <A, B, C, D, E where A == S1<C, E, S2<D>>, B : P2, C : P1, D == B.T, E == D.T, B.T == C.T>
48+
init<C, D, E>(_: C)
49+
where C : P1,
50+
D : P1, // expected-warning {{redundant conformance constraint 'D': 'P1'}}
51+
C.T : P1, // expected-warning {{redundant conformance constraint 'C.T': 'P1'}}
52+
A == S1<C, C.T.T, S2<C.T>>,
53+
C.T == D,
54+
E == D.T { }
55+
}
56+
57+
// Same as above but without the warnings.
58+
struct OriginalExampleWithoutWarning<A, B> where A : P2, B : P2, A.T == B.T {
59+
// CHECK-LABEL: Generic signature: <A, B, C, D, E where A == S1<C, E, S2<D>>, B : P2, C : P1, D == B.T, E == D.T, B.T == C.T>
60+
init<C, D, E>(_: C)
61+
where C : P1,
62+
A == S1<C, C.T.T, S2<C.T>>,
63+
C.T == D,
64+
E == D.T { }
65+
}
66+
67+
// Same as above but without unnecessary generic parameters.
68+
struct WithoutBogusGenericParametersWithWarning<A, B> where A : P2, B : P2, A.T == B.T {
69+
// CHECK-LABEL: Generic signature: <A, B, C where A == S1<C, B.T.T, S2<B.T>>, B : P2, C : P1, B.T == C.T>
70+
init<C>(_: C)
71+
where C : P1,
72+
C.T : P1, // expected-warning {{redundant conformance constraint 'C.T': 'P1'}}
73+
A == S1<C, C.T.T, S2<C.T>> {}
74+
}
75+
76+
// Same as above but without unnecessary generic parameters
77+
// or the warning.
78+
struct WithoutBogusGenericParametersWithoutWarning<A, B> where A : P2, B : P2, A.T == B.T {
79+
// CHECK-LABEL: Generic signature: <A, B, C where A == S1<C, B.T.T, S2<B.T>>, B : P2, C : P1, B.T == C.T>
80+
init<C>(_: C)
81+
where C : P1,
82+
A == S1<C, C.T.T, S2<C.T>> {}
83+
}

test/Generics/requirement_inference.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ struct X18: P18, P17 {
270270
}
271271

272272
// CHECK-LABEL: .X19.foo@
273-
// CHECK: Generic signature: <T, U where T == X18>
273+
// CHECK: Generic signature: <T, U where T == X18.A>
274274
struct X19<T: P18> where T == T.A {
275275
func foo<U>(_: U) where T == X18 { }
276276
}

validation-test/compiler_crashers_2_fixed/sr12812.swift renamed to test/Generics/sr12812.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %target-swift-frontend -emit-ir %s
1+
// RUN: %target-typecheck-verify-swift
2+
// RUN: %target-swift-frontend -debug-generic-signatures -emit-ir %s 2>&1 | %FileCheck %s
23

34
public protocol DefaultInitializable {
45
init()
@@ -74,6 +75,7 @@ public extension GeneralAdjacencyList {
7475
}
7576
}
7677

78+
// CHECK-LABEL: Generic signature: <Spine, VertexIDToIndex where Spine : RangeReplaceableCollection, VertexIDToIndex == IdentityVertexIDToIndex<Spine>, Spine.Element : AdjacencyVertex_, Spine.Index == Spine.Element.Edges.Element.VertexID, Spine.Element.Edges : BidirectionalCollection, Spine.Element.Edges : RangeReplaceableCollection>
7779
public extension GeneralAdjacencyList
7880
where VertexIDToIndex == IdentityVertexIDToIndex<Spine>,
7981
Spine: RangeReplaceableCollection,

0 commit comments

Comments
 (0)