Skip to content

Commit 8f52c26

Browse files
authored
Merge pull request #36598 from slavapestov/enumerate-requirements-explicitly
GSB: Use explicit requirement list in enumerateRequirements()
2 parents 4d9d38d + 524e588 commit 8f52c26

File tree

4 files changed

+137
-144
lines changed

4 files changed

+137
-144
lines changed

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 110 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,7 @@ struct GenericSignatureBuilder::Implementation {
698698
bool HadAnyError = false;
699699

700700
/// All explicit non-same type requirements that were added to the builder.
701-
SmallVector<ExplicitRequirement, 2> ExplicitRequirements;
701+
SmallSetVector<ExplicitRequirement, 2> ExplicitRequirements;
702702

703703
/// All explicit same-type requirements that were added to the builder.
704704
SmallVector<Requirement, 2> ExplicitSameTypeRequirements;
@@ -2607,21 +2607,22 @@ GenericSignatureBuilder::resolveConcreteConformance(ResolvedType type,
26072607
concreteSource = concreteSource->viaConcrete(*this, concrete);
26082608
} else {
26092609
concreteSource = concreteSource->viaConcrete(*this, conformance);
2610-
equivClass->recordConformanceConstraint(*this, type, proto, concreteSource);
2611-
2612-
// Only infer conditional requirements from explicit sources.
2613-
bool hasExplicitSource = llvm::any_of(
2614-
equivClass->concreteTypeConstraints,
2615-
[](const ConcreteConstraint &constraint) {
2616-
return (!constraint.source->isDerivedRequirement() &&
2617-
constraint.source->getLoc().isValid());
2618-
});
2610+
}
26192611

2620-
if (hasExplicitSource) {
2621-
if (addConditionalRequirements(conformance, /*inferForModule=*/nullptr,
2622-
concreteSource->getLoc()))
2623-
return nullptr;
2624-
}
2612+
equivClass->recordConformanceConstraint(*this, type, proto, concreteSource);
2613+
2614+
// Only infer conditional requirements from explicit sources.
2615+
bool hasExplicitSource = llvm::any_of(
2616+
equivClass->concreteTypeConstraints,
2617+
[](const ConcreteConstraint &constraint) {
2618+
return (!constraint.source->isDerivedRequirement() &&
2619+
constraint.source->getLoc().isValid());
2620+
});
2621+
2622+
if (hasExplicitSource) {
2623+
if (addConditionalRequirements(conformance, /*inferForModule=*/nullptr,
2624+
concreteSource->getLoc()))
2625+
return nullptr;
26252626
}
26262627

26272628
return concreteSource;
@@ -4507,8 +4508,9 @@ ConstraintResult GenericSignatureBuilder::addConformanceRequirement(
45074508
auto resolvedSource = source.getSource(*this, type);
45084509

45094510
if (!resolvedSource->isDerivedRequirement()) {
4510-
Impl->ExplicitRequirements.emplace_back(RequirementKind::Conformance,
4511-
resolvedSource, proto);
4511+
Impl->ExplicitRequirements.insert(
4512+
ExplicitRequirement(RequirementKind::Conformance,
4513+
resolvedSource, proto));
45124514
}
45134515

45144516
// Add the conformance requirement, bailing out earlier if we've already
@@ -4529,8 +4531,9 @@ ConstraintResult GenericSignatureBuilder::addLayoutRequirementDirect(
45294531
auto resolvedSource = source.getSource(*this, type);
45304532

45314533
if (!resolvedSource->isDerivedRequirement()) {
4532-
Impl->ExplicitRequirements.emplace_back(RequirementKind::Layout,
4533-
resolvedSource, layout);
4534+
Impl->ExplicitRequirements.insert(
4535+
ExplicitRequirement(RequirementKind::Layout,
4536+
resolvedSource, layout));
45344537
}
45354538

45364539
auto equivClass = type.getEquivalenceClass(*this);
@@ -4670,8 +4673,9 @@ ConstraintResult GenericSignatureBuilder::addSuperclassRequirementDirect(
46704673
auto resolvedSource = source.getSource(*this, type);
46714674

46724675
if (!resolvedSource->isDerivedRequirement()) {
4673-
Impl->ExplicitRequirements.emplace_back(RequirementKind::Superclass,
4674-
resolvedSource, superclass);
4676+
Impl->ExplicitRequirements.insert(
4677+
ExplicitRequirement(RequirementKind::Superclass,
4678+
resolvedSource, superclass));
46754679
}
46764680

46774681
// Record the constraint.
@@ -6466,14 +6470,16 @@ GenericSignatureBuilder::finalize(TypeArrayView<GenericTypeParamType> genericPar
64666470
checkLayoutConstraints(genericParams, &equivClass);
64676471
};
64686472

6469-
// FIXME: Expand all conformance requirements. This is expensive :(
6470-
for (auto &equivClass : Impl->EquivalenceClasses) {
6473+
if (!Impl->ExplicitSameTypeRequirements.empty()) {
6474+
// FIXME: Expand all conformance requirements. This is expensive :(
6475+
for (auto &equivClass : Impl->EquivalenceClasses) {
64716476
expandSameTypeConstraints(*this, &equivClass);
6472-
}
6477+
}
64736478

6474-
// Check same-type constraints.
6475-
for (auto &equivClass : Impl->EquivalenceClasses) {
6476-
checkSameTypeConstraints(genericParams, &equivClass);
6479+
// Check same-type constraints.
6480+
for (auto &equivClass : Impl->EquivalenceClasses) {
6481+
checkSameTypeConstraints(genericParams, &equivClass);
6482+
}
64776483
}
64786484

64796485
// Check for generic parameters which have been made concrete or equated
@@ -7977,26 +7983,6 @@ bool GenericSignatureBuilder::isRedundantExplicitRequirement(
79777983
return (redundantReqs.find(req) != redundantReqs.end());
79787984
}
79797985

7980-
namespace {
7981-
template<typename T>
7982-
bool hasNonRedundantRequirementSource(ArrayRef<Constraint<T>> constraints,
7983-
RequirementKind kind,
7984-
GenericSignatureBuilder &builder) {
7985-
for (auto constraint : constraints) {
7986-
if (constraint.source->isDerivedRequirement())
7987-
continue;
7988-
7989-
auto req = ExplicitRequirement::fromExplicitConstraint(kind, constraint);
7990-
if (builder.isRedundantExplicitRequirement(req))
7991-
continue;
7992-
7993-
return true;
7994-
}
7995-
7996-
return false;
7997-
}
7998-
} // end anonymous namespace
7999-
80007986
static Optional<Requirement> createRequirement(RequirementKind kind,
80017987
Type depTy,
80027988
RequirementRHS rhs,
@@ -8075,116 +8061,89 @@ void GenericSignatureBuilder::enumerateRequirements(
80758061
requirements.push_back(*req);
80768062
};
80778063

8078-
// Collect all of the subject types that will be involved in constraints.
8079-
for (auto &equivClass : Impl->EquivalenceClasses) {
8080-
if (equivClass.derivedSameTypeComponents.empty()) {
8081-
checkSameTypeConstraints(genericParams, &equivClass);
8082-
}
8083-
8084-
for (unsigned i : indices(equivClass.derivedSameTypeComponents)) {
8085-
// Dig out the subject type and its corresponding component.
8086-
auto &component = equivClass.derivedSameTypeComponents[i];
8087-
Type subjectType = component.type;
8088-
8089-
assert(!subjectType->hasError());
8090-
assert(!subjectType->findUnresolvedDependentMemberType());
8064+
// Collect all non-same type requirements.
8065+
for (auto &req : Impl->ExplicitRequirements) {
8066+
if (isRedundantExplicitRequirement(req))
8067+
continue;
80918068

8092-
// If this equivalence class is bound to a concrete type, equate the
8093-
// anchor with a concrete type.
8094-
if (Type concreteType = equivClass.concreteType) {
8095-
concreteType = getCanonicalTypeInContext(concreteType, genericParams);
8069+
auto depTy = getCanonicalTypeInContext(
8070+
req.getSource()->getStoredType(), { });
80968071

8097-
// If the parent of this anchor is also a concrete type, don't
8098-
// create a requirement.
8099-
if (!subjectType->is<GenericTypeParamType>() &&
8100-
maybeResolveEquivalenceClass(
8101-
subjectType->castTo<DependentMemberType>()->getBase(),
8102-
ArchetypeResolutionKind::WellFormed,
8103-
/*wantExactPotentialArchetype=*/false)
8104-
.getEquivalenceClass(*this)->concreteType)
8105-
continue;
8072+
// FIXME: This should be an assert once we ensure that concrete
8073+
// same-type requirements always mark other requirements on the
8074+
// same subject type as redundant or conflicting.
8075+
if (!depTy->isTypeParameter())
8076+
continue;
81068077

8107-
// Drop recursive and invalid concrete-type constraints.
8108-
if (equivClass.recursiveConcreteType ||
8109-
equivClass.invalidConcreteType)
8110-
continue;
8078+
auto rhs = req.getRHS();
8079+
if (auto constraintType = rhs.dyn_cast<Type>()) {
8080+
rhs = getCanonicalTypeInContext(constraintType, genericParams);
8081+
}
81118082

8112-
// Filter out derived requirements... except for concrete-type
8113-
// requirements on generic parameters. The exception is due to
8114-
// the canonicalization of generic signatures, which never
8115-
// eliminates generic parameters even when they have been
8116-
// mapped to a concrete type.
8117-
if (subjectType->is<GenericTypeParamType>() ||
8118-
component.concreteTypeSource == nullptr ||
8119-
!component.concreteTypeSource->isDerivedRequirement()) {
8120-
recordRequirement(RequirementKind::SameType,
8121-
subjectType, concreteType);
8122-
}
8123-
continue;
8124-
}
8083+
recordRequirement(req.getKind(), depTy, rhs);
8084+
}
81258085

8126-
std::function<void()> deferredSameTypeRequirement;
8127-
8128-
// If we're at the last anchor in the component, do nothing;
8129-
if (i + 1 != equivClass.derivedSameTypeComponents.size()) {
8130-
// Form a same-type constraint from this anchor within the component
8131-
// to the next.
8132-
// FIXME: Distinguish between explicit and inferred here?
8133-
auto &nextComponent = equivClass.derivedSameTypeComponents[i + 1];
8134-
Type otherSubjectType = nextComponent.type;
8135-
deferredSameTypeRequirement =
8136-
[&recordRequirement, subjectType, otherSubjectType] {
8137-
recordRequirement(RequirementKind::SameType,
8138-
subjectType, otherSubjectType);
8139-
};
8086+
// Collect all same type requirements.
8087+
if (!Impl->ExplicitSameTypeRequirements.empty()) {
8088+
for (auto &equivClass : Impl->EquivalenceClasses) {
8089+
if (equivClass.derivedSameTypeComponents.empty()) {
8090+
checkSameTypeConstraints(genericParams, &equivClass);
81408091
}
81418092

8142-
SWIFT_DEFER {
8143-
if (deferredSameTypeRequirement) deferredSameTypeRequirement();
8144-
};
8145-
8146-
// If this is not the first component anchor in its equivalence class,
8147-
// we're done.
8148-
if (i > 0)
8149-
continue;
8150-
8151-
// If we have a superclass, produce a superclass requirement
8152-
if (auto superclass = equivClass.superclass) {
8153-
superclass = getCanonicalTypeInContext(superclass, genericParams);
8093+
for (unsigned i : indices(equivClass.derivedSameTypeComponents)) {
8094+
// Dig out the subject type and its corresponding component.
8095+
auto &component = equivClass.derivedSameTypeComponents[i];
8096+
Type subjectType = component.type;
8097+
8098+
assert(!subjectType->hasError());
8099+
assert(!subjectType->findUnresolvedDependentMemberType());
8100+
8101+
// If this equivalence class is bound to a concrete type, equate the
8102+
// anchor with a concrete type.
8103+
if (Type concreteType = equivClass.concreteType) {
8104+
concreteType = getCanonicalTypeInContext(concreteType, genericParams);
8105+
8106+
// If the parent of this anchor is also a concrete type, don't
8107+
// create a requirement.
8108+
if (!subjectType->is<GenericTypeParamType>() &&
8109+
maybeResolveEquivalenceClass(
8110+
subjectType->castTo<DependentMemberType>()->getBase(),
8111+
ArchetypeResolutionKind::WellFormed,
8112+
/*wantExactPotentialArchetype=*/false)
8113+
.getEquivalenceClass(*this)->concreteType)
8114+
continue;
81548115

8155-
if (!equivClass.recursiveSuperclassType &&
8156-
hasNonRedundantRequirementSource<Type>(
8157-
equivClass.superclassConstraints,
8158-
RequirementKind::Superclass, *this)) {
8159-
recordRequirement(RequirementKind::Superclass,
8160-
subjectType, superclass);
8161-
}
8162-
}
8116+
// Drop recursive and invalid concrete-type constraints.
8117+
if (equivClass.recursiveConcreteType ||
8118+
equivClass.invalidConcreteType)
8119+
continue;
81638120

8164-
// If we have a layout constraint, produce a layout requirement.
8165-
if (equivClass.layout) {
8166-
if (hasNonRedundantRequirementSource<LayoutConstraint>(
8167-
equivClass.layoutConstraints,
8168-
RequirementKind::Layout, *this)) {
8169-
recordRequirement(RequirementKind::Layout,
8170-
subjectType, equivClass.layout);
8121+
// Filter out derived requirements... except for concrete-type
8122+
// requirements on generic parameters. The exception is due to
8123+
// the canonicalization of generic signatures, which never
8124+
// eliminates generic parameters even when they have been
8125+
// mapped to a concrete type.
8126+
if (subjectType->is<GenericTypeParamType>() ||
8127+
component.concreteTypeSource == nullptr ||
8128+
!component.concreteTypeSource->isDerivedRequirement()) {
8129+
recordRequirement(RequirementKind::SameType,
8130+
subjectType, concreteType);
8131+
}
8132+
continue;
81718133
}
8172-
}
81738134

8174-
// Enumerate conformance requirements.
8175-
SmallVector<ProtocolDecl *, 4> protocols;
8135+
// If we're at the last anchor in the component, do nothing;
8136+
if (i + 1 != equivClass.derivedSameTypeComponents.size()) {
8137+
// Form a same-type constraint from this anchor within the component
8138+
// to the next.
8139+
// FIXME: Distinguish between explicit and inferred here?
8140+
auto &nextComponent = equivClass.derivedSameTypeComponents[i + 1];
8141+
Type otherSubjectType = nextComponent.type;
81768142

8177-
for (const auto &conforms : equivClass.conformsTo) {
8178-
if (hasNonRedundantRequirementSource<ProtocolDecl *>(
8179-
conforms.second, RequirementKind::Conformance, *this)) {
8180-
protocols.push_back(conforms.first);
8143+
recordRequirement(RequirementKind::SameType,
8144+
subjectType, otherSubjectType);
81818145
}
81828146
}
8183-
8184-
// Enumerate the conformance requirements.
8185-
for (auto proto : protocols) {
8186-
recordRequirement(RequirementKind::Conformance, subjectType, proto);
8187-
}
81888147
}
81898148
}
81908149

@@ -8310,6 +8269,14 @@ static void checkGenericSignature(CanGenericSignature canSig,
83108269
}
83118270
}
83128271

8272+
// If we have a concrete same-type requirement, we shouldn't have any
8273+
// other requirements on the same type.
8274+
if (reqt.getKind() == RequirementKind::SameType &&
8275+
!reqt.getSecondType()->isTypeParameter()) {
8276+
assert(compareLHS < 0 &&
8277+
"Concrete subject type should not have any other requirements");
8278+
}
8279+
83138280
assert(compareRequirements(&prevReqt, &reqt) < 0 &&
83148281
"Out-of-order requirements");
83158282
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %target-typecheck-verify-swift
2+
// RUN: %target-swift-frontend -typecheck -debug-generic-signatures %s 2>&1 | %FileCheck %s
3+
4+
class S<T, U> where T : P, U == T.T {}
5+
6+
protocol P {
7+
associatedtype T
8+
}
9+
10+
struct G<X, T, U> {}
11+
12+
class C : P {
13+
typealias T = Int
14+
}
15+
16+
// CHECK-LABEL: Generic signature: <X, T, U where X : S<T, C.T>, T : C, U == C.T>
17+
extension G where X : S<T, U>, T : C {}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %target-typecheck-verify-swift
2+
// RUN: %target-swift-frontend -typecheck -debug-generic-signatures %s 2>&1 | %FileCheck %s
3+
4+
struct G<T> {}
5+
6+
// CHECK-LABEL: Generic signature: <T where T == Error>
7+
extension G where T : Error, T == Error {}
8+
// expected-warning@-1 {{redundant conformance constraint 'T': 'Error'}}
9+
// expected-note@-2 {{conformance constraint 'T': 'Error' implied here}}

test/IDE/print_ast_tc_decls.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ struct d0200_EscapedIdentifiers {
619619

620620
func `func`<`let`: `protocol`, `where`>(
621621
class: Int, struct: `protocol`, foo: `let`, bar: `where`) where `where` : `protocol` {}
622-
// PASS_COMMON-NEXT: {{^}} func `func`<`let`, `where`>(class: Int, struct: {{(d0200_EscapedIdentifiers.)?}}`protocol`, foo: `let`, bar: `where`) where `let` : {{(d0200_EscapedIdentifiers.)?}}`protocol`, `where` : {{(d0200_EscapedIdentifiers.)?}}`protocol`{{$}}
622+
// PASS_COMMON-NEXT: {{^}} func `func`<`let`, `where`>(class: Int, struct: {{(d0200_EscapedIdentifiers.)?}}`protocol`, foo: `let`, bar: `where`) where `let` : {{(d0200_EscapedIdentifiers.)?}}`class`, `where` : {{(d0200_EscapedIdentifiers.)?}}`class`{{$}}
623623

624624
var `var`: `struct` = `struct`()
625625
// PASS_COMMON-NEXT: {{^}} @_hasInitialValue var `var`: {{(d0200_EscapedIdentifiers.)?}}`struct`{{$}}

0 commit comments

Comments
 (0)