Skip to content

[GSB] Don't emit redundant superclass constraints. #8242

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 27 additions & 32 deletions lib/AST/GenericSignatureBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3555,10 +3555,6 @@ namespace {
/// potential archetypes in this component equivalent to the concrete type.
const RequirementSource *concreteTypeSource;

/// The (best) requirement source within the component that introduces
/// the superclass constraint.
const RequirementSource *superclassSource;

friend bool operator<(const SameTypeComponent &lhs,
const SameTypeComponent &rhs) {
return compareDependentTypes(&lhs.anchor, &rhs.anchor) < 0;
Expand Down Expand Up @@ -3615,7 +3611,7 @@ static SmallVector<SameTypeComponent, 2> getSameTypeComponents(
auto anchor = sameTypeDFS(pa, components.size(), paToComponent);

// Record the anchor.
components.push_back({anchor, nullptr, nullptr});
components.push_back({anchor, nullptr});
}

// If there is a concrete type, figure out the best concrete type anchor
Expand All @@ -3634,29 +3630,26 @@ static SmallVector<SameTypeComponent, 2> getSameTypeComponents(
bestConcreteTypeSource = concrete.source;
}

// If there is a superclass and no concrete type, figure out the best
// superclass source per component.
if (equivClass->superclass && !equivClass->concreteType) {
for (const auto &superclass : equivClass->superclassConstraints) {
// Dig out the component associated with constraint.
assert(paToComponent.count(superclass.archetype) > 0);
auto &component = components[paToComponent[superclass.archetype]];

// If it has a better source than we'd seen before for this component,
// keep it.
auto &bestSuperclassSource = component.superclassSource;
if (!bestSuperclassSource ||
superclass.source->compare(bestSuperclassSource) < 0)
bestSuperclassSource = superclass.source;
}
}

// Sort the components.
llvm::array_pod_sort(components.begin(), components.end());

return components;
}

namespace {
/// Retrieve the best requirement source from a set of constraints.
template<typename T>
const RequirementSource *getBestConstraintSource(
ArrayRef<Constraint<T>> constraints) {
auto bestSource = constraints.front().source;
for (const auto &constraint : constraints) {
if (constraint.source->compare(bestSource) < 0)
bestSource = constraint.source;
}
return bestSource;
}
}

void GenericSignatureBuilder::enumerateRequirements(llvm::function_ref<
void (RequirementKind kind,
PotentialArchetype *archetype,
Expand Down Expand Up @@ -3730,14 +3723,6 @@ void GenericSignatureBuilder::enumerateRequirements(llvm::function_ref<
continue;
}

// If we have a superclass, produce a superclass requirement
if (Type superclass = rep->getSuperclass()) {
f(RequirementKind::Superclass, archetype, superclass,
knownAnchor->superclassSource
? knownAnchor->superclassSource
: RequirementSource::forAbstract(archetype));
}

// If we're at the last anchor in the component, do nothing;
auto nextAnchor = knownAnchor;
++nextAnchor;
Expand All @@ -3762,6 +3747,12 @@ void GenericSignatureBuilder::enumerateRequirements(llvm::function_ref<

auto equivClass = rep->getEquivalenceClassIfPresent();

// If we have a superclass, produce a superclass requirement
if (equivClass && equivClass->superclass) {
f(RequirementKind::Superclass, archetype, equivClass->superclass,
getBestConstraintSource<Type>(equivClass->superclassConstraints));
}

// If we have a layout constraint, produce a layout requirement.
if (equivClass && equivClass->layout) {
// Find the best source among the constraints that describe the layout
Expand All @@ -3772,7 +3763,9 @@ void GenericSignatureBuilder::enumerateRequirements(llvm::function_ref<
bestSource = constraint.source;
}

f(RequirementKind::Layout, archetype, equivClass->layout, bestSource);
f(RequirementKind::Layout, archetype, equivClass->layout,
getBestConstraintSource<LayoutConstraint>(
equivClass->layoutConstraints));
}

// Enumerate conformance requirements.
Expand All @@ -3792,7 +3785,9 @@ void GenericSignatureBuilder::enumerateRequirements(llvm::function_ref<
bestSource = constraint.source;
}

protocolSources.insert({conforms.first, bestSource});
protocolSources.insert(
{conforms.first,
getBestConstraintSource<ProtocolDecl *>(conforms.second)});
}
}

Expand Down
7 changes: 7 additions & 0 deletions test/Generics/superclass_constraint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,10 @@ protocol P7 {
// expected-note@-2{{superclass constraint 'Self.Assoc' : 'A' written here}}
// expected-error@-3{{'Self.Assoc' cannot be a subclass of both 'Other' and 'A'}}
}

// CHECK: superclassConformance4
// CHECK: Generic signature: <T, U where T : P3, U : P3, T.T : C, T.T == U.T>
func superclassConformance4<T: P3, U: P3>(_: T, _: U)
where T.T: C, // expected-note{{superclass constraint 'T.T' : 'C' written here}}
U.T: C, // expected-warning{{redundant superclass constraint 'U.T' : 'C'}}
T.T == U.T { }