there should be a way for a trait to opt-in to non-specializable overlapping impls and require explicit impl selection at use. additionally, a set of "preferred" impls can be provided, so that a currently non-overlapping trait can bemade overlapping. this would be especially useful for Pattern, to make it accept Fn(&char) in addition to Fn(char).
for example, you could have an overlapping trait:
overlapping trait Pattern<'a> {
...
}
and then preferred impls (which act just like existing impls):
// syntax chosen to allow transforming a trait into an overlapping trait backwards-compatibly
// aka we just use existing syntax for non-overlapping impls
impl<'a, 'b> Pattern<'a> for &'b str {
...
}
...
and then the new overlapping impls:
// these don't participate in normal impl resolution
overlapping impl<'a, F> Pattern<'a> for F where F: FnMut(&char) -> bool {
...
}
when using a function, unless impl selection syntax is used, only the preferred impls are visible. (this can be broadened later, but it would introduce backwards-compatibility caveats similar to the IntoIterator/Deref interaction we had with arrays.) in other words:
// these all check the preferred impls
"foo".find("bar");
"foo".find('a');
"foo".find(['a', 'b']);
// this also checks the preferred impls, so it infers FnMut(char) -> bool
"foo".find(|c| c == 'a');
that is to say all existing code would remain working.
additionally, you'd be able to write this:
"foo".find<_: (impl<'a, F> Pattern<'a> for F where F: FnMut(&char) -> bool)>(char::is_ascii_lowercase);
which is very verbose, but makes a good starting point. (as we said, this can be broadened later, but it would introduce backwards-compatibility caveats similar to the IntoIterator/Deref interaction we had with arrays.)