Skip to content
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

**Copyright © 2026 ViudiraTech · Code by JiTianYu391**

- Borrow checker: implicit reborrow when a `mutref` is passed to a `mutref` parameter, explicit `borrow [mut] deref r` reborrows (including nested and through reference parameters), and checking of writes through references (`deref r = v`) against live loans and moves. `consume(first); consume(first)` on a `mutref` is now accepted, as in Rust; `val second = first` still moves.
- Split `borrow.cpp`, `sema.cpp`, `codegen.cpp` and `mir.cpp` into focused translation units (no behavior change; LLVM IR for all examples and tests is byte-identical).
- SMP check: a local or parameter that shadows a mutable global is no longer reported as a global access (`E0363`), and the call-graph and shared-state walkers now share one AST traversal so they cannot drift apart.
- Fixed a heap-use-after-free in `uinx::Type` copy assignment (`t = *t.pointee`) found by AddressSanitizer.
- Repository hygiene: added `CMakePresets.json`, GitHub Actions CI (GCC, Clang, ASan/UBSan, clang-format), issue/PR templates, `CONTRIBUTING.md`, `.editorconfig` and `.gitattributes`; moved `ARCHITECTURE.md` and `BUILD.md` into `docs/`; moved test registration into `tests/CMakeLists.txt`; added `UINX_WARNINGS_AS_ERRORS` and `UINX_ENABLE_SANITIZERS` options; removed the stale `MANIFEST.sha256` and checked-in `verification/` transcripts.
- Reworked borrow checking around backward liveness plus forward control-flow fixed points instead of block-local statement numbering.
Expand Down
15 changes: 15 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,23 @@ add_library(uinx_compiler
src/parser.cpp
src/types.cpp
src/sema.cpp
src/sema_resolve.cpp
src/sema_smp.cpp
src/sema_stmt.cpp
src/sema_expr.cpp
src/borrow.cpp
src/borrow_places.cpp
src/borrow_loans.cpp
src/borrow_liveness.cpp
src/borrow_flow.cpp
src/mir.cpp
src/mir_stmt.cpp
src/mir_expr.cpp
src/mir_optimizer.cpp
src/codegen.cpp
src/codegen_asm.cpp
src/codegen_async.cpp
src/codegen_function.cpp
src/compiler.cpp
)
target_include_directories(uinx_compiler PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
Expand Down Expand Up @@ -74,6 +88,7 @@ if(CLANG_FORMAT_EXECUTABLE)
file(GLOB_RECURSE UINX_FORMAT_SOURCES CONFIGURE_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp
${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/*.hpp
${CMAKE_CURRENT_SOURCE_DIR}/tools/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/runtime/*.c
${CMAKE_CURRENT_SOURCE_DIR}/runtime/*.h
Expand Down
8 changes: 4 additions & 4 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,25 @@ The parser recognizes functions, structs, generic parameters and bounds, traits,

## Resolution and semantic model

`src/sema.cpp` collects declarations, resolves names and builds `SemanticModel`. Function signatures retain generic parameters, trait bounds, receiver types, safety and async properties. Trait implementations are checked for duplicate implementations, duplicate methods, missing methods and signature mismatch.
`src/sema.cpp` collects declarations and builds `SemanticModel`; name resolution and the trait solver live in `src/sema_resolve.cpp`, statement and expression checking in `src/sema_stmt.cpp` and `src/sema_expr.cpp`, and concurrency propagation plus the `E0363` shared-state check in `src/sema_smp.cpp`. Function signatures retain generic parameters, trait bounds, receiver types, safety and async properties. Trait implementations are checked for duplicate implementations, duplicate methods, missing methods and signature mismatch.

Type inference is local and constraint-oriented: declared parameter/result types are fixed while local bindings infer from initializers. Generic function calls infer type arguments from actual argument types when explicit arguments are not supplied.

## Ownership and borrowing

`src/borrow.cpp` tracks places, moves and loans. A place may be a local, a field path or a conservatively normalized indexed path. Shared borrows may coexist; active mutable loans are exclusive. Mutable references are affine and cannot be implicitly copied.
`src/borrow.cpp` drives statement-level checking and tracks places, moves and loans (place helpers in `borrow_places.cpp`, loan creation/access/reborrows in `borrow_loans.cpp`, liveness in `borrow_liveness.cpp`, branch/loop state merging and expression inspection in `borrow_flow.cpp`). A place may be a local, a field path or a conservatively normalized indexed path. Shared borrows may coexist; active mutable loans are exclusive. Mutable references are affine and cannot be implicitly copied.

Last-use information shortens loans before lexical scope end, providing NLL-style behavior. Field paths permit disjoint field borrowing. Indexed paths intentionally alias conservatively unless a stronger proof is available.

## MIR

`src/mir.cpp` lowers typed AST into control-flow blocks and typed instructions. MIR contains storage slots, loads/stores, arithmetic, comparisons, branch/jump, calls, casts, field and index addresses, struct construction, inline assembly, await operations and explicit scope drops.
`src/mir.cpp`, `mir_stmt.cpp` and `mir_expr.cpp` lower typed AST into control-flow blocks and typed instructions. MIR contains storage slots, loads/stores, arithmetic, comparisons, branch/jump, calls, casts, field and index addresses, struct construction, inline assembly, await operations and explicit scope drops.

The MIR optimizer removes instructions unreachable after terminators and canonicalizes the emitted block stream. LLVM optimization levels are then delegated to Clang during object generation.

## LLVM backend

`src/codegen.cpp` serializes valid textual LLVM IR. It emits named struct layouts, specialized generic layouts, function definitions/declarations, control flow, GEPs, slice bounds checks, inline assembly and async state machines.
`src/codegen.cpp` serializes valid textual LLVM IR (functions in `codegen_function.cpp`, async state machines in `codegen_async.cpp`, inline assembly and syscalls in `codegen_asm.cpp`). It emits named struct layouts, specialized generic layouts, function definitions/declarations, control flow, GEPs, slice bounds checks, inline assembly and async state machines.

The backend does not generate C or C++. The driver writes `.ll`, asks Clang to compile LLVM IR into an object, and performs linking as a separate process. This preserves the required `IR -> Object -> Link` boundary.

Expand Down
9 changes: 9 additions & 0 deletions docs/MEMORY_MODEL.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ MIR/code generation:
shared-like, inspects args, then activates to exclusive. This accepts
`v.push(v.len())`. Function `borrow mut` args and `x += x` compound
assignment use the same reservation/activation protocol;
- passing a `mutref` place to a `mutref` parameter reborrows it for the call
instead of moving it (`inc(r); inc(r)`); a second use of the same reference in
the same argument list conflicts, and a call whose result may carry a
reference still moves the argument;
- `borrow deref r` / `borrow mut deref r` reborrow through `r`: the new
reference inherits `r`'s origins without conflicting with `r`'s own loans,
and `r` (and every ancestor of a nested reborrow) is frozen while the
reborrow is live. Writes through a reference (`deref r = v`) respect loans
on `r` and reject a moved `r`;
- reference provenance through bindings, aggregates, calls, method receivers;
- stack references cannot escape scope/function (`E0404/E0405`);
- branch/loop fixed-point merging; NLL-style loan expiry via backward
Expand Down
25 changes: 22 additions & 3 deletions include/uinx/borrow.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ class BorrowChecker {
std::string place;
SourceRange range{};
bool mut{false};
// Reference places this origin was reborrowed through (`borrow deref r`),
// nearest first. Loans held by those references do not conflict with the
// reborrow, and they stay frozen for as long as the reborrow lives.
std::vector<std::string> via;
};
struct State {
std::unordered_set<std::string> moved;
Expand Down Expand Up @@ -99,13 +103,28 @@ class BorrowChecker {
bool is_copy_type(const Type& type) const;
bool states_equivalent(const State& a, const State& b) const;

void
access_place(const std::string& place, const SourceRange& range, Access access, State& state);
void access_place(const std::string& place,
const SourceRange& range,
Access access,
State& state,
const std::vector<std::string>& via = {});
void begin_borrow(const std::string& place,
std::string borrower,
bool mut,
const SourceRange& range,
State& state);
State& state,
const std::vector<std::string>& via = {});
// `borrow deref r` reborrows through the reference place `r`.
std::optional<std::string> reborrow_parent(const ast::Expr& target) const;
// Writing through a reference (`deref r = v`) must respect loans on `r`.
void write_through_reference(const ast::Expr& target, State& state);
// Implicit reborrow of a `mutref` argument passed to a `mutref` parameter.
bool is_reborrow_argument(const ast::CallExpr& call, std::size_t index) const;
void inspect_call_argument(const ast::CallExpr& call,
std::size_t index,
std::vector<std::string>& guards,
State& state);
void release_call_guards(const std::vector<std::string>& guards, State& state);
// Two-phase borrow protocol (rustc two-phase borrows):
// reservation acts as shared, activation upgrades to exclusive.
void begin_two_phase_reservation(const std::string& place,
Expand Down
Loading
Loading