Skip to content

Commit 10a2ddb

Browse files
committed
RequirementMachine: Fix MaxConcreteNesting check to take initial rules into account
Fixes rdar://123357717.
1 parent 3662bb2 commit 10a2ddb

File tree

10 files changed

+38
-18
lines changed

10 files changed

+38
-18
lines changed

lib/AST/RequirementMachine/KnuthBendix.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -325,10 +325,8 @@ RewriteSystem::computeCriticalPair(ArrayRef<Symbol>::const_iterator from,
325325
return true;
326326
}
327327

328-
/// Computes the confluent completion using the Knuth-Bendix algorithm and
329-
/// returns a status code.
330-
///
331-
/// The first element of the pair is a status.
328+
/// Runs the Knuth-Bendix algorithm and returns a pair consisting of a
329+
/// status code and code-specific result.
332330
///
333331
/// The status is CompletionResult::MaxRuleCount if we add more than
334332
/// \p maxRuleCount rules.
@@ -341,8 +339,8 @@ RewriteSystem::computeCriticalPair(ArrayRef<Symbol>::const_iterator from,
341339
/// Otherwise, the status is CompletionResult::Success and the second element
342340
/// is zero.
343341
std::pair<CompletionResult, unsigned>
344-
RewriteSystem::computeConfluentCompletion(unsigned maxRuleCount,
345-
unsigned maxRuleLength) {
342+
RewriteSystem::performKnuthBendix(unsigned maxRuleCount,
343+
unsigned maxRuleLength) {
346344
assert(Initialized);
347345
assert(!Minimized);
348346
assert(!Frozen);

lib/AST/RequirementMachine/RequirementMachine.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ RequirementMachine::computeCompletion(RewriteSystem::ValidityPolicy policy) {
449449
unsigned ruleCount = System.getRules().size();
450450

451451
// First, run the Knuth-Bendix algorithm to resolve overlapping rules.
452-
auto result = System.computeConfluentCompletion(MaxRuleCount, MaxRuleLength);
452+
auto result = System.performKnuthBendix(MaxRuleCount, MaxRuleLength);
453453

454454
unsigned rulesAdded = (System.getRules().size() - ruleCount);
455455

@@ -492,7 +492,7 @@ RequirementMachine::computeCompletion(RewriteSystem::ValidityPolicy policy) {
492492
return std::make_pair(CompletionResult::MaxRuleLength,
493493
ruleCount + i);
494494
}
495-
if (newRule.getNesting() > MaxConcreteNesting) {
495+
if (newRule.getNesting() > MaxConcreteNesting + System.getDeepestInitialRule()) {
496496
return std::make_pair(CompletionResult::MaxConcreteNesting,
497497
ruleCount + i);
498498
}

lib/AST/RequirementMachine/RewriteSystem.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ RewriteSystem::RewriteSystem(RewriteContext &ctx)
3333
Frozen = 0;
3434
RecordLoops = 0;
3535
LongestInitialRule = 0;
36+
DeepestInitialRule = 0;
3637
}
3738

3839
RewriteSystem::~RewriteSystem() {
@@ -88,6 +89,7 @@ void RewriteSystem::initialize(
8889

8990
for (const auto &rule : getLocalRules()) {
9091
LongestInitialRule = std::max(LongestInitialRule, rule.getDepth());
92+
DeepestInitialRule = std::max(DeepestInitialRule, rule.getNesting());
9193
}
9294
}
9395

lib/AST/RequirementMachine/RewriteSystem.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,6 @@ class RewriteSystem final {
7272
/// as rules introduced by the completion procedure.
7373
std::vector<Rule> Rules;
7474

75-
unsigned FirstLocalRule = 0;
76-
7775
/// A prefix trie of rule left hand sides to optimize lookup. The value
7876
/// type is an index into the Rules array defined above.
7977
Trie<unsigned, MatchKind::Shortest> Trie;
@@ -90,6 +88,8 @@ class RewriteSystem final {
9088

9189
DebugOptions Debug;
9290

91+
unsigned FirstLocalRule = 0;
92+
9393
/// Whether we've initialized the rewrite system with a call to initialize().
9494
unsigned Initialized : 1;
9595

@@ -114,6 +114,10 @@ class RewriteSystem final {
114114
/// completion non-termination heuristic.
115115
unsigned LongestInitialRule : 16;
116116

117+
/// The most deeply nested concrete type appearing in an initial rule, used
118+
/// for the MaxConcreteNesting completion non-termination heuristic.
119+
unsigned DeepestInitialRule : 16;
120+
117121
public:
118122
explicit RewriteSystem(RewriteContext &ctx);
119123
~RewriteSystem();
@@ -142,6 +146,10 @@ class RewriteSystem final {
142146
return LongestInitialRule;
143147
}
144148

149+
unsigned getDeepestInitialRule() const {
150+
return DeepestInitialRule;
151+
}
152+
145153
ArrayRef<const ProtocolDecl *> getProtocols() const {
146154
return Protos;
147155
}
@@ -204,8 +212,7 @@ class RewriteSystem final {
204212
llvm::DenseSet<std::pair<unsigned, unsigned>> CheckedOverlaps;
205213

206214
std::pair<CompletionResult, unsigned>
207-
computeConfluentCompletion(unsigned maxRuleCount,
208-
unsigned maxRuleLength);
215+
performKnuthBendix(unsigned maxRuleCount, unsigned maxRuleLength);
209216

210217
void simplifyLeftHandSides();
211218

test/Constraints/same_types.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ protocol P2 {
285285
// CHECK-NEXT: Generic signature: <T, U>
286286

287287
// expected-error@+2 {{cannot build rewrite system for generic signature; concrete nesting limit exceeded}}
288-
// expected-note@+1 {{failed rewrite rule is τ_0_0.[P2:Assoc1].[concrete: ((((((((((((((((((((((((((((((τ_0_0.[P2:Assoc1], τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1)] => τ_0_0.[P2:Assoc1]}}
288+
// expected-note@+1 {{τ_0_0.[P2:Assoc1].[concrete: ((((((((((((((((((((((((((((((((τ_0_0.[P2:Assoc1], τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1), τ_0_1)] => τ_0_0.[P2:Assoc1]}}
289289
func structuralSameTypeRecursive1<T: P2, U>(_: T, _: U)
290290
where T.Assoc1 == Tuple2<T.Assoc1, U>
291291
// expected-error@-1 {{'Assoc1' is not a member type of type 'T'}}

test/Generics/infinite_concrete_type.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
class G<T> {}
44

55
protocol P1 { // expected-error {{cannot build rewrite system for protocol; concrete nesting limit exceeded}}
6-
// expected-note@-1 {{failed rewrite rule is [P1:A].[concrete: G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<[P1].A>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] => [P1:A]}}
6+
// expected-note@-1 {{failed rewrite rule is [P1:A].[concrete: G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<[P1].A>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] => [P1:A]}}
77
associatedtype A where A == G<B>
88
associatedtype B where B == G<A>
99
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %target-typecheck-verify-swift -requirement-machine-max-concrete-nesting=4
2+
// RUN: not %target-typecheck-verify-swift -requirement-machine-max-concrete-nesting=3
3+
4+
struct G<T> {}
5+
6+
// The nesting limit is relative to the initial set of rules, so here we
7+
// can form a type with nesting depth 8.
8+
9+
func f<T, U>(_: T, _: U)
10+
where T: Sequence,
11+
U: Sequence,
12+
T.Element == G<G<G<G<U.Element>>>>,
13+
U.Element == G<G<G<G<T>>>> {}

test/Generics/rdar90402519.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,4 @@ protocol P1 : P0 where C == G1<I> {
2727

2828
protocol P2 : P1 where C == G2<I> {}
2929
// expected-error@-1 {{cannot build rewrite system for protocol; concrete nesting limit exceeded}}
30-
// expected-note@-2 {{failed rewrite rule is [P2:I].[concrete: G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<[P2:I]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] => [P2:I]}}
30+
// expected-note@-2 {{failed rewrite rule is [P2:I].[concrete: G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<G<[P2:I]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] => [P2:I]}}

test/attr/attr_specialize.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class G<T> {
5353
// expected-note@-1 {{missing constraint for 'T' in '_specialize' attribute}}
5454
@_specialize(where T == S<T>)
5555
// expected-error@-1 {{cannot build rewrite system for generic signature; concrete nesting limit exceeded}}
56-
// expected-note@-2 {{failed rewrite rule is τ_0_0.[concrete: S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<τ_0_0>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] => τ_0_0}}
56+
// expected-note@-2 {{failed rewrite rule is τ_0_0.[concrete: S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<S<τ_0_0>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] => τ_0_0}}
5757
// expected-error@-3 {{too few generic parameters are specified in '_specialize' attribute (got 0, but expected 1)}}
5858
// expected-note@-4 {{missing constraint for 'T' in '_specialize' attribute}}
5959
@_specialize(where T == Int, U == Int) // expected-error{{cannot find type 'U' in scope}}

test/decl/protocol/req/recursion.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ protocol SomeProtocol {
99

1010
extension SomeProtocol where T == Optional<T> { }
1111
// expected-error@-1 {{cannot build rewrite system for generic signature; concrete nesting limit exceeded}}
12-
// expected-note@-2 {{failed rewrite rule is τ_0_0.[SomeProtocol:T].[concrete: Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<τ_0_0.[SomeProtocol:T]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] => τ_0_0.[SomeProtocol:T]}}
12+
// expected-note@-2 {{failed rewrite rule is τ_0_0.[SomeProtocol:T].[concrete: Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<Optional<τ_0_0.[SomeProtocol:T]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] => τ_0_0.[SomeProtocol:T]}}
1313

1414
// rdar://problem/19840527
1515

1616
class X<T> where T == X {
1717
// expected-error@-1 {{cannot build rewrite system for generic signature; concrete nesting limit exceeded}}
18-
// expected-note@-2 {{failed rewrite rule is τ_0_0.[concrete: X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<τ_0_0>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] => τ_0_0}}
18+
// expected-note@-2 {{failed rewrite rule is τ_0_0.[concrete: X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<X<τ_0_0>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] => τ_0_0}}
1919
// expected-error@-3 {{generic class 'X' has self-referential generic requirements}}
2020
var type: T { return Swift.type(of: self) } // expected-error{{cannot convert return expression of type 'X<T>.Type' to return type 'T'}}
2121
}

0 commit comments

Comments
 (0)