Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error redesign #1462

Merged
merged 119 commits into from Feb 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
119 commits
Select commit Hold shift + click to select a range
6ab5f86
WIP
paul-schaaf Feb 17, 2022
c1b7ffb
accounts work
paul-schaaf Feb 17, 2022
fefeee9
WIP
paul-schaaf Feb 17, 2022
c699deb
WIP
paul-schaaf Feb 17, 2022
26099aa
WIP
paul-schaaf Feb 17, 2022
826061e
constraints
paul-schaaf Feb 17, 2022
b158759
constraints
paul-schaaf Feb 17, 2022
31d63cb
constraints
paul-schaaf Feb 17, 2022
bbf4c93
WIP
paul-schaaf Feb 17, 2022
ff49753
LANG COMPILES
paul-schaaf Feb 17, 2022
d4c6133
fmt and clippy
paul-schaaf Feb 17, 2022
8093770
require!
paul-schaaf Feb 17, 2022
b2621c3
WIP
paul-schaaf Feb 17, 2022
dee9580
WIP
paul-schaaf Feb 17, 2022
d476718
WIP
paul-schaaf Feb 17, 2022
0903b06
WIP
paul-schaaf Feb 17, 2022
d5b840b
WIP
paul-schaaf Feb 17, 2022
3a433f4
WIP
paul-schaaf Feb 17, 2022
e7f1fcf
WIP
paul-schaaf Feb 17, 2022
5677031
LANG AND BARE-BONES PROGRAM COMPILES
paul-schaaf Feb 17, 2022
fe0a48f
basic program now also works with build-bpf instead of just build
paul-schaaf Feb 17, 2022
ea5edcd
WIP
paul-schaaf Feb 17, 2022
ffb113e
remove program id from error for now
paul-schaaf Feb 18, 2022
c5dc814
error! now returns Error instead of Err(Error)
paul-schaaf Feb 18, 2022
c501266
remove unused code
paul-schaaf Feb 18, 2022
bf1f0ad
error_with_account_name
paul-schaaf Feb 18, 2022
37c9998
ProgramErrorWithoutOrigin and errors from types
paul-schaaf Feb 18, 2022
fe460c3
fix spl token
paul-schaaf Feb 18, 2022
25815bb
add todo
paul-schaaf Feb 18, 2022
573f507
make client compile
paul-schaaf Feb 18, 2022
211e59f
clippy
paul-schaaf Feb 18, 2022
4e12959
dont use format to error_name
paul-schaaf Feb 19, 2022
34dbacb
error_without_origin for DeclaredProgramIdMismatch error
paul-schaaf Feb 19, 2022
fe050d6
add all error structures to prelude
paul-schaaf Feb 19, 2022
8087460
fix tests
paul-schaaf Feb 19, 2022
234ca57
adjust idl creation to use error_codes instead of error attribute
paul-schaaf Feb 19, 2022
5667345
fix error tests
paul-schaaf Feb 19, 2022
08a48d4
fmt
paul-schaaf Feb 19, 2022
8671951
add todos
paul-schaaf Feb 19, 2022
aa64f5a
fix basic4
paul-schaaf Feb 19, 2022
32a20dc
fmt
paul-schaaf Feb 19, 2022
0810228
fix cashiers-check
paul-schaaf Feb 19, 2022
11b8a77
error_with_account_name for all constraint errors
paul-schaaf Feb 19, 2022
a772cfc
fix compile errors
paul-schaaf Feb 19, 2022
5411764
fix basic3 example
paul-schaaf Feb 19, 2022
fbd8037
fmt
paul-schaaf Feb 19, 2022
121080a
fix interface test
paul-schaaf Feb 19, 2022
6a51b4a
fix chat tests
paul-schaaf Feb 19, 2022
365fce1
close now uses error_without_origin
paul-schaaf Feb 19, 2022
646a60d
try_account ix deser now uses error_without_origin
paul-schaaf Feb 19, 2022
65f6126
fix lockup test
paul-schaaf Feb 19, 2022
c56e401
ido pool
paul-schaaf Feb 19, 2022
ea4532c
fix misc test
paul-schaaf Feb 19, 2022
0f8d1ec
fix multisig test
paul-schaaf Feb 19, 2022
cf42ee4
fix swap test
paul-schaaf Feb 19, 2022
51706fa
AnchorResult -> Result
paul-schaaf Feb 19, 2022
ef4cd3f
entry function use ProgramResult with full path
paul-schaaf Feb 19, 2022
ecd9cb8
anchor_lang::Result -> Result
paul-schaaf Feb 19, 2022
9b944b6
fmt
paul-schaaf Feb 19, 2022
70b19ea
clippy
paul-schaaf Feb 19, 2022
59d0f7f
fmt
paul-schaaf Feb 19, 2022
a72c384
add Result<()> spl crate compile
paul-schaaf Feb 19, 2022
0152d9a
spl dex crate compile
paul-schaaf Feb 19, 2022
c4f7468
fix tests
paul-schaaf Feb 19, 2022
10553cb
fix composite test
paul-schaaf Feb 19, 2022
0fe7409
fmt
paul-schaaf Feb 19, 2022
1761d57
fix events test
paul-schaaf Feb 19, 2022
ac83700
fix examples tests
paul-schaaf Feb 19, 2022
207857d
fix more tests
paul-schaaf Feb 19, 2022
5528173
revert custom-coder back to master
paul-schaaf Feb 19, 2022
599461f
Merge branch 'master' into error-redesign
paul-schaaf Feb 19, 2022
e953f17
fix floats test
paul-schaaf Feb 19, 2022
64ab4c0
run all test except those with submodules
paul-schaaf Feb 19, 2022
7eb0d06
fix interface tests
paul-schaaf Feb 19, 2022
8deaeff
fix TODOs
paul-schaaf Feb 19, 2022
571210d
fix todos
paul-schaaf Feb 19, 2022
61eb0eb
fix todos
paul-schaaf Feb 19, 2022
f9323f3
fix todo
paul-schaaf Feb 19, 2022
17290eb
remove todo
paul-schaaf Feb 19, 2022
ddae8c6
fmt
paul-schaaf Feb 19, 2022
1946f2f
fix auctionhouse tests
paul-schaaf Feb 19, 2022
c5fca8a
swap was already working
paul-schaaf Feb 19, 2022
a98b228
fix cfo test
paul-schaaf Feb 19, 2022
6f111e1
add docs todo
paul-schaaf Feb 19, 2022
fdf6578
error_codes -> error_code
paul-schaaf Feb 19, 2022
bce05b1
move error parsing into syn crate
paul-schaaf Feb 19, 2022
2630cdd
refactor error
paul-schaaf Feb 20, 2022
30cbcb9
update docs
paul-schaaf Feb 20, 2022
5abac35
fix error macro
paul-schaaf Feb 20, 2022
064e527
add require! test
paul-schaaf Feb 20, 2022
21f3281
Fix error test
paul-schaaf Feb 20, 2022
283f43c
lang: add bail! macro
paul-schaaf Feb 20, 2022
ef2f181
docs
paul-schaaf Feb 20, 2022
2bb6be8
lang: fix ProgramError logging
paul-schaaf Feb 20, 2022
43a200f
tests: add tests for error logging
paul-schaaf Feb 20, 2022
007eafc
ci: turn off fail-fast for matrix
paul-schaaf Feb 20, 2022
7647c04
lang: remove TODO
paul-schaaf Feb 20, 2022
e6ea718
fmt
paul-schaaf Feb 20, 2022
39209ca
ts: ts library can now also parse real tx errors instead of just simu…
paul-schaaf Feb 20, 2022
c8904ae
tests: fix error tests
paul-schaaf Feb 20, 2022
69f89a3
tests: add sleep to errors test to allow logs to come in
paul-schaaf Feb 20, 2022
13dcede
tests: fix sleep
paul-schaaf Feb 20, 2022
3692e9c
tests fix sleep placement
paul-schaaf Feb 20, 2022
39e1719
remove dead todo
paul-schaaf Feb 20, 2022
c99d335
docs: changelog
paul-schaaf Feb 20, 2022
22fbe6c
lang: add with_source method on Error type so ProgramErrors can be en…
paul-schaaf Feb 20, 2022
c83e28f
lang: remove error_without_origin
paul-schaaf Feb 20, 2022
34ea949
pe.into() -> Into::into
paul-schaaf Feb 20, 2022
93b6bd3
.into() -> Error::from()
paul-schaaf Feb 20, 2022
a7ae6ae
bail! -> err!
paul-schaaf Feb 20, 2022
d85a310
tests: use err!
paul-schaaf Feb 20, 2022
62b9902
lang: use .map_err again in close
paul-schaaf Feb 20, 2022
88e4510
lang: import anchor_lang::Result
paul-schaaf Feb 20, 2022
9f40e76
tests: fix lockup test
paul-schaaf Feb 20, 2022
aeca9a3
try not using Error::from
armaniferrante Feb 20, 2022
0148808
Update lang/attribute/interface/src/lib.rs
armaniferrante Feb 20, 2022
68c5188
fmt import
armaniferrante Feb 20, 2022
9dc873b
fmt more imports
armaniferrante Feb 20, 2022
a3bb227
update submodule pointers
armaniferrante Feb 20, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/tests.yaml
Expand Up @@ -121,6 +121,7 @@ jobs:
name: Setup Client Example Test
runs-on: ubuntu-18.04
strategy:
fail-fast: false
matrix:
node:
- path: tests/events/
Expand Down Expand Up @@ -232,6 +233,7 @@ jobs:
name: Test ${{ matrix.node.path }}
runs-on: ubuntu-18.04
strategy:
fail-fast: false
matrix:
node:
- cmd: cd tests/sysvars && anchor test
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Expand Up @@ -25,6 +25,11 @@ incremented for features.
* lang: Enforce that the payer for an init-ed account be marked `mut` ([#1271](https://github.com/project-serum/anchor/pull/1271)).
* lang: All error-related code is now in the error module ([#1426](https://github.com/project-serum/anchor/pull/1426)).
* lang: Require doc comments when using AccountInfo or UncheckedAccount types ([#1452](https://github.com/project-serum/anchor/pull/1452)).
* lang: add [`error!`](https://docs.rs/anchor-lang/latest/anchor_lang/prelude/macro.error.html) and [`err!`](https://docs.rs/anchor-lang/latest/anchor_lang/prelude/macro.err.html) macro and `Result` type ([#1462](https://github.com/project-serum/anchor/pull/1462)).
This change will break most programs. Do the following to upgrade:
* change all `ProgramResult`'s to `Result<()>`
* change `#[error]` to `#[error_code]`
* change all `Err(MyError::SomeError.into())` to `Err(error!(MyError::SomeError))` and all `Err(ProgramError::SomeProgramError)` to `Err(ProgramError::SomeProgramError.into())` or `Err(Error::from(ProgramError::SomeProgramError).with_source(source!()))` to provide file and line source of the error (`with_source` is most useful with `ProgramError`s. `error!` already adds source information for custom and anchor internal errors).

## [0.21.0] - 2022-02-07

Expand Down
2 changes: 2 additions & 0 deletions client/src/lib.rs
Expand Up @@ -376,6 +376,8 @@ pub enum ClientError {
#[error("Account not found")]
AccountNotFound,
#[error("{0}")]
AnchorError(#[from] anchor_lang::error::Error),
#[error("{0}")]
ProgramError(#[from] ProgramError),
#[error("{0}")]
SolanaClientError(#[from] SolanaClientError),
Expand Down
21 changes: 8 additions & 13 deletions docs/src/tutorials/tutorial-4.md
@@ -1,8 +1,8 @@
# Errors

If you've ever programmed on a blockchain, you've probably been frustrated by
either non existant or opaque error codes. Anchor attempts to address this by
providing the `#[error]` attribute, which can be used to create typed Errors with
either non existent or opaque error codes. Anchor attempts to address this by
providing the `#[error_code]` attribute, which can be used to create typed Errors with
descriptive messages that automatically propagate to the client.

## Defining a Program
Expand All @@ -16,31 +16,26 @@ use anchor_lang::prelude::*;
mod errors {
use super::*;
pub fn hello(_ctx: Context<Hello>) -> Result<()> {
Err(ErrorCode::Hello.into())
Err(error!(ErrorCode::Hello))
}
}

#[derive(Accounts)]
pub struct Hello {}

#[error]
#[error_code]
pub enum ErrorCode {
#[msg("This is an error message clients will automatically display")]
Hello,
}
```

Observe the [#[error]](https://docs.rs/anchor-lang/latest/anchor_lang/attr.error.html) attribute on the `ErrorCode` enum. This macro generates two types: an `Error` and a `Result`, both of which can be used when returning from your program.
Observe the [#[error_code]](https://docs.rs/anchor-lang/latest/anchor_lang/attr.error_code.html) attribute on the `ErrorCode` enum.
This macro generates internal anchor code that helps anchor turn the error code into an error and display it properly.

To use the `Error`, you can simply use the user defined `ErrorCode` with Rust's [From](https://doc.rust-lang.org/std/convert/trait.From.html) trait. If you're unfamiliar with `From`, no worries. Just know that you need to either call
`.into()` when using your `ErrorCode`. Or use Rust's `?` operator, when returning an error.
Both of these will automatically convert *into* the correct `Error`.
To create an error, use the [`error!`](https://docs.rs/anchor-lang/latest/anchor_lang/prelude/macro.error.html) macro together with an error code. This macro creates an [`AnchorError`](https://docs.rs/anchor-lang/latest/anchor_lang/error/struct.AnchorError.html) that includes helpful information like the file and line the error was created in.

::: details
What's the deal with this From stuff? Well, because the Solana runtime expects a [ProgramError](https://docs.rs/solana-program/1.5.5/solana_program/program_error/enum.ProgramError.html) in the return value. The framework needs to wrap the user defined error code into a
`ProgramError::Code` variant, before returning. The alternative would be to use the
`ProgramError` directly.
:::
To make writing errors even easier, anchor also provides the [`err!`](https://docs.rs/anchor-lang/latest/anchor_lang/prelude/macro.err.html and the [`require!`](https://docs.rs/anchor-lang/latest/anchor_lang/prelude/macro.require.html macros.

## Using the Client

Expand Down
2 changes: 1 addition & 1 deletion examples/tutorial/basic-0/programs/basic-0/src/lib.rs
Expand Up @@ -5,7 +5,7 @@ declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
mod basic_0 {
use super::*;
pub fn initialize(_ctx: Context<Initialize>) -> ProgramResult {
pub fn initialize(_ctx: Context<Initialize>) -> Result<()> {
Ok(())
}
}
Expand Down
4 changes: 2 additions & 2 deletions examples/tutorial/basic-1/programs/basic-1/src/lib.rs
Expand Up @@ -6,13 +6,13 @@ declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
mod basic_1 {
use super::*;

pub fn initialize(ctx: Context<Initialize>, data: u64) -> ProgramResult {
pub fn initialize(ctx: Context<Initialize>, data: u64) -> Result<()> {
let my_account = &mut ctx.accounts.my_account;
my_account.data = data;
Ok(())
}

pub fn update(ctx: Context<Update>, data: u64) -> ProgramResult {
pub fn update(ctx: Context<Update>, data: u64) -> Result<()> {
let my_account = &mut ctx.accounts.my_account;
my_account.data = data;
Ok(())
Expand Down
4 changes: 2 additions & 2 deletions examples/tutorial/basic-2/programs/basic-2/src/lib.rs
Expand Up @@ -6,14 +6,14 @@ declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
mod basic_2 {
use super::*;

pub fn create(ctx: Context<Create>, authority: Pubkey) -> ProgramResult {
pub fn create(ctx: Context<Create>, authority: Pubkey) -> Result<()> {
let counter = &mut ctx.accounts.counter;
counter.authority = authority;
counter.count = 0;
Ok(())
}

pub fn increment(ctx: Context<Increment>) -> ProgramResult {
pub fn increment(ctx: Context<Increment>) -> Result<()> {
let counter = &mut ctx.accounts.counter;
counter.count += 1;
Ok(())
Expand Down
Expand Up @@ -9,7 +9,7 @@ declare_id!("HmbTLCmaGvZhKnn1Zfa1JVnp7vkMV4DYVxPLWBVoN65L");
#[program]
mod puppet_master {
use super::*;
pub fn pull_strings(ctx: Context<PullStrings>, data: u64) -> ProgramResult {
pub fn pull_strings(ctx: Context<PullStrings>, data: u64) -> anchor_lang::Result<()> {
let cpi_program = ctx.accounts.puppet_program.to_account_info();
let cpi_accounts = SetData {
puppet: ctx.accounts.puppet.to_account_info(),
Expand Down
4 changes: 2 additions & 2 deletions examples/tutorial/basic-3/programs/puppet/src/lib.rs
Expand Up @@ -5,11 +5,11 @@ declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod puppet {
use super::*;
pub fn initialize(_ctx: Context<Initialize>) -> ProgramResult {
pub fn initialize(_ctx: Context<Initialize>) -> Result<()> {
Ok(())
}

pub fn set_data(ctx: Context<SetData>, data: u64) -> ProgramResult {
pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
let puppet = &mut ctx.accounts.puppet;
puppet.data = data;
Ok(())
Expand Down
8 changes: 4 additions & 4 deletions examples/tutorial/basic-4/programs/basic-4/src/lib.rs
Expand Up @@ -14,16 +14,16 @@ pub mod basic_4 {
}

impl Counter {
pub fn new(ctx: Context<Auth>) -> Result<Self> {
pub fn new(ctx: Context<Auth>) -> anchor_lang::Result<Self> {
Ok(Self {
authority: *ctx.accounts.authority.key,
count: 0,
})
}

pub fn increment(&mut self, ctx: Context<Auth>) -> Result<()> {
pub fn increment(&mut self, ctx: Context<Auth>) -> anchor_lang::Result<()> {
if &self.authority != ctx.accounts.authority.key {
return Err(ErrorCode::Unauthorized.into());
return Err(error!(ErrorCode::Unauthorized));
}
self.count += 1;
Ok(())
Expand All @@ -37,7 +37,7 @@ pub struct Auth<'info> {
}
// #endregion code

#[error]
#[error_code]
pub enum ErrorCode {
#[msg("You are not authorized to perform this action.")]
Unauthorized,
Expand Down
23 changes: 12 additions & 11 deletions lang/attribute/account/src/lib.rs
Expand Up @@ -146,7 +146,7 @@ pub fn account(
// It's expected on-chain programs deserialize via zero-copy.
#[automatically_derived]
impl #impl_gen anchor_lang::AccountDeserialize for #account_name #type_gen #where_clause {
fn try_deserialize(buf: &mut &[u8]) -> std::result::Result<Self, ProgramError> {
fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
if buf.len() < #discriminator.len() {
return Err(anchor_lang::error::ErrorCode::AccountDiscriminatorNotFound.into());
}
Expand All @@ -157,7 +157,7 @@ pub fn account(
Self::try_deserialize_unchecked(buf)
}

fn try_deserialize_unchecked(buf: &mut &[u8]) -> std::result::Result<Self, ProgramError> {
fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
let data: &[u8] = &buf[8..];
// Re-interpret raw bytes into the POD data structure.
let account = anchor_lang::__private::bytemuck::from_bytes(data);
Expand All @@ -175,20 +175,21 @@ pub fn account(

#[automatically_derived]
impl #impl_gen anchor_lang::AccountSerialize for #account_name #type_gen #where_clause {
fn try_serialize<W: std::io::Write>(&self, writer: &mut W) -> std::result::Result<(), ProgramError> {
writer.write_all(&#discriminator).map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotSerialize)?;
AnchorSerialize::serialize(
self,
writer
)
.map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotSerialize)?;
fn try_serialize<W: std::io::Write>(&self, writer: &mut W) -> anchor_lang::Result<()> {
if writer.write_all(&#discriminator).is_err() {
return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into());
}

if AnchorSerialize::serialize(self, writer).is_err() {
return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into());
}
Ok(())
}
}

#[automatically_derived]
impl #impl_gen anchor_lang::AccountDeserialize for #account_name #type_gen #where_clause {
fn try_deserialize(buf: &mut &[u8]) -> std::result::Result<Self, ProgramError> {
fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
if buf.len() < #discriminator.len() {
return Err(anchor_lang::error::ErrorCode::AccountDiscriminatorNotFound.into());
}
Expand All @@ -199,7 +200,7 @@ pub fn account(
Self::try_deserialize_unchecked(buf)
}

fn try_deserialize_unchecked(buf: &mut &[u8]) -> std::result::Result<Self, ProgramError> {
fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
let mut data: &[u8] = &buf[8..];
AnchorDeserialize::deserialize(&mut data)
.map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize.into())
Expand Down
2 changes: 1 addition & 1 deletion lang/attribute/error/Cargo.toml
Expand Up @@ -17,4 +17,4 @@ anchor-debug = ["anchor-syn/anchor-debug"]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "1.0.60", features = ["full"] }
anchor-syn = { path = "../../syn", version = "0.21.0" }
anchor-syn = { path = "../../syn", version = "0.21.0" }
82 changes: 74 additions & 8 deletions lang/attribute/error/src/lib.rs
@@ -1,9 +1,12 @@
extern crate proc_macro;

use anchor_syn::codegen::error as error_codegen;
use anchor_syn::parser::error as error_parser;
use proc_macro::TokenStream;
use quote::quote;

use anchor_syn::parser::error::{self as error_parser, ErrorWithAccountNameInput};
use anchor_syn::ErrorArgs;
use syn::parse_macro_input;
use anchor_syn::{codegen, parser::error::ErrorInput};
use syn::{parse_macro_input, Expr};

/// Generates `Error` and `type Result<T> = Result<T, Error>` types to be
/// used as return types from Anchor instruction handlers. Importantly, the
Expand All @@ -21,14 +24,14 @@ use syn::parse_macro_input;
/// mod errors {
/// use super::*;
/// pub fn hello(_ctx: Context<Hello>) -> Result<()> {
/// Err(MyError::Hello.into())
/// Err(error!(MyError::Hello))
/// }
/// }
///
/// #[derive(Accounts)]
/// pub struct Hello {}
///
/// #[error]
/// #[error_code]
/// pub enum MyError {
/// #[msg("This is an error message clients will automatically display")]
/// Hello,
Expand All @@ -40,14 +43,14 @@ use syn::parse_macro_input;
/// [`ProgramError`](../solana_program/enum.ProgramError.html), which is used
/// pervasively, throughout solana program crates. The generated `Error` type
/// should almost never be used directly, as the user defined error is
/// preferred. In the example above, `MyError::Hello.into()`.
/// preferred. In the example above, `error!(MyError::Hello)`.
///
/// # Msg
///
/// The `#[msg(..)]` attribute is inert, and is used only as a marker so that
/// parsers and IDLs can map error codes to error messages.
#[proc_macro_attribute]
pub fn error(
pub fn error_code(
args: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
Expand All @@ -56,6 +59,69 @@ pub fn error(
false => Some(parse_macro_input!(args as ErrorArgs)),
};
let mut error_enum = parse_macro_input!(input as syn::ItemEnum);
let error = error_codegen::generate(error_parser::parse(&mut error_enum, args));
let error = codegen::error::generate(error_parser::parse(&mut error_enum, args));
proc_macro::TokenStream::from(error)
}

/// Generates an [`Error::AnchorError`](../../anchor_lang/error/enum.Error.html) that includes file and line information.
///
/// # Example
/// ```rust,ignore
/// #[program]
/// mod errors {
/// use super::*;
/// pub fn example(_ctx: Context<Example>) -> Result<()> {
/// Err(error!(MyError::Hello))
/// }
/// }
///
/// #[error_code]
/// pub enum MyError {
/// #[msg("This is an error message clients will automatically display")]
/// Hello,
/// }
/// ```
#[proc_macro]
pub fn error(ts: proc_macro::TokenStream) -> TokenStream {
let input = parse_macro_input!(ts as ErrorInput);
let error_code = input.error_code;
create_error(error_code, true, None)
}

#[proc_macro]
pub fn error_with_account_name(ts: proc_macro::TokenStream) -> TokenStream {
armaniferrante marked this conversation as resolved.
Show resolved Hide resolved
let input = parse_macro_input!(ts as ErrorWithAccountNameInput);
let error_code = input.error_code;
let account_name = input.account_name;
create_error(error_code, false, Some(account_name))
}

fn create_error(error_code: Expr, source: bool, account_name: Option<Expr>) -> TokenStream {
let source = if source {
quote! {
Some(anchor_lang::error::Source {
filename: file!(),
line: line!()
})
}
} else {
quote! {
None
}
};
let account_name = match account_name {
Some(_) => quote! { Some(#account_name.to_string()) },
None => quote! { None },
};
TokenStream::from(quote! {
anchor_lang::error::Error::from(
anchor_lang::error::AnchorError {
error_name: #error_code.name(),
error_code_number: #error_code.into(),
error_msg: #error_code.to_string(),
source: #source,
account_name: #account_name
}
)
})
}