capy-language / capy

🍊 A statically typed, compiled programming language, largely inspired by Jai, Odin, and Zig.
Apache License 2.0
64 stars 4 forks source link

`todo!` reached when trying to compile function, dependent on constant with double comptime #17

Closed lenawanel closed 8 months ago

lenawanel commented 1 year ago

input:

a :: comptime { b };
b :: comptime { 30 };

main :: () -> i32 {
    a 
}

backtrace:

thread 'main' panicked at crates/codegen/src/compiler/functions.rs:258:17:
not yet implemented: Oh shit I forgot to account for this possibility
stack backtrace:
   0: rust_begin_unwind
             at /rustc/030e4d382f1df30240408540f25cd1ccc8dbbf50/library/std/src/panicking.rs:619:5
   1: core::panicking::panic_fmt
             at /rustc/030e4d382f1df30240408540f25cd1ccc8dbbf50/library/core/src/panicking.rs:72:14
   2: codegen::compiler::functions::FunctionCompiler::compile_global
             at ./crates/codegen/src/compiler/functions.rs:258:17
   3: codegen::compiler::functions::FunctionCompiler::compile_expr_with_args
             at ./crates/codegen/src/compiler/functions.rs:1186:43
   4: codegen::compiler::functions::FunctionCompiler::compile_expr_with_args
             at ./crates/codegen/src/compiler/functions.rs:1043:21
   5: codegen::compiler::functions::FunctionCompiler::compile_expr
             at ./crates/codegen/src/compiler/functions.rs:508:9
   6: codegen::compiler::functions::FunctionCompiler::finish
             at ./crates/codegen/src/compiler/functions.rs:131:15
   7: codegen::compiler::Compiler::compile_function
             at ./crates/codegen/src/compiler/mod.rs:227:9
   8: codegen::compiler::comptime::eval_comptime_blocks
             at ./crates/codegen/src/compiler/comptime.rs:102:23
   9: capy::compile_file
             at ./crates/capy/src/main.rs:342:28
NotAFlyingGoose commented 1 year ago

Oh yeah lol 😅

I'm not really sure on this one. At first I was thinking of just "running" the global every single time it is used within a comptime block, but that's probably not the behavior people would expect, especially if you reference a global multiple times.

This could probably be solved if the compiler could see what the most deeply nested comptime blocks are, before running those first. This wouldn't work if comptimes have the possibility of being recursive (which I'm not sure of, and which should probably be tested).

Either way this would require a rethink of how comptime's are currently being evaluated.

NotAFlyingGoose commented 8 months ago

If a global contains a comptime that hasn't been evaluated yet (this issue), the global will now expand to the body of the global.

e.g.

a :: comptime 42;

foo :: () -> i32 {
  a // assuming `a` hasn't been evaluated yet
}

now gets compiled to

foo :: () -> i32 {
  if comptime_0.initialized {
    comptime_0
  } else {
    comptime_0.initialized = true;

    // calculate the value of the comptime
    42
  }
}

(not technically true but gives the idea)

This expansion only happens at compile-time--the final binary will have each comptime replaced with it's constant value just as before.

This change also ensures that every comptime block gets run once, and only once.