Description
Proposal
Problem statement
Using ControlFlow<Self::T>
in a trait where most implementors set T = !
. (or Result<_, Self::T>
) results in a lot of boilerplate for the implementer.
Motivation, use-cases
Visitors with an early return can be modeled as a trait such as the following (used in rustc):
trait Visitor {
type BreakTy = !;
fn visit_foo(&mut self, foo: &Foo) -> ControlFlow<Self::BreakTy> {
walk_foo(self, foo)
}
// And more `visit_*` functions
}
fn walk_foo<V: Visitor>(v: &V, foo: &Foo) -> ControlFlow<V::BreakTy> {
// walk foo using `?` when needed
Continue(())
}
With non-branching implementations looking like (actual implementations can get worse):
impl Visitor for Bar {
fn visit_foo(&mut self, foo: &Foo) -> ControlFlow<!> {
if some_condition() {
// do something
} else if something_else() {
// do something
} else {
walk_foo();
}
Continue(())
}
}
Solution sketches
If Try
and FromResidual<!>
are implemented for ()
, then the previous example would instead be:
trait Visitor {
type ResultTy: Try<Output = ()> = ();
fn visit_foo(&mut self, foo: &Foo) -> Self::ResultTy {
walk_foo(self, foo)
}
// And more `visit_*` functions
}
fn walk_foo<V: Visitor>(v: &V, foo: &Foo) -> V::ResultTy {
// walk foo using `?` when needed
V::ResultTy::from_output(())
}
impl Visitor for Bar {
fn visit_foo(&mut self, foo: &Foo) {
if some_condition() {
// do something
} else if something_else() {
// do something
} else {
walk_foo();
}
}
}
Any impl which requires branching can then set ResultTy
to ControlFlow<T>
(or Result<(), T>
if that makes more sense).
An alternative would be to use a custom ResultTy
trait implemented for both ()
and ControlFlow<T>
(and others if needed). This would allow effectively the same interface, except anything which interacts with generic Visitor
s wouldn't be able to use the ?
operator. This would mainly affect the implementation of walk_*
functions which would otherwise make heavy use of it.
Downsides would be allowing foo()?????
when foo
returns ()
. This is easily solved with a lint any any use of ?
on an expression of the type ()
.
Links and related work
Came up on zulip while discussing using ControlFlow
more.
What happens now?
This issue is part of the libs-api team API change proposal process. Once this issue is filed the libs-api team will review open proposals in its weekly meeting. You should receive feedback within a week or two.