Skip to content

Add #[error_type] and #[error] attributes #7058

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

Merged
merged 6 commits into from
Apr 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/book/spell-check-custom-words.txt
Original file line number Diff line number Diff line change
Expand Up @@ -242,4 +242,6 @@ subdirectories
RawSlice
StringArray
StringSlice
calldata
calldata
Cfg
evm
87 changes: 63 additions & 24 deletions docs/book/src/reference/attributes.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,85 @@
# Attributes

The Sway compiler supports a list of attributes that perform various operations that are useful for building, testing and documenting Sway programs. Below is a list of all available attributes:
Attributes are a form of metadata that can additionally instruct Sway compiler or other tools like `forc test`. Attributes can annotate different language elements, like, e.g., items, enum variants, struct fields, etc.

Below is the list of attributes supported by the Sway compiler, ordered alphabetically:

- [Allow](#allow)
- [Cfg](#cfg)
- [Deprecated](#deprecated)
- [Error](#error)
- [Error Type](#error-type)
- [Fallback](#fallback)
- [Inline](#inline)
- [Payable](#payable)
- [Storage](#payable)
- [Test](#test)

## Allow

The `#[allow(...)]` attribute overrides checks so that violations will go unreported. The following checks can be disabled:
The `#[allow(...)]` attribute disables compiler checks so that certain warnings will go unreported. The following warnings can be disabled:

- `#[allow(dead_code)]` disable checks for dead code;
- `#[allow(deprecated)]` disables checks for usage of deprecated structs, functions and other items.
- `#[allow(dead_code)]` disables warnings for dead code;
- `#[allow(deprecated)]` disables warnings for usage of deprecated elements, like, e.g., structs, functions, enum variants, etc.

## Doc
## Cfg

The `#[doc(..)]` attribute specifies documentation.
The `#[cfg(...)]` attribute allows conditional compilation. The annotated code element will be compiled only if the condition in to the `cfg` attribute evaluates to true. The following conditions can be expressed:

Line doc comments beginning with exactly three slashes `///`, are interpreted as a special syntax for doc attributes. That is, they are equivalent to writing `#[doc("...")]` around the body of the comment, i.e., `/// Foo` turns into `#[doc("Foo")]`
- `#[cfg(target = "<target>")]` where `<target>` can be either "evm" or "fuel";
- `#[cfg(program_type = "<program_type>")]` where `<program_type>` can be either "predicate", "script", "contract", or "library";
- `#[cfg(experimental_<feature_flag> = true/false)]` where `<feature_flag>` is one of the known experimental feature flags.

Line comments beginning with `//!` are doc comments that apply to the module of the source file they are in. That is, they are equivalent to writing `#![doc("...")]` around the body of the comment. `//!` module level doc comments should be at the top of Sway files.
## Deprecated

Documentation can be generated from doc attributes using `forc doc`.
The `#[deprecated]` attribute marks an item as deprecated and makes the compiler emit a warning for every usage of the deprecated item. This warning can be disabled using `#[allow(deprecated)]`.

## Inline
It is possible to improve the warning message with `#[deprecated(note = "Your deprecation message.")]`

## Error

The `#[error]` defines an error message for an error type enum variant:

The inline attribute suggests that a copy of the attributed function should be placed in the caller, rather than generating code to call the function where it is defined.
```sway
#[error_type]
enum SomeErrors {
#[error(m = "An unexpected error occurred.")]
UnexpectedError: (),
}
```

> **Note**: The Sway compiler automatically inlines functions based on internal heuristics. Incorrectly inlining functions can make the program slower, so this attribute should be used with care.
> **Note**: Error types are still an experimental feature. For more info, see the [tracking issue for "Error types"](https://github.com/FuelLabs/sway/issues/6765).

## Error Type

The `#[error_type]` marks an enum as error type enum:

```sway
#[error_type]
enum SomeErrors {
...
}
```

All variants of an error type enum must be annotated with the [`#[error]` attribute](#error). Error type enums are meant to be use in `panic` expressions for rich error reporting.

> **Note**: Error types are still an experimental feature. For more info, see the [tracking issue for "Error types"](https://github.com/FuelLabs/sway/issues/6765).

## Fallback

The `#[fallback]` attribute makes the compiler use the marked function as the contract call fallback function. This means that, when a contract method is called, and the contract method selection fails, the fallback function will be called instead.

More details in [Calling Contracts](../blockchain-development/calling_contracts.md#fallback).

## Inline

The inline attribute *suggests* to the compiler if a copy of the annotated function should be placed in the caller, rather than generating code to call the function where it is defined.

The `#[inline(never)]` attribute *suggests* that an inline expansion should never be performed.

The `#[inline(always)]` attribute *suggests* that an inline expansion should always be performed.

> **Note**: `#[inline(..)]` in every form is a hint, with no *requirements*
on the language to place a copy of the attributed function in the caller.
> **Note**: `#[inline(..)]` in every form is a hint, with no *requirements* on the compiler to place a copy of the annotated function in the caller. The Sway compiler automatically inlines functions based on internal heuristics. Incorrectly inlining functions can make the program slower, so this attribute should be used with care.

## Payable

Expand All @@ -53,13 +102,3 @@ The `#[test]` attribute marks a function to be executed as a test.
The `#[test(should_revert)]` attribute marks a function to be executed as a test that should revert.

More details in [Unit Testing](../testing/unit-testing.md).

## Deprecated

The `#[deprecated]` attribute marks an item as deprecated and makes the compiler emit a warning for every usage of the deprecated item. This warning can be disabled using `#[allow(deprecated)]`.

It is possible to improve the warning message with `#[deprecated(note = "your message")]`

## Fallback

The `#[fallback]` attribute makes the compiler use the marked function as the contract call fallback function, which means that, when a contract is called, and the contract selection fails, the fallback function will be called instead.
58 changes: 22 additions & 36 deletions docs/book/src/reference/keywords.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,51 @@
# Keywords

The following list contains keywords that are reserved for current or
future use by the Sway language. As such, they cannot be used as
identifiers. Identifiers are names of functions, variables,
future use by the Sway language. As such, **they cannot be used as
identifiers**. Identifiers are names of functions, variables,
parameters, modules, constants, attributes, types or
traits, etc.

## Keywords Currently in Use

The following is a list of keywords currently in use, with their
functionality described.
The following is an alphabetically sorted list of keywords currently in use, with their
functionality shortly described.

- `as` - rename items in `use` statements, e.g., `use type::a as alias_name`
- [`abi`](../sway-program-types/smart_contracts.md#the-abi-declaration) - defines a smart contract ABI in a syntactically similar way to traits
- `as` - rename items in `use` statements, e.g., `use type::type_name as alias_name;`
- [`abi`](../sway-program-types/smart_contracts.md#the-abi-declaration) - define a smart contract ABI in a syntactically similar way to traits
- [`asm`](../advanced/assembly.md) - define an assembly block
- [`break`](../basics/control_flow.md#break-and-continue) - exit a loop immediately
- [`const`](../basics/constants.md) - define constant items
- `configurable` - define configurable constants
- [`const`](../basics/constants.md) - define constant
- [`continue`](../basics/control_flow.md#break-and-continue) - continue to the next loop iteration
- [`contract`](../sway-program-types/smart_contracts.md) - define contract program type
- `else` - used in conjunction with `if` conditions for control flow constructs
- [`enum`](../basics/structs_tuples_and_enums.md#enums) - define an enumeration
- [`enum`](../basics/structs_tuples_and_enums.md#enums) - define an enum
- `false` - Boolean false literal
- [`fn`](../basics/functions.md)- define a function or the function pointer type
- [`for`](../basics/control_flow.md#for) - loop based on iterators
- [`fn`](../basics/functions.md)- define a function
- [`if`](../basics/control_flow.md#if-expressions) - branch based on the result of a conditional expression
- `impl` - implement inherent or trait functionality
- `let` - bind a variable
- [`library`](../sway-program-types/libraries.md) - define library program type
- [`match`](../basics/control_flow.md#match-expressions) - exhaustively match a value to patterns
- `mod` - define a module
- `mut` - denote mutability in references, or pattern bindings
- `pub` - denote public visibility of Sway data structures, traits, or modules
- `mut` - denote mutability
- `pub` - denote public visibility
- [`predicate`](../sway-program-types/predicates.md) - define predicate program type
- `ref` - bind by reference
- `return` - return early from a function
- [`script`](../sway-program-types/scripts.md) - define script program type
- `Self` - a type alias for the type we are defining or implementing
- `self` - method subject
- `self` - method call target
- [`storage`](../blockchain-development/storage.md) - define a storage declaration
- `str`- string slice
- [`struct`](../basics/structs_tuples_and_enums.md#structs) - define a structure
- [`trait`](../advanced/traits.md#declaring-a-trait) - define a trait
- `true` - Boolean true literal
- [`type`](../advanced/advanced_types.md#creating-type-synonyms-with-type-aliases) - define a type alias or associated type
- `use` - bring symbols into scope
- `where` - specifies traits for generic types
- `where` - specifies trait constraints for generic type arguments
- [`while`](../basics/control_flow.md#while) - loop conditionally based on the result of an expression

## Keywords Reserved for Possible Future Use
Expand Down Expand Up @@ -64,26 +73,3 @@ functionality described.
- `unsized`
- `virtual`
- `yield`

## Special Keywords

### Program Keywords

Keywords associated with defining the type of Sway program to compile

- [`contract`](../sway-program-types/smart_contracts.md) - analogous to a deployed API with some database state
- [`library`](../sway-program-types/libraries.md) - Sway code that defines new common behavior
- [`predicate`](../sway-program-types/predicates.md) - programs that return a Boolean value and which represent ownership of some resource upon execution to true
- [`script`](../sway-program-types/scripts.md) - a runnable bytecode on the chain, which executes once to perform a task

### Attribute Keywords

Keywords associated with defining the functionality of attributes

- [`allow`](./attributes.md#allow) - overrides checks that would otherwise result in errors or warnings
- [`doc`](./attributes.md#doc) - specifies documentation
- [`inline`](./attributes.md#inline) - suggests that a copy of the attributed function should be placed in the caller, rather than generating code to call the function where it is defined
- [`payable`](./attributes.md#payable) - implies method is payable for compile time
- [`storage`](./attributes.md#storage) - declaration that contains a list of stored variables
- [`test`](./attributes.md#test) - marks a function to be executed as a test
- [`deprecated`](./attributes.md#deprecated) - marks an item as deprecated
5 changes: 5 additions & 0 deletions sway-ast/src/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ pub const CFG_PROGRAM_TYPE_ARG_NAME: &str = "program_type";
pub const DEPRECATED_ATTRIBUTE_NAME: &str = "deprecated";
pub const DEPRECATED_NOTE_ARG_NAME: &str = "note";

// Error types.
pub const ERROR_TYPE_ATTRIBUTE_NAME: &str = "error_type";
pub const ERROR_ATTRIBUTE_NAME: &str = "error";
pub const ERROR_M_ARG_NAME: &str = "m";

pub const KNOWN_ATTRIBUTE_NAMES: &[&str] = &[
STORAGE_ATTRIBUTE_NAME,
DOC_COMMENT_ATTRIBUTE_NAME,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use crate::{
decl_engine::DeclEngineGet,
language::ty::{self, TyAstNode, TyDecl},
language::ty::{self, TyAstNode},
Engines,
};
use sway_error::handler::Handler;
use sway_types::{Named, Spanned};

#[derive(Default)]
Expand All @@ -16,35 +14,40 @@ impl<'a, 'b> MarkerTraitsAutoImplContext<'a, 'b>
where
'a: 'b,
{
/// Generates and implementation of the `Enum` marker trait for the user defined enum
/// Generates an implementation of the `Enum` marker trait for the user defined enum
/// represented by the `enum_decl`.
pub fn generate_enum_marker_trait_impl(
&mut self,
engines: &Engines,
enum_decl: &ty::TyDecl,
enum_decl: &ty::TyEnumDecl,
) -> Option<TyAstNode> {
match enum_decl {
TyDecl::EnumDecl(_) => self.auto_impl_enum_marker_trait(engines, enum_decl),
_ => None,
}
self.auto_impl_empty_marker_trait_on_enum(engines, enum_decl, "Enum")
}

/// Generates an implementation of the `Error` marker trait for the user defined enum
/// represented by the `enum_decl`.
pub fn generate_error_type_marker_trait_impl_for_enum(
&mut self,
engines: &Engines,
enum_decl: &ty::TyEnumDecl,
) -> Option<TyAstNode> {
self.auto_impl_empty_marker_trait_on_enum(engines, enum_decl, "Error")
}

fn auto_impl_enum_marker_trait(
fn auto_impl_empty_marker_trait_on_enum(
&mut self,
engines: &Engines,
enum_decl: &TyDecl,
enum_decl: &ty::TyEnumDecl,
marker_trait_name: &str,
) -> Option<TyAstNode> {
if self.ctx.namespace.current_module().is_std_marker_module() {
return None;
}

let enum_decl_id = enum_decl.to_enum_id(&Handler::default(), engines).unwrap();
let enum_decl = self.ctx.engines().de().get(&enum_decl_id);

let program_id = enum_decl.span().source_id().map(|sid| sid.program_id());

let impl_enum_code = format!(
"#[allow(dead_code)] impl Enum for {} {{ }}",
"#[allow(dead_code, deprecated)] impl {marker_trait_name} for {} {{ }}",
enum_decl.name()
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
pub mod abi_encoding;
pub mod marker_traits;

use std::ops::Deref;

use crate::{
engine_threading::SpannedWithEngines,
language::{
Expand Down Expand Up @@ -304,3 +306,14 @@ where
}
}
}

impl<'a, 'b, I> Deref for AutoImplContext<'a, 'b, I>
where
'a: 'b,
{
type Target = TypeCheckContext<'a>;

fn deref(&self) -> &Self::Target {
self.ctx
}
}
Loading
Loading