# How Sway Derives Auto-Implemented Traits Like Debug and AbiEncode

> Discover how Sway derives auto implemented traits like Debug using Rust macros and AbiEncode via explicit stdlib implementations. Understand Sway's trait derivation.

- Repository: [Fuel Labs/sway](https://github.com/FuelLabs/sway)
- Tags: internals
- Published: 2026-03-04

---

**Sway generates `Debug` implementations through a Rust procedural macro that emits intermediate representation code, while `AbiEncode` relies on explicit hand-written trait implementations in the standard library without automatic derivation.**

The FuelLabs/sway compiler uses two distinct architectural patterns to handle trait derivation. Understanding how auto-implemented traits like `Debug` and `AbiEncode` are derived in Sway is critical for debugging contract code and ensuring proper ABI serialization for the Fuel VM.

## The Debug Derivation Path

### Proc-Macro Architecture in the IR Layer

When you annotate a Sway struct with `#[derive(Debug)]`, the compiler invokes a procedural macro defined in [`sway-ir/sway-ir-macros/src/lib.rs`](https://github.com/FuelLabs/sway/blob/main/sway-ir/sway-ir-macros/src/lib.rs). This macro generates Rust implementations of the `DebugWithContext` trait for the compiler's intermediate representation (IR) types.

The trait definition lives in [`sway-ir/src/pretty.rs`](https://github.com/FuelLabs/sway/blob/main/sway-ir/src/pretty.rs):

```rust
pub trait DebugWithContext {
    fn fmt(&self, engines: &Engines) -> String;
}

```

The macro walks the Sway AST, builds a `fmt` method that recursively calls `debug_with_context` on each field, and injects the generated implementation into the IR. This allows the Sway `debug!` macro to produce formatted output at runtime.

### Debug Code Example

```sway
use std::debug::debug;

#[derive(Debug)]
struct User {
    id: u64,
    name: str[20],
}

fn main() -> u64 {
    let alice = User { id: 1, name: "Alice" };
    debug(alice);  // Prints: User { id: 1, name: "Alice" }
    0
}

```

Behind the scenes, the procedural macro emits Rust code conceptually equivalent to:

```rust
impl DebugWithContext for User {
    fn fmt(&self, engines: &Engines) -> String {
        format!(
            "User {{ id: {}, name: {} }}",
            self.id.fmt(engines),
            self.name.fmt(engines)
        )
    }
}

```

## The AbiEncode Implementation Path

### Standard Library Trait Definition

Unlike `Debug`, the `AbiEncode` trait is defined directly in Sway within `sway-lib-std/src/codec.sw`. There is no automatic derivation mechanism—only hand-written implementations for primitives and generic containers.

```sway
pub trait AbiEncode {
    fn abi_encode(&self) -> RawSlice;
}

```

### Hand-Written Implementations

The standard library provides explicit `impl` blocks for all built-in types. For generic containers like `Vec<T>`, the implementation requires `T: AbiEncode` and encodes the length prefix followed by each element:

```sway
impl<T> AbiEncode for Vec<T>
where
    T: AbiEncode,
{
    fn abi_encode(&self) -> RawSlice {
        // Encode length + recursive element encoding
    }
}

```

### Compile-Time Size Analysis

The compiler validates ABI safety through `abi_encode_size_hint()` in [`sway-core/src/type_system/info.rs`](https://github.com/FuelLabs/sway/blob/main/sway-core/src/type_system/info.rs). This function inspects `TypeInfo` and returns size estimates categorized as:

- **Exact(n)** – Fixed-size types like `u64` or `bool`
- **Range(min, max)** – Dynamic types with known bounds
- **PotentiallyInfinite** – Unbounded collections that might overflow buffers

### Manual Implementation Requirement

User-defined structs must implement `AbiEncode` manually because no derive macro exists:

```sway
struct Point {
    x: u64,
    y: u64,
}

impl AbiEncode for Point {
    fn abi_encode(&self) -> raw_slice {
        let mut buf = RawSlice::new(16);
        buf.write_u64(self.x);
        buf.write_u64(self.y);
        buf
    }
}

```

## Summary

- **`Debug` derivation** uses a Rust procedural macro in [`sway-ir/sway-ir-macros/src/lib.rs`](https://github.com/FuelLabs/sway/blob/main/sway-ir/sway-ir-macros/src/lib.rs) to generate `DebugWithContext` implementations for IR types, enabling `#[derive(Debug)]` in Sway source code.
- **`AbiEncode`** lacks automatic derivation; the trait is defined in `sway-lib-std/src/codec.sw` with hand-written implementations for primitives, standard library types, and generic containers.
- The compiler analyzes encoding sizes via `abi_encode_size_hint()` in [`sway-core/src/type_system/info.rs`](https://github.com/FuelLabs/sway/blob/main/sway-core/src/type_system/info.rs) to ensure contract ABI compatibility at compile time.
- Custom structs require explicit `impl AbiEncode` blocks, while `Debug` works automatically through the derive attribute.

## Frequently Asked Questions

### Can I derive AbiEncode automatically in Sway?

No. Sway does not provide a `#[derive(AbiEncode)]` macro. You must either use types that already implement the trait (primitives, `Vec<T>`, etc.) or provide a manual `impl AbiEncode for YourType` block in your code according to the FuelLabs/sway standard library patterns.

### Where is the Debug derive macro defined?

The `#[derive(Debug)]` functionality is implemented as a procedural macro in [`sway-ir/sway-ir-macros/src/lib.rs`](https://github.com/FuelLabs/sway/blob/main/sway-ir/sway-ir-macros/src/lib.rs). This macro generates implementations of the `DebugWithContext` trait defined in [`sway-ir/src/pretty.rs`](https://github.com/FuelLabs/sway/blob/main/sway-ir/src/pretty.rs), which operates on the compiler's intermediate representation rather than Sway source code directly.

### Why do I need to implement AbiEncode manually for custom structs?

The Sway compiler does not generate `AbiEncode` implementations automatically because ABI encoding requires explicit control over binary layout for Fuel VM contract interactions. The trait is defined in `sway-lib-std/src/codec.sw` with hand-written implementations to ensure predictable, gas-efficient serialization for blockchain transactions.

### How does the compiler estimate ABI encoding size?

The size estimation logic resides in [`sway-core/src/type_system/info.rs`](https://github.com/FuelLabs/sway/blob/main/sway-core/src/type_system/info.rs) within the `abi_encode_size_hint()` function. It inspects `TypeInfo` to return size categories like `Exact(n)` for fixed-size types, `Range(min, max)` for dynamic types with bounds, or `PotentiallyInfinite` for unbounded collections, enabling compile-time validation of contract call buffer sizes.