From b8427047424c3a595c6079a67ee3915e48f574c4 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Thu, 07 May 2026 04:29:35 +0000 Subject: [PATCH] style: fix clippy warnings --- --- a/bindings/jrsonnet-web/src/lib.rs +++ b/bindings/jrsonnet-web/src/lib.rs @@ -65,6 +65,11 @@ } fn unwrap_val_ref(value: &JsValue) -> Result<::Anchor, JsValue> { + #[allow( + clippy::cast_sign_loss, + clippy::cast_possible_truncation, + reason = "defined to be u32" + )] let ptr = get(value, &JsValue::from_str("__wbg_ptr")) .ok() .and_then(|v| v.as_f64()) @@ -371,14 +376,14 @@ impl WasmArrValue { #[wasm_bindgen(getter)] pub fn length(&self) -> u32 { - self.arr.len() + self.arr.len32() } pub fn at(&self, index: u32) -> Result, JsValue> { let result = self.state.as_ref().map_or_else( - || self.arr.get(index), + || self.arr.get32(index), |state| { let _guard = state.try_enter(); - self.arr.get(index) + self.arr.get32(index) }, ); result --- a/bindings/jsonnet/src/lib.rs +++ b/bindings/jsonnet/src/lib.rs @@ -66,14 +66,12 @@ #[cfg(target_family = "unix")] { use std::os::unix::ffi::OsStrExt; - let str = CString::new(input.as_os_str().as_bytes()).expect("input has zero byte in it"); - str + CString::new(input.as_os_str().as_bytes()).expect("input has zero byte in it") } #[cfg(not(target_family = "unix"))] { let str = input.as_os_str().to_str().expect("bad utf-8"); - let cstr = CString::new(str).expect("input has NUL inside"); - cstr + CString::new(str).expect("input has NUL inside") } } --- a/cmds/jrb/src/main.rs +++ b/cmds/jrb/src/main.rs @@ -104,6 +104,7 @@ } } +#[allow(clippy::too_many_lines)] fn main() { tracing_subscriber::fmt().init(); --- a/crates/jrsonnet-evaluator/src/analyze.rs +++ b/crates/jrsonnet-evaluator/src/analyze.rs @@ -28,7 +28,10 @@ use rustc_hash::FxHashMap; use smallvec::SmallVec; -use crate::error::{format_found, suggest_names}; +use crate::{ + arr::arridx, + error::{format_found, suggest_names}, +}; #[derive(Debug, Clone, Copy)] #[must_use] @@ -658,7 +661,7 @@ stack: &'s mut AnalysisStack, bomb: DropBomb, } -impl<'s> PendingBody<'s> { +impl PendingBody<'_> { /// After the body is processed, drop the frame's locals and emit any /// "unused local" warnings. fn finish(self) { @@ -704,7 +707,7 @@ .drain(closures.first_in_frame.idx()..) .collect(); for (i, def) in drained.iter().enumerate().rev() { - let id = LocalId(closures.first_in_frame.0 + i as u32); + let id = LocalId(closures.first_in_frame.0 + arridx(i)); let stack_locals = stack .local_by_name .get_mut(&def.name) @@ -819,7 +822,7 @@ let (this_refs, rest) = refs.split_at(*refs_len); refs = rest; let start = next_id; - next_id += *dest_count as u32; + next_id += arridx(*dest_count); Closure { references: this_refs, ids: start..next_id, @@ -1043,7 +1046,7 @@ } fn next_local_id(&self) -> LocalId { - LocalId(self.local_defs.len() as u32) + LocalId(arridx(self.local_defs.len())) } fn report_error(&mut self, msg: impl Into, span: Option) { @@ -1565,7 +1568,7 @@ let mut pending = alloc.finish(); let mut l_binds: Vec = Vec::with_capacity(binds.len()); - for (bind, destruct) in binds.iter().zip(destructs.into_iter()) { + for (bind, destruct) in binds.iter().zip(destructs) { let mut value_taint = AnalysisResult::default(); let (value_shape, value) = pending .stack @@ -1608,7 +1611,7 @@ let mut pending = alloc.finish(); let mut l_params: Vec = Vec::with_capacity(params.exprs.len()); - for (p, destruct) in params.exprs.iter().zip(param_destructs.into_iter()) { + for (p, destruct) in params.exprs.iter().zip(param_destructs) { let mut value_taint = AnalysisResult::default(); let default = p.default.as_ref().map_or_else( || None, --- a/crates/jrsonnet-evaluator/src/arr/mod.rs +++ b/crates/jrsonnet-evaluator/src/arr/mod.rs @@ -2,6 +2,7 @@ any::Any, fmt::{self}, num::NonZeroU32, + ops::{Bound, RangeBounds}, rc::Rc, }; @@ -104,20 +105,37 @@ Self::new(RangeArray::new_inclusive(a, b)) } + #[inline] #[must_use] - pub fn slice(self, index: Option, end: Option, step: Option) -> Self { + pub fn slice(self, range: impl RangeBounds) -> Self { + fn map_bound(start: bool, bound: Bound<&usize>) -> Option { + match bound { + Bound::Included(&v) => Some(i32::try_from(v).unwrap_or(i32::MAX)), + Bound::Excluded(&v) => Some( + i32::try_from(v) + .unwrap_or(i32::MAX) + .saturating_add(if start { 1 } else { -1 }), + ), + Bound::Unbounded => None, + } + } + self.slice32( + map_bound(true, range.start_bound()), + map_bound(false, range.end_bound()), + None, + ) + } + + #[must_use] + pub fn slice32(self, index: Option, end: Option, step: Option) -> Self { let get_idx = |pos: Option, len: u32, default| match pos { - #[expect( - clippy::cast_sign_loss, - reason = "abs value is used, len is limited to u31" - )] Some(v) if v < 0 => len.saturating_add_signed(v), #[expect(clippy::cast_sign_loss, reason = "abs value is used")] Some(v) => (v as u32).min(len), None => default, }; - let index = get_idx(index, self.len(), 0); - let end = get_idx(end, self.len(), self.len()); + let index = get_idx(index, self.len32(), 0); + let end = get_idx(end, self.len32(), self.len32()); let step = step.unwrap_or_else(|| NonZeroU32::new(1).expect("1 != 0")); if index >= end { @@ -126,24 +144,29 @@ Self::new(SliceArray { inner: self, - #[expect(clippy::cast_possible_truncation, reason = "len is limited to u31")] - from: index as u32, - #[expect(clippy::cast_possible_truncation, reason = "len is limited to u31")] - to: end as u32, + from: index, + to: end, step: step.get(), }) } /// Array length. - pub fn len(&self) -> u32 { - self.0.len() + #[inline] + pub fn len32(&self) -> u32 { + self.0.len32() } + pub fn len(&self) -> usize { + self.len32() as usize + } + /// Is array contains no elements? + #[inline] pub fn is_empty(&self) -> bool { self.0.is_empty() } + #[inline] pub fn is_cheap(&self) -> bool { self.0.is_cheap() } @@ -151,24 +174,37 @@ /// Get array element by index, evaluating it, if it is lazy. /// /// Returns `None` on out-of-bounds condition. - pub fn get(&self, index: u32) -> Result> { - self.0.get(index) + #[inline] + pub fn get32(&self, index: u32) -> Result> { + self.0.get32(index) + } + + pub fn get(&self, index: usize) -> Result> { + let Ok(i) = u32::try_from(index) else { + return Ok(None); + }; + self.get32(i) } /// Get array element by index, without evaluation. /// /// Returns `None` on out-of-bounds condition. - pub fn get_lazy(&self, index: u32) -> Option> { - self.0.get_lazy(index) + #[inline] + pub fn get_lazy32(&self, index: u32) -> Option> { + self.0.get_lazy32(index) + } + + pub fn get_lazy(&self, index: usize) -> Option> { + u32::try_from(index).ok().and_then(|i| self.get_lazy32(i)) } pub fn iter(&self) -> impl ArrayLikeIter> + '_ { - (0..self.len()).map(|i| self.get(i).transpose().expect("length checked")) + (0..self.len32()).map(|i| self.get32(i).transpose().expect("length checked")) } /// Iterate over elements, returning lazy values. pub fn iter_lazy(&self) -> impl ArrayLikeIter> + '_ { - (0..self.len()).map(|i| self.get_lazy(i).expect("length checked")) + (0..self.len32()).map(|i| self.get_lazy32(i).expect("length checked")) } /// Return a reversed view on current array. @@ -201,3 +237,18 @@ Self::new(iter.into_iter().collect::>()) } } + +/// Checks that the usize does not exceed 4g with debug assertions enabled +/// Should only be used on values that can't reasonably exceed this value +#[inline] +pub(crate) fn arridx(i: usize) -> u32 { + #[allow( + clippy::cast_possible_truncation, + reason = "array indexes never exceed 4g" + )] + if cfg!(debug_assertions) { + u32::try_from(i).expect("4g hard limit") + } else { + i as u32 + } +} --- a/crates/jrsonnet-evaluator/src/arr/spec.rs +++ b/crates/jrsonnet-evaluator/src/arr/spec.rs @@ -9,7 +9,7 @@ use jrsonnet_gcmodule::{Cc, Trace}; use jrsonnet_interner::{IBytes, IStr}; -use super::ArrValue; +use super::{ArrValue, arridx}; use crate::{ Context, Error, ObjValue, Result, Thunk, Val, analyze::{ClosureShape, LExpr}, @@ -21,12 +21,12 @@ }; pub trait ArrayLike: Any + Trace + Debug { - fn len(&self) -> u32; + fn len32(&self) -> u32; fn is_empty(&self) -> bool { - self.len() == 0 + self.len32() == 0 } - fn get(&self, index: u32) -> Result>; - fn get_lazy(&self, index: u32) -> Option>; + fn get32(&self, index: u32) -> Result>; + fn get_lazy32(&self, index: u32) -> Option>; fn is_cheap(&self) -> bool { false @@ -40,15 +40,15 @@ where T: Any + Trace + Debug + ArrayCheap, { - fn len(&self) -> u32 { + fn len32(&self) -> u32 { ::len(self) } - fn get(&self, index: u32) -> Result> { + fn get32(&self, index: u32) -> Result> { Ok(::get(self, index)) } - fn get_lazy(&self, index: u32) -> Option> { + fn get_lazy32(&self, index: u32) -> Option> { ::get(self, index).map(Thunk::evaluated) } @@ -80,16 +80,16 @@ } } impl ArrayLike for SliceArray { - fn len(&self) -> u32 { + fn len32(&self) -> u32 { (self.to - self.from).div_ceil(self.step) } - fn get(&self, index: u32) -> Result> { - self.inner.get(self.map_idx(index)) + fn get32(&self, index: u32) -> Result> { + self.inner.get32(self.map_idx(index)) } - fn get_lazy(&self, index: u32) -> Option> { - self.inner.get_lazy(self.map_idx(index)) + fn get_lazy32(&self, index: u32) -> Option> { + self.inner.get_lazy32(self.map_idx(index)) } fn is_cheap(&self) -> bool { @@ -99,7 +99,7 @@ impl ArrayCheap for IBytes { fn len(&self) -> u32 { - self.as_slice().len() as u32 + arridx(self.as_slice().len()) } fn get(&self, index: u32) -> Option { self.as_slice() @@ -132,11 +132,11 @@ } } impl ArrayLike for ExprArray { - fn len(&self) -> u32 { - self.cached.borrow().len() as u32 + fn len32(&self) -> u32 { + arridx(self.cached.borrow().len()) } - fn get(&self, index: u32) -> Result> { - if index >= self.len() { + fn get32(&self, index: u32) -> Result> { + if index >= self.len32() { return Ok(None); } match &self.cached.borrow()[index as usize] { @@ -157,7 +157,7 @@ self.cached.borrow_mut()[index as usize] = ArrayThunk::Computed(new_value.clone()); Ok(Some(new_value)) } - fn get_lazy(&self, index: u32) -> Option> { + fn get_lazy32(&self, index: u32) -> Option> { #[derive(Trace)] struct ExprArrThunk { expr: ExprArray, @@ -168,13 +168,13 @@ fn get(&self) -> Result { self.expr - .get(self.index) + .get32(self.index) .transpose() .expect("index checked") } } - if index >= self.len() { + if index >= self.len32() { return None; } match &self.cached.borrow()[index as usize] { @@ -202,8 +202,8 @@ } impl ExtendedArray { pub fn new(a: ArrValue, b: ArrValue) -> Option { - let a_len = a.len(); - let b_len = b.len(); + let a_len = a.len32(); + let b_len = b.len32(); let len = a_len.checked_add(b_len)?; Some(Self { a, @@ -251,22 +251,22 @@ } } impl ArrayLike for ExtendedArray { - fn get(&self, index: u32) -> Result> { + fn get32(&self, index: u32) -> Result> { if self.split > index { - self.a.get(index) + self.a.get32(index) } else { - self.b.get(index - self.split) + self.b.get32(index - self.split) } } - fn get_lazy(&self, index: u32) -> Option> { + fn get_lazy32(&self, index: u32) -> Option> { if self.split > index { - self.a.get_lazy(index) + self.a.get_lazy32(index) } else { - self.b.get_lazy(index - self.split) + self.b.get_lazy32(index - self.split) } } - fn len(&self) -> u32 { + fn len32(&self) -> u32 { self.len } @@ -280,18 +280,18 @@ T: IntoUntyped + Trace + fmt::Debug, for<'a> &'a T: IntoUntyped, { - fn len(&self) -> u32 { + fn len32(&self) -> u32 { self.as_slice().len().try_into().unwrap_or(u32::MAX) } - fn get(&self, index: u32) -> Result> { + fn get32(&self, index: u32) -> Result> { let Some(elem) = self.as_slice().get(index as usize) else { return Ok(None); }; IntoUntyped::into_untyped(elem).map(Some) } - fn get_lazy(&self, index: u32) -> Option> { + fn get_lazy32(&self, index: u32) -> Option> { let elem = self.as_slice().get(index as usize)?; Some(IntoUntyped::into_lazy_untyped(elem)) } @@ -343,16 +343,16 @@ #[derive(Debug, Trace)] pub struct ReverseArray(pub ArrValue); impl ArrayLike for ReverseArray { - fn len(&self) -> u32 { - self.0.len() + fn len32(&self) -> u32 { + self.0.len32() } - fn get(&self, index: u32) -> Result> { - self.0.get(self.0.len() - index - 1) + fn get32(&self, index: u32) -> Result> { + self.0.get32(self.0.len32() - index - 1) } - fn get_lazy(&self, index: u32) -> Option> { - self.0.get_lazy(self.0.len() - index - 1) + fn get_lazy32(&self, index: u32) -> Option> { + self.0.get_lazy32(self.0.len32() - index - 1) } fn is_cheap(&self) -> bool { @@ -374,7 +374,7 @@ } impl MappedArray { pub fn new(inner: ArrValue, mapper: ArrayMapper) -> Self { - let len = inner.len(); + let len = inner.len32(); Self { inner, cached: Cc::new(RefCell::new(vec![ArrayThunk::Waiting; len as usize])), @@ -389,12 +389,12 @@ } } impl ArrayLike for MappedArray { - fn len(&self) -> u32 { - self.cached.borrow().len() as u32 + fn len32(&self) -> u32 { + arridx(self.cached.borrow().len()) } - fn get(&self, index: u32) -> Result> { - if index >= self.len() { + fn get32(&self, index: u32) -> Result> { + if index >= self.len32() { return Ok(None); } match &self.cached.borrow()[index as usize] { @@ -413,7 +413,7 @@ let val = self .inner - .get(index) + .get32(index) .transpose() .expect("index checked") .and_then(|r| self.evaluate(index, r)); @@ -428,7 +428,7 @@ self.cached.borrow_mut()[index as usize] = ArrayThunk::Computed(new_value.clone()); Ok(Some(new_value)) } - fn get_lazy(&self, index: u32) -> Option> { + fn get_lazy32(&self, index: u32) -> Option> { #[derive(Trace)] struct MappedArrayThunk { arr: MappedArray, @@ -438,11 +438,14 @@ type Output = Val; fn get(&self) -> Result { - self.arr.get(self.index).transpose().expect("index checked") + self.arr + .get32(self.index) + .transpose() + .expect("index checked") } } - if index >= self.len() { + if index >= self.len32() { return None; } match &self.cached.borrow()[index as usize] { @@ -471,12 +474,12 @@ } } impl ArrayLike for MakeArray { - fn len(&self) -> u32 { - self.cached.borrow().len() as u32 + fn len32(&self) -> u32 { + arridx(self.cached.borrow().len()) } - fn get(&self, index: u32) -> Result> { - if index >= self.len() { + fn get32(&self, index: u32) -> Result> { + if index >= self.len32() { return Ok(None); } match &self.cached.borrow()[index as usize] { @@ -493,7 +496,7 @@ unreachable!() }; - let val = self.mapper.call(index as u32); + let val = self.mapper.call(index); let new_value = match val { Ok(v) => v, @@ -505,7 +508,7 @@ self.cached.borrow_mut()[index as usize] = ArrayThunk::Computed(new_value.clone()); Ok(Some(new_value)) } - fn get_lazy(&self, index: u32) -> Option> { + fn get_lazy32(&self, index: u32) -> Option> { #[derive(Trace)] struct MakeArrayThunk { arr: MakeArray, @@ -515,11 +518,14 @@ type Output = Val; fn get(&self) -> Result { - self.arr.get(self.index).transpose().expect("index checked") + self.arr + .get32(self.index) + .transpose() + .expect("index checked") } } - if index >= self.len() { + if index >= self.len32() { return None; } match &self.cached.borrow()[index as usize] { @@ -543,7 +549,7 @@ } impl RepeatedArray { pub fn new(data: ArrValue, repeats: u32) -> Option { - let total_len = data.len().checked_mul(repeats)?; + let total_len = data.len32().checked_mul(repeats)?; Some(Self { data, repeats, @@ -554,25 +560,25 @@ if index > self.total_len { return None; } - Some(index % self.data.len()) + Some(index % self.data.len32()) } } impl ArrayLike for RepeatedArray { - fn len(&self) -> u32 { + fn len32(&self) -> u32 { self.total_len } - fn get(&self, index: u32) -> Result> { + fn get32(&self, index: u32) -> Result> { let Some(idx) = self.map_idx(index) else { return Ok(None); }; - self.data.get(idx) + self.data.get32(idx) } - fn get_lazy(&self, index: u32) -> Option> { + fn get_lazy32(&self, index: u32) -> Option> { let idx = self.map_idx(index)?; - self.data.get_lazy(idx) + self.data.get_lazy32(idx) } fn is_cheap(&self) -> bool { @@ -593,18 +599,18 @@ } impl ArrayLike for PickObjectValues { - fn len(&self) -> u32 { - self.keys.len() as u32 + fn len32(&self) -> u32 { + arridx(self.keys.len()) } - fn get(&self, index: u32) -> Result> { + fn get32(&self, index: u32) -> Result> { let Some(key) = self.keys.as_slice().get(index as usize) else { return Ok(None); }; Ok(Some(self.obj.get_or_bail(key.clone())?)) } - fn get_lazy(&self, index: u32) -> Option> { + fn get_lazy32(&self, index: u32) -> Option> { let key = self.keys.as_slice().get(index as usize)?; Some(self.obj.get_lazy_or_bail(key.clone())) } @@ -633,11 +639,11 @@ } impl ArrayLike for PickObjectKeyValues { - fn len(&self) -> u32 { - self.keys.len() as u32 + fn len32(&self) -> u32 { + arridx(self.keys.len()) } - fn get(&self, index: u32) -> Result> { + fn get32(&self, index: u32) -> Result> { let Some(key) = self.keys.as_slice().get(index as usize) else { return Ok(None); }; @@ -650,7 +656,7 @@ )) } - fn get_lazy(&self, index: u32) -> Option> { + fn get_lazy32(&self, index: u32) -> Option> { let key = self.keys.as_slice().get(index as usize)?; // Nothing can fail in the key part, yet value is still // lazy-evaluated --- a/crates/jrsonnet-evaluator/src/ctx.rs +++ b/crates/jrsonnet-evaluator/src/ctx.rs @@ -122,7 +122,7 @@ pub fn enter(self, sup_this: SupThis, build: impl FnOnce(&LocalsFrame, &Context)) -> Context { let locals = LocalsFrame::new_once(self.n_locals); let val = Context(Cc::new(ContextInternal { - captures: self.captures.clone(), + captures: self.captures, locals, sup_this: Some(sup_this), })); --- a/crates/jrsonnet-evaluator/src/evaluate/compspec.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/compspec.rs @@ -97,7 +97,7 @@ let value_ctx = inner_ctx .pack_captures_sup_this(self.frame_shape) .enter(|fill, ctx| { - fill_letrec_binds(fill, &ctx, self.locals); + fill_letrec_binds(fill, ctx, self.locals); }); evaluate_field_member_static(self.builder, inner_ctx, value_ctx, self.field) } @@ -336,6 +336,7 @@ Ok(()) } +#[allow(clippy::too_many_lines)] fn evaluate_compspecs( ctx: Context, specs: &[LCompSpec], @@ -381,7 +382,7 @@ for (i, item) in arr.iter().enumerate() { let item = item?; let inner_ctx = ctx.pack_captures_sup_this(frame_shape).enter(|fill, ctx| { - destruct(dst, fill, Thunk::evaluated(item), &ctx); + destruct(dst, fill, Thunk::evaluated(item), ctx); }); evaluate_compspecs( inner_ctx, --- a/crates/jrsonnet-evaluator/src/evaluate/destructure.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/destructure.rs @@ -5,7 +5,7 @@ use crate::{ Context, LocalsFrame, PackedContext, Result, SupThis, Thunk, Unbound, Val, analyze::{ - ClosureShape, LBind, LDestruct, LDestructField, LDestructRest, LExpr, LLocalExpr, LocalSlot, + ClosureShape, LBind, LDestruct, LDestructField, LDestructRest, LLocalExpr, LocalSlot, }, bail, evaluate::evaluate, @@ -19,7 +19,7 @@ fill: &LocalsFrame, value: Thunk, - a_ctx: &Context, + ctx: &Context, ) { let min_len = start.len() + end.len(); let has_rest = rest.is_some(); @@ -29,14 +29,14 @@ bail!("expected array"); }; if !has_rest { - if arr.len() as usize != min_len { - bail!("expected {} elements, got {}", min_len, arr.len()) + if arr.len() != min_len { + bail!("expected {} elements, got {}", min_len, arr.len32()) } - } else if (arr.len() as usize) < min_len { + } else if arr.len() < min_len { bail!( "expected at least {} elements, but array was only {}", min_len, - arr.len() + arr.len32() ) } Ok(arr) @@ -47,13 +47,13 @@ destruct( d, fill, - Thunk!(move || Ok(full.evaluate()?.get(i as u32)?.expect("length is checked"))), - a_ctx, + Thunk!(move || Ok(full.evaluate()?.get(i)?.expect("length is checked"))), + ctx, ); } - let start_len = start.len() as u32; - let end_len = end.len() as u32; + let start_len = start.len(); + let end_len = end.len(); if let Some(LDestructRest::Keep(slot)) = rest { let full = full.clone(); @@ -62,11 +62,7 @@ Thunk!(move || { let full = full.evaluate()?; let to = full.len() - end_len; - Ok(Val::Arr(full.slice( - Some(start_len as i32), - Some(to as i32), - None, - ))) + Ok(Val::Arr(full.slice(start_len..to))) }), ); } @@ -79,10 +75,10 @@ Thunk!(move || { let full = full.evaluate()?; Ok(full - .get(full.len() - end_len + i as u32)? + .get(full.len() - end_len + i)? .expect("length is checked")) }), - a_ctx, + ctx, ); } } @@ -94,7 +90,7 @@ fill: &LocalsFrame, value: Thunk, - a_ctx: &Context, + ctx: &Context, ) { use jrsonnet_interner::IStr; use rustc_hash::FxHashSet; @@ -118,7 +114,7 @@ } } if !has_rest { - let len = obj.len(); + let len = obj.len32(); if len as usize > field_names.len() { bail!("too many fields, and rest not found"); } @@ -142,10 +138,11 @@ for field in fields { let field_name = field.name.clone(); - let default_thunk: Option> = field - .default - .as_ref() - .map(|(shape, expr)| build_b_thunk(a_ctx, shape, expr.clone())); + let default_thunk: Option> = field.default.as_ref().map(|(shape, expr)| { + let expr = expr.clone(); + let env = Context::enter_using(ctx, shape); + Thunk!(move || evaluate(env, &expr)) + }); let field_full = full.clone(); let value_thunk = Thunk!(move || { @@ -157,7 +154,7 @@ }); if let Some(into) = &field.into { - destruct(into, fill, value_thunk, a_ctx); + destruct(into, fill, value_thunk, ctx); } else { unreachable!("analyzer lowers object-destruct shorthands into `into`"); } @@ -177,21 +174,18 @@ #[cfg(feature = "exp-destruct")] LDestruct::Object { fields, rest } => destruct_object(fields, rest.as_ref(), fill, value, a_ctx), } -} - -pub fn build_b_thunk(a_ctx: &Context, shape: &ClosureShape, expr: Rc) -> Thunk { - let env = Context::enter_using(a_ctx, shape); - Thunk!(move || evaluate(env, &expr)) -} -pub fn build_b_thunk_uno(a_ctx: &Context, shape: Rc<(ClosureShape, LExpr)>) -> Thunk { - let env = Context::enter_using(a_ctx, &shape.0); - Thunk!(move || evaluate(env, &shape.1)) } pub fn fill_letrec_binds(fill: &LocalsFrame, ctx: &Context, binds: &[LBind]) { for bind in binds { - let value_thunk = build_b_thunk(ctx, &bind.value_shape, bind.value.clone()); - destruct(&bind.destruct, fill, value_thunk, ctx); + let expr = bind.value.clone(); + let env = Context::enter_using(ctx, &bind.value_shape); + destruct( + &bind.destruct, + fill, + Thunk!(move || evaluate(env, &expr)), + ctx, + ); } } --- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs @@ -7,7 +7,7 @@ use self::{ compspec::{evaluate_arr_comp, evaluate_obj_comp}, - destructure::{build_b_thunk_uno, evaluate_local_expr, evaluate_locals_unbound}, + destructure::{evaluate_local_expr, evaluate_locals_unbound}, operator::evaluate_binary_op_special, }; use crate::{ @@ -115,6 +115,7 @@ } } +#[allow(clippy::too_many_lines)] pub fn evaluate(ctx: Context, expr: &LExpr) -> Result { Ok(match expr { LExpr::Null => Val::Null, @@ -218,7 +219,7 @@ BoundedUsize::from_untyped(v).description("slice step value") }) .transpose()?; - Val::from(indexable.slice(start, end, step)?) + Val::from(indexable.slice32(start, end, step)?) } LExpr::Super => Val::Obj(ctx.try_sup_this()?.standalone_super().ok_or(NoSuperFound)?), LExpr::Import { @@ -320,6 +321,7 @@ ) } +#[allow(clippy::too_many_lines)] fn evaluate_index(ctx: Context, indexable: &LExpr, parts: &[LIndexPart]) -> Result { let mut parts = parts.iter(); let mut indexable = if matches!(indexable, LExpr::Super) { @@ -394,17 +396,17 @@ if n.fract() > f64::EPSILON { bail!(FractionalIndex) } - let len = arr.len(); + let len = arr.len32(); if n < 0.0 || n > f64::from(len) { bail!(ArrayBoundsError(n, len)); } #[expect( clippy::cast_possible_truncation, clippy::cast_sign_loss, - reason = "n is checked positive" + reason = "n is checked range" )] let i = n as u32; - arr.get(i) + arr.get32(i) .with_description_src(loc, || format!("element <{i}> access"))? .ok_or_else(|| ArrayBoundsError(n, len))? } @@ -507,12 +509,13 @@ return Ok(()); }; - let thunk = build_b_thunk_uno(&value_ctx, value.clone()); + let env = Context::enter_using(&value_ctx, &value.0); + let value = value.clone(); builder .field(name) .with_add(*plus) .with_visibility(*visibility) - .try_thunk(thunk)?; + .try_thunk(Thunk!(move || evaluate(env, &value.1)))?; Ok(()) } --- a/crates/jrsonnet-evaluator/src/function/mod.rs +++ b/crates/jrsonnet-evaluator/src/function/mod.rs @@ -11,12 +11,10 @@ prepared::{PreparedCall, parse_prepared_builtin_call}, }; use crate::{ - PackedContextSupThis, Result, Thunk, Val, + Context, PackedContextSupThis, Result, Thunk, Val, analyze::LFunction, - evaluate::{ - destructure::{build_b_thunk, destruct}, - ensure_sufficient_stack, evaluate, evaluate_trivial, - }, + arr::arridx, + evaluate::{destructure::destruct, ensure_sufficient_stack, evaluate, evaluate_trivial}, function::builtin::BuiltinFunc, }; @@ -83,7 +81,7 @@ &self.func.params[param_idx].destruct, fill, thunk.clone(), - &ctx, + ctx, ); } for &(param_idx, arg_idx) in prepared.named() { @@ -91,15 +89,22 @@ &self.func.params[param_idx].destruct, fill, named[arg_idx].clone(), - &ctx, + ctx, ); } for ¶m_idx in prepared.defaults() { let param = &self.func.params[param_idx]; let (shape, expr) = param.default.as_ref().expect("default exists"); - let thunk = build_b_thunk(&ctx, shape, expr.clone()); - destruct(¶m.destruct, fill, thunk, &ctx); + let expr = expr.clone(); + let env = Context::enter_using(ctx, shape); + + destruct( + ¶m.destruct, + fill, + Thunk!(move || evaluate(env, &expr)), + ctx, + ); } }); @@ -152,8 +157,8 @@ } } /// Amount of non-default required arguments - pub fn params_len(&self) -> u32 { - self.params().iter().filter(|p| !p.has_default()).count() as u32 + pub fn params_len32(&self) -> u32 { + arridx(self.params().iter().filter(|p| !p.has_default()).count()) } /// Function name, as defined in code. pub fn name(&self) -> IStr { --- a/crates/jrsonnet-evaluator/src/integrations/serde.rs +++ b/crates/jrsonnet-evaluator/src/integrations/serde.rs @@ -182,7 +182,7 @@ #[cfg(feature = "exp-bigint")] Self::BigInt(b) => b.serialize(serializer), Self::Arr(arr) => { - let mut seq = serializer.serialize_seq(Some(arr.len() as usize))?; + let mut seq = serializer.serialize_seq(Some(arr.len()))?; for (i, element) in arr.iter().enumerate() { let mut serde_error = None; in_description_frame( @@ -203,7 +203,7 @@ seq.end() } Self::Obj(obj) => { - let mut map = serializer.serialize_map(Some(obj.len() as usize))?; + let mut map = serializer.serialize_map(Some(obj.len32() as usize))?; for (field, value) in obj.iter( #[cfg(feature = "exp-preserve-order")] true, --- a/crates/jrsonnet-evaluator/src/obj/mod.rs +++ b/crates/jrsonnet-evaluator/src/obj/mod.rs @@ -23,7 +23,7 @@ use crate::{ CcUnbound, MaybeUnbound, Result, Thunk, Unbound, Val, - arr::{PickObjectKeyValues, PickObjectValues}, + arr::{PickObjectKeyValues, PickObjectValues, arridx}, bail, error::{ErrorKind::*, suggest_object_fields}, evaluate::operator::evaluate_add_op, @@ -510,11 +510,14 @@ // } /// Returns amount of visible object fields /// If object only contains hidden fields - may return zero. - pub fn len(&self) -> u32 { + pub fn len(&self) -> usize { self.fields_visibility() .values() .filter(|d| d.visible()) - .count() as u32 + .count() + } + pub fn len32(&self) -> u32 { + arridx(self.len()) } /// For each field, calls callback. /// If callback returns false - ends iteration prematurely. @@ -625,7 +628,7 @@ Entry::Vacant(v) => { v.insert(CacheValue::Pending); } - }; + } } let result = self.get_idx_uncached(key, core); { --- a/crates/jrsonnet-evaluator/src/stack.rs +++ b/crates/jrsonnet-evaluator/src/stack.rs @@ -11,7 +11,7 @@ struct NightlyLocalKey(pub T); #[cfg(nightly)] impl NightlyLocalKey { - #[inline(always)] + #[inline] fn with(&self, v: impl FnOnce(&T) -> U) -> U { v(&self.0) } --- a/crates/jrsonnet-evaluator/src/trace/mod.rs +++ b/crates/jrsonnet-evaluator/src/trace/mod.rs @@ -197,7 +197,7 @@ w = align )?; } else { - write!(out, "{: Result<(), fmt::Error> { struct ResetData { loc: Span, --- a/crates/jrsonnet-evaluator/src/typed/conversions.rs +++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs @@ -637,7 +637,7 @@ } ::TYPE.check(&value)?; // Any::downcast_ref::(&a); - let mut out = Vec::with_capacity(a.len() as usize); + let mut out = Vec::with_capacity(a.len()); for e in a.iter() { let r = e?; out.push(u8::from_untyped(r)?); --- a/crates/jrsonnet-evaluator/src/val.rs +++ b/crates/jrsonnet-evaluator/src/val.rs @@ -277,7 +277,7 @@ /// For strings, will create a copy of specified interval. /// /// For arrays, nothing will be copied on this call, instead [`ArrValue::Slice`] view will be returned. - pub fn slice( + pub fn slice32( self, index: Option, end: Option, @@ -321,7 +321,7 @@ .into(), )) } - Self::Arr(arr) => Ok(Self::Arr(arr.clone().slice( + Self::Arr(arr) => Ok(Self::Arr(arr.clone().slice32( index, end, #[expect( @@ -658,7 +658,7 @@ if ArrValue::ptr_eq(a, b) { return Ok(true); } - if a.len() != b.len() { + if a.len32() != b.len32() { return Ok(false); } for (a, b) in a.iter().zip(b.iter()) { --- a/crates/jrsonnet-formatter/src/lib.rs +++ b/crates/jrsonnet-formatter/src/lib.rs @@ -477,8 +477,7 @@ &mut out, ); - let mut compspecs = compspecs.into_iter().peekable(); - while let Some(mem) = compspecs.next() { + for mem in compspecs { if mem.should_start_with_newline { p!(out, nl); } --- a/crates/jrsonnet-peg-parser/src/lib.rs +++ b/crates/jrsonnet-peg-parser/src/lib.rs @@ -273,19 +273,15 @@ Expr::ArrComp(Box::new(expr), specs) } pub rule number_expr(s: &ParserSettings) -> Expr - = n:number() {? if let Some(n) = NumValue::new(n) { - Ok(Expr::Num(n)) - } else { - Err("!!!numbers are finite") - }} + = n:number() {? NumValue::new(n).map_or_else(|| Err("!!!numbers are finite"), |n| Ok(Expr::Num(n)))} rule spanned(x: rule, s: &ParserSettings) -> Spanned - = a:position!() n:x() b:position!() { Spanned::new(n, Span(s.source.clone(), a as u32, b as u32)) } + = a:position!() n:x() b:position!() { Spanned::new(n, Span(s.source.clone(), codeidx(a), codeidx(b))) } pub rule var_expr(s: &ParserSettings) -> Expr = n:spanned(, s) { Expr::Var(n) } pub rule id_loc(s: &ParserSettings) -> Spanned - = a:position!() n:id() b:position!() { Spanned::new(Expr::Str(n), Span(s.source.clone(), a as u32,b as u32)) } + = a:position!() n:id() b:position!() { Spanned::new(Expr::Str(n), Span(s.source.clone(), codeidx(a), codeidx(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(Box::new(IfElse{ cond, @@ -421,6 +417,10 @@ } } +fn codeidx(i: usize) -> u32 { + u32::try_from(i).expect("code has 4g hard limit") +} + pub type ParseError = peg::error::ParseError; pub fn parse(str: &str, settings: &ParserSettings) -> Result { jsonnet_parser::jsonnet(str, settings) @@ -428,7 +428,10 @@ /// Used for importstr values pub fn string_to_expr(str: IStr, settings: &ParserSettings) -> Spanned { let len = str.len(); - Spanned::new(Expr::Str(str), Span(settings.source.clone(), 0, len as u32)) + Spanned::new( + Expr::Str(str), + Span(settings.source.clone(), 0, codeidx(len)), + ) } #[cfg(test)] --- a/crates/jrsonnet-pkg/src/install/accessor.rs +++ b/crates/jrsonnet-pkg/src/install/accessor.rs @@ -66,6 +66,10 @@ Ok(Some(out)) } #[allow(clippy::significant_drop_tightening, reason = "false-positive")] + #[allow( + clippy::iter_not_returning_iterator, + reason = "idk for a better name, it is still inner iteration" + )] pub fn iter( &self, subdir: &SubDir, --- a/crates/jrsonnet-rowan-parser/src/parser.rs +++ b/crates/jrsonnet-rowan-parser/src/parser.rs @@ -226,12 +226,12 @@ self.nth_at(0, kind) } pub fn nth_at(&self, n: usize, kind: SyntaxKind) -> bool { - if n == 0 { - if let ExpectedSyntax::Unnamed(kinds) = self.expected_syntax_tracking_state.get() { - let kinds = kinds.with(kind); - self.expected_syntax_tracking_state - .set(ExpectedSyntax::Unnamed(kinds)); - } + if n == 0 + && let ExpectedSyntax::Unnamed(kinds) = self.expected_syntax_tracking_state.get() + { + let kinds = kinds.with(kind); + self.expected_syntax_tracking_state + .set(ExpectedSyntax::Unnamed(kinds)); } self.nth(n) == kind } --- a/crates/jrsonnet-stdlib/src/arrays.rs +++ b/crates/jrsonnet-stdlib/src/arrays.rs @@ -52,7 +52,7 @@ step: Option>>, ) -> Result { indexable - .slice(index.flatten(), end.flatten(), step.flatten()) + .slice32(index.flatten(), end.flatten(), step.flatten()) .map(Val::from) } @@ -204,14 +204,14 @@ let item = item?.clone(); if let Val::Arr(items) = item { if !first { - out.reserve(joiner_items.len() as usize); + out.reserve(joiner_items.len()); // TODO: extend for item in joiner_items.iter() { out.push(item?); } } first = false; - out.reserve(items.len() as usize); + out.reserve(items.len()); for item in items.iter() { out.push(item?); } @@ -372,10 +372,10 @@ #[builtin] pub fn builtin_remove_at(arr: ArrValue, at: i32) -> Result { - let newArrLeft = arr.clone().slice(None, Some(at), None); - let newArrRight = arr.slice(Some(at + 1), None, None); + let newArrLeft = arr.clone().slice32(None, Some(at), None); + let newArrRight = arr.slice32(Some(at + 1), None, None); - Ok(ArrValue::extended(newArrLeft, newArrRight).ok_or_else(|| error!("array is too large"))?) + ArrValue::extended(newArrLeft, newArrRight).ok_or_else(|| error!("array is too large")) } #[builtin] --- a/crates/jrsonnet-stdlib/src/manifest/xml.rs +++ b/crates/jrsonnet-stdlib/src/manifest/xml.rs @@ -44,15 +44,15 @@ bail!("JSONML value should have tag (array length should be >=1)"); } let tag = String::from_untyped( - arr.get(0) + arr.get32(0) .description("getting JSONML tag")? .expect("length checked"), ) .description("parsing JSONML tag")?; - let (has_attrs, attrs) = if arr.len() >= 2 { + let (has_attrs, attrs) = if arr.len32() >= 2 { let maybe_attrs = arr - .get(1) + .get32(1) .with_description(|| "getting JSONML attrs")? .expect("length checked"); if let Val::Obj(attrs) = maybe_attrs { @@ -68,13 +68,7 @@ attrs, children: in_description_frame( || "parsing children".to_owned(), - || { - FromUntyped::from_untyped(Val::Arr(arr.slice( - Some(if has_attrs { 2 } else { 1 }), - None, - None, - ))) - }, + || FromUntyped::from_untyped(Val::Arr(arr.slice(if has_attrs { 2 } else { 1 }..))), )?, }) } --- a/crates/jrsonnet-stdlib/src/misc.rs +++ b/crates/jrsonnet-stdlib/src/misc.rs @@ -16,10 +16,10 @@ pub fn builtin_length(x: Either![IStr, ArrValue, ObjValue, FuncVal]) -> u32 { use Either4::*; match x { - A(x) => x.chars().count() as u32, - B(x) => x.len(), - C(x) => x.len(), - D(f) => f.params_len(), + A(x) => u32::try_from(x.chars().count()).expect("4g limit"), + B(x) => x.len32(), + C(x) => x.len32(), + D(f) => f.params_len32(), } } @@ -102,7 +102,7 @@ } else if b.len() == a.len() { return equals(&Val::Arr(a), &Val::Arr(b)); } - for (a, b) in a.iter().take(b.len() as usize).zip(b.iter()) { + for (a, b) in a.iter().take(b.len()).zip(b.iter()) { let a = a?; let b = b?; if !equals(&a, &b)? { @@ -127,7 +127,7 @@ return equals(&Val::Arr(a), &Val::Arr(b)); } let a_len = a.len(); - for (a, b) in a.iter().skip((a_len - b.len()) as usize).zip(b.iter()) { + for (a, b) in a.iter().skip(a_len - b.len()).zip(b.iter()) { let a = a?; let b = b?; if !equals(&a, &b)? { --- a/crates/jrsonnet-stdlib/src/sets.rs +++ b/crates/jrsonnet-stdlib/src/sets.rs @@ -8,13 +8,13 @@ #[allow(non_snake_case)] pub fn builtin_set_member(x: Thunk, arr: ArrValue, #[default] keyF: KeyF) -> Result { let mut low = 0; - let mut high = arr.len(); + let mut high = arr.len32(); let x = keyF.eval(x)?; while low < high { let middle = u32::midpoint(high, low); - let comp = keyF.eval(arr.get_lazy(middle).expect("in bounds"))?; + let comp = keyF.eval(arr.get_lazy32(middle).expect("in bounds"))?; match Val::try_cmp(&comp, &x)? { Ordering::Less => low = middle + 1, Ordering::Equal => return Ok(true), --- a/crates/jrsonnet-stdlib/src/sort.rs +++ b/crates/jrsonnet-stdlib/src/sort.rs @@ -69,7 +69,7 @@ fn sort_keyf(values: ArrValue, keyf: KeyF) -> Result>> { // Slow path, user provided key getter - let mut vk = Vec::with_capacity(values.len() as usize); + let mut vk = Vec::with_capacity(values.len()); for value in values.iter_lazy() { vk.push((value.clone(), keyf.eval(value)?)); } @@ -137,7 +137,7 @@ fn uniq_keyf(arr: ArrValue, keyf: KeyF) -> Result>> { let mut out = Vec::new(); - let last_value = arr.get_lazy(0).unwrap(); + let last_value = arr.get_lazy32(0).unwrap(); let mut last_key = keyf.eval(last_value.clone())?; out.push(last_value); --- a/crates/jrsonnet-types/src/lib.rs +++ b/crates/jrsonnet-types/src/lib.rs @@ -103,10 +103,8 @@ Self::BoundedNumber(a, b) => write!( f, "BoundedNumber<{}, {}>", - a.map(|e| e.to_string()) - .unwrap_or_else(|| "open".to_owned()), - b.map(|e| e.to_string()) - .unwrap_or_else(|| "open".to_owned()) + a.map_or_else(|| "open".to_owned(), |e| e.to_string()), + b.map_or_else(|| "open".to_owned(), |e| e.to_string()) )?, Self::ArrayRef(a) => print_array(a, f)?, Self::Array(a) => print_array(a, f)?, --- a/tests/tests/cpp_test_suite.rs +++ b/tests/tests/cpp_test_suite.rs @@ -60,7 +60,7 @@ let _entered = s.enter(); let trace_format = CompactFormat { - resolver: resolver.clone(), + resolver, max_trace: 20, padding: 4, }; --- a/xtask/src/bench.rs +++ b/xtask/src/bench.rs @@ -91,6 +91,10 @@ let start = Instant::now(); let child = cmd.spawn()?; + #[allow( + clippy::cast_possible_wrap, + reason = "it is signed, but libc didn't set unsigned for it" + )] let pid = child.id() as libc::pid_t; // We'll reap via wait4 ourselves; don't let std touch this handle again. mem::forget(child); @@ -133,10 +137,10 @@ ); eprintln!( " max_rss: {} ± {} KiB [{}..{}]", - r.max_rss_kib.mean as i64, - r.max_rss_kib.stddev as i64, - r.max_rss_kib.min as i64, - r.max_rss_kib.max as i64, + r.max_rss_kib.mean.trunc(), + r.max_rss_kib.stddev.trunc(), + r.max_rss_kib.min.trunc(), + r.max_rss_kib.max.trunc(), ); Ok(()) } --- a/xtask/src/sourcegen/mod.rs +++ b/xtask/src/sourcegen/mod.rs @@ -113,6 +113,7 @@ Ok(()) } +#[allow(clippy::too_many_lines)] fn generate_syntax_kinds(kinds: &KindsSrc, grammar: &AstSrc, lexer: bool) -> Result { let t_macros = kinds.tokens().filter_map(TokenKind::expand_t_macros); let token_kinds = kinds.tokens().map(|t| t.expand_kind(lexer)); -- gitstuff