Merge pull request #14 from mist-go/docs-allman-fixes

Fix Allman brace style and field terminator consistency across docs
This commit is contained in:
2026-07-03 22:24:27 +02:00
committed by GitHub
9 changed files with 185 additions and 45 deletions
+128 -7
View File
@@ -7,8 +7,9 @@ icon: Shapes
Mist introduces `class` as syntactic sugar for a Rust struct with a virtual method table (vtable). Mist introduces `class` as syntactic sugar for a Rust struct with a virtual method table (vtable).
```mist ```mist
pub class Animal { pub class Animal
str& name, {
str& name;
pub constructor(str& name) pub constructor(str& name)
{ {
@@ -25,19 +26,21 @@ pub class Animal {
Class fields can have default initializers: Class fields can have default initializers:
```mist ```mist
class Player { class Player
i32 health = 100, {
str& name, i32 health = 100;
str& name;
} }
``` ```
### Inheritance ### Inheritance
```mist ```mist
class Dog : Animal { class Dog : Animal
{
pub constructor(str& name) pub constructor(str& name)
{ {
super(name); super = Super::new(name);
} }
void speak(&self) override 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 ### Under the Hood
A class `Dog : Animal` generates: 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)` 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. 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::<Self>::zeroed().assume_init() };
let _: &Target = this; // Forces compiler to check Deref<Target = Target>
}
```
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.
+18 -10
View File
@@ -7,17 +7,20 @@ icon: ArrowLeftRight
### If/Else ### If/Else
```mist ```mist
if condition { if condition
{
// body // body
} else if other_condition { }
else if other_condition
{
// body // body
} else { }
else
{
// body // body
} }
``` ```
Conditions must be parenthesized: `if (expr) { }` or `if expr_no_struct { }` (struct literals require parentheses).
Used as an expression: Used as an expression:
```mist ```mist
@@ -27,7 +30,8 @@ let x = if true { 1 } else { 2 };
### While ### While
```mist ```mist
while condition { while condition
{
// body // body
} }
``` ```
@@ -35,11 +39,13 @@ while condition {
### For ### For
```mist ```mist
for pattern in iterator { for pattern in iterator
{
// body // body
} }
for i in 0 .. 10 { for i in 0 .. 10
{
// body // body
} }
``` ```
@@ -47,7 +53,8 @@ for i in 0 .. 10 {
### C-Style For ### C-Style For
```mist ```mist
for (let mut i = 0; i < 10; i++) { for (let mut i = 0; i < 10; i++)
{
// body // body
} }
``` ```
@@ -55,7 +62,8 @@ for (let mut i = 0; i < 10; i++) {
### Loop ### Loop
```mist ```mist
loop { loop
{
// infinite loop // infinite loop
} }
``` ```
+1 -5
View File
@@ -42,13 +42,9 @@ unsafe i32 dangerous()
} }
``` ```
Function syntax: `[pub] [void | <type>] <name>[<generics>](<params>) [override] { <body> }`
Functions use **Allman brace style** (opening brace on the next line).
### Self Parameter ### 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 ```mist
pub void set_value(&mut self, i32 v) pub void set_value(&mut self, i32 v)
+6 -4
View File
@@ -12,15 +12,17 @@ T id<T>(T x)
} }
// Generic struct // Generic struct
struct Pair<A, B> { struct Pair<A, B>
{
A first, A first,
B second, B second,
} }
// Generic enum // Generic enum
enum Result<T, E> { enum Result<T, E>
Ok(T), {
Err(E), Ok(T);
Err(E);
} }
// Generic with trait bounds // Generic with trait bounds
+3 -3
View File
@@ -25,11 +25,11 @@ match value {
// Named tuple patterns (newtype) // Named tuple patterns (newtype)
let MyType(value) = my_var; let MyType(value) = my_var;
// Wildcard / etc // Wildcard / rest
let _ = get_side_effect(); let _ = get_side_effect();
match x { match x {
1 => ..., 1 => expr,
.. => ..., // rest / etc .. => expr, // rest / etc
} }
// Mutable binding in pattern // Mutable binding in pattern
+10 -5
View File
@@ -7,12 +7,14 @@ icon: Box
### Structs ### Structs
```mist ```mist
pub struct Point { pub struct Point
{
i32 x, i32 x,
i32 y, i32 y,
} }
pub struct Generic<T> { pub struct Generic<T>
{
T value, T value,
} }
``` ```
@@ -20,7 +22,8 @@ pub struct Generic<T> {
Fields can be public or private: Fields can be public or private:
```mist ```mist
struct User { struct User
{
pub str& name, pub str& name,
i32 age, // private i32 age, // private
} }
@@ -29,12 +32,14 @@ struct User {
### Enums ### Enums
```mist ```mist
pub enum Option<T> { pub enum Option<T>
{
Some(T), Some(T),
None, None,
} }
pub enum Message { pub enum Message
{
Quit, Quit,
Move(i32, i32), Move(i32, i32),
Write { str& content, i32 length }, Write { str& content, i32 length },
+12 -6
View File
@@ -7,11 +7,13 @@ icon: Puzzle
### Traits ### Traits
```mist ```mist
pub trait Drawable { pub trait Drawable
{
void draw(&self); void draw(&self);
} }
pub trait Comparable<T> : Eq { pub trait Comparable<T> : Eq
{
i32 cmp(&self, T other); i32 cmp(&self, T other);
} }
``` ```
@@ -19,7 +21,8 @@ pub trait Comparable<T> : Eq {
Trait requirements are specified after `:`: Trait requirements are specified after `:`:
```mist ```mist
trait MyTrait : SuperTrait + OtherTrait { trait MyTrait : SuperTrait + OtherTrait
{
void required_method(&self); void required_method(&self);
void another(&self); void another(&self);
} }
@@ -28,15 +31,18 @@ trait MyTrait : SuperTrait + OtherTrait {
### Impl Blocks ### Impl Blocks
```mist ```mist
impl MyType { impl MyType
{
void method(&self) { } void method(&self) { }
} }
impl Trait for MyType { impl Trait for MyType
{
void method(&self) { } void method(&self) { }
} }
impl<T> GenericTrait<T> for MyType { impl<T> GenericTrait<T> for MyType
{
void method(&self, T value) { } void method(&self, T value) { }
} }
``` ```
+4 -3
View File
@@ -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: The primary semantic check ensures all class fields are initialized in the constructor:
```mist ```mist
class Player { class Player
i32 health, {
str& name, i32 health;
str& name;
pub constructor(str& name) pub constructor(str& name)
{ {
+3 -2
View File
@@ -21,8 +21,9 @@ The transpiler (`transpiler.mist` in `mist_api`) orchestrates the full pipeline.
The `Module` struct represents the file-to-module mapping: The `Module` struct represents the file-to-module mapping:
```rust ```mist
pub class Module { pub class Module
{
pub String name; pub String name;
pub PathBuf path; pub PathBuf path;
pub Vec<Module> children; pub Vec<Module> children;