From da0b0ce9abbf5826318a3dfb3707af006e76745d Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 20 Aug 2018 20:57:22 +0100 Subject: [PATCH 1/5] Initial draft of the undisambiguated_expr_generics RFC --- text/0000-undisambiguated-expr-generics.md | 116 +++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 text/0000-undisambiguated-expr-generics.md diff --git a/text/0000-undisambiguated-expr-generics.md b/text/0000-undisambiguated-expr-generics.md new file mode 100644 index 00000000000..3ff4e911494 --- /dev/null +++ b/text/0000-undisambiguated-expr-generics.md @@ -0,0 +1,116 @@ +- Feature Name: `undisambiguated_expr_generics` +- Start Date: 2018-08-20 +- RFC PR: +- Rust Issue: + +# Summary +[summary]: #summary + +Make disambiguating generic arguments in expressions with `::` optional, allowing generic arguments to be specified without `::`. This makes the following valid syntax: + +```rust +struct Nooper(T); + +impl Nooper { + fn noop(&self, _: U) {} +} + +fn id(t: T) -> T { + t +} + +fn main() { + id(0u32); // ok + let n = Nooper<&str>(":)"); // ok + n.noop<()>(()); // ok +} +``` + +# Motivation +[motivation]: #motivation + +The requirement to write `::` before generic arguments in expressions is an unexpected corner case in the language, violating the principle of least surprise. There were historical reasons for its necessity in the past, acting as a disambiguator for other uses of `<` and `>` in expressions. However, the syntax is no longer ambiguous with uses of the comparison operators and it is possible to parse generic arguments in expressions without disambiguation. Making `::` optional in expressions takes a step towards eliminating an oddity in the Rust syntax, making it more uniform and less confusing (e.g. [1](https://users.rust-lang.org/t/why-cant-i-specify-type-parameters-directly-after-the-type/2365), [2](https://users.rust-lang.org/t/type-parameter-syntax-when-defining-vs-calling-functions/15037), [3](https://github.com/rust-lang/book/issues/385), [4](https://www.reddit.com/r/rust/comments/73pm5e/whats_the_rationale_behind_for_type_parameters/), [5](https://matematikaadit.github.io/posts/rust-turbofish.html)) to beginners. + +There have been two historical reasons to require `::` before generic arguments in expressions. + +## Syntax ambiguity +Originally, providing generic arguments without `::` meant that some expressions were ambiguous in meaning. + +```rust +// Take the following: +a < b > ( c ); +// Is this a generic function call..? +a(c); +// Or a chained comparison? +(a < b) > (c); +``` + +However, chained comparisons are now banned in Rust: the previous example results in an error: + +```rust +a < b > ( c ); // error: chained comparison operators require parentheses +``` + +This means that syntax is no longer ambiguous and we can determine whether `<` is a comparison operator or the start of a generic argument list during parsing. + +## Performance +Since the ambiguity resolution, the main concern regarding allowing `::` to be omitted was the potential performance implications. Although by the time we reach the closing angle bracket `>` we know whether we're parsing a comparison or a generic argument list, when we initially encounter `<`, we are not guaranteed to know which case we're parsing. In order to solve this problem, we need to first start parsing a generic argument list and then backtrack if this fails (or use a parser that can deal with ambiguous grammars). We generally prefer to avoid backtracking, as it can be slow. However, up until now the concern with using backtracking for `<` disambiguation was purely theoretical, without any empirical testing to validate it. + +[A recent experiment](https://github.com/rust-lang/rust/pull/53511) to allow generic arguments without `::` disambiguation [showed no performance regressions](https://github.com/rust-lang/rust/pull/53511#issuecomment-414172984) using the backtracking technique. This indicates that in existing codebases, allowing `::` to be omitted is unlikely to lead to any performance regressions. + +Similarly, the performance implications of deleting all occurrences of `::` (and simply using generic arguments directly) [also showed no performance regressions](https://github.com/rust-lang/rust/pull/53511#issuecomment-414360849). This is likely to be due to the relative uncommonness of providing explicit generic arguments and using comparison operators in the cases of ambiguous prefixes, relative to typical codebases. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +To explicitly pass generic arguments to a type, value or method, you may write the lifetime, type and const arguments in angle brackets (`<` and `>`) directly after the expression. + +```rust +struct Nooper(T); + +impl Nooper { + fn noop(&self, _: U) {} +} + +fn id(t: T) -> T { + t +} + +fn main() { + id(0u32); + let n = Nooper<&str>(":)"); + n.noop<()>(()); +} +``` + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +There's an initial implementation in https://github.com/rust-lang/rust/pull/53511, upon which the implementation can be based. The parser will now attempt to parse generic argument lists without `::`, falling back on attempting to parse a comparison if that fails. + +The feature will initially be gated (e.g. `#![feature(undisambiguated_expr_generics)]`). However, note that the parser changes will be present regardless of whether the feature is enabled or not, because feature detection occurs after parsing. However, because it has been shown that there are little-to-no performance regressions when modifying the parser and without taking advantage of `::` optionality, this should not be a problem. + +An allow-by-default lint `disambiguated_expr_generics` will be added to suggest removing `::` when the feature is enabled. Obviously this is undesirable in most existing codebases, as the number of linted expressions is likely to be large, but could be useful for new codebases and in the future. + +Note that, apart from for those users who explicitly increase the level of the lint, no steps are taken to discourage the use of `::` at this stage. + +# Drawbacks +[drawbacks]: #drawbacks + +The primary drawback is the potential for performance regressions due to backtracking. However, empirical evidence ([1](https://github.com/rust-lang/rust/pull/53511#issuecomment-414172984) and [2](https://github.com/rust-lang/rust/pull/53511#issuecomment-414360849)) suggests this should not be a problem. Although it is probable that a pathological example could be constructed that does result in poorer performance, such an example would not be representative of typical Rust code and therefore is not helpful to seriously consider. Backtracking is already used for some cases in the parser. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +If we want to allow `::` to be omitted, there are two solutions: +- Backtracking, as suggested here. +- Using a parser for nondeterministic grammars, such as GLL. + +Although using a more sophisticated parser would come with its own advantages, it's an overly complex solution to this particular problem. Backtracking seems to work well in typical codebases and provides an immediate solution to the problem. + +Alternatively we could continue to require `::`. This would ensure there would be no performance implications, but would leave the nonconformal and surprising syntax in place. + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +None. From e048307c58397b93cdf51fd9f69c5ad6832d192d Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 20 Aug 2018 22:14:48 +0100 Subject: [PATCH 2/5] Make formatting changes --- text/0000-undisambiguated-expr-generics.md | 84 +++++++++++++++++----- 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/text/0000-undisambiguated-expr-generics.md b/text/0000-undisambiguated-expr-generics.md index 3ff4e911494..f76afe392cf 100644 --- a/text/0000-undisambiguated-expr-generics.md +++ b/text/0000-undisambiguated-expr-generics.md @@ -6,7 +6,8 @@ # Summary [summary]: #summary -Make disambiguating generic arguments in expressions with `::` optional, allowing generic arguments to be specified without `::`. This makes the following valid syntax: +Make disambiguating generic arguments in expressions with `::` optional, allowing generic arguments +to be specified without `::`. This makes the following valid syntax: ```rust struct Nooper(T); @@ -29,12 +30,24 @@ fn main() { # Motivation [motivation]: #motivation -The requirement to write `::` before generic arguments in expressions is an unexpected corner case in the language, violating the principle of least surprise. There were historical reasons for its necessity in the past, acting as a disambiguator for other uses of `<` and `>` in expressions. However, the syntax is no longer ambiguous with uses of the comparison operators and it is possible to parse generic arguments in expressions without disambiguation. Making `::` optional in expressions takes a step towards eliminating an oddity in the Rust syntax, making it more uniform and less confusing (e.g. [1](https://users.rust-lang.org/t/why-cant-i-specify-type-parameters-directly-after-the-type/2365), [2](https://users.rust-lang.org/t/type-parameter-syntax-when-defining-vs-calling-functions/15037), [3](https://github.com/rust-lang/book/issues/385), [4](https://www.reddit.com/r/rust/comments/73pm5e/whats_the_rationale_behind_for_type_parameters/), [5](https://matematikaadit.github.io/posts/rust-turbofish.html)) to beginners. +The requirement to write `::` before generic arguments in expressions is an unexpected corner case +in the language, violating the principle of least surprise. There were historical reasons for its +necessity in the past, acting as a disambiguator for other uses of `<` and `>` in expressions. +However, the syntax is no longer ambiguous with uses of the comparison operators and it is possible +to parse generic arguments in expressions without disambiguation. Making `::` optional in +expressions takes a step towards eliminating an oddity in the Rust syntax, making it more uniform +and less confusing (e.g. +[1](https://users.rust-lang.org/t/why-cant-i-specify-type-parameters-directly-after-the-type/2365), +[2](https://users.rust-lang.org/t/type-parameter-syntax-when-defining-vs-calling-functions/15037), +[3](https://github.com/rust-lang/book/issues/385), +[4](https://www.reddit.com/r/rust/comments/73pm5e/whats_the_rationale_behind_for_type_parameters/), +[5](https://matematikaadit.github.io/posts/rust-turbofish.html)) to beginners. There have been two historical reasons to require `::` before generic arguments in expressions. ## Syntax ambiguity -Originally, providing generic arguments without `::` meant that some expressions were ambiguous in meaning. +Originally, providing generic arguments without `::` meant that some expressions were ambiguous in +meaning. ```rust // Take the following: @@ -45,25 +58,42 @@ a(c); (a < b) > (c); ``` -However, chained comparisons are now banned in Rust: the previous example results in an error: +However, chained comparisons are [now banned in Rust](https://github.com/rust-lang/rfcs/pull/558): +the previous example results in an error. ```rust a < b > ( c ); // error: chained comparison operators require parentheses ``` -This means that syntax is no longer ambiguous and we can determine whether `<` is a comparison operator or the start of a generic argument list during parsing. +This means that syntax is no longer ambiguous and we can determine whether `<` is a comparison +operator or the start of a generic argument list during parsing. ## Performance -Since the ambiguity resolution, the main concern regarding allowing `::` to be omitted was the potential performance implications. Although by the time we reach the closing angle bracket `>` we know whether we're parsing a comparison or a generic argument list, when we initially encounter `<`, we are not guaranteed to know which case we're parsing. In order to solve this problem, we need to first start parsing a generic argument list and then backtrack if this fails (or use a parser that can deal with ambiguous grammars). We generally prefer to avoid backtracking, as it can be slow. However, up until now the concern with using backtracking for `<` disambiguation was purely theoretical, without any empirical testing to validate it. - -[A recent experiment](https://github.com/rust-lang/rust/pull/53511) to allow generic arguments without `::` disambiguation [showed no performance regressions](https://github.com/rust-lang/rust/pull/53511#issuecomment-414172984) using the backtracking technique. This indicates that in existing codebases, allowing `::` to be omitted is unlikely to lead to any performance regressions. - -Similarly, the performance implications of deleting all occurrences of `::` (and simply using generic arguments directly) [also showed no performance regressions](https://github.com/rust-lang/rust/pull/53511#issuecomment-414360849). This is likely to be due to the relative uncommonness of providing explicit generic arguments and using comparison operators in the cases of ambiguous prefixes, relative to typical codebases. +Since the ambiguity resolution, the main concern regarding allowing `::` to be omitted was the +potential performance implications. Although by the time we reach the closing angle bracket `>` we +know whether we're parsing a comparison or a generic argument list, when we initially encounter `<`, +we are not guaranteed to know which case we're parsing. To solve this problem, we need to +first start parsing a generic argument list and then backtrack if this fails (or use a parser that +can deal with ambiguous grammars). We generally prefer to avoid backtracking, as it can be slow. +However, up until now the concern with using backtracking for `<` disambiguation was purely +theoretical, without any empirical testing to validate it. + +[A recent experiment](https://github.com/rust-lang/rust/pull/53511) to allow generic arguments +without `::` disambiguation [showed no performance regressions](https://github.com/rust-lang/rust/pull/53511#issuecomment-414172984) +using the backtracking technique. This indicates that in existing codebases, allowing `::` to be +omitted is unlikely to lead to any performance regressions. + +Similarly, the performance implications of deleting all occurrences of `::` (and simply using +generic arguments directly) +[also showed no performance regressions](https://github.com/rust-lang/rust/pull/53511#issuecomment-414360849). +This is likely to be due to the relative uncommonness of providing explicit generic arguments and +using comparison operators in the cases of ambiguous prefixes, relative to typical codebases. # Guide-level explanation [guide-level-explanation]: #guide-level-explanation -To explicitly pass generic arguments to a type, value or method, you may write the lifetime, type and const arguments in angle brackets (`<` and `>`) directly after the expression. +To explicitly pass generic arguments to a type, value or method, you may write the lifetime, type +and const arguments in angle brackets (`<` and `>`) directly after the expression. ```rust struct Nooper(T); @@ -86,18 +116,33 @@ fn main() { # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -There's an initial implementation in https://github.com/rust-lang/rust/pull/53511, upon which the implementation can be based. The parser will now attempt to parse generic argument lists without `::`, falling back on attempting to parse a comparison if that fails. +There's an initial implementation in https://github.com/rust-lang/rust/pull/53511, upon which the +implementation can be based. The parser will now attempt to parse generic argument lists without +`::`, falling back on attempting to parse a comparison if that fails. -The feature will initially be gated (e.g. `#![feature(undisambiguated_expr_generics)]`). However, note that the parser changes will be present regardless of whether the feature is enabled or not, because feature detection occurs after parsing. However, because it has been shown that there are little-to-no performance regressions when modifying the parser and without taking advantage of `::` optionality, this should not be a problem. +The feature will initially be gated (e.g. `#![feature(undisambiguated_expr_generics)]`). However, +note that the parser changes will be present regardless of whether the feature is enabled or not, +because feature detection occurs after parsing. However, because it has been shown that there are +little-to-no performance regressions when modifying the parser and without taking advantage of `::` +optionality, this should not be a problem. -An allow-by-default lint `disambiguated_expr_generics` will be added to suggest removing `::` when the feature is enabled. Obviously this is undesirable in most existing codebases, as the number of linted expressions is likely to be large, but could be useful for new codebases and in the future. +An allow-by-default lint `disambiguated_expr_generics` will be added to suggest removing `::` when +the feature is enabled. This is undesirable in most existing codebases, as the number of +linted expressions is likely to be large, but could be useful for new codebases and in the future. -Note that, apart from for those users who explicitly increase the level of the lint, no steps are taken to discourage the use of `::` at this stage. +Note that, apart from for those users who explicitly increase the level of the lint, no steps are +taken to discourage the use of `::` at this stage. # Drawbacks [drawbacks]: #drawbacks -The primary drawback is the potential for performance regressions due to backtracking. However, empirical evidence ([1](https://github.com/rust-lang/rust/pull/53511#issuecomment-414172984) and [2](https://github.com/rust-lang/rust/pull/53511#issuecomment-414360849)) suggests this should not be a problem. Although it is probable that a pathological example could be constructed that does result in poorer performance, such an example would not be representative of typical Rust code and therefore is not helpful to seriously consider. Backtracking is already used for some cases in the parser. +The primary drawback is the potential for performance regressions due to backtracking. However, +empirical evidence ([1](https://github.com/rust-lang/rust/pull/53511#issuecomment-414172984) and +[2](https://github.com/rust-lang/rust/pull/53511#issuecomment-414360849)) suggests this should not +be a problem. Although it is probable that a pathological example could be constructed that does +result in poorer performance, such an example would not be representative of typical Rust code and +therefore is not helpful to seriously consider. Backtracking is already used for some cases in the +parser. # Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives @@ -106,9 +151,12 @@ If we want to allow `::` to be omitted, there are two solutions: - Backtracking, as suggested here. - Using a parser for nondeterministic grammars, such as GLL. -Although using a more sophisticated parser would come with its own advantages, it's an overly complex solution to this particular problem. Backtracking seems to work well in typical codebases and provides an immediate solution to the problem. +Although using a more sophisticated parser would come with its own advantages, it's an overly +complex solution to this particular problem. Backtracking seems to work well in typical codebases +and provides an immediate solution to the problem. -Alternatively we could continue to require `::`. This would ensure there would be no performance implications, but would leave the nonconformal and surprising syntax in place. +Alternatively we could continue to require `::`. This would ensure there would be no performance +implications, but would leave the nonconformal and surprising syntax in place. # Unresolved questions [unresolved-questions]: #unresolved-questions From a936bd9a362c26ddc8036ac090968cd19811ca91 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 20 Aug 2018 22:30:00 +0100 Subject: [PATCH 3/5] Add some advantages and drawbacks Also: mention the turbofish. --- text/0000-undisambiguated-expr-generics.md | 25 +++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/text/0000-undisambiguated-expr-generics.md b/text/0000-undisambiguated-expr-generics.md index f76afe392cf..7c995739133 100644 --- a/text/0000-undisambiguated-expr-generics.md +++ b/text/0000-undisambiguated-expr-generics.md @@ -7,7 +7,8 @@ [summary]: #summary Make disambiguating generic arguments in expressions with `::` optional, allowing generic arguments -to be specified without `::`. This makes the following valid syntax: +to be specified without `::`, making the "turbofish" notation no longer necessary. +This makes the following valid syntax: ```rust struct Nooper(T); @@ -93,7 +94,7 @@ using comparison operators in the cases of ambiguous prefixes, relative to typic [guide-level-explanation]: #guide-level-explanation To explicitly pass generic arguments to a type, value or method, you may write the lifetime, type -and const arguments in angle brackets (`<` and `>`) directly after the expression. +and const arguments in angle brackets (`<` and `>`) directly after the expression. (Note that the "turbofish" notation is no longer necessary.) ```rust struct Nooper(T); @@ -126,12 +127,18 @@ because feature detection occurs after parsing. However, because it has been sho little-to-no performance regressions when modifying the parser and without taking advantage of `::` optionality, this should not be a problem. +When `undisambiguated_expr_generics` is not enabled, the parser modifications will allow us to +provide better diagnostics: specifically, we'll be able to correctly suggest (in a machine- +applicable manner) using `::` whenever the user has actually typed undisambiguated generic +arguments. The current diagnostic suggestions suggesting the use of `::` trigger whenever there are +chained comparisons, which has false positives and does not provide a fix suggestion. + An allow-by-default lint `disambiguated_expr_generics` will be added to suggest removing `::` when the feature is enabled. This is undesirable in most existing codebases, as the number of linted expressions is likely to be large, but could be useful for new codebases and in the future. Note that, apart from for those users who explicitly increase the level of the lint, no steps are -taken to discourage the use of `::` at this stage. +taken to discourage the use of `::` at this stage (including in tools, such as rustfmt). # Drawbacks [drawbacks]: #drawbacks @@ -144,6 +151,18 @@ result in poorer performance, such an example would not be representative of typ therefore is not helpful to seriously consider. Backtracking is already used for some cases in the parser. +The other potential drawback is that other parsers for Rust's syntax would also have to implement +some form of backtracking (or similar) to handle this case. However, backtracking is straightforward +to implement in many forms (such as recursive decent) of parser and it is likely this will not cause +significant problems. + +Although it has been suggested that using backtracking would mean Rust's grammar was no longer +LL(k), requiring potentially infinite lookahead, backtracking is already present for some (uncommon) +cases in the Rust parser (notably one situation involving disambiguating between comparions and +generic parameters). Although erring towards less backtracking is desirably, the performance +results suggest that the practical benefits outweigh the theoretical drawbacks in this +regard. + # Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives From af12181548561275386df55b8dbaf509ec46ffc6 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 20 Aug 2018 23:41:03 +0100 Subject: [PATCH 4/5] Add comment about backtracking without making `::` optional --- text/0000-undisambiguated-expr-generics.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/text/0000-undisambiguated-expr-generics.md b/text/0000-undisambiguated-expr-generics.md index 7c995739133..813ed3c9a22 100644 --- a/text/0000-undisambiguated-expr-generics.md +++ b/text/0000-undisambiguated-expr-generics.md @@ -175,7 +175,8 @@ complex solution to this particular problem. Backtracking seems to work well in and provides an immediate solution to the problem. Alternatively we could continue to require `::`. This would ensure there would be no performance -implications, but would leave the nonconformal and surprising syntax in place. +implications, but would leave the nonconformal and surprising syntax in place. We could potentially use backtracking to provide the improved diagnostic suggestions to use `::`, while still preventing +`::` from being omitted. # Unresolved questions [unresolved-questions]: #unresolved-questions From 2b5961a2d060caca55aa0178e9ece850edafbc71 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 21 Aug 2018 10:56:55 +0100 Subject: [PATCH 5/5] Make some tweaks --- text/0000-undisambiguated-expr-generics.md | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/text/0000-undisambiguated-expr-generics.md b/text/0000-undisambiguated-expr-generics.md index 813ed3c9a22..72244f88a9c 100644 --- a/text/0000-undisambiguated-expr-generics.md +++ b/text/0000-undisambiguated-expr-generics.md @@ -1,5 +1,5 @@ - Feature Name: `undisambiguated_expr_generics` -- Start Date: 2018-08-20 +- Start Date: 2018-08-21 - RFC PR: - Rust Issue: @@ -7,7 +7,7 @@ [summary]: #summary Make disambiguating generic arguments in expressions with `::` optional, allowing generic arguments -to be specified without `::`, making the "turbofish" notation no longer necessary. +to be specified without `::` (making the "turbofish" notation no longer necessary). This makes the following valid syntax: ```rust @@ -76,11 +76,11 @@ know whether we're parsing a comparison or a generic argument list, when we init we are not guaranteed to know which case we're parsing. To solve this problem, we need to first start parsing a generic argument list and then backtrack if this fails (or use a parser that can deal with ambiguous grammars). We generally prefer to avoid backtracking, as it can be slow. -However, up until now the concern with using backtracking for `<` disambiguation was purely +However, up until now, the concern with using backtracking for `<`-disambiguation was purely theoretical, without any empirical testing to validate it. [A recent experiment](https://github.com/rust-lang/rust/pull/53511) to allow generic arguments -without `::` disambiguation [showed no performance regressions](https://github.com/rust-lang/rust/pull/53511#issuecomment-414172984) +without `::`-disambiguation [showed no performance regressions](https://github.com/rust-lang/rust/pull/53511#issuecomment-414172984) using the backtracking technique. This indicates that in existing codebases, allowing `::` to be omitted is unlikely to lead to any performance regressions. @@ -117,8 +117,8 @@ fn main() { # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -There's an initial implementation in https://github.com/rust-lang/rust/pull/53511, upon which the -implementation can be based. The parser will now attempt to parse generic argument lists without +An initial implementation is present in https://github.com/rust-lang/rust/pull/53511, upon which the +implementation may be based. The parser will now attempt to parse generic argument lists without `::`, falling back on attempting to parse a comparison if that fails. The feature will initially be gated (e.g. `#![feature(undisambiguated_expr_generics)]`). However, @@ -128,8 +128,8 @@ little-to-no performance regressions when modifying the parser and without takin optionality, this should not be a problem. When `undisambiguated_expr_generics` is not enabled, the parser modifications will allow us to -provide better diagnostics: specifically, we'll be able to correctly suggest (in a machine- -applicable manner) using `::` whenever the user has actually typed undisambiguated generic +provide better diagnostics: specifically, we'll be able to correctly suggest (in a +machine-applicable manner) using `::` whenever the user has actually typed undisambiguated generic arguments. The current diagnostic suggestions suggesting the use of `::` trigger whenever there are chained comparisons, which has false positives and does not provide a fix suggestion. @@ -151,15 +151,15 @@ result in poorer performance, such an example would not be representative of typ therefore is not helpful to seriously consider. Backtracking is already used for some cases in the parser. -The other potential drawback is that other parsers for Rust's syntax would also have to implement -some form of backtracking (or similar) to handle this case. However, backtracking is straightforward -to implement in many forms (such as recursive decent) of parser and it is likely this will not cause -significant problems. +The other potential drawback is that other parsers for Rust's syntax (for example in external tools) +would also have to implement some form of backtracking (or similar) to handle this case. However, +backtracking is straightforward to implement in many forms of parser (such as recursive decent) and +it is likely this will not cause significant problems. Although it has been suggested that using backtracking would mean Rust's grammar was no longer LL(k), requiring potentially infinite lookahead, backtracking is already present for some (uncommon) cases in the Rust parser (notably one situation involving disambiguating between comparions and -generic parameters). Although erring towards less backtracking is desirably, the performance +generic parameters). Although erring towards less backtracking is desirable, the performance results suggest that the practical benefits outweigh the theoretical drawbacks in this regard.