Deterministic artifact graph - bring back the clockwork universe (#7483)
* Change to use deterministic artifact graph * Update output to use the new order * Fix to clear everything when scene is cleared * Fix lots * Update artifact graph output for the last time * Delete unused sorting code * Remove unneeded cfg * Fix to preserve top-level artifacts when there's an error * Update output after error fix * Add better doc comments * Remove duplicate global operations * Update comments * Update ignored tests that were flaky * Update graph for new samples after rebase * Fix test assertion message
This commit is contained in:
@ -519,6 +519,12 @@ impl ExecutorContext {
|
||||
exec_state: &mut ExecState,
|
||||
source_range: crate::execution::SourceRange,
|
||||
) -> Result<(), KclError> {
|
||||
// Ensure artifacts are cleared so that we don't accumulate them across
|
||||
// runs.
|
||||
exec_state.mod_local.artifacts.clear();
|
||||
exec_state.global.root_module_artifacts.clear();
|
||||
exec_state.global.artifacts.clear();
|
||||
|
||||
self.engine
|
||||
.clear_scene(&mut exec_state.mod_local.id_generator, source_range)
|
||||
.await
|
||||
@ -650,8 +656,8 @@ impl ExecutorContext {
|
||||
let (new_universe, new_universe_map) =
|
||||
self.get_universe(&program, &mut new_exec_state).await?;
|
||||
|
||||
let clear_scene = new_universe.keys().any(|key| {
|
||||
let id = new_universe[key].1;
|
||||
let clear_scene = new_universe.values().any(|value| {
|
||||
let id = value.1;
|
||||
match (
|
||||
cached_state.exec_state.get_source(id),
|
||||
new_exec_state.global.get_source(id),
|
||||
@ -965,11 +971,10 @@ impl ExecutorContext {
|
||||
// Since we haven't technically started executing the root module yet,
|
||||
// the operations corresponding to the imports will be missing unless we
|
||||
// track them here.
|
||||
#[cfg(all(test, feature = "artifact-graph"))]
|
||||
exec_state
|
||||
.global
|
||||
.root_module_artifacts
|
||||
.extend(exec_state.mod_local.artifacts.clone());
|
||||
.extend(std::mem::take(&mut exec_state.mod_local.artifacts));
|
||||
|
||||
self.inner_run(program, exec_state, preserve_mem).await
|
||||
}
|
||||
@ -1114,7 +1119,7 @@ impl ExecutorContext {
|
||||
// Because of execution caching, we may start with operations from a
|
||||
// previous run.
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
let start_op = exec_state.global.artifacts.operations.len();
|
||||
let start_op = exec_state.global.root_module_artifacts.operations.len();
|
||||
|
||||
self.eval_prelude(exec_state, SourceRange::from(program).start_as_range())
|
||||
.await?;
|
||||
@ -1127,32 +1132,39 @@ impl ExecutorContext {
|
||||
ModuleId::default(),
|
||||
&ModulePath::Main,
|
||||
)
|
||||
.await;
|
||||
#[cfg(all(test, feature = "artifact-graph"))]
|
||||
let exec_result = exec_result.map(|(_, env_ref, _, module_artifacts)| {
|
||||
exec_state.global.root_module_artifacts.extend(module_artifacts);
|
||||
env_ref
|
||||
});
|
||||
#[cfg(not(all(test, feature = "artifact-graph")))]
|
||||
let exec_result = exec_result.map(|(_, env_ref, _, _)| env_ref);
|
||||
.await
|
||||
.map(|(_, env_ref, _, module_artifacts)| {
|
||||
// We need to extend because it may already have operations from
|
||||
// imports.
|
||||
exec_state.global.root_module_artifacts.extend(module_artifacts);
|
||||
env_ref
|
||||
})
|
||||
.map_err(|(err, module_artifacts)| {
|
||||
if let Some(module_artifacts) = module_artifacts {
|
||||
// We need to extend because it may already have operations
|
||||
// from imports.
|
||||
exec_state.global.root_module_artifacts.extend(module_artifacts);
|
||||
}
|
||||
err
|
||||
});
|
||||
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
{
|
||||
// Fill in NodePath for operations.
|
||||
let cached_body_items = exec_state.global.artifacts.cached_body_items();
|
||||
for op in exec_state.global.artifacts.operations.iter_mut().skip(start_op) {
|
||||
for op in exec_state
|
||||
.global
|
||||
.root_module_artifacts
|
||||
.operations
|
||||
.iter_mut()
|
||||
.skip(start_op)
|
||||
{
|
||||
op.fill_node_paths(program, cached_body_items);
|
||||
}
|
||||
#[cfg(test)]
|
||||
{
|
||||
for op in exec_state.global.root_module_artifacts.operations.iter_mut() {
|
||||
op.fill_node_paths(program, cached_body_items);
|
||||
}
|
||||
for module in exec_state.global.module_infos.values_mut() {
|
||||
if let ModuleRepr::Kcl(_, Some((_, _, _, module_artifacts))) = &mut module.repr {
|
||||
for op in &mut module_artifacts.operations {
|
||||
op.fill_node_paths(program, cached_body_items);
|
||||
}
|
||||
for module in exec_state.global.module_infos.values_mut() {
|
||||
if let ModuleRepr::Kcl(_, Some((_, _, _, module_artifacts))) = &mut module.repr {
|
||||
for op in &mut module_artifacts.operations {
|
||||
op.fill_node_paths(program, cached_body_items);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1177,7 +1189,7 @@ impl ExecutorContext {
|
||||
async fn eval_prelude(&self, exec_state: &mut ExecState, source_range: SourceRange) -> Result<(), KclError> {
|
||||
if exec_state.stack().memory.requires_std() {
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
let initial_ops = exec_state.global.artifacts.operations.len();
|
||||
let initial_ops = exec_state.mod_local.artifacts.operations.len();
|
||||
|
||||
let path = vec!["std".to_owned(), "prelude".to_owned()];
|
||||
let resolved_path = ModulePath::from_std_import_path(&path)?;
|
||||
@ -1194,7 +1206,7 @@ impl ExecutorContext {
|
||||
// TODO: Should we also clear them out of each module so that they
|
||||
// don't appear in test output?
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
exec_state.global.artifacts.operations.truncate(initial_ops);
|
||||
exec_state.mod_local.artifacts.operations.truncate(initial_ops);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -2274,6 +2286,39 @@ w = f() + f()
|
||||
ctx2.close().await;
|
||||
}
|
||||
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn sim_sketch_mode_real_mock_real() {
|
||||
let ctx = ExecutorContext::new_with_default_client().await.unwrap();
|
||||
let code = r#"sketch001 = startSketchOn(XY)
|
||||
profile001 = startProfile(sketch001, at = [0, 0])
|
||||
|> line(end = [10, 0])
|
||||
|> line(end = [0, 10])
|
||||
|> line(end = [-10, 0])
|
||||
|> line(end = [0, -10])
|
||||
|> close()
|
||||
"#;
|
||||
let program = crate::Program::parse_no_errs(code).unwrap();
|
||||
let result = ctx.run_with_caching(program).await.unwrap();
|
||||
assert_eq!(result.operations.len(), 1);
|
||||
|
||||
let mock_ctx = ExecutorContext::new_mock(None).await;
|
||||
let mock_program = crate::Program::parse_no_errs(code).unwrap();
|
||||
let mock_result = mock_ctx.run_mock(mock_program, true).await.unwrap();
|
||||
assert_eq!(mock_result.operations.len(), 0);
|
||||
|
||||
let code2 = code.to_owned()
|
||||
+ r#"
|
||||
extrude001 = extrude(profile001, length = 10)
|
||||
"#;
|
||||
let program2 = crate::Program::parse_no_errs(&code2).unwrap();
|
||||
let result = ctx.run_with_caching(program2).await.unwrap();
|
||||
assert_eq!(result.operations.len(), 2);
|
||||
|
||||
ctx.close().await;
|
||||
mock_ctx.close().await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn read_tag_version() {
|
||||
let ast = r#"fn bar(@t) {
|
||||
|
Reference in New Issue
Block a user