gobanos / cargo-aoc

439 stars 47 forks source link

Naming a type `Box` produces crazy errors #111

Open Chris--B opened 10 months ago

Chris--B commented 10 months ago

For 2023 Day 15, I named a type Box, forgetting about the std type. Since I didn't use std::boxed::Box in this file, I didn't think much of it.

But when I move my type definition out of my function, it goes into file scope and conflicts with the Std's Box:

error[E0107]: type alias takes 0 generic arguments but 1 generic argument was supplied
  --> src/day15.rs:15:1
   |
15 | #[aoc(day15, part1)]
   | ^^^^^^^^^^^^^^^^^^^^- help: remove these generics
   | |
   | expected 0 generic arguments
   |
note: type alias defined here, with 0 generic parameters
  --> src/day15.rs:25:6
   |
25 | type Box = <redacted for minor AOC spoilers>
   |      ^^^
   = note: this error originates in the attribute macro `aoc` (in Nightly builds, run with -Z macro-backtrace for more info)

It doesn't matter much what Box is aliased to, as long as it's not std::boxed::Box.

It's not at all obvious what's just happened. In normal Rust, this kind of error can highlight the right code and make things more obvious. In this case, it seems cargo-aoc is using Box in generated code and Rust doesn't have a good way to show that.

To protect against type renames, I think cargo-aoc should consider either fulling qualifying std types when used, or importing them explicitly. An example from a quick search of the repo:

    pm::TokenStream::from(quote! {
        #original_fn

        #[allow(unused_imports)]
        mod #mod_name {
            use super::*;
            use aoc_runner::{ArcStr, Runner};
            use std::marker::PhantomData;
            use std::error::Error;
            use std::fmt::Display;
            use std::borrow::Borrow;
            use std::boxed::Box; // <----- new line to protect against shadowing
            use crate::{Factory, #trait_name};

            impl #trait_name for Factory {
                fn #mod_name(input: ArcStr) -> Result<Box<dyn Runner>, Box<dyn Error>> {
                    Ok(Box::new( RunnerStruct::try_gen(input)? ))
                }
            }

            #def
        }
    })