diff --git a/lib/AST/RequirementMachine/KnuthBendix.cpp b/lib/AST/RequirementMachine/KnuthBendix.cpp index 1081218e468bc..884bb480eb52e 100644 --- a/lib/AST/RequirementMachine/KnuthBendix.cpp +++ b/lib/AST/RequirementMachine/KnuthBendix.cpp @@ -398,7 +398,7 @@ RewriteSystem::computeConfluentCompletion(unsigned maxRuleCount, continue; // Check if the new rule is too long. - if (Rules.back().getDepth() > maxRuleLength) + if (Rules.back().getDepth() > maxRuleLength + getLongestInitialRule()) return std::make_pair(CompletionResult::MaxRuleLength, Rules.size() - 1); } diff --git a/lib/AST/RequirementMachine/RequirementMachine.cpp b/lib/AST/RequirementMachine/RequirementMachine.cpp index ca75428d9054f..c6a8c3e0a12f7 100644 --- a/lib/AST/RequirementMachine/RequirementMachine.cpp +++ b/lib/AST/RequirementMachine/RequirementMachine.cpp @@ -301,7 +301,7 @@ RequirementMachine::computeCompletion(RewriteSystem::ValidityPolicy policy) { // Check new rules added by the property map against configured limits. for (unsigned i = 0; i < rulesAdded; ++i) { const auto &newRule = System.getRule(ruleCount + i); - if (newRule.getDepth() > MaxRuleLength) { + if (newRule.getDepth() > MaxRuleLength + System.getLongestInitialRule()) { return std::make_pair(CompletionResult::MaxRuleLength, ruleCount + i); } diff --git a/lib/AST/RequirementMachine/RewriteSystem.cpp b/lib/AST/RequirementMachine/RewriteSystem.cpp index 905462f33080c..de864cb592c69 100644 --- a/lib/AST/RequirementMachine/RewriteSystem.cpp +++ b/lib/AST/RequirementMachine/RewriteSystem.cpp @@ -30,6 +30,7 @@ RewriteSystem::RewriteSystem(RewriteContext &ctx) Complete = 0; Minimized = 0; RecordLoops = 0; + LongestInitialRule = 0; } RewriteSystem::~RewriteSystem() { @@ -85,6 +86,10 @@ void RewriteSystem::initialize( addRules(std::move(importedRules), std::move(permanentRules), std::move(requirementRules)); + + for (const auto &rule : getLocalRules()) { + LongestInitialRule = std::max(LongestInitialRule, rule.getDepth()); + } } /// Reduce a term by applying all rewrite rules until fixed point. diff --git a/lib/AST/RequirementMachine/RewriteSystem.h b/lib/AST/RequirementMachine/RewriteSystem.h index 21feb77e6d3b1..3b7a3f47960f7 100644 --- a/lib/AST/RequirementMachine/RewriteSystem.h +++ b/lib/AST/RequirementMachine/RewriteSystem.h @@ -106,6 +106,10 @@ class RewriteSystem final { /// identities among rewrite rules discovered while resolving critical pairs. unsigned RecordLoops : 1; + /// The length of the longest initial rule, used for the MaxRuleLength + /// completion non-termination heuristic. + unsigned LongestInitialRule : 16; + public: explicit RewriteSystem(RewriteContext &ctx); ~RewriteSystem(); @@ -131,6 +135,10 @@ class RewriteSystem final { std::vector> &&permanentRules, std::vector>> &&requirementRules); + unsigned getLongestInitialRule() const { + return LongestInitialRule; + } + ArrayRef getProtocols() const { return Protos; } diff --git a/test/Generics/non_confluent.swift b/test/Generics/non_confluent.swift index fd20105fb0f3f..0c3b72168ed89 100644 --- a/test/Generics/non_confluent.swift +++ b/test/Generics/non_confluent.swift @@ -1,14 +1,14 @@ // RUN: %target-typecheck-verify-swift -requirement-machine-protocol-signatures=on -requirement-machine-inferred-signatures=on protocol ABA // expected-error {{cannot build rewrite system for protocol; rule length limit exceeded}} -// 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]}} +// 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]}} where A.B == A.B.A { // expected-error *{{is not a member type}} associatedtype A : ABA associatedtype B : ABA } protocol Undecidable // expected-error {{cannot build rewrite system for protocol; rule length limit exceeded}} -// 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]}} +// 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]}} where A.C == C.A, // expected-error *{{is not a member type}} A.D == D.A, // expected-error *{{is not a member type}} B.C == C.B, // expected-error *{{is not a member type}} @@ -33,11 +33,11 @@ protocol P2 { func foo(_: T) {} // expected-error@-1 {{cannot build rewrite system for generic signature; rule length limit exceeded}} -// 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]}} +// 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]}} extension P1 where Self : P2 {} // expected-error@-1 {{cannot build rewrite system for generic signature; rule length limit exceeded}} -// 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]}} +// 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]}} struct S : P1 { typealias T = S> @@ -45,7 +45,7 @@ struct S : P1 { protocol P3 { // expected-error@-1 {{cannot build rewrite system for protocol; rule length limit exceeded}} -// 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>>>>>>>>>>>] => [P3:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T].[P1:T]}} +// 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>>>>>>>>>>>>>] => [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]}} associatedtype T : P1 where T == S // expected-error@-1 {{type 'Self.U' does not conform to protocol 'P1'}} diff --git a/test/Generics/opaque_archetype_concrete_requirement_recursive_rejected.swift b/test/Generics/opaque_archetype_concrete_requirement_recursive_rejected.swift index e002c24bbb4ac..0fffcf36677a0 100644 --- a/test/Generics/opaque_archetype_concrete_requirement_recursive_rejected.swift +++ b/test/Generics/opaque_archetype_concrete_requirement_recursive_rejected.swift @@ -31,5 +31,5 @@ protocol HasRecursiveP { extension HasRecursiveP where T == DefinesRecursiveP.T {} // expected-error@-1 {{cannot build rewrite system for generic signature; rule length limit exceeded}} -// 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]}} +// 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]}} diff --git a/test/Generics/sr16024.swift b/test/Generics/sr16024.swift new file mode 100644 index 0000000000000..06b9bdba5918a --- /dev/null +++ b/test/Generics/sr16024.swift @@ -0,0 +1,7 @@ +// RUN: %target-swift-frontend -typecheck %s -requirement-machine-protocol-signatures=on + +// The rule length limit (12 by default) is relative to the longest initial rule. + +protocol P { + 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 +} diff --git a/validation-test/compiler_crashers_2_fixed/sr9584.swift b/validation-test/compiler_crashers_2_fixed/sr9584.swift index 2f78bda682e8b..df602b73f501f 100644 --- a/validation-test/compiler_crashers_2_fixed/sr9584.swift +++ b/validation-test/compiler_crashers_2_fixed/sr9584.swift @@ -10,7 +10,7 @@ protocol P { extension S: P where N: P { static func f(_ x: X) -> S where A == X, X.A == N { // expected-error@-1 {{cannot build rewrite system for generic signature; rule length limit exceeded}} - // 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>>>>>>>>>>>] => τ_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↓]}} + // 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>>>>>>>>>>>>>] => τ_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↓]}} // expected-error@-3 {{'A' is not a member type of type 'X'}} // expected-error@-4 {{'A' is not a member type of type 'X'}} return S()