Skip to content

Commit 2adc6ac

Browse files
jfechermichaeljklein
andauthored
fix: Filter comptime globals (#5538)
# Description ## Problem\* Comptime globals were not being added to the list of `comptime` items ## Summary\* ## Additional Context ## Documentation\* Check one: - [x] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings. --------- Co-authored-by: Michael J Klein <[email protected]>
1 parent d85bf61 commit 2adc6ac

6 files changed

Lines changed: 110 additions & 65 deletions

File tree

compiler/noirc_frontend/src/elaborator/comptime.rs

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::mem::replace;
2-
31
use crate::{
42
hir_def::expr::HirIdent,
53
node_interner::{DependencyId, FuncId},
@@ -11,42 +9,40 @@ impl<'context> Elaborator<'context> {
119
/// Elaborate an expression from the middle of a comptime scope.
1210
/// When this happens we require additional information to know
1311
/// what variables should be in scope.
14-
pub fn elaborate_item_from_comptime<T>(
15-
&mut self,
12+
pub fn elaborate_item_from_comptime<'a, T>(
13+
&'a mut self,
1614
current_function: Option<FuncId>,
17-
f: impl FnOnce(&mut Self) -> T,
15+
f: impl FnOnce(&mut Elaborator<'a>) -> T,
1816
) -> T {
19-
self.function_context.push(FunctionContext::default());
20-
let old_scope = self.scopes.end_function();
21-
self.scopes.start_function();
22-
let function_id = current_function.map(DependencyId::Function);
23-
let old_item = replace(&mut self.current_item, function_id);
17+
// Create a fresh elaborator to ensure no state is changed from
18+
// this elaborator
19+
let mut elaborator = Elaborator::new(
20+
self.interner,
21+
self.def_maps,
22+
self.crate_id,
23+
self.debug_comptime_in_file,
24+
);
2425

25-
// Note: recover_generics isn't good enough here because any existing generics
26-
// should not be in scope of this new function
27-
let old_generics = std::mem::take(&mut self.generics);
26+
elaborator.function_context.push(FunctionContext::default());
27+
elaborator.scopes.start_function();
2828

29-
let old_crate_and_module = current_function.map(|function| {
30-
let meta = self.interner.function_meta(&function);
31-
let old_crate = replace(&mut self.crate_id, meta.source_crate);
32-
let old_module = replace(&mut self.local_module, meta.source_module);
33-
self.introduce_generics_into_scope(meta.all_generics.clone());
34-
(old_crate, old_module)
35-
});
29+
if let Some(function) = current_function {
30+
let meta = elaborator.interner.function_meta(&function);
31+
elaborator.current_item = Some(DependencyId::Function(function));
32+
elaborator.crate_id = meta.source_crate;
33+
elaborator.local_module = meta.source_module;
34+
elaborator.file = meta.source_file;
35+
elaborator.introduce_generics_into_scope(meta.all_generics.clone());
36+
}
3637

37-
self.populate_scope_from_comptime_scopes();
38-
let result = f(self);
38+
elaborator.comptime_scopes = std::mem::take(&mut self.comptime_scopes);
39+
elaborator.populate_scope_from_comptime_scopes();
3940

40-
if let Some((old_crate, old_module)) = old_crate_and_module {
41-
self.crate_id = old_crate;
42-
self.local_module = old_module;
43-
}
41+
let result = f(&mut elaborator);
42+
elaborator.check_and_pop_function_context();
4443

45-
self.generics = old_generics;
46-
self.current_item = old_item;
47-
self.scopes.end_function();
48-
self.scopes.0.push(old_scope);
49-
self.check_and_pop_function_context();
44+
self.comptime_scopes = elaborator.comptime_scopes;
45+
self.errors.append(&mut elaborator.errors);
5046
result
5147
}
5248

compiler/noirc_frontend/src/elaborator/mod.rs

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::{
1515
},
1616
dc_mod,
1717
},
18+
def_map::DefMaps,
1819
resolution::{errors::ResolverError, path_resolver::PathResolver},
1920
scope::ScopeForest as GenericScopeForest,
2021
type_check::TypeCheckError,
@@ -54,7 +55,7 @@ use crate::{
5455
use crate::{
5556
hir::{
5657
def_collector::dc_crate::{UnresolvedFunctions, UnresolvedTraitImpl},
57-
def_map::{CrateDefMap, ModuleData},
58+
def_map::ModuleData,
5859
},
5960
hir_def::traits::TraitImpl,
6061
macros_api::ItemVisibility,
@@ -102,7 +103,7 @@ pub struct Elaborator<'context> {
102103

103104
pub(crate) interner: &'context mut NodeInterner,
104105

105-
def_maps: &'context mut BTreeMap<CrateId, CrateDefMap>,
106+
def_maps: &'context mut DefMaps,
106107

107108
file: FileId,
108109

@@ -130,8 +131,6 @@ pub struct Elaborator<'context> {
130131
/// to the corresponding trait impl ID.
131132
current_trait_impl: Option<TraitImplId>,
132133

133-
trait_id: Option<TraitId>,
134-
135134
/// In-resolution names
136135
///
137136
/// This needs to be a set because we can have multiple in-resolution
@@ -195,22 +194,22 @@ struct FunctionContext {
195194

196195
impl<'context> Elaborator<'context> {
197196
pub fn new(
198-
context: &'context mut Context,
197+
interner: &'context mut NodeInterner,
198+
def_maps: &'context mut DefMaps,
199199
crate_id: CrateId,
200200
debug_comptime_in_file: Option<FileId>,
201201
) -> Self {
202202
Self {
203203
scopes: ScopeForest::default(),
204204
errors: Vec::new(),
205-
interner: &mut context.def_interner,
206-
def_maps: &mut context.def_maps,
205+
interner,
206+
def_maps,
207207
file: FileId::dummy(),
208208
nested_loops: 0,
209209
generics: Vec::new(),
210210
lambda_stack: Vec::new(),
211211
self_type: None,
212212
current_item: None,
213-
trait_id: None,
214213
local_module: LocalModuleId::dummy_id(),
215214
crate_id,
216215
resolving_ids: BTreeSet::new(),
@@ -223,6 +222,19 @@ impl<'context> Elaborator<'context> {
223222
}
224223
}
225224

225+
pub fn from_context(
226+
context: &'context mut Context,
227+
crate_id: CrateId,
228+
debug_comptime_in_file: Option<FileId>,
229+
) -> Self {
230+
Self::new(
231+
&mut context.def_interner,
232+
&mut context.def_maps,
233+
crate_id,
234+
debug_comptime_in_file,
235+
)
236+
}
237+
226238
pub fn elaborate(
227239
context: &'context mut Context,
228240
crate_id: CrateId,
@@ -238,7 +250,7 @@ impl<'context> Elaborator<'context> {
238250
items: CollectedItems,
239251
debug_comptime_in_file: Option<FileId>,
240252
) -> Self {
241-
let mut this = Self::new(context, crate_id, debug_comptime_in_file);
253+
let mut this = Self::from_context(context, crate_id, debug_comptime_in_file);
242254

243255
// Filter out comptime items to execute their functions first if needed.
244256
// This step is why comptime items can only refer to other comptime items
@@ -337,17 +349,12 @@ impl<'context> Elaborator<'context> {
337349
}
338350

339351
fn elaborate_functions(&mut self, functions: UnresolvedFunctions) {
340-
self.file = functions.file_id;
341-
self.trait_id = functions.trait_id; // TODO: Resolve?
342-
self.self_type = functions.self_type;
343-
344-
for (local_module, id, _) in functions.functions {
345-
self.local_module = local_module;
346-
self.recover_generics(|this| this.elaborate_function(id));
352+
for (_, id, _) in functions.functions {
353+
self.elaborate_function(id);
347354
}
348355

356+
self.generics.clear();
349357
self.self_type = None;
350-
self.trait_id = None;
351358
}
352359

353360
fn introduce_generics_into_scope(&mut self, all_generics: Vec<ResolvedGeneric>) {
@@ -365,7 +372,7 @@ impl<'context> Elaborator<'context> {
365372
self.generics = all_generics;
366373
}
367374

368-
fn elaborate_function(&mut self, id: FuncId) {
375+
pub(crate) fn elaborate_function(&mut self, id: FuncId) {
369376
let func_meta = self.interner.func_meta.get_mut(&id);
370377
let func_meta =
371378
func_meta.expect("FuncMetas should be declared before a function is elaborated");
@@ -378,11 +385,21 @@ impl<'context> Elaborator<'context> {
378385
FunctionBody::Resolving => return,
379386
};
380387

388+
let func_meta = func_meta.clone();
389+
390+
assert_eq!(
391+
self.crate_id, func_meta.source_crate,
392+
"Functions in other crates should be already elaborated"
393+
);
394+
395+
self.local_module = func_meta.source_module;
396+
self.file = func_meta.source_file;
397+
self.self_type = func_meta.self_type.clone();
398+
self.current_trait_impl = func_meta.trait_impl;
399+
381400
self.scopes.start_function();
382401
let old_item = std::mem::replace(&mut self.current_item, Some(DependencyId::Function(id)));
383402

384-
let func_meta = func_meta.clone();
385-
386403
self.trait_bounds = func_meta.trait_constraints.clone();
387404
self.function_context.push(FunctionContext::default());
388405

@@ -775,6 +792,8 @@ impl<'context> Elaborator<'context> {
775792
source_crate: self.crate_id,
776793
source_module: self.local_module,
777794
function_body: FunctionBody::Unresolved(func.kind, body, func.def.span),
795+
self_type: self.self_type.clone(),
796+
source_file: self.file,
778797
};
779798

780799
self.interner.push_fn_meta(meta, func_id);
@@ -1003,10 +1022,7 @@ impl<'context> Elaborator<'context> {
10031022
self.self_type = None;
10041023
}
10051024

1006-
fn get_module_mut(
1007-
def_maps: &mut BTreeMap<CrateId, CrateDefMap>,
1008-
module: ModuleId,
1009-
) -> &mut ModuleData {
1025+
fn get_module_mut(def_maps: &mut DefMaps, module: ModuleId) -> &mut ModuleData {
10101026
let message = "A crate should always be present for a given crate id";
10111027
&mut def_maps.get_mut(&module.krate).expect(message).modules[module.local_id.0]
10121028
}
@@ -1528,19 +1544,23 @@ impl<'context> Elaborator<'context> {
15281544
let (comptime_structs, structs) =
15291545
items.types.into_iter().partition(|typ| typ.1.struct_def.is_comptime);
15301546

1547+
let (comptime_globals, globals) =
1548+
items.globals.into_iter().partition(|global| global.stmt_def.comptime);
1549+
15311550
let comptime = CollectedItems {
15321551
functions: comptime_function_sets,
15331552
types: comptime_structs,
15341553
type_aliases: BTreeMap::new(),
15351554
traits: BTreeMap::new(),
15361555
trait_impls: comptime_trait_impls,
1537-
globals: Vec::new(),
1556+
globals: comptime_globals,
15381557
impls: rustc_hash::FxHashMap::default(),
15391558
};
15401559

15411560
items.functions = function_sets;
15421561
items.trait_impls = trait_impls;
15431562
items.types = structs;
1563+
items.globals = globals;
15441564
(comptime, items)
15451565
}
15461566

compiler/noirc_frontend/src/elaborator/types.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,8 @@ impl<'context> Elaborator<'context> {
412412
&mut self,
413413
path: &Path,
414414
) -> Option<(TraitMethodId, TraitConstraint, bool)> {
415-
let trait_id = self.trait_id?;
415+
let trait_impl = self.current_trait_impl?;
416+
let trait_id = self.interner.try_get_trait_implementation(trait_impl)?.borrow().trait_id;
416417

417418
if path.kind == PathKind::Plain && path.segments.len() == 2 {
418419
let name = &path.segments[0].0.contents;

compiler/noirc_frontend/src/hir/comptime/interpreter.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::ast::{BinaryOpKind, FunctionKind, IntegerBitSize, Signedness};
1111
use crate::elaborator::Elaborator;
1212
use crate::graph::CrateId;
1313
use crate::hir_def::expr::ImplKind;
14+
use crate::hir_def::function::FunctionBody;
1415
use crate::macros_api::UnaryOp;
1516
use crate::monomorphization::{
1617
perform_impl_bindings, perform_instantiation_bindings, resolve_trait_method,
@@ -135,18 +136,35 @@ impl<'local, 'interner> Interpreter<'local, 'interner> {
135136
self.define_pattern(parameter, typ, argument, arg_location)?;
136137
}
137138

138-
let function_body =
139-
self.elaborator.interner.function(&function).try_as_expr().ok_or_else(|| {
140-
let function = self.elaborator.interner.function_name(&function).to_owned();
141-
InterpreterError::NonComptimeFnCallInSameCrate { function, location }
142-
})?;
143-
139+
let function_body = self.get_function_body(function, location)?;
144140
let result = self.evaluate(function_body)?;
145-
146141
self.exit_function(previous_state);
147142
Ok(result)
148143
}
149144

145+
/// Try to retrieve a function's body.
146+
/// If the function has not yet been resolved this will attempt to lazily resolve it.
147+
/// Afterwards, if the function's body is still not known or the function is still
148+
/// in a Resolving state we issue an error.
149+
fn get_function_body(&mut self, function: FuncId, location: Location) -> IResult<ExprId> {
150+
let meta = self.elaborator.interner.function_meta(&function);
151+
match self.elaborator.interner.function(&function).try_as_expr() {
152+
Some(body) => Ok(body),
153+
None => {
154+
if matches!(&meta.function_body, FunctionBody::Unresolved(..)) {
155+
self.elaborator.elaborate_item_from_comptime(None, |elaborator| {
156+
elaborator.elaborate_function(function);
157+
});
158+
159+
self.get_function_body(function, location)
160+
} else {
161+
let function = self.elaborator.interner.function_name(&function).to_owned();
162+
Err(InterpreterError::NonComptimeFnCallInSameCrate { function, location })
163+
}
164+
}
165+
}
166+
}
167+
150168
fn call_special(
151169
&mut self,
152170
function: FuncId,

compiler/noirc_frontend/src/hir/def_map/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@ impl ModuleId {
4848
}
4949

5050
impl ModuleId {
51-
pub fn module(self, def_maps: &BTreeMap<CrateId, CrateDefMap>) -> &ModuleData {
51+
pub fn module(self, def_maps: &DefMaps) -> &ModuleData {
5252
&def_maps[&self.krate].modules()[self.local_id.0]
5353
}
5454
}
5555

56+
pub type DefMaps = BTreeMap<CrateId, CrateDefMap>;
57+
5658
/// Map of all modules and scopes defined within a crate.
5759
///
5860
/// The definitions of the crate are accessible indirectly via the scopes of each module.

compiler/noirc_frontend/src/hir_def/function.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use fm::FileId;
12
use iter_extended::vecmap;
23
use noirc_errors::{Location, Span};
34

@@ -156,6 +157,13 @@ pub struct FuncMeta {
156157

157158
/// The module this function was defined in
158159
pub source_module: LocalModuleId,
160+
161+
/// THe file this function was defined in
162+
pub source_file: FileId,
163+
164+
/// If this function is from an impl (trait or regular impl), this
165+
/// is the object type of the impl. Otherwise this is None.
166+
pub self_type: Option<Type>,
159167
}
160168

161169
#[derive(Debug, Clone)]

0 commit comments

Comments
 (0)