Skip to content

Commit d40e30d

Browse files
authored
Merge pull request #42017 from slavapestov/rqm-rule-length-heuristic
RequirementMachine: Tweak rule limit non-termination heuristic
2 parents 5acea84 + 7d0215e commit d40e30d

File tree

8 files changed

+29
-9
lines changed

8 files changed

+29
-9
lines changed

lib/AST/RequirementMachine/KnuthBendix.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ RewriteSystem::computeConfluentCompletion(unsigned maxRuleCount,
398398
continue;
399399

400400
// Check if the new rule is too long.
401-
if (Rules.back().getDepth() > maxRuleLength)
401+
if (Rules.back().getDepth() > maxRuleLength + getLongestInitialRule())
402402
return std::make_pair(CompletionResult::MaxRuleLength, Rules.size() - 1);
403403
}
404404

lib/AST/RequirementMachine/RequirementMachine.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ RequirementMachine::computeCompletion(RewriteSystem::ValidityPolicy policy) {
301301
// Check new rules added by the property map against configured limits.
302302
for (unsigned i = 0; i < rulesAdded; ++i) {
303303
const auto &newRule = System.getRule(ruleCount + i);
304-
if (newRule.getDepth() > MaxRuleLength) {
304+
if (newRule.getDepth() > MaxRuleLength + System.getLongestInitialRule()) {
305305
return std::make_pair(CompletionResult::MaxRuleLength,
306306
ruleCount + i);
307307
}

lib/AST/RequirementMachine/RewriteSystem.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ RewriteSystem::RewriteSystem(RewriteContext &ctx)
3030
Complete = 0;
3131
Minimized = 0;
3232
RecordLoops = 0;
33+
LongestInitialRule = 0;
3334
}
3435

3536
RewriteSystem::~RewriteSystem() {
@@ -85,6 +86,10 @@ void RewriteSystem::initialize(
8586
addRules(std::move(importedRules),
8687
std::move(permanentRules),
8788
std::move(requirementRules));
89+
90+
for (const auto &rule : getLocalRules()) {
91+
LongestInitialRule = std::max(LongestInitialRule, rule.getDepth());
92+
}
8893
}
8994

9095
/// Reduce a term by applying all rewrite rules until fixed point.

lib/AST/RequirementMachine/RewriteSystem.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ class RewriteSystem final {
106106
/// identities among rewrite rules discovered while resolving critical pairs.
107107
unsigned RecordLoops : 1;
108108

109+
/// The length of the longest initial rule, used for the MaxRuleLength
110+
/// completion non-termination heuristic.
111+
unsigned LongestInitialRule : 16;
112+
109113
public:
110114
explicit RewriteSystem(RewriteContext &ctx);
111115
~RewriteSystem();
@@ -131,6 +135,10 @@ class RewriteSystem final {
131135
std::vector<std::pair<MutableTerm, MutableTerm>> &&permanentRules,
132136
std::vector<std::tuple<MutableTerm, MutableTerm, Optional<unsigned>>> &&requirementRules);
133137

138+
unsigned getLongestInitialRule() const {
139+
return LongestInitialRule;
140+
}
141+
134142
ArrayRef<const ProtocolDecl *> getProtocols() const {
135143
return Protos;
136144
}

test/Generics/non_confluent.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
// RUN: %target-typecheck-verify-swift -requirement-machine-protocol-signatures=on -requirement-machine-inferred-signatures=on
22

33
protocol ABA // expected-error {{cannot build rewrite system for protocol; rule length limit exceeded}}
4-
// expected-note@-1 {{failed rewrite rule is [ABA:A].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:A] => [ABA:A].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B]}}
4+
// expected-note@-1 {{failed rewrite rule is [ABA:A].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:A] => [ABA:A].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B].[ABA:B]}}
55
where A.B == A.B.A { // expected-error *{{is not a member type}}
66
associatedtype A : ABA
77
associatedtype B : ABA
88
}
99

1010
protocol Undecidable // expected-error {{cannot build rewrite system for protocol; rule length limit exceeded}}
11-
// expected-note@-1 {{failed rewrite rule is [Undecidable:A].[Undecidable:B].[Undecidable:D].[Undecidable:C].[Undecidable:C].[Undecidable:C].[Undecidable:E].[Undecidable:B].[Undecidable:A].[Undecidable:A].[Undecidable:E].[Undecidable:C].[Undecidable:E] => [Undecidable:A].[Undecidable:B].[Undecidable:D].[Undecidable:C].[Undecidable:C].[Undecidable:C].[Undecidable:E].[Undecidable:B].[Undecidable:A].[Undecidable:A].[Undecidable:E].[Undecidable:C]}}
11+
// expected-note@-1 {{failed rewrite rule is [Undecidable:A].[Undecidable:C].[Undecidable:C].[Undecidable:C].[Undecidable:D].[Undecidable:C].[Undecidable:E].[Undecidable:E].[Undecidable:B].[Undecidable:B].[Undecidable:A].[Undecidable:B].[Undecidable:C].[Undecidable:C].[Undecidable:C].[Undecidable:D].[Undecidable:D] => [Undecidable:A].[Undecidable:C].[Undecidable:C].[Undecidable:C].[Undecidable:D].[Undecidable:C].[Undecidable:C].[Undecidable:C].[Undecidable:C].[Undecidable:D].[Undecidable:D].[Undecidable:E].[Undecidable:A].[Undecidable:B]}}
1212
where A.C == C.A, // expected-error *{{is not a member type}}
1313
A.D == D.A, // expected-error *{{is not a member type}}
1414
B.C == C.B, // expected-error *{{is not a member type}}
@@ -33,19 +33,19 @@ protocol P2 {
3333

3434
func foo<T : P1 & P2>(_: T) {}
3535
// expected-error@-1 {{cannot build rewrite system for generic signature; rule length limit exceeded}}
36-
// expected-note@-2 {{failed rewrite rule is τ_0_0.[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P2] => τ_0_0.[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T]}}
36+
// expected-note@-2 {{failed rewrite rule is τ_0_0.[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P2] => τ_0_0.[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T]}}
3737

3838
extension P1 where Self : P2 {}
3939
// expected-error@-1 {{cannot build rewrite system for generic signature; rule length limit exceeded}}
40-
// expected-note@-2 {{failed rewrite rule is τ_0_0.[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P2] => τ_0_0.[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T]}}
40+
// expected-note@-2 {{failed rewrite rule is τ_0_0.[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P2] => τ_0_0.[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T]}}
4141

4242
struct S<U : P1> : P1 {
4343
typealias T = S<S<U>>
4444
}
4545

4646
protocol P3 {
4747
// expected-error@-1 {{cannot build rewrite system for protocol; rule length limit exceeded}}
48-
// expected-note@-2 {{failed rewrite rule is [P3:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[concrete: S<S<S<S<S<S<S<S<S<S<S<S<[P3:U]>>>>>>>>>>>>] => [P3:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T]}}
48+
// expected-note@-2 {{failed rewrite rule is [P3:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[concrete: S<S<S<S<S<S<S<S<S<S<S<S<S<S<[P3:U]>>>>>>>>>>>>>>] => [P3:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T]}}
4949

5050
associatedtype T : P1 where T == S<U>
5151
// expected-error@-1 {{type 'Self.U' does not conform to protocol 'P1'}}

test/Generics/opaque_archetype_concrete_requirement_recursive_rejected.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,5 @@ protocol HasRecursiveP {
3131

3232
extension HasRecursiveP where T == DefinesRecursiveP.T {}
3333
// expected-error@-1 {{cannot build rewrite system for generic signature; rule length limit exceeded}}
34-
// expected-note@-2 {{failed rewrite rule is τ_0_0.[HasRecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[concrete: (((((((((@_opaqueReturnTypeOf("$s56opaque_archetype_concrete_requirement_recursive_rejected17DefinesRecursivePV1tQrvp", 0) __.T).T).T).T).T).T).T).T).T).T] => τ_0_0.[HasRecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T]}}
34+
// expected-note@-2 {{failed rewrite rule is τ_0_0.[HasRecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[concrete: ((((((((((((@_opaqueReturnTypeOf("$s56opaque_archetype_concrete_requirement_recursive_rejected17DefinesRecursivePV1tQrvp", 0) __.T).T).T).T).T).T).T).T).T).T).T).T).T] => τ_0_0.[HasRecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T].[RecursiveP:T]}}
3535

test/Generics/sr16024.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// RUN: %target-swift-frontend -typecheck %s -requirement-machine-protocol-signatures=on
2+
3+
// The rule length limit (12 by default) is relative to the longest initial rule.
4+
5+
protocol P {
6+
associatedtype T : P where T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T.T == Self
7+
}

validation-test/compiler_crashers_2_fixed/sr9584.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ protocol P {
1010
extension S: P where N: P {
1111
static func f<X: P>(_ x: X) -> S<X.A> where A == X, X.A == N {
1212
// expected-error@-1 {{cannot build rewrite system for generic signature; rule length limit exceeded}}
13-
// expected-note@-2 {{failed rewrite rule is τ_0_0.[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[concrete: S<S<S<S<S<S<S<S<S<S<S<S<τ_0_0>>>>>>>>>>>>] => τ_0_0.[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A] [subst↓]}}
13+
// expected-note@-2 {{failed rewrite rule is τ_0_0.[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[concrete: S<S<S<S<S<S<S<S<S<S<S<S<S<S<τ_0_0>>>>>>>>>>>>>>] => τ_0_0.[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A].[P:A] [subst↓]}}
1414
// expected-error@-3 {{'A' is not a member type of type 'X'}}
1515
// expected-error@-4 {{'A' is not a member type of type 'X'}}
1616
return S<X.A>()

0 commit comments

Comments
 (0)