From: Olli Saarikivi Date: Tue, 26 Jul 2022 23:31:20 +0000 (-0700) Subject: Add missing case in PruneLowerPriorityThanNullability (#72871) X-Git-Tag: accepted/tizen/unified/riscv/20231226.055536~7530 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f652b24f845f772ac01c6fb9132883b28fdfa39c;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Add missing case in PruneLowerPriorityThanNullability (#72871) * Add missing case in pruning * Enable previously failing Rust test --- diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexNode.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexNode.cs index ad55cc5..8460923 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexNode.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Symbolic/SymbolicRegexNode.cs @@ -1072,9 +1072,8 @@ namespace System.Text.RegularExpressions.Symbolic } else { - // If this node is nullable for the given context then prune any branches that are less preferred than - // just the empty match. This is done in order to maintain backtracking semantics. - SymbolicRegexNode node = IsNullableFor(context) ? PruneLowerPriorityThanNullability(builder, context) : this; + // To maintain backtracking semantics, prune any branches that are less preferred than just the empty match + SymbolicRegexNode node = PruneLowerPriorityThanNullability(builder, context); return node.CreateDerivative(builder, elem, context); } } @@ -1082,7 +1081,10 @@ namespace System.Text.RegularExpressions.Symbolic /// Prune this node wrt the given context in order to maintain backtracking semantics. Mimics how backtracking chooses a path. private SymbolicRegexNode PruneLowerPriorityThanNullability(SymbolicRegexBuilder builder, uint context) { - //caching pruning to avoid otherwise potential quadratic worst case behavior + if (!IsNullableFor(context)) + return this; + + // Cache result to avoid otherwise potential quadratic worst case behavior SymbolicRegexNode? prunedNode; (SymbolicRegexNode, uint) key = (this, context); if (builder._pruneLowerPriorityThanNullabilityCache.TryGetValue(key, out prunedNode)) @@ -1125,19 +1127,21 @@ namespace System.Text.RegularExpressions.Symbolic CreateConcat(builder, _left.PruneLowerPriorityThanNullability(builder, context), _right.PruneLowerPriorityThanNullability(builder, context)); break; - case SymbolicRegexNodeKind.Loop when _info.IsLazyLoop && _lower == 0: - //lazy nullable loop reduces to (), i.e., the loop body is just forgotten - prunedNode = builder.Epsilon; + case SymbolicRegexNodeKind.Loop: + Debug.Assert(_left is not null); + // Lazy nullable loop reduces to (), i.e., the loop body is just forgotten + prunedNode = _info.IsLazyLoop && _lower == 0 ? builder.Epsilon : + CreateLoop(builder, _left.PruneLowerPriorityThanNullability(builder, context), _lower, _upper, _info.IsLazyLoop); break; case SymbolicRegexNodeKind.Effect: - //Effects are maintained and the pruning is propagated to the body of the effect + // Effects are maintained and the pruning is propagated to the body of the effect Debug.Assert(_left is not null && _right is not null); prunedNode = CreateEffect(builder, _left.PruneLowerPriorityThanNullability(builder, context), _right); break; default: - //In all other remaining cases no pruning takes place + // In all other remaining cases no pruning takes place prunedNode = this; break; } diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexRustTests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexRustTests.cs index 45b7f54..102e1e9 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexRustTests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexRustTests.cs @@ -61,11 +61,8 @@ namespace System.Text.RegularExpressions.Tests yield return new object[] { engine, @"(?m)$[a-z]", "abc\ndef\nxyz", new ValueTuple[] { } }; yield return new object[] { engine, @"(?m)^$", "", new[] { (0, 0) } }; yield return new object[] { engine, @"(?m)(?:^$)*", "a\nb\nc", new[] { (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5) } }; - if (!RegexHelpers.IsNonBacktracking(engine)) // https://github.com/dotnet/runtime/issues/72470 - { - yield return new object[] { engine, @"(?m)(?:^|a)+", "a\naaa\n", new[] { (0, 0), (2, 2), (3, 5), (6, 6) } }; - yield return new object[] { engine, @"(?m)(?:^|a)*", "a\naaa\n", new[] { (0, 0), (1, 1), (2, 2), (3, 5), (5, 5), (6, 6) } }; - } + yield return new object[] { engine, @"(?m)(?:^|a)+", "a\naaa\n", new[] { (0, 0), (2, 2), (3, 5), (6, 6) } }; + yield return new object[] { engine, @"(?m)(?:^|a)*", "a\naaa\n", new[] { (0, 0), (1, 1), (2, 2), (3, 5), (5, 5), (6, 6) } }; yield return new object[] { engine, @"(?m)(?:^[a-z])+", "abc\ndef\nxyz", new[] { (0, 1), (4, 5), (8, 9) } }; yield return new object[] { engine, @"(?m)(?:^[a-z]{3}\n?)+", "abc\ndef\nxyz", new[] { (0, 11) } }; yield return new object[] { engine, @"(?m)(?:^[a-z]{3}\n?)*", "abc\ndef\nxyz", new[] { (0, 11), (11, 11) } };