framesurge / perseus

A state-driven web development framework for Rust with full support for server-side rendering and static generation.
https://framesurge.sh/perseus/en-US
MIT License
2.15k stars 89 forks source link

Build state function with non-`Clone` state results in suboptimal compiler error #263

Open marienz opened 1 year ago

marienz commented 1 year ago

(Filing manually because the compiler error is too long for Tribble, see https://github.com/arctic-hen7/tribble/issues/4)

I'm not sure how fixable this is, but I spent longer than I'd prefer to admit banging my head against the compiler error resulting from (simplified):

// Whoops: this should be Clone...
#[derive(Serialize, Deserialize, UnreactiveState)]
struct IndexState {}

// The error type is a placeholder for example purposes. Pretend this is a more interesting error type than `std::io::Error`
#[engine_only_fn]
async fn get_build_state(
    _info: StateGeneratorInfo<()>,
) -> Result<IndexState, BlamedError<std::io::Error>> {
    Ok(IndexState {})
}

pub fn get_template<G: Html>() -> Template<G> {
    Template::build("index")
        .build_state_fn(get_build_state)
        // This should be view_with_unreactive_state, but I was trying to get the previous bit to
        // compile so I hadn't changed this yet.
        .view(index_page)
        .head(head)
        .build()
}

This fails to compile with:

error[E0277]: the trait bound `BlamedGeneratorResult<_>: From<Result<IndexState, perseus::errors::BlamedError<std::io::Error>>>` is not satisfied
   --> src/templates/index.rs:43:25
    |
43  |         .build_state_fn(get_build_state)
    |          -------------- ^^^^^^^^^^^^^^^ the trait `From<Result<IndexState, perseus::errors::BlamedError<std::io::Error>>>` is not implemented for `BlamedG
eneratorResult<_>`
    |          |
    |          required by a bound introduced by this call
    |
    = help: the following other types implement trait `From<T>`:
              <BlamedGeneratorResult<S> as From<Result<S, perseus::errors::BlamedError<E>>>>
              <BlamedGeneratorResult<S> as From<S>>
              <BlamedGeneratorResult<bool> as From<Result<bool, perseus::errors::BlamedError<E>>>>
              <BlamedGeneratorResult<bool> as From<bool>>
    = note: required for `Result<IndexState, perseus::errors::BlamedError<std::io::Error>>` to implement `Into<BlamedGeneratorResult<_>>`
    = note: required for `fn(perseus::state::StateGeneratorInfo<()>) -> impl Future<Output = Result<IndexState, ...>> {get_build_state}` to implement `GetBuildS
tateUserFnType<_, (), Result<IndexState, perseus::errors::BlamedError<std::io::Error>>>`
    = note: the full type name has been written to '/var/tmp/noclone/dist/target_engine/debug/deps/noclone-64af1131e0177d5b.long-type-2534625397002286986.txt'
note: required by a bound in `perseus::template::core::setters::<impl TemplateInner<G>>::build_state_fn`
   --> /home/marienz/.cargo/registry/src/github.com-1ecc6299db9ec823/perseus-0.4.0-beta.19/src/template/core/setters.rs:119:19
    |
119 |         val: impl GetBuildStateUserFnType<S, B, V> + Clone + Send + Sync + 'static,
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `perseus::template::core::setters::<impl TemplateInner<G>>::build_state_fn`

error[E0277]: the trait bound `BlamedGeneratorResult<_>: From<Result<IndexState, perseus::errors::BlamedError<std::io::Error>>>` is not satisfied
   --> src/templates/index.rs:43:10
    |
43  |         .build_state_fn(get_build_state)
    |          ^^^^^^^^^^^^^^ the trait `From<Result<IndexState, perseus::errors::BlamedError<std::io::Error>>>` is not implemented for `BlamedGeneratorResult<_
>`
    |
    = help: the following other types implement trait `From<T>`:
              <BlamedGeneratorResult<S> as From<Result<S, perseus::errors::BlamedError<E>>>>
              <BlamedGeneratorResult<S> as From<S>>
              <BlamedGeneratorResult<bool> as From<Result<bool, perseus::errors::BlamedError<E>>>>
              <BlamedGeneratorResult<bool> as From<bool>>
    = note: required for `Result<IndexState, perseus::errors::BlamedError<std::io::Error>>` to implement `Into<BlamedGeneratorResult<_>>`
note: required by a bound in `perseus::template::core::setters::<impl TemplateInner<G>>::build_state_fn`
   --> /home/marienz/.cargo/registry/src/github.com-1ecc6299db9ec823/perseus-0.4.0-beta.19/src/template/core/setters.rs:124:12
    |
124 |         V: Into<BlamedGeneratorResult<S>>,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `perseus::template::core::setters::<impl TemplateInner<G>>::build_state_fn`

The error message does not mention any constraints on S, so I incorrectly assumed the problem was with the conversion from my error type to BlamedError.

In Perseus's defense it does document that build state should be Clone, and once you switch from view() to view_with_unreactive_state() you get a better error message. But I was changing my mind between global state (documented as not needing to be Clone) and build state, and hadn't gotten as far as changing my view function before running into this.

github-actions[bot] commented 1 year ago

This repo is set up to triage issues with Tribble, but this issue couldn't be processed. If you deliberately didn't use Tribble to report this issue, you can safely ignore this warning. If you did, something's gone wrong here.

arctic-hen7 commented 1 year ago

Not sure how this could be made into a nicer error at the compiler level, but the CLI could certainly do some parsing and provide suggestions.

arctic-hen7 commented 1 year ago

CLI error inference will be implemented after v0.4.0 goes stable.