Skip to content

Commit 3976849

Browse files
committed
[RequirementMachine] Suppress redundancy warnings when an explicit, redundant
rule has a non-explicit, non-redundant rule in its rewrite path. This fixes bogus redundancy diagnostics in cases where the canonical form of a redundant rule is not explicit in source, e.g. protocol Swappable2 { associatedtype A associatedtype B associatedtype Swapped : Swappable2 where Swapped.B == A, Swapped.Swapped == Self } in the above case, the canonical rule for `Swapped.B == A` is the rule [Swappable2:Swapped].[Swappable2:A] => [Swappable2:B], which is not explicit.
1 parent a154641 commit 3976849

File tree

7 files changed

+46
-6
lines changed

7 files changed

+46
-6
lines changed

lib/AST/RequirementMachine/RewriteSystem.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,13 +725,25 @@ RewriteSystem::getRedundantRequirements() {
725725
// The resulting set of redundant requirements.
726726
std::vector<RequirementError> redundantRequirements;
727727

728+
// Map redundant rule IDs to their rewrite path for easy access
729+
// in the `isRedundantRule` lambda.
730+
llvm::SmallDenseMap<unsigned, RewritePath> redundantRules;
731+
for (auto &pair : RedundantRules)
732+
redundantRules[pair.first] = pair.second;
733+
728734
// Collect all rule IDs for each unique requirement ID.
729735
llvm::SmallDenseMap<unsigned, llvm::SmallDenseSet<unsigned, 2>>
730736
rulesPerRequirement;
731737

738+
// Collect non-explicit requirements that are not redundant.
739+
llvm::SmallDenseSet<unsigned, 2> impliedRequirements;
740+
732741
for (unsigned ruleID : indices(getRules())) {
733742
auto &rule = getRules()[ruleID];
734743

744+
if (!rule.isExplicit() && !rule.isPermanent() && !rule.isRedundant())
745+
impliedRequirements.insert(ruleID);
746+
735747
if (!rule.isExplicit())
736748
continue;
737749

@@ -744,6 +756,30 @@ RewriteSystem::getRedundantRequirements() {
744756

745757
auto isRedundantRule = [&](unsigned ruleID) {
746758
auto &rule = getRules()[ruleID];
759+
760+
// If this rule is replaced using a non-explicit,
761+
// non-redundant rule, it's not redundant.
762+
auto rewritePath = redundantRules[ruleID];
763+
for (auto step : rewritePath) {
764+
switch (step.Kind) {
765+
case RewriteStep::Rule: {
766+
if (impliedRequirements.count(step.getRuleID()))
767+
return false;
768+
769+
break;
770+
}
771+
772+
case RewriteStep::LeftConcreteProjection:
773+
case RewriteStep::Decompose:
774+
case RewriteStep::PrefixSubstitutions:
775+
case RewriteStep::Shift:
776+
case RewriteStep::Relation:
777+
case RewriteStep::DecomposeConcrete:
778+
case RewriteStep::RightConcreteProjection:
779+
break;
780+
}
781+
}
782+
747783
return rule.isRedundant();
748784
};
749785

test/Constraints/generic_super_constraint.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
class Base<T> { }
44
class Derived: Base<Int> { }
55

6+
// expected-warning@+1 {{redundant superclass constraint 'T' : 'Base<Int>'}}
67
func foo<T>(_ x: T) -> Derived where T: Base<Int>, T: Derived {
78
return x
89
}

test/Generics/requirement_machine_diagnostics.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,8 @@ protocol P7 : P6 {
152152
associatedtype AssocP7: P6
153153
}
154154

155-
extension P7 where AssocP6.Element : P6, // expected-warning{{redundant conformance constraint 'Self.AssocP6.Element' : 'P6'}}
155+
// FIXME: diagnose redundant requirement 'AssocP6.Element : P6'
156+
extension P7 where AssocP6.Element : P6,
156157
AssocP7.AssocP6.Element : P6,
157158
AssocP6.Element == AssocP7.AssocP6.Element {
158159
func nestedSameType1() { }

test/Generics/sr10752.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ protocol P {
99
// CHECK: sr10752.(file).Q@
1010
// CHECK-NEXT: Requirement signature: <Self where Self.[Q]A == Self.[Q]C.[P]A, Self.[Q]C : P>
1111
protocol Q {
12-
associatedtype A : P
12+
associatedtype A : P // expected-warning {{redundant conformance constraint 'Self.A' : 'P'}}
1313
associatedtype C : P where A == C.A
1414
}

test/Generics/sr12120.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ protocol Swappable1 {
66
associatedtype A
77
associatedtype B
88
associatedtype Swapped : Swappable1
9-
where Swapped.B == A,
10-
Swapped.A == B, // FIXME: Diagnose redundancy
9+
where Swapped.B == A, // expected-warning {{redundant same-type constraint 'Self.Swapped.B' == 'Self.A'}}
10+
Swapped.A == B,
1111
Swapped.Swapped == Self
1212
}
1313

test/Generics/sr14485.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// CHECK: sr14485.(file).P@
44
// CHECK-NEXT: Requirement signature: <Self where Self.[P]Input == Self.[P]Output.[Numeric]Magnitude, Self.[P]Output : FixedWidthInteger, Self.[P]Output : SignedInteger>
55
protocol P {
6+
// expected-warning@+2 {{redundant conformance constraint 'Self.Input' : 'FixedWidthInteger'}}
7+
// expected-warning@+1 {{redundant conformance constraint 'Self.Input' : 'UnsignedInteger'}}
68
associatedtype Input: FixedWidthInteger & UnsignedInteger & BinaryInteger
79
associatedtype Output: FixedWidthInteger & SignedInteger & BinaryInteger
810
where Output.Magnitude == Input

test/decl/protocol/req/associated_type_ambiguity.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ protocol P2 {
1111

1212
// CHECK: ExtensionDecl line={{.*}} base=P1
1313
// CHECK-NEXT: Generic signature: <Self where Self : P1, Self : P2>
14-
extension P1 where Self : P2, T == Int {
14+
extension P1 where Self : P2, T == Int { // expected-warning {{redundant same-type constraint 'Self.T' == 'Int'}}
1515
func takeT11(_: T) {}
1616
func takeT12(_: Self.T) {}
1717
}
1818

1919
// CHECK: ExtensionDecl line={{.*}} base=P1
2020
// CHECK-NEXT: Generic signature: <Self where Self : P1, Self : P2>
21-
extension P1 where Self : P2, Self.T == Int {
21+
extension P1 where Self : P2, Self.T == Int { // expected-warning {{redundant same-type constraint 'Self.T' == 'Int'}}
2222
func takeT21(_: T) {}
2323
func takeT22(_: Self.T) {}
2424
}

0 commit comments

Comments
 (0)