diff --git a/content/docs/guide/classes.mdx b/content/docs/guide/classes.mdx index 5926dfa..57cb07d 100644 --- a/content/docs/guide/classes.mdx +++ b/content/docs/guide/classes.mdx @@ -7,8 +7,9 @@ icon: Shapes Mist introduces `class` as syntactic sugar for a Rust struct with a virtual method table (vtable). ```mist -pub class Animal { - str& name, +pub class Animal +{ + str& name; pub constructor(str& name) { @@ -25,19 +26,21 @@ pub class Animal { Class fields can have default initializers: ```mist -class Player { - i32 health = 100, - str& name, +class Player +{ + i32 health = 100; + str& name; } ``` ### Inheritance ```mist -class Dog : Animal { +class Dog : Animal +{ pub constructor(str& name) { - super(name); + super = Super::new(name); } void speak(&self) override @@ -56,6 +59,25 @@ void speak(&self) override(Animal) } ``` +### Implementations + +You can implement directly on the class body: + +```mist +class Circle +{ + constructor() {} + + impl std::fmt::Display + { + Result<(), std::fmt::Error> fmt(&self, Formatter<'_> f) + { + write!(f, "●") + } + } +} +``` + ### Under the Hood A class `Dog : Animal` generates: @@ -67,3 +89,102 @@ A class `Dog : Animal` generates: 5. A `new()` constructor that initializes via `MaybeUninit` and calls the user's `constructor(&mut self)` The vtable is unified: parent entries are copied, overridden entries replace parent slots, and new methods are appended. + +### Safety + +Classes use `MaybeUninit::zeroed().assume_init()` inside the generated `new()` function — an inherently unsafe operation. This raises a natural question: **Are class constructors unsafe?** + +The answer is **no**. The compiler statically verifies that every field is initialized before the constructor returns, eliminating the undefined behavior that raw `MaybeUninit` would normally carry. + +#### Static Field Initialization Verification + +When a class has a constructor, the semantic checker (`check_class_semantics`) collects every declared field and walks the constructor body to prove each one is written to: + +1. **Direct assignment tracking** — Expressions like `self.field = value` are recognized as mutations of `field`. The analyzer checks for `=` and `->` operators whose left-hand side is a `self.field` path. + +2. **`&mut self.field` tracking** — Taking a mutable reference to a field (`&mut self.field`) also counts as initializing it, since the reference can only be taken if the field is being set up. + +3. **Transitive method calls** — If the constructor calls `self.helper()`, the analyzer follows into `helper`'s body and tracks which fields *it* initializes. This transitively propagates through nested calls: + +```mist +class Player +{ + str& name; + i32 health; + + pub constructor(str& name) + { + self.name = name; + self.setup_health(); + } + + void setup_health(&mut self) + { + self.health = 100; // Counts toward constructor's verification + } +} +``` + +4. **Branch intersection** — For `if`/`else`, `match`, and loops, fields must be initialized in **all** branches. If one branch initializes `x` but another does not, `x` is considered uninitialized. This ensures soundness regardless of the runtime path: + +```mist +pub constructor(bool flag) +{ + if flag { + self.health = 100; + } else { + self.health = 0; + } + // Both branches init health ✓ +} +``` + +5. **Super initialization** — When a class inherits, the `_super` field is added to the required-field list. Any assignment to `super` counts: + +```mist +pub constructor(str& name) +{ + super = Super::new(name); +} +``` + +If any field is uninitialized after the full analysis, a compile-time error is reported with the field's exact source location: + +``` +class field `Player.health` is uninitialized +``` + +#### Override Validation at Compile Time + +When a method uses the `override` keyword, the codegen emits a hidden test function that verifies the Deref chain at compile time: + +```rust +#[allow(invalid_value)] +fn __test_vt() { + let this: &Self = &unsafe { std::mem::MaybeUninit::::zeroed().assume_init() }; + let _: &Target = this; // Forces compiler to check Deref +} +``` + +This ensures `&Self` can always deref into the base class type. If the inheritance hierarchy is invalid, the Rust compiler rejects it. + +#### VTable Safety + +The `_vptr` (vtable pointer) is set *twice* during construction: + +1. **Before** the constructor body runs — enabling virtual dispatch inside the constructor itself +2. **After** the constructor body — in case a base-class constructor ran and overwrote the pointer + +This ensures that virtual method calls work correctly even during object construction, without exposing uninitialized memory through the vtable. + +#### Summary + +| Risk | Mitigation | +|------|-----------| +| Uninitialized fields via `MaybeUninit` | Static field-initialization verification rejects incomplete constructors | +| UB from reading uninitialized fields | Intersection analysis ensures all branches init the same fields | +| Invalid override signatures | Compile-time Deref test validates the inheritance chain | +| Vtable corruption during construction | `_vptr` is set before and after the constructor body | +| Unsafe code in generated constructors | `#[allow(invalid_value)]` is scoped to the generated `new()` only | + +The `MaybeUninit` pattern is an implementation detail of the generated code — the Mist compiler proves soundness at the language level, so the user's constructor body is safe Mist code with no manual `unsafe` annotations required. diff --git a/content/docs/guide/control-flow.mdx b/content/docs/guide/control-flow.mdx index effa561..33d0390 100644 --- a/content/docs/guide/control-flow.mdx +++ b/content/docs/guide/control-flow.mdx @@ -7,17 +7,20 @@ icon: ArrowLeftRight ### If/Else ```mist -if condition { +if condition +{ // body -} else if other_condition { +} +else if other_condition +{ // body -} else { +} +else +{ // body } ``` -Conditions must be parenthesized: `if (expr) { }` or `if expr_no_struct { }` (struct literals require parentheses). - Used as an expression: ```mist @@ -27,7 +30,8 @@ let x = if true { 1 } else { 2 }; ### While ```mist -while condition { +while condition +{ // body } ``` @@ -35,11 +39,13 @@ while condition { ### For ```mist -for pattern in iterator { +for pattern in iterator +{ // body } -for i in 0 .. 10 { +for i in 0 .. 10 +{ // body } ``` @@ -47,7 +53,8 @@ for i in 0 .. 10 { ### C-Style For ```mist -for (let mut i = 0; i < 10; i++) { +for (let mut i = 0; i < 10; i++) +{ // body } ``` @@ -55,7 +62,8 @@ for (let mut i = 0; i < 10; i++) { ### Loop ```mist -loop { +loop +{ // infinite loop } ``` diff --git a/content/docs/guide/functions.mdx b/content/docs/guide/functions.mdx index b45507a..8cfa5b0 100644 --- a/content/docs/guide/functions.mdx +++ b/content/docs/guide/functions.mdx @@ -42,13 +42,9 @@ unsafe i32 dangerous() } ``` -Function syntax: `[pub] [void | ] []() [override] { }` - -Functions use **Allman brace style** (opening brace on the next line). - ### Self Parameter -Methods can take `self`, `mut self`, `&self`, `&mut self` additionally with lifetimes: +Methods can take `self`, `mut self`, `&self`, `&mut self`, and `&'a self` / `&'a mut self` with lifetimes: ```mist pub void set_value(&mut self, i32 v) diff --git a/content/docs/guide/generics.mdx b/content/docs/guide/generics.mdx index 458f696..ba3d6a1 100644 --- a/content/docs/guide/generics.mdx +++ b/content/docs/guide/generics.mdx @@ -12,15 +12,17 @@ T id(T x) } // Generic struct -struct Pair { +struct Pair +{ A first, B second, } // Generic enum -enum Result { - Ok(T), - Err(E), +enum Result +{ + Ok(T); + Err(E); } // Generic with trait bounds diff --git a/content/docs/guide/patterns.mdx b/content/docs/guide/patterns.mdx index 05f76d5..57a11e4 100644 --- a/content/docs/guide/patterns.mdx +++ b/content/docs/guide/patterns.mdx @@ -25,11 +25,11 @@ match value { // Named tuple patterns (newtype) let MyType(value) = my_var; -// Wildcard / etc +// Wildcard / rest let _ = get_side_effect(); match x { - 1 => ..., - .. => ..., // rest / etc + 1 => expr, + .. => expr, // rest / etc } // Mutable binding in pattern diff --git a/content/docs/guide/structs-enums.mdx b/content/docs/guide/structs-enums.mdx index e047bb3..05922f3 100644 --- a/content/docs/guide/structs-enums.mdx +++ b/content/docs/guide/structs-enums.mdx @@ -7,12 +7,14 @@ icon: Box ### Structs ```mist -pub struct Point { +pub struct Point +{ i32 x, i32 y, } -pub struct Generic { +pub struct Generic +{ T value, } ``` @@ -20,7 +22,8 @@ pub struct Generic { Fields can be public or private: ```mist -struct User { +struct User +{ pub str& name, i32 age, // private } @@ -29,12 +32,14 @@ struct User { ### Enums ```mist -pub enum Option { +pub enum Option +{ Some(T), None, } -pub enum Message { +pub enum Message +{ Quit, Move(i32, i32), Write { str& content, i32 length }, diff --git a/content/docs/guide/traits-impls.mdx b/content/docs/guide/traits-impls.mdx index 4a6370a..022dfbd 100644 --- a/content/docs/guide/traits-impls.mdx +++ b/content/docs/guide/traits-impls.mdx @@ -7,11 +7,13 @@ icon: Puzzle ### Traits ```mist -pub trait Drawable { +pub trait Drawable +{ void draw(&self); } -pub trait Comparable : Eq { +pub trait Comparable : Eq +{ i32 cmp(&self, T other); } ``` @@ -19,7 +21,8 @@ pub trait Comparable : Eq { Trait requirements are specified after `:`: ```mist -trait MyTrait : SuperTrait + OtherTrait { +trait MyTrait : SuperTrait + OtherTrait +{ void required_method(&self); void another(&self); } @@ -28,15 +31,18 @@ trait MyTrait : SuperTrait + OtherTrait { ### Impl Blocks ```mist -impl MyType { +impl MyType +{ void method(&self) { } } -impl Trait for MyType { +impl Trait for MyType +{ void method(&self) { } } -impl GenericTrait for MyType { +impl GenericTrait for MyType +{ void method(&self, T value) { } } ``` diff --git a/content/docs/internals/semantic-analysis.mdx b/content/docs/internals/semantic-analysis.mdx index 0359913..2cc268f 100644 --- a/content/docs/internals/semantic-analysis.mdx +++ b/content/docs/internals/semantic-analysis.mdx @@ -11,9 +11,10 @@ The semantic checker (`semantics.rs`) performs class field initialization analys The primary semantic check ensures all class fields are initialized in the constructor: ```mist -class Player { - i32 health, - str& name, +class Player +{ + i32 health; + str& name; pub constructor(str& name) { diff --git a/content/docs/internals/transpiler.mdx b/content/docs/internals/transpiler.mdx index c7d6256..b25cb75 100644 --- a/content/docs/internals/transpiler.mdx +++ b/content/docs/internals/transpiler.mdx @@ -21,8 +21,9 @@ The transpiler (`transpiler.mist` in `mist_api`) orchestrates the full pipeline. The `Module` struct represents the file-to-module mapping: -```rust -pub class Module { +```mist +pub class Module +{ pub String name; pub PathBuf path; pub Vec children;