Skip to content

Commit 3fe2534

Browse files
authored
Merge pull request #36576 from slavapestov/concrete-constraint-calamity
GSB: Fix some issues with concrete same-type requirements
2 parents 4ca8a66 + 99d49f0 commit 3fe2534

File tree

5 files changed

+158
-55
lines changed

5 files changed

+158
-55
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: 105 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7860,8 +7860,6 @@ void GenericSignatureBuilder::checkConcreteTypeConstraints(
78607860
diag::same_type_conflict,
78617861
diag::redundant_same_type_to_concrete,
78627862
diag::same_type_redundancy_here);
7863-
7864-
equivClass->concreteType = resolvedConcreteType;
78657863
}
78667864

78677865
void GenericSignatureBuilder::checkSuperclassConstraints(
@@ -7898,9 +7896,6 @@ void GenericSignatureBuilder::checkSuperclassConstraints(
78987896
diag::redundant_superclass_constraint,
78997897
diag::superclass_redundancy_here);
79007898

7901-
// Record the resolved superclass type.
7902-
equivClass->superclass = resolvedSuperclass;
7903-
79047899
// If we have a concrete type, check it.
79057900
// FIXME: Substitute into the concrete type.
79067901
if (equivClass->concreteType) {
@@ -8097,6 +8092,8 @@ void GenericSignatureBuilder::enumerateRequirements(
80978092
// If this equivalence class is bound to a concrete type, equate the
80988093
// anchor with a concrete type.
80998094
if (Type concreteType = equivClass.concreteType) {
8095+
concreteType = getCanonicalTypeInContext(concreteType, genericParams);
8096+
81008097
// If the parent of this anchor is also a concrete type, don't
81018098
// create a requirement.
81028099
if (!subjectType->is<GenericTypeParamType>() &&
@@ -8152,14 +8149,15 @@ void GenericSignatureBuilder::enumerateRequirements(
81528149
continue;
81538150

81548151
// If we have a superclass, produce a superclass requirement
8155-
if (equivClass.superclass &&
8156-
!equivClass.recursiveSuperclassType &&
8157-
!equivClass.superclass->hasError()) {
8158-
if (hasNonRedundantRequirementSource<Type>(
8152+
if (auto superclass = equivClass.superclass) {
8153+
superclass = getCanonicalTypeInContext(superclass, genericParams);
8154+
8155+
if (!equivClass.recursiveSuperclassType &&
8156+
hasNonRedundantRequirementSource<Type>(
81598157
equivClass.superclassConstraints,
81608158
RequirementKind::Superclass, *this)) {
81618159
recordRequirement(RequirementKind::Superclass,
8162-
subjectType, equivClass.superclass);
8160+
subjectType, superclass);
81638161
}
81648162
}
81658163

@@ -8183,25 +8181,16 @@ void GenericSignatureBuilder::enumerateRequirements(
81838181
}
81848182
}
81858183

8186-
// Sort the protocols in canonical order.
8187-
llvm::array_pod_sort(protocols.begin(), protocols.end(),
8188-
TypeDecl::compare);
8189-
81908184
// Enumerate the conformance requirements.
81918185
for (auto proto : protocols) {
81928186
recordRequirement(RequirementKind::Conformance, subjectType, proto);
81938187
}
81948188
}
81958189
}
81968190

8197-
// Sort the subject types in canonical order. This needs to be a stable sort
8198-
// so that the relative order of requirements that have the same subject type
8199-
// is preserved.
8200-
std::stable_sort(requirements.begin(), requirements.end(),
8201-
[](const Requirement &lhs, const Requirement &rhs) {
8202-
return compareDependentTypes(lhs.getFirstType(),
8203-
rhs.getFirstType()) < 0;
8204-
});
8191+
// Sort the requirements in canonical order.
8192+
llvm::array_pod_sort(requirements.begin(), requirements.end(),
8193+
compareRequirements);
82058194
}
82068195

82078196
void GenericSignatureBuilder::dump() {
@@ -8377,19 +8366,97 @@ static Requirement stripBoundDependentMemberTypes(Requirement req) {
83778366
llvm_unreachable("Bad requirement kind");
83788367
}
83798368

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+
83808443
GenericSignature GenericSignatureBuilder::computeGenericSignature(
83818444
bool allowConcreteGenericParams,
83828445
bool buildingRequirementSignature,
83838446
bool rebuildingWithoutRedundantConformances) && {
83848447
// Finalize the builder, producing any necessary diagnostics.
83858448
finalize(getGenericParams(), allowConcreteGenericParams);
83868449

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

8391-
// Form the generic signature.
8392-
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+
}
83938460

83948461
// If any of our explicit conformance requirements were implied by
83958462
// superclass or concrete same-type requirements, we have to build the
@@ -8400,34 +8467,22 @@ GenericSignature GenericSignatureBuilder::computeGenericSignature(
84008467
// we might end up emitting duplicate diagnostics.
84018468
//
84028469
// Also, don't do this when building a requirement signature.
8403-
if (!buildingRequirementSignature &&
8470+
if (!rebuildingWithoutRedundantConformances &&
8471+
!buildingRequirementSignature &&
84048472
!Impl->HadAnyError &&
84058473
hasExplicitConformancesImpliedByConcrete()) {
8406-
NumSignaturesRebuiltWithoutRedundantRequirements++;
8407-
8408-
if (rebuildingWithoutRedundantConformances) {
8409-
llvm::errs() << "Rebuilt signature still has "
8410-
<< "redundant conformance requirements: ";
8411-
llvm::errs() << sig << "\n";
8412-
abort();
8413-
}
8414-
8415-
GenericSignatureBuilder newBuilder(Context);
8416-
8417-
for (auto param : sig->getGenericParams())
8418-
newBuilder.addGenericParameter(param);
8419-
8420-
for (auto &req : sig->getRequirements()) {
8421-
newBuilder.addRequirement(stripBoundDependentMemberTypes(req),
8422-
FloatingRequirementSource::forAbstract(), nullptr);
8423-
}
8424-
8425-
return std::move(newBuilder).computeGenericSignature(
8474+
return std::move(*this).rebuildSignatureWithoutRedundantRequirements(
84268475
allowConcreteGenericParams,
8427-
buildingRequirementSignature,
8428-
/*rebuildingWithoutRedundantConformances=*/true);
8476+
buildingRequirementSignature);
84298477
}
84308478

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+
84318486
#ifndef NDEBUG
84328487
if (!Impl->HadAnyError) {
84338488
checkGenericSignature(sig.getCanonicalSignature(), *this);
@@ -8537,9 +8592,6 @@ void GenericSignatureBuilder::verifyGenericSignature(ASTContext &context,
85378592
context.Diags.diagnose(SourceLoc(), diag::generic_signature_not_minimal,
85388593
reqString, sig->getAsString());
85398594
}
8540-
8541-
// Canonicalize the signature to check that it is canonical.
8542-
(void)newSig.getCanonicalSignature();
85438595
}
85448596
}
85458597

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)