This repository was archived by the owner on Jan 11, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 12
This repository was archived by the owner on Jan 11, 2026. It is now read-only.
Incorrect type is generated when using generics #27
Copy link
Copy link
Open
Description
Using generics in any of the states causes the automaton's type to be stripped away. Take the following example:
use typestate::typestate;
#[typestate]
mod my_state {
#[automaton]
pub struct Automaton;
#[state]
pub struct State1<T>(T);
pub trait State1 {
fn new<T>() -> State1<T>
where
T: Default;
fn to_state_2(self) -> State2;
}
impl<T> State1State for Automaton<State1<T>> {
fn new<U>() -> State1<U>
where
U: Default,
{
State1(U::default())
}
fn to_state_2(self) -> Automaton<State2> {
Automaton { state: State2 }
}
}
#[state]
pub struct State2;
pub trait State2 {
fn done(self);
}
impl State2State for Automaton<State2> {
fn done(self) {}
}
}
fn t() {
use my_state::*;
let s1: State1<()> = Automaton::<State1<()>>::new();
}
fn main() {}cargo expand output:
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2018::*;
#[macro_use]
extern crate std;
use typestate::typestate;
///```mermaid
///stateDiagram-v2
///[*] --> State1 : new
///State1 --> State2 : to_state_2
///State2 --> [*] : done
///```
mod my_state {
pub struct Automaton<State: AutomatonState> {
pub state: State,
}
pub struct State1<T>(T);
pub trait State1State {
fn new<T>() -> State1<T>
where
T: Default;
#[must_use]
fn to_state_2(self) -> Automaton<State2>;
}
impl<T> State1State for Automaton<State1<T>> {
fn new<U>() -> State1<U>
where
U: Default,
{
State1(U::default())
}
fn to_state_2(self) -> Automaton<State2> {
Automaton { state: State2 }
}
}
pub struct State2;
pub trait State2State {
fn done(self);
}
impl State2State for Automaton<State2> {
fn done(self) {}
}
#[doc(hidden)]
mod __private {
pub trait AutomatonState {}
}
pub trait AutomatonState: __private::AutomatonState {}
impl<__T: ?::core::marker::Sized> AutomatonState for __T where __T: __private::AutomatonState {}
impl<T> __private::AutomatonState for State1<T> {}
impl __private::AutomatonState for State2 {}
}
fn t() {
use my_state::*;
let s1: State1<()> = Automaton::<State1<()>>::new();
}
fn main() {}We see that Automaton::<State1<()>>::new() yields us a type State1<()> instead of the correct type Automaton<State1<()>>. If we remove the generic parameters to State1, all is well again.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels