Skip to content

Commit 6d7c543

Browse files
authored
fix: allow referring to comptime locals at runtime (#7681)
1 parent dfb2c26 commit 6d7c543

File tree

4 files changed

+45
-4
lines changed

4 files changed

+45
-4
lines changed

compiler/noirc_frontend/src/elaborator/patterns.rs

+24-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ use crate::{
1717
expr::{HirExpression, HirIdent, HirMethodReference, ImplKind, TraitMethod},
1818
stmt::HirPattern,
1919
},
20-
node_interner::{DefinitionId, DefinitionKind, ExprId, FuncId, GlobalId, TraitImplKind},
20+
node_interner::{
21+
DefinitionId, DefinitionInfo, DefinitionKind, ExprId, FuncId, GlobalId, TraitImplKind,
22+
},
2123
};
2224

2325
use super::{Elaborator, ResolverMeta, path_resolution::PathResolutionItem};
@@ -542,8 +544,10 @@ impl Elaborator<'_> {
542544

543545
let type_generics = item.map(|item| self.resolve_item_turbofish(item)).unwrap_or_default();
544546

545-
let definition_kind =
546-
self.interner.try_definition(definition_id).map(|definition| definition.kind.clone());
547+
let definition = self.interner.try_definition(definition_id);
548+
let is_comptime_local = !self.in_comptime_context()
549+
&& definition.is_some_and(DefinitionInfo::is_comptime_local);
550+
let definition_kind = definition.as_ref().map(|definition| definition.kind.clone());
547551

548552
let mut bindings = TypeBindings::new();
549553

@@ -574,7 +578,23 @@ impl Elaborator<'_> {
574578
let typ = self.type_check_variable_with_bindings(expr, id, generics, bindings);
575579
self.interner.push_expr_type(id, typ.clone());
576580

577-
(id, typ)
581+
// If this variable it a comptime local variable, use its current value as the final expression
582+
if is_comptime_local {
583+
let mut interpreter = self.setup_interpreter();
584+
let value = interpreter.evaluate(id);
585+
// If the value is an error it means the variable already had an error, so don't report it here again
586+
// (the error will make no sense, it will say that a non-comptime variable was referenced at runtime
587+
// but that's not true)
588+
if value.is_ok() {
589+
let (id, typ) = self.inline_comptime_value(value, location);
590+
self.debug_comptime(location, |interner| id.to_display_ast(interner).kind);
591+
(id, typ)
592+
} else {
593+
(id, typ)
594+
}
595+
} else {
596+
(id, typ)
597+
}
578598
}
579599

580600
/// Solve any generics that are part of the path before the function, for example:

compiler/noirc_frontend/src/node_interner.rs

+4
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,10 @@ impl DefinitionInfo {
573573
pub fn is_global(&self) -> bool {
574574
self.kind.is_global()
575575
}
576+
577+
pub fn is_comptime_local(&self) -> bool {
578+
self.comptime && matches!(self.kind, DefinitionKind::Local(..))
579+
}
576580
}
577581

578582
#[derive(Debug, Clone, Eq, PartialEq)]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "comptime_variable_at_runtime"
3+
type = "bin"
4+
authors = [""]
5+
6+
[dependencies]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
fn main() {
2+
comptime let mut x = 1;
3+
4+
println(x); // prints 1
5+
6+
comptime {
7+
x += 1;
8+
}
9+
10+
println(x); // prints 2
11+
}

0 commit comments

Comments
 (0)