From a7408d3bc96e45d6459bd238024f7b49179d6a86 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Sat, 27 Nov 2021 01:16:53 +0000 Subject: [PATCH] refactor: switch gc to gcmodule --- --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ args: --all cargo-release: - if: startsWith(github.ref, 'refs/tags/') + if: startsWith(github.ref, 'refs/tags/') && !endsWith(github.ref, '-test') needs: [test] runs-on: ubuntu-latest steps: --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,6 @@ [workspace] members = [ - "crates/jrsonnet-interner", - "crates/jrsonnet-parser", - "crates/jrsonnet-evaluator", - "crates/jrsonnet-stdlib", - "crates/jrsonnet-cli", - "crates/jrsonnet-types", + "crates/*", "bindings/jsonnet", "cmds/jrsonnet", ] --- a/bindings/jsonnet/Cargo.toml +++ b/bindings/jsonnet/Cargo.toml @@ -10,7 +10,7 @@ [dependencies] jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "0.4.2" } jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "0.4.2" } -jrsonnet-gc = { version = "0.4.2", features = ["derive"] } +gcmodule = { git = "https://github.com/CertainLach/gcmodule", branch = "jrsonnet" } [lib] crate-type = ["cdylib"] --- a/bindings/jsonnet/src/native.rs +++ b/bindings/jsonnet/src/native.rs @@ -1,9 +1,10 @@ +use gcmodule::Cc; use jrsonnet_evaluator::{ error::{Error, LocError}, + gc::TraceBox, native::{NativeCallback, NativeCallbackHandler}, EvaluationState, Val, }; -use jrsonnet_gc::{unsafe_empty_trace, Finalize, Gc, Trace}; use jrsonnet_parser::{Param, ParamsDesc}; use std::{ ffi::{c_void, CStr}, @@ -18,16 +19,15 @@ success: *mut c_int, ) -> *mut Val; +#[derive(gcmodule::Trace)] struct JsonnetNativeCallbackHandler { + #[skip_trace] ctx: *const c_void, + #[skip_trace] cb: JsonnetNativeCallback, -} -impl Finalize for JsonnetNativeCallbackHandler {} -unsafe impl Trace for JsonnetNativeCallbackHandler { - unsafe_empty_trace!(); } impl NativeCallbackHandler for JsonnetNativeCallbackHandler { - fn call(&self, _from: Option>, args: &[Val]) -> Result { + fn call(&self, _from: Rc, args: &[Val]) -> Result { let mut n_args = Vec::new(); for a in args { n_args.push(Some(Box::new(a.clone()))); @@ -74,9 +74,9 @@ vm.add_native( name, - Gc::new(NativeCallback::new( + Cc::new(NativeCallback::new( params, - Box::new(JsonnetNativeCallbackHandler { ctx, cb }), + TraceBox(Box::new(JsonnetNativeCallbackHandler { ctx, cb })), )), ) } --- a/bindings/jsonnet/src/val_make.rs +++ b/bindings/jsonnet/src/val_make.rs @@ -1,7 +1,7 @@ //! Create values in VM +use gcmodule::Cc; use jrsonnet_evaluator::{ArrValue, EvaluationState, ObjValue, Val}; -use jrsonnet_gc::Gc; use std::{ ffi::CStr, os::raw::{c_char, c_double, c_int}, @@ -38,7 +38,7 @@ #[no_mangle] pub extern "C" fn jsonnet_json_make_array(_vm: &EvaluationState) -> *mut Val { - Box::into_raw(Box::new(Val::Arr(ArrValue::Eager(Gc::new(Vec::new()))))) + Box::into_raw(Box::new(Val::Arr(ArrValue::Eager(Cc::new(Vec::new()))))) } #[no_mangle] --- a/bindings/jsonnet/src/val_modify.rs +++ b/bindings/jsonnet/src/val_modify.rs @@ -2,8 +2,8 @@ //! Only tested with variables, which haven't altered by code before appearing here //! In jrsonnet every value is immutable, and this code is probally broken +use gcmodule::Cc; use jrsonnet_evaluator::{ArrValue, EvaluationState, LazyBinding, LazyVal, ObjMember, Val}; -use jrsonnet_gc::Gc; use jrsonnet_parser::Visibility; use std::{ffi::CStr, os::raw::c_char}; @@ -23,7 +23,7 @@ new.push(item); } new.push(LazyVal::new_resolved(val.clone())); - *arr = Val::Arr(ArrValue::Lazy(Gc::new(new))); + *arr = Val::Arr(ArrValue::Lazy(Cc::new(new))); } _ => panic!("should receive array"), } --- a/cmds/jrsonnet/Cargo.toml +++ b/cmds/jrsonnet/Cargo.toml @@ -17,6 +17,7 @@ jrsonnet-cli = { path = "../../crates/jrsonnet-cli", version = "0.4.2" } mimallocator = { version = "0.1.3", optional = true } thiserror = "1.0" +gcmodule = { git = "https://github.com/CertainLach/gcmodule", branch = "jrsonnet" } [dependencies.clap] git = "https://github.com/clap-rs/clap" --- a/cmds/jrsonnet/src/main.rs +++ b/cmds/jrsonnet/src/main.rs @@ -136,7 +136,7 @@ let val = if opts.input.exec { state.evaluate_snippet_raw( - PathBuf::from("args").into(), + PathBuf::from("").into(), (&opts.input.input as &str).into(), )? } else if opts.input.input == "-" { --- a/crates/jrsonnet-cli/Cargo.toml +++ b/crates/jrsonnet-cli/Cargo.toml @@ -12,11 +12,7 @@ "explaining-traces", ] } jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "0.4.2" } -jrsonnet-gc = { version = "0.4.2", features = [ - "derive", - "unstable-config", - "unstable-stats", -] } +gcmodule = { git = "https://github.com/CertainLach/gcmodule", branch = "jrsonnet" } [dependencies.clap] git = "https://github.com/clap-rs/clap" --- a/crates/jrsonnet-cli/src/lib.rs +++ b/crates/jrsonnet-cli/src/lib.rs @@ -103,12 +103,6 @@ #[derive(Clap)] #[clap(help_heading = "GARBAGE COLLECTION")] pub struct GcOpts { - /// Min bytes allocated to start garbage collection - #[clap(long, default_value = "20000000")] - gc_initial_threshold: usize, - /// How much heap should grow after unsuccessful garbage collection - #[clap(long)] - gc_used_space_ratio: Option, /// Do not skip gc on exit #[clap(long)] gc_collect_on_exit: bool, @@ -122,32 +116,28 @@ gc_collect_before_printing_stats: bool, } impl GcOpts { + pub fn configure_global(&self) { + if !self.gc_collect_on_exit { + gcmodule::set_thread_collect_on_drop(false) + } + } pub fn stats_printer(&self) -> Option { - self.gc_print_stats - .then(|| GcStatsPrinter(self.gc_collect_before_printing_stats)) + self.gc_print_stats.then(|| GcStatsPrinter { + collect_before_printing_stats: self.gc_collect_before_printing_stats, + }) } - pub fn configure_global(&self) { - jrsonnet_gc::configure(|config| { - config.leak_on_drop = !self.gc_collect_on_exit; - config.threshold = self.gc_initial_threshold; - if let Some(used_space_ratio) = self.gc_used_space_ratio { - config.used_space_ratio = used_space_ratio; - } - }); - } } -pub struct GcStatsPrinter(bool); + +pub struct GcStatsPrinter { + collect_before_printing_stats: bool, +} impl Drop for GcStatsPrinter { fn drop(&mut self) { - if self.0 { - jrsonnet_gc::force_collect() + eprintln!("=== GC STATS ==="); + if self.collect_before_printing_stats { + let collected = gcmodule::collect_thread_cycles(); + eprintln!("Collected: {}", collected); } - eprintln!("=== GC STATS ==="); - jrsonnet_gc::configure(|c| { - eprintln!("Final threshold: {:?}", c.threshold); - }); - let stats = jrsonnet_gc::stats(); - eprintln!("Collections performed: {}", stats.collections_performed); - eprintln!("Bytes still allocated: {}", stats.bytes_allocated); + eprintln!("Tracked: {}", gcmodule::count_thread_tracked()) } } --- a/crates/jrsonnet-evaluator/Cargo.toml +++ b/crates/jrsonnet-evaluator/Cargo.toml @@ -32,7 +32,7 @@ rustc-hash = "1.1.0" thiserror = "1.0" -jrsonnet-gc = { version = "0.4.2", features = ["derive"] } +gcmodule = { git = "https://github.com/CertainLach/gcmodule", branch = "jrsonnet" } [dependencies.anyhow] version = "1.0" @@ -53,7 +53,7 @@ # Explaining traces [dependencies.annotate-snippets] -version = "0.9.0" +version = "0.9.1" features = ["color"] optional = true --- a/crates/jrsonnet-evaluator/build.rs +++ b/crates/jrsonnet-evaluator/build.rs @@ -13,7 +13,6 @@ STDLIB_STR, &ParserSettings { file_name: PathBuf::from("std.jsonnet").into(), - loc_data: true, }, ) .expect("parse"); --- a/crates/jrsonnet-evaluator/src/builtin/format.rs +++ b/crates/jrsonnet-evaluator/src/builtin/format.rs @@ -2,13 +2,12 @@ #![allow(clippy::too_many_arguments)] use crate::{error::Error::*, throw, LocError, ObjValue, Result, Val}; -use jrsonnet_gc::Trace; +use gcmodule::Trace; use jrsonnet_interner::IStr; use jrsonnet_types::ValType; use thiserror::Error; #[derive(Debug, Clone, Error, Trace)] -#[trivially_drop] pub enum FormatError { #[error("truncated format code")] TruncatedFormatCode, --- a/crates/jrsonnet-evaluator/src/builtin/manifest.rs +++ b/crates/jrsonnet-evaluator/src/builtin/manifest.rs @@ -1,6 +1,6 @@ use crate::error::Error::*; use crate::error::Result; -use crate::push_frame; +use crate::push_description_frame; use crate::{throw, Val}; #[derive(PartialEq, Clone, Copy)] @@ -103,8 +103,7 @@ buf.push_str(cur_padding); escape_string_json_buf(&field, buf); buf.push_str(": "); - push_frame( - None, + push_description_frame( || format!("field <{}> manifestification", field.clone()), || { let value = obj.get(field.clone())?.unwrap(); --- a/crates/jrsonnet-evaluator/src/builtin/mod.rs +++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs @@ -7,7 +7,7 @@ EvaluationState, FuncVal, IndexableVal, LazyVal, Val, }; use format::{format_arr, format_obj}; -use jrsonnet_gc::Gc; +use gcmodule::Cc; use jrsonnet_interner::IStr; use jrsonnet_parser::{ArgsDesc, ExprLocation}; use jrsonnet_types::ty; @@ -24,7 +24,7 @@ pub fn std_format(str: IStr, vals: Val) -> Result { push_frame( - Some(&ExprLocation(Rc::from(PathBuf::from("std.jsonnet")), 0, 0)), + &ExprLocation(Rc::from(PathBuf::from("std.jsonnet")), 0, 0), || format!("std.format of {}", str), || { Ok(match vals { @@ -68,7 +68,7 @@ } } -type Builtin = fn(context: Context, loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result; +type Builtin = fn(context: Context, loc: &ExprLocation, args: &ArgsDesc) -> Result; type BuiltinsType = HashMap, Builtin>; @@ -136,7 +136,7 @@ }; } -fn builtin_length(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_length(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "length", args, 1, [ 0, x: ty!((string | object | array)); ], { @@ -154,7 +154,7 @@ }) } -fn builtin_type(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_type(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "type", args, 1, [ 0, x: ty!(any); ], { @@ -162,11 +162,7 @@ }) } -fn builtin_make_array( - context: Context, - _loc: Option<&ExprLocation>, - args: &ArgsDesc, -) -> Result { +fn builtin_make_array(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "makeArray", args, 2, [ 0, sz: ty!(BoundedNumber<(Some(0.0)), (None)>) => Val::Num; 1, func: ty!(function) => Val::Func; @@ -182,11 +178,7 @@ }) } -fn builtin_codepoint( - context: Context, - _loc: Option<&ExprLocation>, - args: &ArgsDesc, -) -> Result { +fn builtin_codepoint(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "codepoint", args, 1, [ 0, str: ty!(char) => Val::Str; ], { @@ -194,11 +186,7 @@ }) } -fn builtin_object_fields_ex( - context: Context, - _loc: Option<&ExprLocation>, - args: &ArgsDesc, -) -> Result { +fn builtin_object_fields_ex(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "objectFieldsEx", args, 2, [ 0, obj: ty!(object) => Val::Obj; 1, inc_hidden: ty!(boolean) => Val::Bool; @@ -208,11 +196,7 @@ }) } -fn builtin_object_has_ex( - context: Context, - _loc: Option<&ExprLocation>, - args: &ArgsDesc, -) -> Result { +fn builtin_object_has_ex(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "objectHasEx", args, 3, [ 0, obj: ty!(object) => Val::Obj; 1, f: ty!(string) => Val::Str; @@ -222,11 +206,7 @@ }) } -fn builtin_parse_json( - context: Context, - _loc: Option<&ExprLocation>, - args: &ArgsDesc, -) -> Result { +fn builtin_parse_json(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "parseJson", args, 1, [ 0, s: ty!(string) => Val::Str; ], { @@ -236,7 +216,7 @@ }) } -fn builtin_slice(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_slice(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "slice", args, 4, [ 0, indexable: ty!((string | array)); 1, index: ty!((number | null)); @@ -252,7 +232,7 @@ }) } -fn builtin_substr(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_substr(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "substr", args, 3, [ 0, str: ty!(string) => Val::Str; 1, from: ty!(BoundedNumber<(Some(0.0)), (None)>) => Val::Num; @@ -263,11 +243,7 @@ }) } -fn builtin_primitive_equals( - context: Context, - _loc: Option<&ExprLocation>, - args: &ArgsDesc, -) -> Result { +fn builtin_primitive_equals(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "primitiveEquals", args, 2, [ 0, a: ty!(any); 1, b: ty!(any); @@ -276,7 +252,7 @@ }) } -fn builtin_equals(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_equals(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "equals", args, 2, [ 0, a: ty!(any); 1, b: ty!(any); @@ -285,7 +261,7 @@ }) } -fn builtin_modulo(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_modulo(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "modulo", args, 2, [ 0, a: ty!(number) => Val::Num; 1, b: ty!(number) => Val::Num; @@ -294,7 +270,7 @@ }) } -fn builtin_mod(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_mod(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "mod", args, 2, [ 0, a: ty!((number | string)); 1, b: ty!(any); @@ -303,7 +279,7 @@ }) } -fn builtin_floor(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_floor(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "floor", args, 1, [ 0, x: ty!(number) => Val::Num; ], { @@ -311,7 +287,7 @@ }) } -fn builtin_ceil(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_ceil(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "ceil", args, 1, [ 0, x: ty!(number) => Val::Num; ], { @@ -319,7 +295,7 @@ }) } -fn builtin_log(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_log(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "log", args, 1, [ 0, n: ty!(number) => Val::Num; ], { @@ -327,7 +303,7 @@ }) } -fn builtin_pow(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_pow(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "pow", args, 2, [ 0, x: ty!(number) => Val::Num; 1, n: ty!(number) => Val::Num; @@ -336,7 +312,7 @@ }) } -fn builtin_sqrt(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_sqrt(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "sqrt", args, 1, [ 0, x: ty!(BoundedNumber<(Some(0.0)), (None)>) => Val::Num; ], { @@ -344,7 +320,7 @@ }) } -fn builtin_sin(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_sin(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "sin", args, 1, [ 0, x: ty!(number) => Val::Num; ], { @@ -352,7 +328,7 @@ }) } -fn builtin_cos(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_cos(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "cos", args, 1, [ 0, x: ty!(number) => Val::Num; ], { @@ -360,7 +336,7 @@ }) } -fn builtin_tan(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_tan(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "tan", args, 1, [ 0, x: ty!(number) => Val::Num; ], { @@ -368,7 +344,7 @@ }) } -fn builtin_asin(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_asin(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "asin", args, 1, [ 0, x: ty!(number) => Val::Num; ], { @@ -376,7 +352,7 @@ }) } -fn builtin_acos(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_acos(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "acos", args, 1, [ 0, x: ty!(number) => Val::Num; ], { @@ -384,7 +360,7 @@ }) } -fn builtin_atan(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_atan(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "atan", args, 1, [ 0, x: ty!(number) => Val::Num; ], { @@ -392,7 +368,7 @@ }) } -fn builtin_exp(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_exp(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "exp", args, 1, [ 0, x: ty!(number) => Val::Num; ], { @@ -411,7 +387,7 @@ } } -fn builtin_mantissa(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_mantissa(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "mantissa", args, 1, [ 0, x: ty!(number) => Val::Num; ], { @@ -419,7 +395,7 @@ }) } -fn builtin_exponent(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_exponent(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "exponent", args, 1, [ 0, x: ty!(number) => Val::Num; ], { @@ -427,7 +403,7 @@ }) } -fn builtin_ext_var(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_ext_var(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "extVar", args, 1, [ 0, x: ty!(string) => Val::Str; ], { @@ -435,15 +411,15 @@ }) } -fn builtin_native(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_native(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "native", args, 1, [ 0, x: ty!(string) => Val::Str; ], { - Ok(with_state(|s| s.settings().ext_natives.get(&x).cloned()).map(|v| Val::Func(Gc::new(FuncVal::NativeExt(x.clone(), v)))).ok_or(UndefinedExternalFunction(x))?) + Ok(with_state(|s| s.settings().ext_natives.get(&x).cloned()).map(|v| Val::Func(Cc::new(FuncVal::NativeExt(x.clone(), v)))).ok_or(UndefinedExternalFunction(x))?) }) } -fn builtin_filter(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_filter(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "filter", args, 2, [ 0, func: ty!(function) => Val::Func; 1, arr: ty!(array) => Val::Arr; @@ -454,7 +430,7 @@ }) } -fn builtin_map(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_map(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "map", args, 2, [ 0, func: ty!(function) => Val::Func; 1, arr: ty!(array) => Val::Arr; @@ -464,7 +440,7 @@ }) } -fn builtin_flatmap(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_flatmap(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "flatMap", args, 2, [ 0, func: ty!(function) => Val::Func; 1, arr: ty!((array | string)); @@ -498,7 +474,7 @@ }) } -fn builtin_foldl(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_foldl(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "foldl", args, 3, [ 0, func: ty!(function) => Val::Func; 1, arr: ty!(array) => Val::Arr; @@ -512,7 +488,7 @@ }) } -fn builtin_foldr(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_foldr(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "foldr", args, 3, [ 0, func: ty!(function) => Val::Func; 1, arr: ty!(array) => Val::Arr; @@ -527,11 +503,7 @@ } #[allow(non_snake_case)] -fn builtin_sort_impl( - context: Context, - _loc: Option<&ExprLocation>, - args: &ArgsDesc, -) -> Result { +fn builtin_sort_impl(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "sort", args, 2, [ 0, arr: ty!(array) => Val::Arr; 1, keyF: ty!(function) => Val::Func; @@ -543,7 +515,7 @@ }) } -fn builtin_format(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_format(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "format", args, 2, [ 0, str: ty!(string) => Val::Str; 1, vals: ty!(any) @@ -552,7 +524,7 @@ }) } -fn builtin_range(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_range(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "range", args, 2, [ 0, from: ty!(number) => Val::Num; 1, to: ty!(number) => Val::Num; @@ -568,7 +540,7 @@ }) } -fn builtin_char(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_char(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "char", args, 1, [ 0, n: ty!(number) => Val::Num; ], { @@ -580,11 +552,7 @@ }) } -fn builtin_encode_utf8( - context: Context, - _loc: Option<&ExprLocation>, - args: &ArgsDesc, -) -> Result { +fn builtin_encode_utf8(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "encodeUTF8", args, 1, [ 0, str: ty!(string) => Val::Str; ], { @@ -592,11 +560,7 @@ }) } -fn builtin_decode_utf8( - context: Context, - _loc: Option<&ExprLocation>, - args: &ArgsDesc, -) -> Result { +fn builtin_decode_utf8(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "decodeUTF8", args, 1, [ 0, arr: ty!((Array)) => Val::Arr; ], { @@ -609,7 +573,7 @@ }) } -fn builtin_md5(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_md5(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "md5", args, 1, [ 0, str: ty!(string) => Val::Str; ], { @@ -617,24 +581,22 @@ }) } -fn builtin_trace(context: Context, loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_trace(context: Context, loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "trace", args, 2, [ 0, str: ty!(string) => Val::Str; 1, rest: ty!(any); ], { eprint!("TRACE:"); - if let Some(loc) = loc { with_state(|s|{ let locs = s.map_source_locations(&loc.0, &[loc.1]); eprint!(" {}:{}", loc.0.file_name().unwrap().to_str().unwrap(), locs[0].line); }); - } eprintln!(" {}", str); Ok(rest) }) } -fn builtin_base64(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_base64(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "base64", args, 1, [ 0, input: ty!((string | (Array))); ], { @@ -654,7 +616,7 @@ fn builtin_base64_decode_bytes( context: Context, - _loc: Option<&ExprLocation>, + _loc: &ExprLocation, args: &ArgsDesc, ) -> Result { parse_args!(context, "base64DecodeBytes", args, 1, [ @@ -669,11 +631,7 @@ }) } -fn builtin_base64_decode( - context: Context, - _loc: Option<&ExprLocation>, - args: &ArgsDesc, -) -> Result { +fn builtin_base64_decode(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "base64Decode", args, 1, [ 0, input: ty!(string) => Val::Str; ], { @@ -685,7 +643,7 @@ }) } -fn builtin_join(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_join(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "join", args, 2, [ 0, sep: ty!((string | array)); 1, arr: ty!(array) => Val::Arr; @@ -744,7 +702,7 @@ fn builtin_escape_string_json( context: Context, - _loc: Option<&ExprLocation>, + _loc: &ExprLocation, args: &ArgsDesc, ) -> Result { parse_args!(context, "escapeStringJson", args, 1, [ @@ -754,11 +712,7 @@ }) } -fn builtin_manifest_json_ex( - context: Context, - _loc: Option<&ExprLocation>, - args: &ArgsDesc, -) -> Result { +fn builtin_manifest_json_ex(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "manifestJsonEx", args, 2, [ 0, value: ty!(any); 1, indent: ty!(string) => Val::Str; @@ -772,7 +726,7 @@ fn builtin_manifest_yaml_doc( context: Context, - _loc: Option<&ExprLocation>, + _loc: &ExprLocation, args: &ArgsDesc, ) -> Result { parse_args!(context, "manifestYamlDoc", args, 2, [ @@ -786,7 +740,7 @@ }) } -fn builtin_reverse(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_reverse(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "reverse", args, 1, [ 0, value: ty!(array) => Val::Arr; ], { @@ -794,7 +748,7 @@ }) } -fn builtin_id(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_id(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "id", args, 1, [ 0, v: ty!(any); ], { @@ -802,11 +756,7 @@ }) } -fn builtin_str_replace( - context: Context, - _loc: Option<&ExprLocation>, - args: &ArgsDesc, -) -> Result { +fn builtin_str_replace(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "strReplace", args, 3, [ 0, str: ty!(string) => Val::Str; 1, from: ty!(string) => Val::Str; @@ -816,11 +766,7 @@ }) } -fn builtin_splitlimit( - context: Context, - _loc: Option<&ExprLocation>, - args: &ArgsDesc, -) -> Result { +fn builtin_splitlimit(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "splitLimit", args, 3, [ 0, str: ty!(string) => Val::Str; 1, c: ty!(char) => Val::Str; @@ -839,11 +785,7 @@ }) } -fn builtin_ascii_upper( - context: Context, - _loc: Option<&ExprLocation>, - args: &ArgsDesc, -) -> Result { +fn builtin_ascii_upper(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "asciiUpper", args, 1, [ 0, str: ty!(string) => Val::Str; ], { @@ -851,11 +793,7 @@ }) } -fn builtin_ascii_lower( - context: Context, - _loc: Option<&ExprLocation>, - args: &ArgsDesc, -) -> Result { +fn builtin_ascii_lower(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "asciiLower", args, 1, [ 0, str: ty!(string) => Val::Str; ], { @@ -863,7 +801,7 @@ }) } -fn builtin_member(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_member(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "member", args, 2, [ 0, arr: ty!((array | string)); 1, x: ty!(any); @@ -887,7 +825,7 @@ }) } -fn builtin_count(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { +fn builtin_count(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result { parse_args!(context, "count", args, 2, [ 0, arr: ty!(array) => Val::Arr; 1, x: ty!(any); @@ -905,7 +843,7 @@ pub fn call_builtin( context: Context, - loc: Option<&ExprLocation>, + loc: &ExprLocation, name: &str, args: &ArgsDesc, ) -> Result { --- a/crates/jrsonnet-evaluator/src/builtin/sort.rs +++ b/crates/jrsonnet-evaluator/src/builtin/sort.rs @@ -2,9 +2,9 @@ error::{Error, LocError, Result}, throw, Context, FuncVal, Val, }; -use jrsonnet_gc::{Finalize, Gc, Trace}; +use gcmodule::{Cc, Trace}; -#[derive(Debug, Clone, thiserror::Error, Trace, Finalize)] +#[derive(Debug, Clone, thiserror::Error, Trace)] pub enum SortError { #[error("sort key should be string or number")] SortKeyShouldBeStringOrNumber, @@ -59,7 +59,7 @@ Ok(sort_type) } -pub fn sort(ctx: Context, values: Gc>, key_getter: &FuncVal) -> Result>> { +pub fn sort(ctx: Context, values: Cc>, key_getter: &FuncVal) -> Result>> { if values.len() <= 1 { return Ok(values); } @@ -77,7 +77,7 @@ }), SortKeyType::Unknown => unreachable!(), }; - Ok(Gc::new(mvalues)) + Ok(Cc::new(mvalues)) } else { let mut vk = Vec::with_capacity(values.len()); for value in values.iter() { @@ -98,6 +98,6 @@ }), SortKeyType::Unknown => unreachable!(), }; - Ok(Gc::new(vk.into_iter().map(|v| v.0).collect())) + Ok(Cc::new(vk.into_iter().map(|v| v.0).collect())) } } --- a/crates/jrsonnet-evaluator/src/builtin/stdlib.rs +++ b/crates/jrsonnet-evaluator/src/builtin/stdlib.rs @@ -15,7 +15,6 @@ jrsonnet_parser::parse( jrsonnet_stdlib::STDLIB_STR, &ParserSettings { - loc_data: true, file_name: PathBuf::from("std.jsonnet").into(), }, ) --- a/crates/jrsonnet-evaluator/src/ctx.rs +++ b/crates/jrsonnet-evaluator/src/ctx.rs @@ -1,16 +1,15 @@ +use crate::cc_ptr_eq; +use crate::gc::GcHashMap; use crate::{ error::Error::*, map::LayeredHashMap, FutureWrapper, LazyBinding, LazyVal, ObjValue, Result, Val, }; -use jrsonnet_gc::{Gc, Trace}; +use gcmodule::{Cc, Trace}; use jrsonnet_interner::IStr; -use rustc_hash::FxHashMap; use std::fmt::Debug; -use std::hash::BuildHasherDefault; #[derive(Clone, Trace)] -#[trivially_drop] -pub struct ContextCreator(pub Context, pub FutureWrapper>); +pub struct ContextCreator(pub Context, pub FutureWrapper>); impl ContextCreator { pub fn create(&self, this: Option, super_obj: Option) -> Result { self.0.clone().extend_unbound( @@ -23,7 +22,6 @@ } #[derive(Trace)] -#[trivially_drop] struct ContextInternals { dollar: Option, this: Option, @@ -37,8 +35,7 @@ } #[derive(Debug, Clone, Trace)] -#[trivially_drop] -pub struct Context(Gc); +pub struct Context(Cc); impl Context { pub fn new_future() -> FutureWrapper { FutureWrapper::new() @@ -57,7 +54,7 @@ } pub fn new() -> Self { - Self(Gc::new(ContextInternals { + Self(Cc::new(ContextInternals { dollar: None, this: None, super_obj: None, @@ -84,19 +81,18 @@ } pub fn with_var(self, name: IStr, value: Val) -> Self { - let mut new_bindings = - FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default()); + let mut new_bindings = GcHashMap::with_capacity(1); new_bindings.insert(name, LazyVal::new_resolved(value)); self.extend(new_bindings, None, None, None) } pub fn with_this_super(self, new_this: ObjValue, new_super_obj: Option) -> Self { - self.extend(FxHashMap::default(), None, Some(new_this), new_super_obj) + self.extend(GcHashMap::new(), None, Some(new_this), new_super_obj) } pub fn extend( self, - new_bindings: FxHashMap, + new_bindings: GcHashMap, new_dollar: Option, new_this: Option, new_super_obj: Option, @@ -110,30 +106,29 @@ } else { ctx.bindings.clone().extend(new_bindings) }; - Self(Gc::new(ContextInternals { + Self(Cc::new(ContextInternals { dollar, this, super_obj, bindings, })) } - pub fn extend_bound(self, new_bindings: FxHashMap) -> Self { + pub fn extend_bound(self, new_bindings: GcHashMap) -> Self { let new_this = self.0.this.clone(); let new_super_obj = self.0.super_obj.clone(); self.extend(new_bindings, None, new_this, new_super_obj) } pub fn extend_unbound( self, - new_bindings: FxHashMap, + new_bindings: GcHashMap, new_dollar: Option, new_this: Option, new_super_obj: Option, ) -> Result { let this = new_this.or_else(|| self.0.this.clone()); let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone()); - let mut new = - FxHashMap::with_capacity_and_hasher(new_bindings.len(), BuildHasherDefault::default()); - for (k, v) in new_bindings.into_iter() { + let mut new = GcHashMap::with_capacity(new_bindings.len()); + for (k, v) in new_bindings.0.into_iter() { new.insert(k, v.evaluate(this.clone(), super_obj.clone())?); } Ok(self.extend(new, new_dollar, this, super_obj)) @@ -152,6 +147,6 @@ impl PartialEq for Context { fn eq(&self, other: &Self) -> bool { - Gc::ptr_eq(&self.0, &other.0) + cc_ptr_eq(&self.0, &other.0) } } --- a/crates/jrsonnet-evaluator/src/dynamic.rs +++ b/crates/jrsonnet-evaluator/src/dynamic.rs @@ -1,11 +1,12 @@ -use jrsonnet_gc::{Gc, GcCell, Trace}; +use std::cell::RefCell; +use gcmodule::{Cc, Trace}; + #[derive(Clone, Trace)] -#[trivially_drop] -pub struct FutureWrapper(pub Gc>>); +pub struct FutureWrapper(pub Cc>>); impl FutureWrapper { pub fn new() -> Self { - Self(Gc::new(GcCell::new(None))) + Self(Cc::new(RefCell::new(None))) } pub fn fill(self, value: T) { assert!(self.0.borrow().is_none(), "wrapper is filled already"); --- a/crates/jrsonnet-evaluator/src/error.rs +++ b/crates/jrsonnet-evaluator/src/error.rs @@ -1,5 +1,8 @@ -use crate::{Val, builtin::{format::FormatError, sort::SortError}, typed::TypeLocError}; -use jrsonnet_gc::Trace; +use crate::{ + builtin::{format::FormatError, sort::SortError}, + typed::TypeLocError, +}; +use gcmodule::Trace; use jrsonnet_interner::IStr; use jrsonnet_parser::{BinaryOpType, ExprLocation, UnaryOpType}; use jrsonnet_types::ValType; @@ -10,7 +13,6 @@ use thiserror::Error; #[derive(Error, Debug, Clone, Trace)] -#[trivially_drop] pub enum Error { #[error("intrinsic not found: {0}")] IntrinsicNotFound(IStr), @@ -85,14 +87,15 @@ #[error("tried to import {1} from {0}, but imports is not supported")] ImportNotSupported(PathBuf, PathBuf), #[error( - "syntax error, expected one of {}, got {:?}", + "syntax error: expected {}, got {:?}", .error.expected, .source_code.chars().nth(error.location.offset).map(|c| c.to_string()).unwrap_or_else(|| "EOF".into()) )] ImportSyntaxError { + #[skip_trace] path: Rc, source_code: IStr, - #[unsafe_ignore_trace] + #[skip_trace] error: Box, }, @@ -150,17 +153,14 @@ } #[derive(Clone, Debug, Trace)] -#[trivially_drop] pub struct StackTraceElement { pub location: Option, pub desc: String, } #[derive(Debug, Clone, Trace)] -#[trivially_drop] pub struct StackTrace(pub Vec); #[derive(Debug, Clone, Trace)] -#[trivially_drop] pub struct LocError(Box<(Error, StackTrace)>); impl LocError { pub fn new(e: Error) -> Self { --- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs @@ -2,19 +2,18 @@ builtin::std_slice, error::Error::*, evaluate::operator::{evaluate_add_op, evaluate_binary_op_special, evaluate_unary_op}, + gc::TraceBox, push_frame, throw, with_state, ArrValue, Bindable, Context, ContextCreator, FuncDesc, FuncVal, - FutureWrapper, LazyBinding, LazyVal, LazyValValue, ObjValue, ObjValueBuilder, ObjectAssertion, - Result, Val, + FutureWrapper, GcHashMap, LazyBinding, LazyVal, LazyValValue, ObjValue, + ObjValueBuilder, ObjectAssertion, Result, Val, }; -use jrsonnet_gc::{Gc, Trace}; +use gcmodule::{Cc, Trace}; use jrsonnet_interner::IStr; use jrsonnet_parser::{ ArgsDesc, AssertStmt, BindSpec, CompSpec, Expr, ExprLocation, FieldMember, ForSpecData, IfSpecData, LiteralType, LocExpr, Member, ObjBody, ParamsDesc, }; use jrsonnet_types::ValType; -use rustc_hash::{FxHashMap, FxHasher}; -use std::{collections::HashMap, hash::BuildHasherDefault}; pub mod operator; pub fn evaluate_binding_in_future( @@ -26,7 +25,6 @@ let params = params.clone(); #[derive(Trace)] - #[trivially_drop] struct LazyMethodBinding { context_creator: FutureWrapper, name: IStr, @@ -44,15 +42,14 @@ } } - LazyVal::new(Box::new(LazyMethodBinding { + LazyVal::new(TraceBox(Box::new(LazyMethodBinding { context_creator, name: b.name.clone(), params, value: b.value.clone(), - })) + }))) } else { #[derive(Trace)] - #[trivially_drop] struct LazyNamedBinding { context_creator: FutureWrapper, name: IStr, @@ -63,11 +60,11 @@ evaluate_named(self.context_creator.unwrap(), &self.value, self.name) } } - LazyVal::new(Box::new(LazyNamedBinding { + LazyVal::new(TraceBox(Box::new(LazyNamedBinding { context_creator, name: b.name.clone(), value: b.value, - })) + }))) } } @@ -77,7 +74,6 @@ let params = params.clone(); #[derive(Trace)] - #[trivially_drop] struct BindableMethodLazyVal { this: Option, super_obj: Option, @@ -99,7 +95,6 @@ } #[derive(Trace)] - #[trivially_drop] struct BindableMethod { context_creator: ContextCreator, name: IStr, @@ -108,30 +103,31 @@ } impl Bindable for BindableMethod { fn bind(&self, this: Option, super_obj: Option) -> Result { - Ok(LazyVal::new(Box::new(BindableMethodLazyVal { - this, - super_obj, + Ok(LazyVal::new(TraceBox(Box::new( + BindableMethodLazyVal { + this, + super_obj, - context_creator: self.context_creator.clone(), - name: self.name.clone(), - params: self.params.clone(), - value: self.value.clone(), - }))) + context_creator: self.context_creator.clone(), + name: self.name.clone(), + params: self.params.clone(), + value: self.value.clone(), + }, + )))) } } ( b.name.clone(), - LazyBinding::Bindable(Gc::new(Box::new(BindableMethod { + LazyBinding::Bindable(Cc::new(TraceBox(Box::new(BindableMethod { context_creator, name: b.name.clone(), params, value: b.value.clone(), - }))), + })))), ) } else { #[derive(Trace)] - #[trivially_drop] struct BindableNamedLazyVal { this: Option, super_obj: Option, @@ -151,7 +147,6 @@ } #[derive(Trace)] - #[trivially_drop] struct BindableNamed { context_creator: ContextCreator, name: IStr, @@ -159,30 +154,32 @@ } impl Bindable for BindableNamed { fn bind(&self, this: Option, super_obj: Option) -> Result { - Ok(LazyVal::new(Box::new(BindableNamedLazyVal { - this, - super_obj, + Ok(LazyVal::new(TraceBox(Box::new( + BindableNamedLazyVal { + this, + super_obj, - context_creator: self.context_creator.clone(), - name: self.name.clone(), - value: self.value.clone(), - }))) + context_creator: self.context_creator.clone(), + name: self.name.clone(), + value: self.value.clone(), + }, + )))) } } ( b.name.clone(), - LazyBinding::Bindable(Gc::new(Box::new(BindableNamed { + LazyBinding::Bindable(Cc::new(TraceBox(Box::new(BindableNamed { context_creator, name: b.name.clone(), value: b.value.clone(), - }))), + })))), ) } } pub fn evaluate_method(ctx: Context, name: IStr, params: ParamsDesc, body: LocExpr) -> Val { - Val::Func(Gc::new(FuncVal::Normal(FuncDesc { + Val::Func(Cc::new(FuncVal::Normal(FuncDesc { name, ctx, params, @@ -240,8 +237,7 @@ let future_this = FutureWrapper::new(); let context_creator = ContextCreator(context.clone(), new_bindings.clone()); { - let mut bindings: FxHashMap = - FxHashMap::with_capacity_and_hasher(members.len(), BuildHasherDefault::default()); + let mut bindings: GcHashMap = GcHashMap::with_capacity(members.len()); for (n, b) in members .iter() .filter_map(|m| match m { @@ -272,7 +268,6 @@ let name = name.unwrap(); #[derive(Trace)] - #[trivially_drop] struct ObjMemberBinding { context_creator: ContextCreator, value: LocExpr, @@ -296,11 +291,11 @@ .with_add(*plus) .with_visibility(*visibility) .with_location(value.1.clone()) - .bindable(Box::new(ObjMemberBinding { + .bindable(TraceBox(Box::new(ObjMemberBinding { context_creator: context_creator.clone(), value: value.clone(), name, - })); + }))); } Member::Field(FieldMember { name, @@ -314,7 +309,6 @@ } let name = name.unwrap(); #[derive(Trace)] - #[trivially_drop] struct ObjMemberBinding { context_creator: ContextCreator, value: LocExpr, @@ -339,17 +333,16 @@ .member(name.clone()) .hide() .with_location(value.1.clone()) - .bindable(Box::new(ObjMemberBinding { + .bindable(TraceBox(Box::new(ObjMemberBinding { context_creator: context_creator.clone(), value: value.clone(), params: params.clone(), name, - })); + }))); } Member::BindStmt(_) => {} Member::AssertStmt(stmt) => { #[derive(Trace)] - #[trivially_drop] struct ObjectAssert { context_creator: ContextCreator, assert: AssertStmt, @@ -364,10 +357,10 @@ evaluate_assert(ctx, &self.assert) } } - builder.assert(Box::new(ObjectAssert { + builder.assert(TraceBox(Box::new(ObjectAssert { context_creator: context_creator.clone(), assert: stmt.clone(), - })); + }))); } } } @@ -385,11 +378,8 @@ evaluate_comp(context.clone(), &obj.compspecs, &mut |ctx| { let new_bindings = FutureWrapper::new(); let context_creator = ContextCreator(context.clone(), new_bindings.clone()); - let mut bindings: FxHashMap = - FxHashMap::with_capacity_and_hasher( - obj.pre_locals.len() + obj.post_locals.len(), - BuildHasherDefault::default(), - ); + let mut bindings: GcHashMap = + GcHashMap::with_capacity(obj.pre_locals.len() + obj.post_locals.len()); for (n, b) in obj .pre_locals .iter() @@ -406,7 +396,6 @@ Val::Null => {} Val::Str(n) => { #[derive(Trace)] - #[trivially_drop] struct ObjCompBinding { context: Context, value: LocExpr, @@ -418,12 +407,9 @@ _super_obj: Option, ) -> Result { Ok(LazyVal::new_resolved(evaluate( - self.context.clone().extend( - FxHashMap::default(), - None, - this, - None, - ), + self.context + .clone() + .extend(GcHashMap::new(), None, this, None), &self.value, )?)) } @@ -432,10 +418,10 @@ .member(n) .with_location(obj.value.1.clone()) .with_add(obj.plus) - .bindable(Box::new(ObjCompBinding { + .bindable(TraceBox(Box::new(ObjCompBinding { context: ctx, value: obj.value.clone(), - })); + }))); } v => throw!(FieldMustBeStringGot(v.value_type())), } @@ -454,7 +440,7 @@ context: Context, value: &LocExpr, args: &ArgsDesc, - loc: Option<&ExprLocation>, + loc: &ExprLocation, tailstrict: bool, ) -> Result { let value = evaluate(context.clone(), value)?; @@ -475,7 +461,7 @@ let value = &assertion.0; let msg = &assertion.1; let assertion_result = push_frame( - value.1.as_ref(), + &value.1, || "assertion condition".to_owned(), || { evaluate(context.clone(), value)? @@ -484,7 +470,7 @@ )?; if !assertion_result { push_frame( - value.1.as_ref(), + &value.1, || "assertion failure".to_owned(), || { if let Some(msg) = msg { @@ -534,8 +520,8 @@ BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, v1, *o, v2)?, UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?, Var(name) => push_frame( - loc.as_ref(), - || format!("variable <{}>", name), + loc, + || format!("variable <{}> access", name), || context.binding(name.clone())?.evaluate(), )?, Index(value, index) => { @@ -543,7 +529,7 @@ (Val::Obj(v), Val::Str(s)) => { let sn = s.clone(); push_frame( - loc.as_ref(), + loc, || format!("field <{}> access", sn), || { if let Some(v) = v.get(s.clone())? { @@ -591,10 +577,8 @@ } } LocalExpr(bindings, returned) => { - let mut new_bindings: FxHashMap = HashMap::with_capacity_and_hasher( - bindings.len(), - BuildHasherDefault::::default(), - ); + let mut new_bindings: GcHashMap = + GcHashMap::with_capacity(bindings.len()); let future_context = Context::new_future(); for b in bindings { new_bindings.insert( @@ -612,7 +596,6 @@ for item in items { // TODO: Implement ArrValue::Lazy with same context for every element? #[derive(Trace)] - #[trivially_drop] struct ArrayElement { context: Context, item: LocExpr, @@ -622,10 +605,10 @@ evaluate(self.context, &self.item) } } - out.push(LazyVal::new(Box::new(ArrayElement { + out.push(LazyVal::new(TraceBox(Box::new(ArrayElement { context: context.clone(), item: item.clone(), - }))); + })))); } Val::Arr(out.into()) } @@ -635,26 +618,24 @@ out.push(evaluate(ctx, expr)?); Ok(()) })?; - Val::Arr(ArrValue::Eager(Gc::new(out))) + Val::Arr(ArrValue::Eager(Cc::new(out))) } Obj(body) => Val::Obj(evaluate_object(context, body)?), ObjExtend(s, t) => evaluate_add_op( &evaluate(context.clone(), s)?, &Val::Obj(evaluate_object(context, t)?), )?, - Apply(value, args, tailstrict) => { - evaluate_apply(context, value, args, loc.as_ref(), *tailstrict)? - } + Apply(value, args, tailstrict) => evaluate_apply(context, value, args, loc, *tailstrict)?, Function(params, body) => { evaluate_method(context, "anonymous".into(), params.clone(), body.clone()) } - Intrinsic(name) => Val::Func(Gc::new(FuncVal::Intrinsic(name.clone()))), + Intrinsic(name) => Val::Func(Cc::new(FuncVal::Intrinsic(name.clone()))), AssertExpr(assert, returned) => { evaluate_assert(context.clone(), assert)?; evaluate(context, returned)? } ErrorStmt(e) => push_frame( - loc.as_ref(), + loc, || "error statement".to_owned(), || { throw!(RuntimeError( @@ -668,7 +649,7 @@ cond_else, } => { if push_frame( - loc.as_ref(), + loc, || "if condition".to_owned(), || evaluate(context.clone(), &cond.0)?.try_cast_bool("in if condition"), )? { @@ -703,23 +684,17 @@ std_slice(indexable.into_indexable()?, start, end, step)? } Import(path) => { - let tmp = loc - .clone() - .expect("imports cannot be used without loc_data") - .0; + let tmp = loc.clone().0; let mut import_location = tmp.to_path_buf(); import_location.pop(); push_frame( - loc.as_ref(), + loc, || format!("import {:?}", path), || with_state(|s| s.import_file(&import_location, path)), )? } ImportStr(path) => { - let tmp = loc - .clone() - .expect("imports cannot be used without loc_data") - .0; + let tmp = loc.clone().0; let mut import_location = tmp.to_path_buf(); import_location.pop(); Val::Str(with_state(|s| s.import_file_str(&import_location, path))?) --- a/crates/jrsonnet-evaluator/src/function.rs +++ b/crates/jrsonnet-evaluator/src/function.rs @@ -1,18 +1,13 @@ -use crate::{ - error::Error::*, evaluate, evaluate_named, throw, Context, FutureWrapper, LazyVal, - LazyValValue, Result, Val, -}; -use jrsonnet_gc::Trace; +use crate::{Context, FutureWrapper, GcHashMap, LazyVal, LazyValValue, Result, Val, error::Error::*, evaluate, evaluate_named, gc::TraceBox, throw}; +use gcmodule::Trace; use jrsonnet_interner::IStr; use jrsonnet_parser::{ArgsDesc, LocExpr, ParamsDesc}; -use rustc_hash::FxHashMap; -use std::{collections::HashMap, hash::BuildHasherDefault}; +use std::collections::HashMap; const NO_DEFAULT_CONTEXT: &str = "no default context set for call with defined default parameter value"; #[derive(Trace)] -#[trivially_drop] struct EvaluateLazyVal { context: Context, expr: LocExpr, @@ -38,8 +33,7 @@ args: &ArgsDesc, tailstrict: bool, ) -> Result { - let mut passed_args = - HashMap::with_capacity_and_hasher(params.len(), BuildHasherDefault::default()); + let mut passed_args = GcHashMap::with_capacity(params.len()); if args.unnamed.len() > params.len() { throw!(TooManyArgsFunctionHas(params.len())) } @@ -53,10 +47,10 @@ if tailstrict { LazyVal::new_resolved(evaluate(ctx.clone(), arg)?) } else { - LazyVal::new(Box::new(EvaluateLazyVal { + LazyVal::new(TraceBox(Box::new(EvaluateLazyVal { context: ctx.clone(), expr: arg.clone(), - })) + }))) }, ); filled_args += 1; @@ -73,10 +67,10 @@ if tailstrict { LazyVal::new_resolved(evaluate(ctx.clone(), value)?) } else { - LazyVal::new(Box::new(EvaluateLazyVal { + LazyVal::new(TraceBox(Box::new(EvaluateLazyVal { context: ctx.clone(), expr: value.clone(), - })) + }))) }, ) .is_some() @@ -90,17 +84,13 @@ // Some args are unset, but maybe we have defaults for them // Default values should be created in newly created context let future_context = FutureWrapper::::new(); - let mut defaults = HashMap::with_capacity_and_hasher( - params.len() - filled_args, - BuildHasherDefault::default(), - ); + let mut defaults = GcHashMap::with_capacity(params.len() - filled_args); for param in params.iter().filter(|p| p.1.is_some()) { if passed_args.contains_key(¶m.0.clone()) { continue; } #[derive(Trace)] - #[trivially_drop] struct LazyNamedBinding { future_context: FutureWrapper, name: IStr, @@ -111,19 +101,19 @@ evaluate_named(self.future_context.unwrap(), &self.value, self.name) } } - LazyVal::new(Box::new(LazyNamedBinding { + LazyVal::new(TraceBox(Box::new(LazyNamedBinding { future_context: future_context.clone(), name: param.0.clone(), value: param.1.clone().unwrap(), - })); + }))); defaults.insert( param.0.clone(), - LazyVal::new(Box::new(LazyNamedBinding { + LazyVal::new(TraceBox(Box::new(LazyNamedBinding { future_context: future_context.clone(), name: param.0.clone(), value: param.1.clone().unwrap(), - })), + }))), ); filled_args += 1; } @@ -155,7 +145,7 @@ args: &HashMap, tailstrict: bool, ) -> Result { - let mut out = FxHashMap::with_capacity_and_hasher(params.len(), BuildHasherDefault::default()); + let mut out = GcHashMap::with_capacity(params.len()); let mut positioned_args = vec![None; params.0.len()]; for (name, val) in args.iter() { let idx = params @@ -185,7 +175,6 @@ let body_ctx = body_ctx.clone(); let default = default.clone(); #[derive(Trace)] - #[trivially_drop] struct EvaluateLazyVal { body_ctx: Option, default: LocExpr, @@ -198,7 +187,10 @@ ) } } - LazyVal::new(Box::new(EvaluateLazyVal { body_ctx, default })) + LazyVal::new(TraceBox(Box::new(EvaluateLazyVal { + body_ctx, + default, + }))) } } else { throw!(FunctionParameterNotBoundInCall(p.0.clone())); @@ -215,7 +207,7 @@ params: &ParamsDesc, args: &[Val], ) -> Result { - let mut out = FxHashMap::with_capacity_and_hasher(params.len(), BuildHasherDefault::default()); + let mut out = GcHashMap::with_capacity(params.len()); let mut positioned_args = vec![None; params.0.len()]; for (id, arg) in args.iter().enumerate() { if id >= params.len() { @@ -243,7 +235,7 @@ ($ctx: expr, $fn_name: expr, $args: expr, $total_args: expr, [ $($id: expr, $name: ident: $ty: expr $(=>$match: path)?);+ $(;)? ], $handler:block) => {{ - use $crate::{error::Error::*, throw, evaluate, push_frame, typed::CheckType}; + use $crate::{error::Error::*, throw, evaluate, push_description_frame, typed::CheckType}; let args = $args; if args.unnamed.len() + args.named.len() > $total_args { @@ -263,7 +255,7 @@ } else { &$args.unnamed[$id] }; - let $name = push_frame(None, || format!("evaluating argument"), || { + let $name = push_description_frame(|| format!("evaluating builtin argument {}", stringify!($name)), || { let value = evaluate($ctx.clone(), &$name)?; $ty.check(&value)?; Ok(value) --- /dev/null +++ b/crates/jrsonnet-evaluator/src/gc.rs @@ -0,0 +1,141 @@ +/// Macros to help deal with Gc +use std::{ + borrow::{Borrow, BorrowMut}, + hash::BuildHasherDefault, + ops::{Deref, DerefMut}, +}; + +use gcmodule::{Trace, Tracer}; +use rustc_hash::{FxHashMap, FxHashSet}; + +/// Replacement for box, which assumes that the underlying type is [`Trace`] +#[derive(Debug, Clone)] +pub struct TraceBox(pub Box); + +impl Trace for TraceBox { + fn trace(&self, tracer: &mut Tracer) { + self.0.trace(tracer) + } + + fn is_type_tracked() -> bool { + return true; + } +} + +// TODO: Replace with CoerceUnsized +impl From> for TraceBox { + fn from(inner: Box) -> Self { + Self(inner) + } +} + +impl Deref for TraceBox { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for TraceBox { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl Borrow for TraceBox { + fn borrow(&self) -> &T { + &*self.0 + } +} + +impl BorrowMut for TraceBox { + fn borrow_mut(&mut self) -> &mut T { + &mut *self.0 + } +} + +impl AsRef for TraceBox { + fn as_ref(&self) -> &T { + &*self.0 + } +} + +impl AsMut for TraceBox { + fn as_mut(&mut self) -> &mut T { + &mut *self.0 + } +} + +#[derive(Clone)] +pub struct GcHashSet(pub FxHashSet); +impl GcHashSet { + pub fn new() -> Self { + Self(Default::default()) + } + pub fn with_capacity(capacity: usize) -> Self { + Self(FxHashSet::with_capacity_and_hasher( + capacity, + BuildHasherDefault::default(), + )) + } +} +impl Trace for GcHashSet +where + V: Trace, +{ + fn trace(&self, tracer: &mut gcmodule::Tracer) { + for v in &self.0 { + v.trace(tracer); + } + } +} +impl Deref for GcHashSet { + type Target = FxHashSet; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for GcHashSet { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +#[derive(Clone)] +pub struct GcHashMap(pub FxHashMap); +impl GcHashMap { + pub fn new() -> Self { + Self(Default::default()) + } + pub fn with_capacity(capacity: usize) -> Self { + Self(FxHashMap::with_capacity_and_hasher( + capacity, + BuildHasherDefault::default(), + )) + } +} +impl Trace for GcHashMap +where + K: Trace, + V: Trace, +{ + fn trace(&self, tracer: &mut gcmodule::Tracer) { + for (k, v) in &self.0 { + k.trace(tracer); + v.trace(tracer); + } + } +} +impl Deref for GcHashMap { + type Target = FxHashMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for GcHashMap { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} --- a/crates/jrsonnet-evaluator/src/lib.rs +++ b/crates/jrsonnet-evaluator/src/lib.rs @@ -25,30 +25,31 @@ use error::{Error::*, LocError, Result, StackTraceElement}; pub use evaluate::*; pub use function::parse_function_call; +use gc::{GcHashMap, TraceBox}; +use gcmodule::{Cc, Trace}; pub use import::*; -use jrsonnet_gc::{Finalize, Gc, Trace}; pub use jrsonnet_interner::IStr; use jrsonnet_parser::*; use native::NativeCallback; pub use obj::*; -use rustc_hash::FxHashMap; use std::{ cell::{Ref, RefCell, RefMut}, collections::HashMap, fmt::Debug, - hash::BuildHasherDefault, path::{Path, PathBuf}, rc::Rc, }; use trace::{location_to_offset, offset_to_location, CodeLocation, CompactFormat, TraceFormat}; pub use val::*; +pub mod gc; -pub trait Bindable: Trace { +pub trait Bindable: Trace + 'static { fn bind(&self, this: Option, super_obj: Option) -> Result; } -#[derive(Trace, Finalize, Clone)] + +#[derive(Clone, Trace)] pub enum LazyBinding { - Bindable(Gc>), + Bindable(Cc>), Bound(LazyVal), } @@ -74,7 +75,7 @@ /// Used for s`td.extVar` pub ext_vars: HashMap, /// Used for ext.native - pub ext_natives: HashMap>, + pub ext_natives: HashMap>, /// TLA vars pub tla_vars: HashMap, /// Global variables are inserted in default context @@ -172,19 +173,27 @@ EVAL_STATE.with(|s| f(s.borrow().as_ref().unwrap())) } pub(crate) fn push_frame( - e: Option<&ExprLocation>, + e: &ExprLocation, frame_desc: impl FnOnce() -> String, f: impl FnOnce() -> Result, ) -> Result { with_state(|s| s.push(e, frame_desc, f)) } +#[allow(dead_code)] pub(crate) fn push_val_frame( - e: Option<&ExprLocation>, + e: &ExprLocation, frame_desc: impl FnOnce() -> String, f: impl FnOnce() -> Result, ) -> Result { - with_state(|s| s.push(e, frame_desc, f)) + with_state(|s| s.push_val(e, frame_desc, f)) +} +#[allow(dead_code)] +pub(crate) fn push_description_frame( + frame_desc: impl FnOnce() -> String, + f: impl FnOnce() -> Result, +) -> Result { + with_state(|s| s.push_description(frame_desc, f)) } /// Maintains stack trace and import resolution @@ -201,7 +210,6 @@ &source_code, &ParserSettings { file_name: path.clone(), - loc_data: true, }, ) .map_err(|error| ImportSyntaxError { @@ -246,7 +254,7 @@ ro_map.get(name).map(|value| value.source_code.clone()) } pub fn map_source_locations(&self, file: &Path, locs: &[usize]) -> Vec { - offset_to_location(&self.get_source(file).unwrap(), locs) + offset_to_location(&self.get_source(file).unwrap_or("".into()), locs) } pub fn map_from_source_location( &self, @@ -322,8 +330,7 @@ /// Creates context with all passed global variables pub fn create_default_context(&self) -> Context { let globals = &self.settings().globals; - let mut new_bindings: FxHashMap = - FxHashMap::with_capacity_and_hasher(globals.len(), BuildHasherDefault::default()); + let mut new_bindings = GcHashMap::with_capacity(globals.len()); for (name, value) in globals.iter() { new_bindings.insert(name.clone(), LazyVal::new_resolved(value.clone())); } @@ -333,7 +340,7 @@ /// Executes code creating a new stack frame pub fn push( &self, - e: Option<&ExprLocation>, + e: &ExprLocation, frame_desc: impl FnOnce() -> String, f: impl FnOnce() -> Result, ) -> Result { @@ -353,25 +360,21 @@ let mut data = self.data_mut(); data.stack_depth -= 1; data.stack_generation += 1; - // if let Some(e) = e { - // result = - // data.breakpoints - // .insert(data.stack_depth, data.stack_generation, &e, result) - // } } if let Err(mut err) = result { err.trace_mut().0.push(StackTraceElement { - location: e.cloned(), + location: Some(e.clone()), desc: frame_desc(), }); return Err(err); } result } + /// Executes code creating a new stack frame pub fn push_val( &self, - e: Option<&ExprLocation>, + e: &ExprLocation, frame_desc: impl FnOnce() -> String, f: impl FnOnce() -> Result, ) -> Result { @@ -391,15 +394,45 @@ let mut data = self.data_mut(); data.stack_depth -= 1; data.stack_generation += 1; - if let Some(e) = e { - result = - data.breakpoints - .insert(data.stack_depth, data.stack_generation, &e, result) + result = data + .breakpoints + .insert(data.stack_depth, data.stack_generation, &e, result); + } + if let Err(mut err) = result { + err.trace_mut().0.push(StackTraceElement { + location: Some(e.clone()), + desc: frame_desc(), + }); + return Err(err); + } + result + } + /// Executes code creating a new stack frame + pub fn push_description( + &self, + frame_desc: impl FnOnce() -> String, + f: impl FnOnce() -> Result, + ) -> Result { + { + let mut data = self.data_mut(); + let stack_depth = &mut data.stack_depth; + if *stack_depth > self.max_stack() { + // Error creation uses data, so i drop guard here + drop(data); + throw!(StackOverflow); + } else { + *stack_depth += 1; } } + let result = f(); + { + let mut data = self.data_mut(); + data.stack_depth -= 1; + data.stack_generation += 1; + } if let Err(mut err) = result { err.trace_mut().0.push(StackTraceElement { - location: e.cloned(), + location: None, desc: frame_desc(), }); return Err(err); @@ -451,7 +484,12 @@ } pub fn manifest(&self, val: Val) -> Result { - self.run_in_state(|| val.manifest(&self.manifest_format())) + self.run_in_state(|| { + push_description_frame( + || format!("manifestification"), + || val.manifest(&self.manifest_format()), + ) + }) } pub fn manifest_multi(&self, val: Val) -> Result> { self.run_in_state(|| val.manifest_multi(&self.manifest_format())) @@ -464,8 +502,7 @@ pub fn with_tla(&self, val: Val) -> Result { self.run_in_state(|| { Ok(match val { - Val::Func(func) => push_frame( - None, + Val::Func(func) => push_description_frame( || "during TLA call".to_owned(), || { func.evaluate_map( @@ -511,7 +548,6 @@ &code, &ParserSettings { file_name: source.clone(), - loc_data: true, }, ) .map_err(|e| ImportSyntaxError { @@ -570,7 +606,7 @@ self.settings_mut().import_resolver = resolver; } - pub fn add_native(&self, name: IStr, cb: Gc) { + pub fn add_native(&self, name: IStr, cb: Cc) { self.settings_mut().ext_natives.insert(name, cb); } @@ -603,13 +639,20 @@ } } +pub fn cc_ptr_eq(a: &Cc, b: &Cc) -> bool { + let a = &a as &T; + let b = &b as &T; + std::ptr::eq(a, b) +} + #[cfg(test)] pub mod tests { use super::Val; use crate::{ - error::Error::*, native::NativeCallbackHandler, primitive_equals, EvaluationState, + error::Error::*, gc::TraceBox, native::NativeCallbackHandler, primitive_equals, + EvaluationState, }; - use jrsonnet_gc::{Finalize, Gc, Trace}; + use gcmodule::{Cc, Trace}; use jrsonnet_interner::IStr; use jrsonnet_parser::*; use std::{ @@ -624,11 +667,11 @@ state.run_in_state(|| { state .push( - Some(&ExprLocation(PathBuf::from("test1.jsonnet").into(), 10, 20)), + &ExprLocation(PathBuf::from("test1.jsonnet").into(), 10, 20), || "outer".to_owned(), || { state.push( - Some(&ExprLocation(PathBuf::from("test2.jsonnet").into(), 30, 40)), + &ExprLocation(PathBuf::from("test2.jsonnet").into(), 30, 40), || "inner".to_owned(), || Err(RuntimeError("".into()).into()), )?; @@ -1028,7 +1071,6 @@ "{ x: 1, y: 2 } == { x: 1, y: 2 }", &ParserSettings { file_name: PathBuf::from("equality").into(), - loc_data: true, } ) ); @@ -1042,14 +1084,11 @@ evaluator.with_stdlib(); - #[derive(Trace, Finalize)] + #[derive(Trace)] struct NativeAdd; impl NativeCallbackHandler for NativeAdd { - fn call(&self, from: Option>, args: &[Val]) -> crate::error::Result { - assert_eq!( - &from.unwrap() as &Path, - &PathBuf::from("native_caller.jsonnet") - ); + fn call(&self, from: Rc, args: &[Val]) -> crate::error::Result { + assert_eq!(&from as &Path, &PathBuf::from("native_caller.jsonnet")); match (&args[0], &args[1]) { (Val::Num(a), Val::Num(b)) => Ok(Val::Num(a + b)), (_, _) => unreachable!(), @@ -1058,12 +1097,12 @@ } evaluator.settings_mut().ext_natives.insert( "native_add".into(), - Gc::new(NativeCallback::new( + Cc::new(NativeCallback::new( ParamsDesc(Rc::new(vec![ Param("a".into(), None), Param("b".into(), None), ])), - Box::new(NativeAdd), + TraceBox(Box::new(NativeAdd)), )), ); evaluator.evaluate_snippet_raw( --- a/crates/jrsonnet-evaluator/src/map.rs +++ b/crates/jrsonnet-evaluator/src/map.rs @@ -1,23 +1,21 @@ -use jrsonnet_gc::{Gc, Trace}; +use gcmodule::{Cc, Trace}; use jrsonnet_interner::IStr; -use rustc_hash::FxHashMap; -use crate::LazyVal; +use crate::{GcHashMap, LazyVal}; #[derive(Trace)] -#[trivially_drop] +#[force_tracking] pub struct LayeredHashMapInternals { parent: Option, - current: FxHashMap, + current: GcHashMap, } #[derive(Trace)] -#[trivially_drop] -pub struct LayeredHashMap(Gc); +pub struct LayeredHashMap(Cc); impl LayeredHashMap { - pub fn extend(self, new_layer: FxHashMap) -> Self { - Self(Gc::new(LayeredHashMapInternals { + pub fn extend(self, new_layer: GcHashMap) -> Self { + Self(Cc::new(LayeredHashMapInternals { parent: Some(self), current: new_layer, })) @@ -49,9 +47,9 @@ impl Default for LayeredHashMap { fn default() -> Self { - Self(Gc::new(LayeredHashMapInternals { + Self(Cc::new(LayeredHashMapInternals { parent: None, - current: FxHashMap::default(), + current: GcHashMap::new(), })) } } --- a/crates/jrsonnet-evaluator/src/native.rs +++ b/crates/jrsonnet-evaluator/src/native.rs @@ -1,27 +1,27 @@ #![allow(clippy::type_complexity)] +use crate::gc::TraceBox; use crate::{error::Result, Val}; -use jrsonnet_gc::Trace; +use gcmodule::Trace; use jrsonnet_parser::ParamsDesc; use std::fmt::Debug; use std::path::Path; use std::rc::Rc; pub trait NativeCallbackHandler: Trace { - fn call(&self, from: Option>, args: &[Val]) -> Result; + fn call(&self, from: Rc, args: &[Val]) -> Result; } #[derive(Trace)] -#[trivially_drop] pub struct NativeCallback { pub params: ParamsDesc, - handler: Box, + handler: TraceBox, } impl NativeCallback { - pub fn new(params: ParamsDesc, handler: Box) -> Self { + pub fn new(params: ParamsDesc, handler: TraceBox) -> Self { Self { params, handler } } - pub fn call(&self, caller: Option>, args: &[Val]) -> Result { + pub fn call(&self, caller: Rc, args: &[Val]) -> Result { self.handler.call(caller, args) } } --- a/crates/jrsonnet-evaluator/src/obj.rs +++ b/crates/jrsonnet-evaluator/src/obj.rs @@ -1,15 +1,15 @@ +use crate::gc::{GcHashMap, GcHashSet, TraceBox}; use crate::operator::evaluate_add_op; -use crate::{Bindable, LazyBinding, LazyVal, Result, Val}; -use jrsonnet_gc::{Gc, GcCell, Trace}; +use crate::{cc_ptr_eq, Bindable, LazyBinding, LazyVal, Result, Val}; +use gcmodule::{Cc, Trace}; use jrsonnet_interner::IStr; use jrsonnet_parser::{ExprLocation, Visibility}; -use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; -use std::collections::HashMap; +use rustc_hash::FxHashMap; +use std::cell::RefCell; +use std::fmt::Debug; use std::hash::{Hash, Hasher}; -use std::{fmt::Debug, hash::BuildHasherDefault}; #[derive(Debug, Trace)] -#[trivially_drop] pub struct ObjMember { pub add: bool, pub visibility: Visibility, @@ -24,19 +24,18 @@ // Field => This type CacheKey = (IStr, ObjValue); #[derive(Trace)] -#[trivially_drop] +#[force_tracking] pub struct ObjValueInternals { super_obj: Option, - assertions: Gc>>, - assertions_ran: GcCell>, + assertions: Cc>>, + assertions_ran: RefCell>, this_obj: Option, - this_entries: Gc>, - value_cache: GcCell>>, + this_entries: Cc>, + value_cache: RefCell>>, } #[derive(Clone, Trace)] -#[trivially_drop] -pub struct ObjValue(pub(crate) Gc); +pub struct ObjValue(pub(crate) Cc); impl Debug for ObjValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if let Some(super_obj) = self.0.super_obj.as_ref() { @@ -65,20 +64,20 @@ impl ObjValue { pub fn new( super_obj: Option, - this_entries: Gc>, - assertions: Gc>>, + this_entries: Cc>, + assertions: Cc>>, ) -> Self { - Self(Gc::new(ObjValueInternals { + Self(Cc::new(ObjValueInternals { super_obj, assertions, - assertions_ran: GcCell::new(FxHashSet::default()), + assertions_ran: RefCell::new(GcHashSet::new()), this_obj: None, this_entries, - value_cache: GcCell::new(FxHashMap::default()), + value_cache: RefCell::new(GcHashMap::new()), })) } pub fn new_empty() -> Self { - Self::new(None, Gc::new(FxHashMap::default()), Gc::new(Vec::new())) + Self::new(None, Cc::new(GcHashMap::new()), Cc::new(Vec::new())) } pub fn extend_from(&self, super_obj: Self) -> Self { match &self.0.super_obj { @@ -95,13 +94,13 @@ } } pub fn with_this(&self, this_obj: Self) -> Self { - Self(Gc::new(ObjValueInternals { + Self(Cc::new(ObjValueInternals { super_obj: self.0.super_obj.clone(), assertions: self.0.assertions.clone(), - assertions_ran: GcCell::new(FxHashSet::default()), + assertions_ran: RefCell::new(GcHashSet::new()), this_obj: Some(this_obj), this_entries: self.0.this_entries.clone(), - value_cache: GcCell::new(FxHashMap::default()), + value_cache: RefCell::new(GcHashMap::new()), })) } @@ -117,14 +116,14 @@ } /// Run callback for every field found in object - pub(crate) fn enum_fields(&self, handler: &mut impl FnMut(&IStr, &Visibility) -> bool) -> bool { + pub(crate) fn enum_fields(&self, handler: &mut impl FnMut(&IStr, &ObjMember) -> bool) -> bool { if let Some(s) = &self.0.super_obj { if s.enum_fields(handler) { return true; } } for (name, member) in self.0.this_entries.iter() { - if handler(name, &member.visibility) { + if handler(name, &member) { return true; } } @@ -133,8 +132,8 @@ pub fn fields_visibility(&self) -> FxHashMap { let mut out = FxHashMap::default(); - self.enum_fields(&mut |name, visibility| { - match visibility { + self.enum_fields(&mut |name, member| { + match member.visibility { Visibility::Normal => { let entry = out.entry(name.to_owned()); entry.or_insert(true); @@ -211,9 +210,9 @@ } pub fn extend_with_field(self, key: IStr, value: ObjMember) -> Self { - let mut new = FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default()); + let mut new = GcHashMap::with_capacity(1); new.insert(key, value); - Self::new(Some(self), Gc::new(new), Gc::new(Vec::new())) + Self::new(Some(self), Cc::new(new), Cc::new(Vec::new())) } fn get_raw(&self, key: IStr, real_this: Option<&Self>) -> Result> { @@ -270,13 +269,13 @@ } pub fn ptr_eq(a: &Self, b: &Self) -> bool { - Gc::ptr_eq(&a.0, &b.0) + cc_ptr_eq(&a.0, &b.0) } } impl PartialEq for ObjValue { fn eq(&self, other: &Self) -> bool { - Gc::ptr_eq(&self.0, &other.0) + cc_ptr_eq(&self.0, &other.0) } } @@ -289,8 +288,8 @@ pub struct ObjValueBuilder { super_obj: Option, - map: FxHashMap, - assertions: Vec>, + map: GcHashMap, + assertions: Vec>, } impl ObjValueBuilder { pub fn new() -> Self { @@ -299,10 +298,7 @@ pub fn with_capacity(capacity: usize) -> Self { Self { super_obj: None, - map: HashMap::with_capacity_and_hasher( - capacity, - BuildHasherDefault::::default(), - ), + map: GcHashMap::with_capacity(capacity), assertions: Vec::new(), } } @@ -315,7 +311,7 @@ self } - pub fn assert(&mut self, assertion: Box) -> &mut Self { + pub fn assert(&mut self, assertion: TraceBox) -> &mut Self { self.assertions.push(assertion); self } @@ -330,7 +326,7 @@ } pub fn build(self) -> ObjValue { - ObjValue::new(self.super_obj, Gc::new(self.map), Gc::new(self.assertions)) + ObjValue::new(self.super_obj, Cc::new(self.map), Cc::new(self.assertions)) } } impl Default for ObjValueBuilder { @@ -364,15 +360,15 @@ pub fn hide(self) -> Self { self.with_visibility(Visibility::Hidden) } - pub fn with_location(mut self, location: Option) -> Self { - self.location = location; + pub fn with_location(mut self, location: ExprLocation) -> Self { + self.location = Some(location); self } pub fn value(self, value: Val) -> &'v mut ObjValueBuilder { self.binding(LazyBinding::Bound(LazyVal::new_resolved(value))) } - pub fn bindable(self, bindable: Box) -> &'v mut ObjValueBuilder { - self.binding(LazyBinding::Bindable(Gc::new(bindable))) + pub fn bindable(self, bindable: TraceBox) -> &'v mut ObjValueBuilder { + self.binding(LazyBinding::Bindable(Cc::new(bindable))) } pub fn binding(self, binding: LazyBinding) -> &'v mut ObjValueBuilder { self.value.map.insert( --- a/crates/jrsonnet-evaluator/src/trace/mod.rs +++ b/crates/jrsonnet-evaluator/src/trace/mod.rs @@ -119,16 +119,21 @@ .trace() .0 .iter() - .map(|el| { - el.location.as_ref().map(|l| { - use std::fmt::Write; - let mut resolved_path = self.resolver.resolve(&l.0); + .map(|el| &el.location) + .map(|location| { + use std::fmt::Write; + if let Some(location) = location { + let mut resolved_path = self.resolver.resolve(&location.0); // TODO: Process all trace elements first - let location = evaluation_state.map_source_locations(&l.0, &[l.1, l.2]); + let location = evaluation_state + .map_source_locations(&location.0, &[location.1, location.2]); write!(resolved_path, ":").unwrap(); print_code_location(&mut resolved_path, &location[0], &location[1]).unwrap(); - resolved_path - }) + write!(resolved_path, ":").unwrap(); + Some(resolved_path) + } else { + None + } }) .collect::>(); let align = file_names @@ -139,15 +144,19 @@ .unwrap_or(0); for (el, file) in error.trace().0.iter().zip(file_names) { writeln!(out)?; - write!( - out, - "{:= source_code.len() { - offset = source_code.len() - 1; - } - let mut location = offset_to_location(source_code, &[offset]) + let offset = error.location.offset; + let location = offset_to_location(source_code, &[offset]) .into_iter() .next() .unwrap(); - if location.column >= 1 { - location.column -= 1; - } + let mut end_location = location.clone(); + end_location.offset += 1; self.print_snippet( out, source_code, path, &location, - &location, - "^ syntax error", + &end_location, + "syntax error", )?; } let trace = &error.trace(); @@ -289,7 +294,7 @@ annotation_type: AnnotationType::Error, range: ( start.offset - start.line_start_offset, - end.offset - start.line_start_offset, + (end.offset - start.line_start_offset).min(source_fragment.len()), ), }], }], --- a/crates/jrsonnet-evaluator/src/typed.rs +++ b/crates/jrsonnet-evaluator/src/typed.rs @@ -1,11 +1,7 @@ use std::{fmt::Display, rc::Rc}; -use crate::{ - error::{Error, LocError, Result}, - push_frame, Val, -}; -use jrsonnet_gc::Trace; -use jrsonnet_parser::ExprLocation; +use crate::{Val, error::{Error, LocError, Result}, push_description_frame}; +use gcmodule::Trace; use jrsonnet_types::{ComplexValType, ValType}; use thiserror::Error; @@ -22,12 +18,11 @@ } #[derive(Debug, Error, Clone, Trace)] -#[trivially_drop] pub enum TypeError { #[error("expected {0}, got {1}")] ExpectedGot(ComplexValType, ValType), #[error("missing property {0} from {1:?}")] - MissingProperty(Rc, ComplexValType), + MissingProperty(#[skip_trace] Rc, ComplexValType), #[error("every failed from {0}:\n{1}")] UnionFailed(ComplexValType, TypeLocErrorList), #[error( @@ -44,7 +39,6 @@ } #[derive(Debug, Clone, Trace)] -#[trivially_drop] pub struct TypeLocError(Box, ValuePathStack); impl From for TypeLocError { fn from(e: TypeError) -> Self { @@ -67,7 +61,6 @@ } #[derive(Debug, Clone, Trace)] -#[trivially_drop] pub struct TypeLocErrorList(Vec); impl Display for TypeLocErrorList { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -97,13 +90,12 @@ } } -fn push_type( - location: Option<&ExprLocation>, +fn push_type_description( error_reason: impl Fn() -> String, path: impl Fn() -> ValuePathItem, item: impl Fn() -> Result<()>, ) -> Result<()> { - push_frame(location, error_reason, || match item() { + push_description_frame(error_reason, || match item() { Ok(_) => Ok(()), Err(mut e) => { if let Error::TypeError(e) = &mut e.error_mut() { @@ -131,9 +123,8 @@ } #[derive(Clone, Debug, Trace)] -#[trivially_drop] enum ValuePathItem { - Field(Rc), + Field(#[skip_trace] Rc), Index(u64), } impl Display for ValuePathItem { @@ -147,7 +138,6 @@ } #[derive(Clone, Debug, Trace)] -#[trivially_drop] struct ValuePathStack(Vec); impl Display for ValuePathStack { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -183,8 +173,7 @@ Self::Array(elem_type) => match value { Val::Arr(a) => { for (i, item) in a.iter().enumerate() { - push_type( - None, + push_type_description( || format!("array index {}", i), || ValuePathItem::Index(i as u64), || elem_type.check(&item.clone()?), @@ -197,8 +186,7 @@ Self::ArrayRef(elem_type) => match value { Val::Arr(a) => { for (i, item) in a.iter().enumerate() { - push_type( - None, + push_type_description( || format!("array index {}", i), || ValuePathItem::Index(i as u64), || elem_type.check(&item.clone()?), @@ -212,8 +200,7 @@ Val::Obj(obj) => { for (k, v) in elems.iter() { if let Some(got_v) = obj.get((*k).into())? { - push_type( - None, + push_type_description( || format!("property {}", k), || ValuePathItem::Field((*k).into()), || v.check(&got_v), --- a/crates/jrsonnet-evaluator/src/val.rs +++ b/crates/jrsonnet-evaluator/src/val.rs @@ -6,40 +6,40 @@ ManifestYamlOptions, }, }, + cc_ptr_eq, error::{Error::*, LocError}, evaluate, function::{parse_function_call, parse_function_call_map, place_args}, + gc::TraceBox, native::NativeCallback, throw, Context, ObjValue, Result, }; -use jrsonnet_gc::{Gc, GcCell, Trace}; +use gcmodule::{Cc, Trace}; use jrsonnet_interner::IStr; use jrsonnet_parser::{ArgsDesc, ExprLocation, LocExpr, ParamsDesc}; use jrsonnet_types::ValType; -use std::{collections::HashMap, fmt::Debug, rc::Rc}; +use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc}; pub trait LazyValValue: Trace { fn get(self: Box) -> Result; } #[derive(Trace)] -#[trivially_drop] enum LazyValInternals { Computed(Val), Errored(LocError), - Waiting(Box), + Waiting(TraceBox), Pending, } #[derive(Clone, Trace)] -#[trivially_drop] -pub struct LazyVal(Gc>); +pub struct LazyVal(Cc>); impl LazyVal { - pub fn new(f: Box) -> Self { - Self(Gc::new(GcCell::new(LazyValInternals::Waiting(f)))) + pub fn new(f: TraceBox) -> Self { + Self(Cc::new(RefCell::new(LazyValInternals::Waiting(f)))) } pub fn new_resolved(val: Val) -> Self { - Self(Gc::new(GcCell::new(LazyValInternals::Computed(val)))) + Self(Cc::new(RefCell::new(LazyValInternals::Computed(val)))) } pub fn evaluate(&self) -> Result { match &*self.0.borrow() { @@ -55,7 +55,7 @@ } else { unreachable!() }; - let new_value = match value.get() { + let new_value = match value.0.get() { Ok(v) => v, Err(e) => { *self.0.borrow_mut() = LazyValInternals::Errored(e.clone()); @@ -74,12 +74,11 @@ } impl PartialEq for LazyVal { fn eq(&self, other: &Self) -> bool { - Gc::ptr_eq(&self.0, &other.0) + cc_ptr_eq(&self.0, &other.0) } } #[derive(Debug, PartialEq, Trace)] -#[trivially_drop] pub struct FuncDesc { pub name: IStr, pub ctx: Context, @@ -88,14 +87,13 @@ } #[derive(Debug, Trace)] -#[trivially_drop] pub enum FuncVal { /// Plain function implemented in jsonnet Normal(FuncDesc), /// Standard library function Intrinsic(IStr), /// Library functions implemented in native - NativeExt(IStr, Gc), + NativeExt(IStr, Cc), } impl PartialEq for FuncVal { @@ -122,7 +120,7 @@ pub fn evaluate( &self, call_ctx: Context, - loc: Option<&ExprLocation>, + loc: &ExprLocation, args: &ArgsDesc, tailstrict: bool, ) -> Result { @@ -145,7 +143,7 @@ for p in handler.params.0.iter() { out_args.push(args.binding(p.0.clone())?.evaluate()?); } - Ok(handler.call(loc.map(|l| l.0.clone()), &out_args)?) + Ok(handler.call(loc.0.clone(), &out_args)?) } } } @@ -194,15 +192,15 @@ } #[derive(Debug, Clone, Trace)] -#[trivially_drop] +#[force_tracking] pub enum ArrValue { - Lazy(Gc>), - Eager(Gc>), + Lazy(Cc>), + Eager(Cc>), Extended(Box<(Self, Self)>), } impl ArrValue { pub fn new_eager() -> Self { - Self::Eager(Gc::new(Vec::new())) + Self::Eager(Cc::new(Vec::new())) } pub fn len(&self) -> usize { @@ -253,14 +251,14 @@ } } - pub fn evaluated(&self) -> Result>> { + pub fn evaluated(&self) -> Result>> { Ok(match self { Self::Lazy(vec) => { let mut out = Vec::with_capacity(vec.len()); for item in vec.iter() { out.push(item.evaluate()?); } - Gc::new(out) + Cc::new(out) } Self::Eager(vec) => vec.clone(), Self::Extended(_v) => { @@ -268,7 +266,7 @@ for item in self.iter() { out.push(item?); } - Gc::new(out) + Cc::new(out) } }) } @@ -294,12 +292,12 @@ Self::Lazy(vec) => { let mut out = (&vec as &Vec<_>).clone(); out.reverse(); - Self::Lazy(Gc::new(out)) + Self::Lazy(Cc::new(out)) } Self::Eager(vec) => { let mut out = (&vec as &Vec<_>).clone(); out.reverse(); - Self::Eager(Gc::new(out)) + Self::Eager(Cc::new(out)) } Self::Extended(b) => Self::Extended(Box::new((b.1.reversed(), b.0.reversed()))), } @@ -312,7 +310,7 @@ out.push(mapper(value?)?); } - Ok(Self::Eager(Gc::new(out))) + Ok(Self::Eager(Cc::new(out))) } pub fn filter(self, filter: impl Fn(&Val) -> Result) -> Result { @@ -325,13 +323,13 @@ } } - Ok(Self::Eager(Gc::new(out))) + Ok(Self::Eager(Cc::new(out))) } pub fn ptr_eq(a: &Self, b: &Self) -> bool { match (a, b) { - (Self::Lazy(a), Self::Lazy(b)) => Gc::ptr_eq(a, b), - (Self::Eager(a), Self::Eager(b)) => Gc::ptr_eq(a, b), + (Self::Lazy(a), Self::Lazy(b)) => cc_ptr_eq(a, b), + (Self::Eager(a), Self::Eager(b)) => cc_ptr_eq(a, b), _ => false, } } @@ -339,13 +337,13 @@ impl From> for ArrValue { fn from(v: Vec) -> Self { - Self::Lazy(Gc::new(v)) + Self::Lazy(Cc::new(v)) } } impl From> for ArrValue { fn from(v: Vec) -> Self { - Self::Eager(Gc::new(v)) + Self::Eager(Cc::new(v)) } } @@ -355,7 +353,6 @@ } #[derive(Debug, Clone, Trace)] -#[trivially_drop] pub enum Val { Bool(bool), Null, @@ -363,7 +360,7 @@ Num(f64), Arr(ArrValue), Obj(ObjValue), - Func(Gc), + Func(Cc), } macro_rules! matches_unwrap { @@ -402,7 +399,7 @@ pub fn unwrap_arr(self) -> Result { Ok(matches_unwrap!(self, Self::Arr(v), v)) } - pub fn unwrap_func(self) -> Result> { + pub fn unwrap_func(self) -> Result> { Ok(matches_unwrap!(self, Self::Func(v), v)) } pub fn try_cast_bool(self, context: &'static str) -> Result { --- a/crates/jrsonnet-interner/Cargo.toml +++ b/crates/jrsonnet-interner/Cargo.toml @@ -9,4 +9,4 @@ [dependencies] serde = { version = "1.0" } rustc-hash = "1.1.0" -jrsonnet-gc = { version = "0.4.2", features = ["derive"] } +gcmodule = { git = "https://github.com/CertainLach/gcmodule", branch = "jrsonnet" } --- a/crates/jrsonnet-interner/src/lib.rs +++ b/crates/jrsonnet-interner/src/lib.rs @@ -1,4 +1,4 @@ -use jrsonnet_gc::{unsafe_empty_trace, Finalize, Trace}; +use gcmodule::Trace; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; use std::{ @@ -11,9 +11,10 @@ #[derive(Clone, PartialOrd, Ord, Eq)] pub struct IStr(Rc); -impl Finalize for IStr {} -unsafe impl Trace for IStr { - unsafe_empty_trace!(); +impl Trace for IStr { + fn is_type_tracked() -> bool { + false + } } impl Deref for IStr { --- a/crates/jrsonnet-parser/Cargo.toml +++ b/crates/jrsonnet-parser/Cargo.toml @@ -15,10 +15,9 @@ jrsonnet-interner = { path = "../jrsonnet-interner", version = "0.4.2" } peg = "0.7.0" -unescape = "0.1.0" serde = { version = "1.0", features = ["derive", "rc"], optional = true } -jrsonnet-gc = { version = "0.4.2", features = ["derive"] } +gcmodule = { git = "https://github.com/CertainLach/gcmodule", branch = "jrsonnet" } [dev-dependencies] jrsonnet-stdlib = { path = "../jrsonnet-stdlib", version = "0.4.2" } --- a/crates/jrsonnet-parser/src/expr.rs +++ b/crates/jrsonnet-parser/src/expr.rs @@ -1,4 +1,4 @@ -use jrsonnet_gc::{unsafe_empty_trace, Finalize, Trace}; +use gcmodule::Trace; use jrsonnet_interner::IStr; #[cfg(feature = "deserialize")] use serde::Deserialize; @@ -14,7 +14,6 @@ #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[derive(Debug, PartialEq, Trace)] -#[trivially_drop] pub enum FieldName { /// {fixed: 2} Fixed(IStr), @@ -25,7 +24,6 @@ #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[derive(Debug, Clone, Copy, PartialEq, Trace)] -#[trivially_drop] pub enum Visibility { /// : Normal, @@ -44,13 +42,11 @@ #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[derive(Clone, Debug, PartialEq, Trace)] -#[trivially_drop] pub struct AssertStmt(pub LocExpr, pub Option); #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[derive(Debug, PartialEq, Trace)] -#[trivially_drop] pub struct FieldMember { pub name: FieldName, pub plus: bool, @@ -62,7 +58,6 @@ #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[derive(Debug, PartialEq, Trace)] -#[trivially_drop] pub enum Member { Field(FieldMember), BindStmt(BindSpec), @@ -72,7 +67,6 @@ #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[derive(Debug, Clone, Copy, PartialEq, Trace)] -#[trivially_drop] pub enum UnaryOpType { Plus, Minus, @@ -99,7 +93,6 @@ #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[derive(Debug, Clone, Copy, PartialEq, Trace)] -#[trivially_drop] pub enum BinaryOpType { Mul, Div, @@ -167,21 +160,13 @@ #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[derive(Debug, PartialEq, Trace)] -#[trivially_drop] pub struct Param(pub IStr, pub Option); /// Defined function parameters #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Trace)] pub struct ParamsDesc(pub Rc>); - -/// Safety: -/// AST is acyclic, and there should be no gc pointers -unsafe impl Trace for ParamsDesc { - unsafe_empty_trace!(); -} -impl Finalize for ParamsDesc {} impl Deref for ParamsDesc { type Target = Vec; @@ -193,7 +178,6 @@ #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[derive(Debug, PartialEq, Trace)] -#[trivially_drop] pub struct ArgsDesc { pub unnamed: Vec, pub named: Vec<(IStr, LocExpr)>, @@ -207,7 +191,6 @@ #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[derive(Debug, Clone, PartialEq, Trace)] -#[trivially_drop] pub struct BindSpec { pub name: IStr, pub params: Option, @@ -217,19 +200,16 @@ #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[derive(Debug, PartialEq, Trace)] -#[trivially_drop] pub struct IfSpecData(pub LocExpr); #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[derive(Debug, PartialEq, Trace)] -#[trivially_drop] pub struct ForSpecData(pub IStr, pub LocExpr); #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[derive(Debug, PartialEq, Trace)] -#[trivially_drop] pub enum CompSpec { IfSpec(IfSpecData), ForSpec(ForSpecData), @@ -238,7 +218,6 @@ #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[derive(Debug, PartialEq, Trace)] -#[trivially_drop] pub struct ObjComp { pub pre_locals: Vec, pub key: LocExpr, @@ -251,7 +230,6 @@ #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[derive(Debug, PartialEq, Trace)] -#[trivially_drop] pub enum ObjBody { MemberList(Vec), ObjComp(ObjComp), @@ -260,7 +238,6 @@ #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[derive(Debug, PartialEq, Clone, Copy, Trace)] -#[trivially_drop] pub enum LiteralType { This, Super, @@ -273,7 +250,6 @@ #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[derive(Debug, PartialEq, Trace)] -#[trivially_drop] pub struct SliceDesc { pub start: Option, pub end: Option, @@ -284,7 +260,6 @@ #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[derive(Debug, PartialEq, Trace)] -#[trivially_drop] pub enum Expr { Literal(LiteralType), @@ -354,7 +329,7 @@ #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] #[derive(Clone, PartialEq, Trace)] -#[trivially_drop] +#[skip_trace] pub struct ExprLocation(pub Rc, pub usize, pub usize); impl ExprLocation { pub fn belongs_to(&self, other: &ExprLocation) -> bool { @@ -371,14 +346,8 @@ /// Holds AST expression and its location in source file #[cfg_attr(feature = "serialize", derive(Serialize))] #[cfg_attr(feature = "deserialize", derive(Deserialize))] -#[derive(Clone, PartialEq)] -pub struct LocExpr(pub Rc, pub Option); -/// Safety: -/// AST is acyclic, and there should be no gc pointers -unsafe impl Trace for LocExpr { - unsafe_empty_trace!(); -} -impl Finalize for LocExpr {} +#[derive(Clone, PartialEq, Trace)] +pub struct LocExpr(pub Rc, pub ExprLocation); impl Debug for LocExpr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -387,24 +356,7 @@ } else { write!(f, "{:?}", self.0)?; } - if let Some(loc) = &self.1 { - write!(f, " from {:?}", loc)?; - } + write!(f, " from {:?}", self.1)?; Ok(()) } -} - -/// Creates LocExpr from Expr and ExprLocation components -#[macro_export] -macro_rules! loc_expr { - ($expr:expr, $need_loc:expr,($name:expr, $start:expr, $end:expr)) => { - LocExpr( - std::rc::Rc::new($expr), - if $need_loc { - Some(ExprLocation($name, $start, $end)) - } else { - None - }, - ) - }; } --- a/crates/jrsonnet-parser/src/lib.rs +++ b/crates/jrsonnet-parser/src/lib.rs @@ -9,9 +9,9 @@ pub use expr::*; pub use jrsonnet_interner::IStr; pub use peg; +mod unescape; pub struct ParserSettings { - pub loc_data: bool, pub file_name: Rc, } @@ -103,10 +103,20 @@ lines:("\n" {"\n"} / [' ' | '\t']*<{prefix.len()}> s:whole_line() {s})* [' ' | '\t']*<, {prefix.len() - 1}> "|||" {let mut l = empty_lines.to_owned(); l.push_str(first_line); l.extend(lines); l} + + rule hex_char() + = quiet! { ['0'..='9' | 'a'..='f' | 'A'..='F'] } / expected!("") + + rule string_char(c: rule<()>) + = (!['\\']!c()[_])+ + / "\\\\" + / "\\u" hex_char() hex_char() hex_char() hex_char() + / "\\x" hex_char() hex_char() + / ['\\'] (quiet! { ['b' | 'f' | 'n' | 'r' | 't'] / c() } / expected!("")) pub rule string() -> String - = quiet!{ "\"" str:$(("\\\"" / "\\\\" / (!['"'][_]))*) "\"" {unescape::unescape(str).unwrap()} - / "'" str:$(("\\'" / "\\\\" / (!['\''][_]))*) "'" {unescape::unescape(str).unwrap()} - / "@'" str:$(("''" / (!['\''][_]))*) "'" {str.replace("''", "'")} + = ['"'] str:$(string_char(<['"']>)*) ['"'] {? unescape::unescape(str).ok_or("")} + / ['\''] str:$(string_char(<['\'']>)*) ['\''] {? unescape::unescape(str).ok_or("")} + / quiet!{ "@'" str:$(("''" / (!['\''][_]))*) "'" {str.replace("''", "'")} / "@\"" str:$(("\"\"" / (!['"'][_]))*) "\"" {str.replace("\"\"", "\"")} / string_block() } / expected!("") @@ -177,6 +187,8 @@ = n:number() { expr::Expr::Num(n) } pub rule var_expr(s: &ParserSettings) -> Expr = n:$(id()) { expr::Expr::Var(n.into()) } + pub rule id_loc(s: &ParserSettings) -> LocExpr + = a:position!() n:$(id()) b:position!() { LocExpr(Rc::new(expr::Expr::Str(n.into())), ExprLocation(s.file_name.clone(), a,b)) } pub rule if_then_else_expr(s: &ParserSettings) -> Expr = cond:ifspec(s) _ keyword("then") _ cond_then:expr(s) cond_else:(_ keyword("else") _ e:expr(s) {e})? {Expr::IfElse{ cond, @@ -240,7 +252,7 @@ use UnaryOpType::*; rule expr(s: &ParserSettings) -> LocExpr = precedence! { - start:position!() v:@ end:position!() { loc_expr!(v, s.loc_data, (s.file_name.clone(), start, end)) } + start:position!() v:@ end:position!() { LocExpr(Rc::new(v), ExprLocation(s.file_name.clone(), start, end)) } -- a:(@) _ binop(<"||">) _ b:@ {expr_bin!(a Or b)} -- @@ -276,7 +288,7 @@ unaryop(<"~">) _ b:@ {expr_un!(BitNot b)} -- a:(@) _ "[" _ e:slice_desc(s) _ "]" {Expr::Slice(a, e)} - a:(@) _ "." _ e:$(id()) {Expr::Index(a, el!(Expr::Str(e.into())))} + a:(@) _ "." _ a:position!() e:id_loc(s) b:position!() {Expr::Index(a, e)} a:(@) _ "[" _ e:expr(s) _ "]" {Expr::Index(a, e)} a:(@) _ "(" _ args:args(s) _ ")" ts:(_ keyword("tailstrict"))? {Expr::Apply(a, args, ts.is_some())} a:(@) _ "{" _ body:objinside(s) _ "}" {Expr::ObjExtend(a, body)} @@ -292,13 +304,6 @@ pub type ParseError = peg::error::ParseError; pub fn parse(str: &str, settings: &ParserSettings) -> Result { jsonnet_parser::jsonnet(str, settings) -} - -#[macro_export] -macro_rules! el { - ($expr:expr) => { - LocExpr(std::rc::Rc::new($expr), None) - }; } #[cfg(test)] @@ -313,53 +318,39 @@ parse( $s, &ParserSettings { - loc_data: false, - file_name: PathBuf::from("/test.jsonnet").into(), + file_name: PathBuf::from("test.jsonnet").into(), }, ) .unwrap() }; } - macro_rules! el_loc { - ($expr:expr, $loc:expr$(,)?) => { - LocExpr(std::rc::Rc::new($expr), Some($loc)) + macro_rules! el { + ($expr:expr, $from:expr, $to:expr$(,)?) => { + LocExpr( + std::rc::Rc::new($expr), + ExprLocation(PathBuf::from("test.jsonnet").into(), $from, $to), + ) }; - } - - mod expressions { - use super::*; - - pub fn basic_math() -> LocExpr { - el!(Expr::BinaryOp( - el!(Expr::Num(2.0)), - Add, - el!(Expr::BinaryOp( - el!(Expr::Num(2.0)), - Mul, - el!(Expr::Num(2.0)), - )), - )) - } } #[test] fn multiline_string() { assert_eq!( parse!("|||\n Hello world!\n a\n|||"), - el!(Expr::Str("Hello world!\n a\n".into())), + el!(Expr::Str("Hello world!\n a\n".into()), 0, 31), ); assert_eq!( parse!("|||\n Hello world!\n a\n|||"), - el!(Expr::Str("Hello world!\n a\n".into())), + el!(Expr::Str("Hello world!\n a\n".into()), 0, 27), ); assert_eq!( parse!("|||\n\t\tHello world!\n\t\t\ta\n|||"), - el!(Expr::Str("Hello world!\n\ta\n".into())), + el!(Expr::Str("Hello world!\n\ta\n".into()), 0, 27), ); assert_eq!( parse!("|||\n Hello world!\n a\n |||"), - el!(Expr::Str("Hello world!\n a\n".into())), + el!(Expr::Str("Hello world!\n a\n".into()), 0, 30), ); } @@ -376,20 +367,20 @@ fn string_escaping() { assert_eq!( parse!(r#""Hello, \"world\"!""#), - el!(Expr::Str(r#"Hello, "world"!"#.into())), + el!(Expr::Str(r#"Hello, "world"!"#.into()), 0, 19), ); assert_eq!( parse!(r#"'Hello \'world\'!'"#), - el!(Expr::Str("Hello 'world'!".into())), + el!(Expr::Str("Hello 'world'!".into()), 0, 18), ); - assert_eq!(parse!(r#"'\\\\'"#), el!(Expr::Str("\\\\".into())),); + assert_eq!(parse!(r#"'\\\\'"#), el!(Expr::Str("\\\\".into()), 0, 6)); } #[test] fn string_unescaping() { assert_eq!( parse!(r#""Hello\nWorld""#), - el!(Expr::Str("Hello\nWorld".into())), + el!(Expr::Str("Hello\nWorld".into()), 0, 14), ); } @@ -397,7 +388,7 @@ fn string_verbantim() { assert_eq!( parse!(r#"@"Hello\n""World""""#), - el!(Expr::Str("Hello\\n\"World\"".into())), + el!(Expr::Str("Hello\\n\"World\"".into()), 0, 19), ); } @@ -405,49 +396,95 @@ fn imports() { assert_eq!( parse!("import \"hello\""), - el!(Expr::Import(PathBuf::from("hello"))), + el!(Expr::Import(PathBuf::from("hello")), 0, 14), ); assert_eq!( parse!("importstr \"garnish.txt\""), - el!(Expr::ImportStr(PathBuf::from("garnish.txt"))) + el!(Expr::ImportStr(PathBuf::from("garnish.txt")), 0, 23) ); } #[test] fn empty_object() { - assert_eq!(parse!("{}"), el!(Expr::Obj(ObjBody::MemberList(vec![])))); + assert_eq!( + parse!("{}"), + el!(Expr::Obj(ObjBody::MemberList(vec![])), 0, 2) + ); } #[test] fn basic_math() { assert_eq!( parse!("2+2*2"), - el!(Expr::BinaryOp( - el!(Expr::Num(2.0)), - Add, - el!(Expr::BinaryOp( - el!(Expr::Num(2.0)), - Mul, - el!(Expr::Num(2.0)) - )) - )) + el!( + Expr::BinaryOp( + el!(Expr::Num(2.0), 0, 1), + Add, + el!( + Expr::BinaryOp(el!(Expr::Num(2.0), 2, 3), Mul, el!(Expr::Num(2.0), 4, 5)), + 2, + 5 + ) + ), + 0, + 5 + ) ); } #[test] fn basic_math_with_indents() { - assert_eq!(parse!("2 + 2 * 2 "), expressions::basic_math()); + assert_eq!( + parse!("2 + 2 * 2 "), + el!( + Expr::BinaryOp( + el!(Expr::Num(2.0), 0, 1), + Add, + el!( + Expr::BinaryOp(el!(Expr::Num(2.0), 7, 8), Mul, el!(Expr::Num(2.0), 13, 14),), + 7, + 14 + ), + ), + 0, + 14 + ) + ); } #[test] fn basic_math_parened() { assert_eq!( parse!("2+(2+2*2)"), - el!(Expr::BinaryOp( - el!(Expr::Num(2.0)), - Add, - el!(Expr::Parened(expressions::basic_math())), - )) + el!( + Expr::BinaryOp( + el!(Expr::Num(2.0), 0, 1), + Add, + el!( + Expr::Parened(el!( + Expr::BinaryOp( + el!(Expr::Num(2.0), 3, 4), + Add, + el!( + Expr::BinaryOp( + el!(Expr::Num(2.0), 5, 6), + Mul, + el!(Expr::Num(2.0), 7, 8), + ), + 5, + 8 + ), + ), + 3, + 8 + )), + 2, + 9 + ), + ), + 0, + 9 + ) ); } @@ -456,15 +493,23 @@ fn comments() { assert_eq!( parse!("2//comment\n+//comment\n3/*test*/*/*test*/4"), - el!(Expr::BinaryOp( - el!(Expr::Num(2.0)), - Add, - el!(Expr::BinaryOp( - el!(Expr::Num(3.0)), - Mul, - el!(Expr::Num(4.0)) - )) - )) + el!( + Expr::BinaryOp( + el!(Expr::Num(2.0), 0, 1), + Add, + el!( + Expr::BinaryOp( + el!(Expr::Num(3.0), 22, 23), + Mul, + el!(Expr::Num(4.0), 40, 41) + ), + 22, + 41 + ) + ), + 0, + 41 + ) ); } @@ -473,11 +518,11 @@ fn comment_escaping() { assert_eq!( parse!("2/*\\*/+*/ - 22"), - el!(Expr::BinaryOp( - el!(Expr::Num(2.0)), - Sub, - el!(Expr::Num(22.0)) - )) + el!( + Expr::BinaryOp(el!(Expr::Num(2.0), 0, 1), Sub, el!(Expr::Num(22.0), 12, 14)), + 0, + 14 + ) ); } @@ -492,27 +537,46 @@ #[test] fn array_comp() { use Expr::*; + /* + `ArrComp(Apply(Index(Var("std") from "test.jsonnet":1-4, Var("deepJoin") from "test.jsonnet":5-13) from "test.jsonnet":1-13, ArgsDesc { unnamed: [Var("x") from "test.jsonnet":14-15], named: [] }, false) from "test.jsonnet":1-16, [ForSpec(ForSpecData("x", Var("arr") from "test.jsonnet":26-29))]) from "test.jsonnet":0-30`, + `ArrComp(Apply(Index(Var("std") from "test.jsonnet":1-4, Str("deepJoin") from "test.jsonnet":5-13) from "test.jsonnet":1-13, ArgsDesc { unnamed: [Var("x") from "test.jsonnet":14-15], named: [] }, false) from "test.jsonnet":1-16, [ForSpec(ForSpecData("x", Var("arr") from "test.jsonnet":26-29))]) from "test.jsonnet":0-30` + */ assert_eq!( parse!("[std.deepJoin(x) for x in arr]"), - el!(ArrComp( - el!(Apply( - el!(Index(el!(Var("std".into())), el!(Str("deepJoin".into())))), - ArgsDesc::new(vec![el!(Var("x".into()))], vec![]), - false, - )), - vec![CompSpec::ForSpec(ForSpecData( - "x".into(), - el!(Var("arr".into())) - ))] - )), + el!( + ArrComp( + el!( + Apply( + el!( + Index( + el!(Var("std".into()), 1, 4), + el!(Str("deepJoin".into()), 5, 13) + ), + 1, + 13 + ), + ArgsDesc::new(vec![el!(Var("x".into()), 14, 15)], vec![]), + false, + ), + 1, + 16 + ), + vec![CompSpec::ForSpec(ForSpecData( + "x".into(), + el!(Var("arr".into()), 26, 29) + ))] + ), + 0, + 30 + ), ) } #[test] fn reserved() { use Expr::*; - assert_eq!(parse!("null"), el!(Literal(LiteralType::Null))); - assert_eq!(parse!("nulla"), el!(Var("nulla".into()))); + assert_eq!(parse!("null"), el!(Literal(LiteralType::Null), 0, 4)); + assert_eq!(parse!("nulla"), el!(Var("nulla".into()), 0, 5)); } #[test] @@ -525,11 +589,15 @@ use Expr::*; assert_eq!( parse!("!a && !b"), - el!(BinaryOp( - el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into())))), - And, - el!(UnaryOp(UnaryOpType::Not, el!(Var("b".into())))) - )) + el!( + BinaryOp( + el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into()), 1, 2)), 0, 2), + And, + el!(UnaryOp(UnaryOpType::Not, el!(Var("b".into()), 7, 8)), 6, 8) + ), + 0, + 8 + ) ); } @@ -538,11 +606,15 @@ use Expr::*; assert_eq!( parse!("!a / !b"), - el!(BinaryOp( - el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into())))), - Div, - el!(UnaryOp(UnaryOpType::Not, el!(Var("b".into())))) - )) + el!( + BinaryOp( + el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into()), 1, 2)), 0, 2), + Div, + el!(UnaryOp(UnaryOpType::Not, el!(Var("b".into()), 6, 7)), 5, 7) + ), + 0, + 7 + ) ); } @@ -551,10 +623,14 @@ use Expr::*; assert_eq!( parse!("!!a"), - el!(UnaryOp( - UnaryOpType::Not, - el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into())))) - )) + el!( + UnaryOp( + UnaryOpType::Not, + el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into()), 2, 3)), 1, 3) + ), + 0, + 3 + ) ) } @@ -587,55 +663,44 @@ fn add_location_info_to_all_sub_expressions() { use Expr::*; - let file_name: std::rc::Rc = PathBuf::from("/test.jsonnet").into(); + let file_name: std::rc::Rc = PathBuf::from("test.jsonnet").into(); let expr = parse( "{} { local x = 1, x: x } + {}", &ParserSettings { - loc_data: true, file_name: file_name.clone(), }, ) .unwrap(); assert_eq!( expr, - el_loc!( + el!( BinaryOp( - el_loc!( + el!( ObjExtend( - el_loc!( - Obj(ObjBody::MemberList(vec![])), - ExprLocation(file_name.clone(), 0, 2) - ), + el!(Obj(ObjBody::MemberList(vec![])), 0, 2), ObjBody::MemberList(vec![ Member::BindStmt(BindSpec { name: "x".into(), params: None, - value: el_loc!( - Num(1.0), - ExprLocation(file_name.clone(), 15, 16) - ) + value: el!(Num(1.0), 15, 16) }), Member::Field(FieldMember { name: FieldName::Fixed("x".into()), plus: false, params: None, visibility: Visibility::Normal, - value: el_loc!( - Var("x".into()), - ExprLocation(file_name.clone(), 21, 22) - ), + value: el!(Var("x".into()), 21, 22), }) ]) ), - ExprLocation(file_name.clone(), 0, 24) + 0, + 24 ), BinaryOpType::Add, - el_loc!( - Obj(ObjBody::MemberList(vec![])), - ExprLocation(file_name.clone(), 27, 29) - ), + el!(Obj(ObjBody::MemberList(vec![])), 27, 29), ), - ExprLocation(file_name.clone(), 0, 29), + 0, + 29 ), ); } --- /dev/null +++ b/crates/jrsonnet-parser/src/unescape.rs @@ -0,0 +1,38 @@ +pub fn unescape(s: &str) -> Option { + let mut chars = s.chars(); + let mut out = String::with_capacity(s.len()); + + while let Some(c) = chars.next() { + if c != '\\' { + out.push(c); + continue; + } + match chars.next()? { + c @ ('\\' | '"' | '\'') => out.push(c), + 'b' => out.push('\u{0008}'), + 'f' => out.push('\u{000c}'), + 'n' => out.push('\n'), + 'r' => out.push('\r'), + 't' => out.push('\t'), + 'u' => { + let c = IntoIterator::into_iter([ + chars.next()?, + chars.next()?, + chars.next()?, + chars.next()?, + ]) + .map(|c| c.to_digit(16)) + .try_fold(0u32, |acc, v| Some((acc << 8) | (v?)))?; + out.push(char::from_u32(c)?) + } + 'x' => { + let c = IntoIterator::into_iter([chars.next()?, chars.next()?]) + .map(|c| c.to_digit(16)) + .try_fold(0u32, |acc, v| Some((acc << 8) | (v?)))?; + out.push(char::from_u32(c)?) + } + _ => return None, + } + } + Some(out) +} --- a/crates/jrsonnet-stdlib/src/std.jsonnet +++ b/crates/jrsonnet-stdlib/src/std.jsonnet @@ -370,7 +370,7 @@ ch; std.foldl(function(a, b) a + trans(b), std.stringChars(str), ''), - manifestJson(value):: std.manifestJsonEx(value, ' '), + manifestJson(value):: std.manifestJsonEx(value, ' ') tailstrict, manifestJsonEx:: $intrinsic(manifestJsonEx), --- a/crates/jrsonnet-types/Cargo.toml +++ b/crates/jrsonnet-types/Cargo.toml @@ -8,4 +8,4 @@ [dependencies] peg = "0.7.0" -jrsonnet-gc = { version = "0.4.2", features = ["derive"] } +gcmodule = { git = "https://github.com/CertainLach/gcmodule", branch = "jrsonnet" } --- a/crates/jrsonnet-types/src/lib.rs +++ b/crates/jrsonnet-types/src/lib.rs @@ -1,6 +1,6 @@ #![allow(clippy::redundant_closure_call)] -use jrsonnet_gc::Trace; +use gcmodule::Trace; use std::fmt::Display; #[macro_export] @@ -82,7 +82,6 @@ } #[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)] -#[trivially_drop] pub enum ValType { Bool, Null, @@ -115,7 +114,7 @@ } #[derive(Debug, Clone, PartialEq, Trace)] -#[trivially_drop] +#[skip_trace] pub enum ComplexValType { Any, Char, -- gitstuff