Skip to content

Commit 6c8b549

Browse files
committed
More conservative impl of Replacer for closures
This is an alternative flavor of PR rust-lang#1048: Require `Replacer` closures to take a `&'a Captures<'b>` (for all `'a, 'b: 'a`) as argument and have a return type that must not depend on `'b` (but only on `'a`).
1 parent 664a0f2 commit 6c8b549

File tree

2 files changed

+17
-20
lines changed

2 files changed

+17
-20
lines changed

src/regex/string.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -2376,16 +2376,21 @@ mod replacer_closure {
23762376
use super::*;
23772377
/// If a closure implements this for all `'a`, then it also implements
23782378
/// [`Replacer`].
2379+
// TODO: Use two lifetimes `'a` and `'b`: one for the reference and one for
2380+
// the lifetime argument `'b` of `Captures<'b>`. This requires a syntax
2381+
// like `for<'a, 'b: 'a> ReplacerClosure<'a, 'b> when using this trait,
2382+
// which currently doesn't exist.
2383+
// See also: https://github.com/rust-lang/rfcs/pull/3261
23792384
pub trait ReplacerClosure<'a>
23802385
where
2381-
Self: FnMut(&'a Captures<'a>) -> <Self as ReplacerClosure<'a>>::Output,
2386+
Self: FnMut(&'a Captures<'_>) -> <Self as ReplacerClosure<'a>>::Output,
23822387
{
23832388
/// Return type of the closure (may depend on lifetime `'a`).
23842389
type Output: AsRef<str>;
23852390
}
23862391
impl<'a, F: ?Sized, O> ReplacerClosure<'a> for F
23872392
where
2388-
F: FnMut(&'a Captures<'a>) -> O,
2393+
F: FnMut(&'a Captures<'_>) -> O,
23892394
O: AsRef<str>,
23902395
{
23912396
type Output = O;
@@ -2430,7 +2435,8 @@ use replacer_closure::*;
24302435
///
24312436
/// Closures that take an argument of type `&'a Captures<'b>` for any `'a` and
24322437
/// `'b: 'a` and which return a type `T: AsRef<str>` (that may depend on `'a`
2433-
/// or `'b`) implement the `Replacer` trait through a [blanket implementation].
2438+
/// but not on `'b`) implement the `Replacer` trait through a [blanket
2439+
/// implementation].
24342440
///
24352441
/// [blanket implementation]: Self#impl-Replacer-for-F
24362442
///
@@ -2580,7 +2586,7 @@ impl<'a> Replacer for &'a Cow<'a, str> {
25802586
/// ```ignore
25812587
/// impl<F, T> Replacer for F
25822588
/// where
2583-
/// F: for<'a> FnMut(&'a Captures<'a>) -> T,
2589+
/// F: for<'a, 'b> FnMut(&'a Captures<'b>) -> T,
25842590
/// T: AsRef<str>, // `T` may also depend on `'a`, which cannot be expressed easily
25852591
/// {
25862592
/// /* … */

tests/misc.rs

+7-16
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,12 @@ mod replacer_closure_lifetimes {
159159
.replace_all("x", coerce(|caps| Cow::Borrowed(&caps[0])));
160160
assert_eq!(s, "x");
161161
}
162+
// The following test is commented out yet because currently `Replacer` is
163+
// not implemented for closures whose return type depends on the lifetime
164+
// parameter `'b` of the `Captures<'b>` type.
165+
// TODO: Fix this when/if the hidden `ReplacerClosure` helper trait gets
166+
// two lifetime parameters.
167+
/*
162168
#[test]
163169
fn parameter_lifetime() {
164170
fn coerce<F: for<'b> FnMut(&Captures<'b>) -> Cow<'b, str>>(f: F) -> F {
@@ -170,20 +176,5 @@ mod replacer_closure_lifetimes {
170176
);
171177
assert_eq!(s, "x");
172178
}
173-
// Additionally demand that its sufficient if the closure accepts a single
174-
// lifetime `'u` which is used both for the reference to and the lifetime
175-
// argument of the `Captures` argument. Note that `Captures<'u>` is
176-
// covariant over `'u`.
177-
#[test]
178-
fn unified_lifetime() {
179-
fn coerce<F: for<'u> FnMut(&'u Captures<'u>) -> Cow<'u, str>>(
180-
f: F,
181-
) -> F {
182-
f
183-
}
184-
let s = Regex::new("x")
185-
.unwrap()
186-
.replace_all("x", coerce(|caps| Cow::Borrowed(&caps[0])));
187-
assert_eq!(s, "x");
188-
}
179+
*/
189180
}

0 commit comments

Comments
 (0)