rokdocs
v0.1

6.4. #[lang(...)] magic

The #[lang(slot_name)] attribute connects a standard library item to a slot the compiler recognizes directly. It is the channel through which the compiler and runtime learn which item carries which meaning.

6.4.1. Motivation

As described in the boundary between language and standard library, the language provides only syntax such as + and -, and the standard library decides its meaning. For this model to work, the compiler must know which library trait or type is connected to which language meaning.

compiler slot           ← language-known anchor
                          (e.g. "add trait", "option slot", "iterator trait")

library item            ← trait / type / fn defined by standard libraries

  ←── #[lang(slot)] connects the two sides ──→

6.4.2. Form

lang_attr       ::= "#" "[" "lang" "(" string_lit ")" "]"
#[lang("add_trait")]
trait Add<Rhs = Self> {
    type Output;
    #[infix("+")]
    fn add(self, rhs: Rhs) -> Output;
}

#[lang("iterator_trait")]
trait Iterator { ... }

#[lang("none_type")]
struct NoneSentinel;               // the type the 'none' literal evaluates to

It is written #[lang("slot_name")], taking the slot name as a string literal argument. It can be attached to items such as traits, types, functions, const, and static.

6.4.3. Classification of slot names

Slot names form a fixed set known to the compiler in advance; users cannot create new slots.

Representative slots:

SlotKind of item connectedCompiler use
"add_trait"trait+ operator desugar
"sub_trait"trait- operator desugar
"mul_trait"trait* operator desugar
.........
"none_type"typeType of the none literal
"iterator_trait"traitfor loop desugar
"into_iterator_trait"traitfor loop desugar
"future_trait"traitawait desugar
"index_trait"trait[i] indexing desugar
"slice_trait"trait[1:3] slicing desugar
"display_trait"traitf"{x}" formatting
"debug_trait"traitf"{x:?}" debug format
"clone_trait"trait#[derive(Clone)]
"eq_trait"trait== / != operators (PartialEq)
.........

The full slot list and the item attached to each slot are given authoritatively by the standard library 0.4 #[lang] slot mapping table; the table above is an excerpt. Changes to the slot set start from the 0.4 table.

6.4.4. Effect of the mapping

When a trait carries #[lang("add_trait")], the compiler connects that trait to the meaning of addition. A subsequent + operator desugars as:

a + b    →    <typeof(a) as the_trait<typeof(b)>>::add(a, b)

Here the_trait is the trait carrying #[lang("add_trait")].

6.4.5. Use in user code (rare)

#[lang] is used almost exclusively by the standard library. User code attaches it directly only when building its own library in a no_std environment, or in environments such as embedded systems or operating systems where the language core must be redefined. Ordinary users never need to attach #[lang] directly.

6.4.6. One item per slot

Attaching the same slot name to several items is a compile error.

#[lang("add_trait")] trait MyAdd { ... }
#[lang("add_trait")] trait OtherAdd { ... }    // ERROR - duplicate slot

Each slot maps to exactly one item. This uniqueness holds program-wide (across all linked packages). A user package therefore cannot reattach and replace a slot defined by rok::core (panic_fn, oom_fn, unreachable_fn, etc.); doing so is a compile error.

6.4.7. Signature checking of slots

Each slot predetermines the signature of the item it accepts.

#[lang("add_trait")]
trait Add<Rhs = Self> {              // the form the slot requires
    type Output;
    fn add(self, rhs: Rhs) -> Output;
}

If the signature does not match the form the slot requires, it is a compile error.

#[lang("add_trait")]
trait BadAdd { fn run() }            // ERROR - does not match the form of the 'add_trait' slot

6.4.8. Unknown slot names

#[lang("nonexistent_slot")]
trait T { ... }

Using an unknown slot name is likewise a compile error.

6.4.9. Stability of slots

The set of slot names is itself part of the language specification, so adding, changing, or removing a slot changes the language version (SemVer).

6.4.10. Difference between magic and ordinary attributes

Aspect#[derive], #[inline], etc.#[lang]
Attached byUsersStandard library (mostly)
EffectCode generation or compiler hintBinds to language meaning
Slot or keyFree (identified by attribute name)Fixed slot set

#[lang] is the most privileged attribute in the meta-system. The other magics - #[literal], #[keyword], and the operator magics - can all be viewed as refined forms of #[lang].

6.4.11. Relation between #[lang] and other magic

Operator magics (#[infix] etc.) are usually attached to methods of a trait carrying #[lang(...)].

#[lang("add_trait")]
trait Add<Rhs = Self> {
    type Output;
    #[infix("+")]
    fn add(self, rhs: Rhs) -> Output;
}

Here #[lang("add_trait")] declares that this trait is where the meaning of addition lives, and #[infix("+", ...)] marks the method as the dispatch target of the + token. Working together, the two magics connect the language and the library in both directions.

#[literal] and #[keyword] can likewise be understood as tools connected to the literal position and the keyword registration slot, respectively.

Edit this page on GitHub