From bf5d6ab35afb8a4da2022022d507cf3f9822bc4a Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 27 Aug 2022 16:26:41 +0800 Subject: [PATCH] Shut up clippy. --- src/api/custom_syntax.rs | 5 +- src/api/definitions/mod.rs | 10 +-- src/api/events.rs | 2 +- src/api/type_names.rs | 7 +- src/ast/ast.rs | 12 ++-- src/ast/expr.rs | 28 +++----- src/ast/flags.rs | 4 +- src/ast/stmt.rs | 42 ++++++------ src/engine.rs | 21 +++--- src/eval/chaining.rs | 45 ++++++++----- src/eval/data_check.rs | 2 +- src/eval/expr.rs | 33 +++++----- src/eval/stmt.rs | 10 +-- src/eval/target.rs | 6 +- src/func/builtin.rs | 17 +++-- src/func/call.rs | 6 +- src/func/register.rs | 4 +- src/lib.rs | 25 ++++++++ src/optimizer.rs | 27 ++++---- src/packages/array_basic.rs | 8 ++- src/packages/blob_basic.rs | 14 ++-- src/packages/iter_basic.rs | 19 +++--- src/packages/lang_core.rs | 4 +- src/packages/string_more.rs | 124 ++++++++++++++++++++++++++++-------- src/parser.rs | 24 +++---- src/reify.rs | 1 + src/tokenizer.rs | 16 ++--- src/types/dynamic.rs | 2 +- 28 files changed, 313 insertions(+), 205 deletions(-) diff --git a/src/api/custom_syntax.rs b/src/api/custom_syntax.rs index 64954d27..26abf716 100644 --- a/src/api/custom_syntax.rs +++ b/src/api/custom_syntax.rs @@ -134,10 +134,7 @@ impl Expression<'_> { Expr::CharConstant(x, ..) => reify!(*x => Option), Expr::StringConstant(x, ..) => reify!(x.clone() => Option), - Expr::Variable(x, ..) => { - let x: ImmutableString = x.3.clone().into(); - reify!(x => Option) - } + Expr::Variable(x, ..) => reify!(x.3.clone() => Option), Expr::BoolConstant(x, ..) => reify!(*x => Option), Expr::Unit(..) => reify!(() => Option), diff --git a/src/api/definitions/mod.rs b/src/api/definitions/mod.rs index e0caef31..8cb3b3ee 100644 --- a/src/api/definitions/mod.rs +++ b/src/api/definitions/mod.rs @@ -3,9 +3,8 @@ #![cfg(feature = "metadata")] use crate::module::FuncInfo; -use crate::plugin::*; use crate::tokenizer::{is_valid_function_name, Token}; -use crate::{Engine, Module, Scope, INT}; +use crate::{Engine, FnAccess, Module, Scope, INT}; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -117,19 +116,20 @@ impl Definitions<'_> { } /// Get the [`Engine`]. #[inline(always)] - pub fn engine(&self) -> &Engine { + #[must_use] + pub const fn engine(&self) -> &Engine { self.engine } /// Get the [`Scope`]. #[inline(always)] #[must_use] - pub fn scope(&self) -> Option<&Scope> { + pub const fn scope(&self) -> Option<&Scope> { self.scope } /// Get the configuration. #[inline(always)] #[must_use] - pub(crate) fn config(&self) -> &DefinitionsConfig { + pub(crate) const fn config(&self) -> &DefinitionsConfig { &self.config } } diff --git a/src/api/events.rs b/src/api/events.rs index 266c70c8..01463d2b 100644 --- a/src/api/events.rs +++ b/src/api/events.rs @@ -348,7 +348,7 @@ impl Engine { #[inline(always)] pub fn register_debugger( &mut self, - init: impl Fn(&Engine) -> Dynamic + SendSync + 'static, + init: impl Fn(&Self) -> Dynamic + SendSync + 'static, callback: impl Fn( EvalContext, crate::eval::DebuggerEvent, diff --git a/src/api/type_names.rs b/src/api/type_names.rs index 7d802376..de9120ac 100644 --- a/src/api/type_names.rs +++ b/src/api/type_names.rs @@ -102,11 +102,8 @@ fn map_std_type_name(name: &str, shorthands: bool) -> &str { }; } - if let Some(stripped) = name.strip_prefix("rhai::") { - map_std_type_name(stripped, shorthands) - } else { - name - } + name.strip_prefix("rhai::") + .map_or(name, |s| map_std_type_name(s, shorthands)) } impl Engine { diff --git a/src/ast/ast.rs b/src/ast/ast.rs index cabd7c10..da0454fe 100644 --- a/src/ast/ast.rs +++ b/src/ast/ast.rs @@ -167,7 +167,7 @@ impl AST { /// Get a reference to the source. #[inline(always)] #[must_use] - pub(crate) fn source_raw(&self) -> &Identifier { + pub(crate) const fn source_raw(&self) -> &Identifier { &self.source } /// Set the source. @@ -261,7 +261,7 @@ impl AST { #[cfg(not(feature = "no_function"))] #[inline(always)] #[must_use] - pub(crate) fn shared_lib(&self) -> &crate::Shared { + pub(crate) const fn shared_lib(&self) -> &crate::Shared { &self.lib } /// _(internals)_ Get the internal shared [`Module`][crate::Module] containing all script-defined functions. @@ -272,7 +272,7 @@ impl AST { #[cfg(not(feature = "no_function"))] #[inline(always)] #[must_use] - pub fn shared_lib(&self) -> &crate::Shared { + pub const fn shared_lib(&self) -> &crate::Shared { &self.lib } /// Get the embedded [module resolver][crate::ModuleResolver]. @@ -280,7 +280,7 @@ impl AST { #[cfg(not(feature = "no_module"))] #[inline(always)] #[must_use] - pub(crate) fn resolver( + pub(crate) const fn resolver( &self, ) -> Option<&crate::Shared> { self.resolver.as_ref() @@ -293,7 +293,7 @@ impl AST { #[cfg(not(feature = "no_module"))] #[inline(always)] #[must_use] - pub fn resolver( + pub const fn resolver( &self, ) -> Option<&crate::Shared> { self.resolver.as_ref() @@ -910,7 +910,7 @@ impl> Add for &AST { } } -impl> AddAssign for AST { +impl> AddAssign for AST { #[inline(always)] fn add_assign(&mut self, rhs: A) { self.combine(rhs.into()); diff --git a/src/ast/expr.rs b/src/ast/expr.rs index e86531d0..e2f66fd0 100644 --- a/src/ast/expr.rs +++ b/src/ast/expr.rs @@ -338,17 +338,7 @@ impl FloatWrapper { /// Create a new [`FloatWrapper`]. #[inline(always)] #[must_use] - pub fn new(value: F) -> Self { - Self(value) - } -} - -#[cfg(not(feature = "no_float"))] -impl FloatWrapper { - /// Create a new [`FloatWrapper`]. - #[inline(always)] - #[must_use] - pub const fn new_const(value: crate::FLOAT) -> Self { + pub const fn new(value: F) -> Self { Self(value) } } @@ -600,7 +590,7 @@ impl Expr { Self::FnCall(ref x, ..) if !x.is_qualified() && x.args.len() == 1 && x.name == KEYWORD_FN_PTR => { - if let Expr::StringConstant(ref s, ..) = x.args[0] { + if let Self::StringConstant(ref s, ..) = x.args[0] { FnPtr::new(s).ok()?.into() } else { return None; @@ -612,8 +602,8 @@ impl Expr { match x.name.as_str() { // x..y OP_EXCLUSIVE_RANGE => { - if let Expr::IntegerConstant(ref start, ..) = x.args[0] { - if let Expr::IntegerConstant(ref end, ..) = x.args[1] { + if let Self::IntegerConstant(ref start, ..) = x.args[0] { + if let Self::IntegerConstant(ref end, ..) = x.args[1] { (*start..*end).into() } else { return None; @@ -624,8 +614,8 @@ impl Expr { } // x..=y OP_INCLUSIVE_RANGE => { - if let Expr::IntegerConstant(ref start, ..) = x.args[0] { - if let Expr::IntegerConstant(ref end, ..) = x.args[1] { + if let Self::IntegerConstant(ref start, ..) = x.args[0] { + if let Self::IntegerConstant(ref end, ..) = x.args[1] { (*start..=*end).into() } else { return None; @@ -940,9 +930,9 @@ impl Expr { } Self::Index(x, ..) | Self::Dot(x, ..) - | Expr::And(x, ..) - | Expr::Or(x, ..) - | Expr::Coalesce(x, ..) => { + | Self::And(x, ..) + | Self::Or(x, ..) + | Self::Coalesce(x, ..) => { if !x.lhs.walk(path, on_node) { return false; } diff --git a/src/ast/flags.rs b/src/ast/flags.rs index 5d90f261..452a57e6 100644 --- a/src/ast/flags.rs +++ b/src/ast/flags.rs @@ -20,7 +20,7 @@ impl FnAccess { /// Is this function private? #[inline(always)] #[must_use] - pub fn is_private(self) -> bool { + pub const fn is_private(self) -> bool { match self { Self::Private => true, Self::Public => false, @@ -29,7 +29,7 @@ impl FnAccess { /// Is this function public? #[inline(always)] #[must_use] - pub fn is_public(self) -> bool { + pub const fn is_public(self) -> bool { match self { Self::Private => false, Self::Public => true, diff --git a/src/ast/stmt.rs b/src/ast/stmt.rs index 4a5ebcbf..a9d3b096 100644 --- a/src/ast/stmt.rs +++ b/src/ast/stmt.rs @@ -60,7 +60,7 @@ impl OpAssignment { #[must_use] #[inline(always)] pub fn new_op_assignment(name: &str, pos: Position) -> Self { - Self::new_op_assignment_from_token(Token::lookup_from_syntax(name).expect("operator"), pos) + Self::new_op_assignment_from_token(&Token::lookup_from_syntax(name).expect("operator"), pos) } /// Create a new [`OpAssignment`] from a [`Token`]. /// @@ -68,7 +68,7 @@ impl OpAssignment { /// /// Panics if the token is not an op-assignment operator. #[must_use] - pub fn new_op_assignment_from_token(op: Token, pos: Position) -> Self { + pub fn new_op_assignment_from_token(op: &Token, pos: Position) -> Self { let op_raw = op .get_base_op_from_assignment() .expect("op-assignment operator") @@ -90,7 +90,7 @@ impl OpAssignment { #[inline(always)] pub fn new_op_assignment_from_base(name: &str, pos: Position) -> Self { Self::new_op_assignment_from_base_token( - Token::lookup_from_syntax(name).expect("operator"), + &Token::lookup_from_syntax(name).expect("operator"), pos, ) } @@ -101,8 +101,8 @@ impl OpAssignment { /// Panics if the token is cannot be converted into an op-assignment operator. #[inline(always)] #[must_use] - pub fn new_op_assignment_from_base_token(op: Token, pos: Position) -> Self { - Self::new_op_assignment_from_token(op.convert_to_op_assignment().expect("operator"), pos) + pub fn new_op_assignment_from_base_token(op: &Token, pos: Position) -> Self { + Self::new_op_assignment_from_token(&op.convert_to_op_assignment().expect("operator"), pos) } } @@ -157,13 +157,13 @@ impl ConditionalExpr { /// Is the condition always `true`? #[inline(always)] #[must_use] - pub fn is_always_true(&self) -> bool { + pub const fn is_always_true(&self) -> bool { matches!(self.condition, Expr::BoolConstant(true, ..)) } /// Is the condition always `false`? #[inline(always)] #[must_use] - pub fn is_always_false(&self) -> bool { + pub const fn is_always_false(&self) -> bool { matches!(self.condition, Expr::BoolConstant(false, ..)) } } @@ -228,12 +228,12 @@ impl RangeCase { /// Size of the range. #[inline(always)] #[must_use] - pub fn len(&self) -> usize { + pub fn len(&self) -> INT { match self { Self::ExclusiveInt(r, ..) if r.is_empty() => 0, - Self::ExclusiveInt(r, ..) => (r.end - r.start) as usize, + Self::ExclusiveInt(r, ..) => r.end - r.start, Self::InclusiveInt(r, ..) if r.is_empty() => 0, - Self::InclusiveInt(r, ..) => (*r.end() - *r.start()) as usize, + Self::InclusiveInt(r, ..) => *r.end() - *r.start() + 1, } } /// Is the specified number within this range? @@ -248,7 +248,7 @@ impl RangeCase { /// Is the specified range inclusive? #[inline(always)] #[must_use] - pub fn is_inclusive(&self) -> bool { + pub const fn is_inclusive(&self) -> bool { match self { Self::ExclusiveInt(..) => false, Self::InclusiveInt(..) => true, @@ -257,7 +257,7 @@ impl RangeCase { /// Get the index to the [`ConditionalExpr`]. #[inline(always)] #[must_use] - pub fn index(&self) -> usize { + pub const fn index(&self) -> usize { match self { Self::ExclusiveInt(.., n) | Self::InclusiveInt(.., n) => *n, } @@ -611,14 +611,14 @@ impl From for Stmt { } } -impl> From<(T, Position, Position)> for Stmt { +impl> From<(T, Position, Position)> for Stmt { #[inline(always)] fn from(value: (T, Position, Position)) -> Self { StmtBlock::new(value.0, value.1, value.2).into() } } -impl> From<(T, Span)> for Stmt { +impl> From<(T, Span)> for Stmt { #[inline(always)] fn from(value: (T, Span)) -> Self { StmtBlock::new_with_span(value.0, value.1).into() @@ -765,7 +765,7 @@ impl Stmt { Self::Noop(..) => true, Self::Expr(expr) => expr.is_pure(), Self::If(x, ..) => { - x.0.is_pure() && x.1.iter().all(Stmt::is_pure) && x.2.iter().all(Stmt::is_pure) + x.0.is_pure() && x.1.iter().all(Self::is_pure) && x.2.iter().all(Self::is_pure) } Self::Switch(x, ..) => { let (expr, sw) = &**x; @@ -786,7 +786,7 @@ impl Stmt { Self::While(x, ..) if matches!(x.0, Expr::BoolConstant(false, ..)) => true, Self::Do(x, options, ..) if matches!(x.0, Expr::BoolConstant(..)) => match x.0 { Expr::BoolConstant(cond, ..) if cond == options.contains(ASTFlags::NEGATED) => { - x.1.iter().all(Stmt::is_pure) + x.1.iter().all(Self::is_pure) } _ => false, }, @@ -796,13 +796,13 @@ impl Stmt { // For loops can be pure because if the iterable is pure, it is finite, // so infinite loops can never occur. - Self::For(x, ..) => x.2.is_pure() && x.3.iter().all(Stmt::is_pure), + Self::For(x, ..) => x.2.is_pure() && x.3.iter().all(Self::is_pure), Self::Var(..) | Self::Assignment(..) | Self::FnCall(..) => false, - Self::Block(block, ..) => block.iter().all(Stmt::is_pure), + Self::Block(block, ..) => block.iter().all(Self::is_pure), Self::BreakLoop(..) | Self::Return(..) => false, Self::TryCatch(x, ..) => { - x.try_block.iter().all(Stmt::is_pure) && x.catch_block.iter().all(Stmt::is_pure) + x.try_block.iter().all(Self::is_pure) && x.catch_block.iter().all(Self::is_pure) } #[cfg(not(feature = "no_module"))] @@ -828,7 +828,7 @@ impl Stmt { Self::Var(..) => true, Self::Expr(e) => match &**e { - Expr::Stmt(s) => s.iter().all(Stmt::is_block_dependent), + Expr::Stmt(s) => s.iter().all(Self::is_block_dependent), Expr::FnCall(x, ..) => !x.is_qualified() && x.name == KEYWORD_EVAL, _ => false, }, @@ -854,7 +854,7 @@ impl Stmt { Self::Var(x, ..) => x.1.is_pure(), Self::Expr(e) => match &**e { - Expr::Stmt(s) => s.iter().all(Stmt::is_internally_pure), + Expr::Stmt(s) => s.iter().all(Self::is_internally_pure), _ => self.is_pure(), }, diff --git a/src/engine.rs b/src/engine.rs index 1fea8e29..84c85701 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -237,13 +237,16 @@ impl Engine { { engine.print = Box::new(|s| println!("{}", s)); engine.debug = Box::new(|s, source, pos| { - if let Some(source) = source { - println!("{} @ {:?} | {}", source, pos, s); - } else if pos.is_none() { - println!("{}", s); - } else { - println!("{:?} | {}", pos, s); - } + source.map_or_else( + || { + if pos.is_none() { + println!("{}", s); + } else { + println!("{:?} | {}", pos, s); + } + }, + |source| println!("{} @ {:?} | {}", source, pos, s), + ) }); } @@ -316,7 +319,7 @@ impl Engine { &self, string: impl AsRef + Into, ) -> ImmutableString { - locked_write(&self.interned_strings).get(string).into() + locked_write(&self.interned_strings).get(string) } /// _(internals)_ Get an interned [string][ImmutableString]. @@ -331,7 +334,7 @@ impl Engine { &self, string: impl AsRef + Into, ) -> ImmutableString { - locked_write(&self.interned_strings).get(string).into() + locked_write(&self.interned_strings).get(string) } /// Get an empty [`ImmutableString`] which refers to a shared instance. diff --git a/src/eval/chaining.rs b/src/eval/chaining.rs index 93720d79..351df42e 100644 --- a/src/eval/chaining.rs +++ b/src/eval/chaining.rs @@ -152,14 +152,14 @@ impl Engine { if let Ok(val) = self.call_indexer_get(global, caches, lib, target, idx, level) { - let mut res = val.into(); + let mut val = val.into(); // Run the op-assignment self.eval_op_assignment( - global, caches, lib, op_info, &mut res, root, new_val, + global, caches, lib, op_info, &mut val, root, new_val, level, )?; // Replace new value - new_val = res.take_or_clone(); + new_val = val.take_or_clone(); #[cfg(not(feature = "unchecked"))] self.check_data_size(&new_val, op_info.pos)?; } @@ -864,13 +864,16 @@ impl Engine { map.insert(index.clone().into(), Dynamic::UNIT); } - if let Some(value) = map.get_mut(index.as_str()) { - Ok(Target::from(value)) - } else if self.fail_on_invalid_map_property() { - Err(ERR::ErrorPropertyNotFound(index.to_string(), idx_pos).into()) - } else { - Ok(Target::from(Dynamic::UNIT)) - } + map.get_mut(index.as_str()).map_or_else( + || { + if self.fail_on_invalid_map_property() { + Err(ERR::ErrorPropertyNotFound(index.to_string(), idx_pos).into()) + } else { + Ok(Target::from(Dynamic::UNIT)) + } + }, + |value| Ok(Target::from(value)), + ) } #[cfg(not(feature = "no_index"))] @@ -970,21 +973,33 @@ impl Engine { .map_err(|typ| self.make_type_mismatch_err::(typ, idx_pos))?; let (ch, offset) = if index >= 0 { + if index >= crate::MAX_USIZE_INT { + return Err( + ERR::ErrorStringBounds(s.chars().count(), index, idx_pos).into() + ); + } + let offset = index as usize; ( s.chars().nth(offset).ok_or_else(|| { - let chars_len = s.chars().count(); - ERR::ErrorStringBounds(chars_len, index, idx_pos) + ERR::ErrorStringBounds(s.chars().count(), index, idx_pos) })?, offset, ) } else { - let offset = index.unsigned_abs() as usize; + let abs_index = index.unsigned_abs(); + + if abs_index as u64 >= usize::MAX as u64 { + return Err( + ERR::ErrorStringBounds(s.chars().count(), index, idx_pos).into() + ); + } + + let offset = abs_index as usize; ( // Count from end if negative s.chars().rev().nth(offset - 1).ok_or_else(|| { - let chars_len = s.chars().count(); - ERR::ErrorStringBounds(chars_len, index, idx_pos) + ERR::ErrorStringBounds(s.chars().count(), index, idx_pos) })?, offset, ) diff --git a/src/eval/data_check.rs b/src/eval/data_check.rs index a9cda2bc..293b1d99 100644 --- a/src/eval/data_check.rs +++ b/src/eval/data_check.rs @@ -72,7 +72,7 @@ impl Engine { /// Is there a data size limit set? #[cfg(not(feature = "unchecked"))] - pub(crate) fn has_data_size_limit(&self) -> bool { + pub(crate) const fn has_data_size_limit(&self) -> bool { let mut _limited = self.limits.max_string_size.is_some(); #[cfg(not(feature = "no_index"))] diff --git a/src/eval/expr.rs b/src/eval/expr.rs index 51265efc..ab499a6a 100644 --- a/src/eval/expr.rs +++ b/src/eval/expr.rs @@ -74,19 +74,22 @@ impl Engine { (_, namespace, hash_var, var_name) => { // foo:bar::baz::VARIABLE if let Some(module) = self.search_imports(global, namespace) { - return if let Some(mut target) = module.get_qualified_var(*hash_var) { - // Module variables are constant - target.set_access_mode(AccessMode::ReadOnly); - Ok((target.into(), *_var_pos)) - } else { - let sep = crate::tokenizer::Token::DoubleColon.literal_syntax(); + return module.get_qualified_var(*hash_var).map_or_else( + || { + let sep = crate::tokenizer::Token::DoubleColon.literal_syntax(); - Err(ERR::ErrorVariableNotFound( - format!("{namespace}{sep}{var_name}"), - namespace.position(), - ) - .into()) - }; + Err(ERR::ErrorVariableNotFound( + format!("{namespace}{sep}{var_name}"), + namespace.position(), + ) + .into()) + }, + |mut target| { + // Module variables are constant + target.set_access_mode(AccessMode::ReadOnly); + Ok((target.into(), *_var_pos)) + }, + ); } // global::VARIABLE @@ -363,7 +366,7 @@ impl Engine { #[cfg(not(feature = "no_index"))] Expr::Array(x, ..) => { - let mut arr = crate::Array::with_capacity(x.len()); + let mut array = crate::Array::with_capacity(x.len()); let mut result = Ok(Dynamic::UNIT); #[cfg(not(feature = "unchecked"))] @@ -383,7 +386,7 @@ impl Engine { #[cfg(not(feature = "unchecked"))] let val_sizes = Self::calc_data_sizes(&value, true); - arr.push(value); + array.push(value); #[cfg(not(feature = "unchecked"))] if self.has_data_size_limit() { @@ -396,7 +399,7 @@ impl Engine { } } - result.map(|_| arr.into()) + result.map(|_| array.into()) } #[cfg(not(feature = "no_object"))] diff --git a/src/eval/stmt.rs b/src/eval/stmt.rs index 18d16eba..1003e896 100644 --- a/src/eval/stmt.rs +++ b/src/eval/stmt.rs @@ -631,8 +631,12 @@ impl Engine { for (x, iter_value) in func(iter_obj).enumerate() { // Increment counter if counter_index < usize::MAX { + // As the variable increments from 0, this should always work + // since any overflow will first be caught below. + let index_value = x as INT; + #[cfg(not(feature = "unchecked"))] - if x > INT::MAX as usize { + if index_value > crate::MAX_USIZE_INT { loop_result = Err(ERR::ErrorArithmetic( format!("for-loop counter overflow: {x}"), counter.pos, @@ -641,10 +645,8 @@ impl Engine { break; } - let index_value = Dynamic::from(x as INT); - *scope.get_mut_by_index(counter_index).write_lock().unwrap() = - index_value; + Dynamic::from_int(index_value); } let value = match iter_value { diff --git a/src/eval/target.rs b/src/eval/target.rs index e8d1678a..0114fa5b 100644 --- a/src/eval/target.rs +++ b/src/eval/target.rs @@ -16,7 +16,7 @@ use std::prelude::v1::*; pub fn calc_offset_len(length: usize, start: crate::INT, len: crate::INT) -> (usize, usize) { let start = if start < 0 { length - usize::min(start.unsigned_abs() as usize, length) - } else if start as usize >= length { + } else if start > crate::MAX_USIZE_INT || start as usize >= length { return (length, 0); } else { start as usize @@ -24,7 +24,7 @@ pub fn calc_offset_len(length: usize, start: crate::INT, len: crate::INT) -> (us let len = if len <= 0 { 0 - } else if len as usize > length - start { + } else if len > crate::MAX_USIZE_INT || len as usize > length - start { length - start } else { len as usize @@ -59,7 +59,7 @@ pub fn calc_index( } else { err() } - } else if start as usize >= length { + } else if start > crate::MAX_USIZE_INT || start as usize >= length { err() } else { Ok(start as usize) diff --git a/src/func/builtin.rs b/src/func/builtin.rs index 4856c61f..d97d1a27 100644 --- a/src/func/builtin.rs +++ b/src/func/builtin.rs @@ -700,16 +700,15 @@ pub fn get_builtin_op_assignment_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Optio }), _ => None, }; - } else { - return match op { - "+=" => Some(|_, args| { - let x = std::mem::take(args[1]); - let array = &mut *args[0].write_lock::().expect(BUILTIN); - Ok(push(array, x).into()) - }), - _ => None, - }; } + return match op { + "+=" => Some(|_, args| { + let x = std::mem::take(args[1]); + let array = &mut *args[0].write_lock::().expect(BUILTIN); + Ok(push(array, x).into()) + }), + _ => None, + }; } #[cfg(not(feature = "no_index"))] diff --git a/src/func/call.rs b/src/func/call.rs index eb1bffda..071bb5c7 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -68,7 +68,7 @@ impl<'a> ArgBackup<'a> { // Replace the first reference with a reference to the clone, force-casting the lifetime. // Must remember to restore it later with `restore_first_arg`. // - // # Safety + // SAFETY: // // Blindly casting a reference to another lifetime saves allocation and string cloning, // but must be used with the utmost care. @@ -608,7 +608,7 @@ impl Engine { let num_params = args[1].as_int().expect("`INT`"); return Ok(( - if num_params < 0 { + if num_params < 0 || num_params > crate::MAX_USIZE_INT { false } else { let hash_script = calc_fn_hash(fn_name.as_str(), num_params as usize); @@ -1100,7 +1100,7 @@ impl Engine { .as_int() .map_err(|typ| self.make_type_mismatch_err::(typ, arg_pos))?; - return Ok(if num_params < 0 { + return Ok(if num_params < 0 || num_params > crate::MAX_USIZE_INT { false } else { let hash_script = calc_fn_hash(&fn_name, num_params as usize); diff --git a/src/func/register.rs b/src/func/register.rs index 40035b64..c282399f 100644 --- a/src/func/register.rs +++ b/src/func/register.rs @@ -47,9 +47,7 @@ pub fn by_value(data: &mut Dynamic) -> T { // If T is `&str`, data must be `ImmutableString`, so map directly to it data.flatten_in_place(); let ref_str = data.as_str_ref().expect("&str"); - // # Safety - // - // We already checked that `T` is `&str`, so it is safe to cast here. + // SAFETY: We already checked that `T` is `&str`, so it is safe to cast here. return unsafe { mem::transmute_copy::<_, T>(&ref_str) }; } if TypeId::of::() == TypeId::of::() { diff --git a/src/lib.rs b/src/lib.rs index 715dd979..60fc68da 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,7 +58,18 @@ #![cfg_attr(feature = "no_std", no_std)] #![deny(missing_docs)] +#![warn(clippy::all)] +#![warn(clippy::pedantic)] +#![warn(clippy::nursery)] +#![warn(clippy::cargo)] +#![warn(clippy::undocumented_unsafe_blocks)] #![allow(clippy::unit_arg)] +#![allow(clippy::missing_errors_doc)] +#![allow(clippy::used_underscore_binding)] +#![allow(clippy::inline_always)] +#![allow(clippy::module_name_repetitions)] +#![allow(clippy::negative_feature_names)] +#![allow(clippy::module_inception)] #[cfg(feature = "no_std")] extern crate alloc; @@ -123,6 +134,20 @@ type UNSIGNED_INT = u64; #[allow(non_camel_case_types)] type UNSIGNED_INT = u32; +/// The maximum integer that can fit into a [`usize`]. +#[cfg(not(target_pointer_width = "32"))] +const MAX_USIZE_INT: INT = INT::MAX; + +/// The maximum integer that can fit into a [`usize`]. +#[cfg(not(feature = "only_i32"))] +#[cfg(target_pointer_width = "32")] +const MAX_USIZE_INT: INT = usize::MAX as INT; + +/// The maximum integer that can fit into a [`usize`]. +#[cfg(feature = "only_i32")] +#[cfg(target_pointer_width = "32")] +const MAX_USIZE_INT: INT = INT::MAX; + /// Number of bits in [`INT`]. /// /// It is 64 unless the `only_i32` feature is enabled when it will be 32. diff --git a/src/optimizer.rs b/src/optimizer.rs index c45798a0..851628e8 100644 --- a/src/optimizer.rs +++ b/src/optimizer.rs @@ -301,21 +301,20 @@ fn optimize_stmt_block( while index < statements.len() { if preserve_result && index >= statements.len() - 1 { break; - } else { - match statements[index] { - ref stmt if is_pure(stmt) && index >= first_non_constant => { - state.set_dirty(); - statements.remove(index); - } - ref stmt if stmt.is_pure() => { - state.set_dirty(); - if index < first_non_constant { - first_non_constant -= 1; - } - statements.remove(index); - } - _ => index += 1, + } + match statements[index] { + ref stmt if is_pure(stmt) && index >= first_non_constant => { + state.set_dirty(); + statements.remove(index); } + ref stmt if stmt.is_pure() => { + state.set_dirty(); + if index < first_non_constant { + first_non_constant -= 1; + } + statements.remove(index); + } + _ => index += 1, } } diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index 6018a982..3b3e9e5a 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -5,7 +5,7 @@ use crate::eval::{calc_index, calc_offset_len}; use crate::plugin::*; use crate::{ def_package, Array, Dynamic, ExclusiveRange, FnPtr, InclusiveRange, NativeCallContext, - Position, RhaiResultOf, StaticVec, ERR, INT, + Position, RhaiResultOf, StaticVec, ERR, INT, MAX_USIZE_INT, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -217,6 +217,8 @@ pub mod array_functions { len: INT, item: Dynamic, ) -> RhaiResultOf<()> { + let len = len.min(MAX_USIZE_INT); + if len <= 0 || (len as usize) <= array.len() { return Ok(()); } @@ -369,6 +371,8 @@ pub mod array_functions { /// ``` pub fn truncate(array: &mut Array, len: INT) { if !array.is_empty() { + let len = len.min(MAX_USIZE_INT); + if len > 0 { array.truncate(len as usize); } else { @@ -396,6 +400,8 @@ pub mod array_functions { /// ``` pub fn chop(array: &mut Array, len: INT) { if !array.is_empty() { + let len = len.min(MAX_USIZE_INT); + if len <= 0 { array.clear(); } else if (len as usize) < array.len() { diff --git a/src/packages/blob_basic.rs b/src/packages/blob_basic.rs index bdf96fd5..a3bbd532 100644 --- a/src/packages/blob_basic.rs +++ b/src/packages/blob_basic.rs @@ -4,7 +4,7 @@ use crate::eval::{calc_index, calc_offset_len}; use crate::plugin::*; use crate::{ def_package, Array, Blob, Dynamic, ExclusiveRange, InclusiveRange, NativeCallContext, Position, - RhaiResultOf, INT, INT_BYTES, + RhaiResultOf, INT, INT_BYTES, MAX_USIZE_INT, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -74,6 +74,7 @@ pub mod blob_functions { len: INT, value: INT, ) -> RhaiResultOf { + let len = len.min(MAX_USIZE_INT); let len = if len < 0 { 0 } else { len as usize }; let _ctx = ctx; @@ -342,20 +343,21 @@ pub mod blob_functions { if len <= 0 { return Ok(()); } + let len = len.min(MAX_USIZE_INT) as usize; let value = (value & 0x0000_00ff) as u8; let _ctx = ctx; // Check if blob will be over max size limit #[cfg(not(feature = "unchecked"))] - if _ctx.engine().max_array_size() > 0 && (len as usize) > _ctx.engine().max_array_size() { + if _ctx.engine().max_array_size() > 0 && len > _ctx.engine().max_array_size() { return Err( crate::ERR::ErrorDataTooLarge("Size of BLOB".to_string(), Position::NONE).into(), ); } - if len as usize > blob.len() { - blob.resize(len as usize, value); + if len > blob.len() { + blob.resize(len, value); } Ok(()) @@ -461,7 +463,9 @@ pub mod blob_functions { /// ``` pub fn truncate(blob: &mut Blob, len: INT) { if !blob.is_empty() { - if len >= 0 { + let len = len.min(MAX_USIZE_INT); + + if len > 0 { blob.truncate(len as usize); } else { blob.clear(); diff --git a/src/packages/iter_basic.rs b/src/packages/iter_basic.rs index 245f2cb3..6ec293cc 100644 --- a/src/packages/iter_basic.rs +++ b/src/packages/iter_basic.rs @@ -1,6 +1,8 @@ use crate::eval::calc_index; use crate::plugin::*; -use crate::{def_package, ExclusiveRange, InclusiveRange, RhaiResultOf, INT, INT_BITS}; +use crate::{ + def_package, ExclusiveRange, InclusiveRange, RhaiResultOf, INT, INT_BITS, MAX_USIZE_INT, +}; #[cfg(feature = "no_std")] use std::prelude::v1::*; use std::{ @@ -173,18 +175,13 @@ pub struct CharsStream(Vec, usize); impl CharsStream { pub fn new(string: &str, from: INT, len: INT) -> Self { - if len <= 0 { + if len <= 0 || from > MAX_USIZE_INT { return Self(Vec::new(), 0); } + let len = len.min(MAX_USIZE_INT) as usize; + if from >= 0 { - return Self( - string - .chars() - .skip(from as usize) - .take(len as usize) - .collect(), - 0, - ); + return Self(string.chars().skip(from as usize).take(len).collect(), 0); } let abs_from = from.unsigned_abs() as usize; @@ -194,7 +191,7 @@ impl CharsStream { } else { num_chars - abs_from }; - Self(string.chars().skip(offset).take(len as usize).collect(), 0) + Self(string.chars().skip(offset).take(len).collect(), 0) } } diff --git a/src/packages/lang_core.rs b/src/packages/lang_core.rs index 5c073146..25cfaee0 100644 --- a/src/packages/lang_core.rs +++ b/src/packages/lang_core.rs @@ -1,7 +1,7 @@ use crate::def_package; use crate::plugin::*; use crate::types::dynamic::Tag; -use crate::{Dynamic, RhaiResultOf, ERR, INT}; +use crate::{Dynamic, RhaiResultOf, ERR, INT, MAX_USIZE_INT}; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -113,7 +113,7 @@ mod reflection_functions { } #[rhai_fn(name = "get_fn_metadata_list")] pub fn get_fn_metadata2(ctx: NativeCallContext, name: &str, params: INT) -> crate::Array { - if params < 0 { + if params < 0 || params > MAX_USIZE_INT { crate::Array::new() } else { collect_fn_metadata(ctx, |_, _, n, p, _| p == (params as usize) && n == name) diff --git a/src/packages/string_more.rs b/src/packages/string_more.rs index 8e018c22..da53a127 100644 --- a/src/packages/string_more.rs +++ b/src/packages/string_more.rs @@ -1,5 +1,8 @@ use crate::plugin::*; -use crate::{def_package, Dynamic, ExclusiveRange, InclusiveRange, RhaiResultOf, StaticVec, INT}; +use crate::{ + def_package, Dynamic, ExclusiveRange, InclusiveRange, RhaiResultOf, StaticVec, INT, + MAX_USIZE_INT, +}; #[cfg(feature = "no_std")] use std::prelude::v1::*; use std::{any::TypeId, mem}; @@ -263,10 +266,11 @@ mod string_functions { /// ``` pub fn truncate(string: &mut ImmutableString, len: INT) { if len > 0 { + let len = len.min(MAX_USIZE_INT) as usize; let chars: StaticVec<_> = string.chars().collect(); let copy = string.make_mut(); copy.clear(); - copy.extend(chars.into_iter().take(len as usize)); + copy.extend(chars.into_iter().take(len)); } else { clear(string); } @@ -344,8 +348,9 @@ mod string_functions { if string.is_empty() || len <= 0 { return ctx.engine().get_interned_string(""); } + let len = len.min(MAX_USIZE_INT) as usize; - let mut chars = StaticVec::::with_capacity(len as usize); + let mut chars = StaticVec::::with_capacity(len); for _ in 0..len { match string.make_mut().pop() { @@ -556,7 +561,13 @@ mod string_functions { } let start = if start < 0 { - let abs_start = start.unsigned_abs() as usize; + let abs_start = start.unsigned_abs(); + + if abs_start as u64 > MAX_USIZE_INT as u64 { + return -1 as INT; + } + + let abs_start = abs_start as usize; let chars: Vec<_> = string.chars().collect(); let num_chars = chars.len(); if abs_start > num_chars { @@ -570,7 +581,7 @@ mod string_functions { } } else if start == 0 { 0 - } else if start as usize >= string.chars().count() { + } else if start > MAX_USIZE_INT || start as usize >= string.chars().count() { return -1 as INT; } else { string @@ -632,7 +643,13 @@ mod string_functions { } let start = if start < 0 { - let abs_start = start.unsigned_abs() as usize; + let abs_start = start.unsigned_abs(); + + if abs_start as u64 > MAX_USIZE_INT as u64 { + return -1 as INT; + } + + let abs_start = abs_start as usize; let chars = string.chars().collect::>(); let num_chars = chars.len(); if abs_start > num_chars { @@ -646,7 +663,7 @@ mod string_functions { } } else if start == 0 { 0 - } else if start as usize >= string.chars().count() { + } else if start > MAX_USIZE_INT || start as usize >= string.chars().count() { return -1 as INT; } else { string @@ -704,16 +721,26 @@ mod string_functions { /// ``` pub fn get(string: &str, index: INT) -> Dynamic { if index >= 0 { + if index > MAX_USIZE_INT { + return Dynamic::UNIT; + } + string .chars() .nth(index as usize) .map_or_else(|| Dynamic::UNIT, Into::into) } else { // Count from end if negative + let abs_index = index.unsigned_abs(); + + if abs_index as u64 > MAX_USIZE_INT as u64 { + return Dynamic::UNIT; + } + string .chars() .rev() - .nth((index.unsigned_abs() as usize) - 1) + .nth((abs_index as usize) - 1) .map_or_else(|| Dynamic::UNIT, Into::into) } } @@ -742,14 +769,25 @@ mod string_functions { /// ``` pub fn set(string: &mut ImmutableString, index: INT, character: char) { if index >= 0 { + if index > MAX_USIZE_INT { + return; + } + let index = index as usize; + *string = string .chars() .enumerate() .map(|(i, ch)| if i == index { character } else { ch }) .collect(); } else { - let abs_index = index.unsigned_abs() as usize; + let abs_index = index.unsigned_abs(); + + if abs_index as u64 > MAX_USIZE_INT as u64 { + return; + } + + let abs_index = abs_index as usize; let string_len = string.chars().count(); if abs_index <= string_len { @@ -833,14 +871,20 @@ mod string_functions { let offset = if string.is_empty() || len <= 0 { return ctx.engine().get_interned_string(""); } else if start < 0 { - let abs_start = start.unsigned_abs() as usize; + let abs_start = start.unsigned_abs(); + + if abs_start as u64 > MAX_USIZE_INT as u64 { + return ctx.engine().get_interned_string(""); + } + + let abs_start = abs_start as usize; chars.extend(string.chars()); if abs_start > chars.len() { 0 } else { chars.len() - abs_start } - } else if start as usize >= string.chars().count() { + } else if start > MAX_USIZE_INT || start as usize >= string.chars().count() { return ctx.engine().get_interned_string(""); } else { start as usize @@ -962,14 +1006,20 @@ mod string_functions { string.make_mut().clear(); return; } else if start < 0 { - let abs_start = start.unsigned_abs() as usize; + let abs_start = start.unsigned_abs(); + + if abs_start as u64 > MAX_USIZE_INT as u64 { + return; + } + + let abs_start = abs_start as usize; chars.extend(string.chars()); if abs_start > chars.len() { 0 } else { chars.len() - abs_start } - } else if start as usize >= string.chars().count() { + } else if start > MAX_USIZE_INT || start as usize >= string.chars().count() { string.make_mut().clear(); return; } else { @@ -1131,11 +1181,12 @@ mod string_functions { if len <= 0 { return Ok(()); } + let len = len.min(MAX_USIZE_INT) as usize; let _ctx = ctx; // Check if string will be over max size limit #[cfg(not(feature = "unchecked"))] - if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() { + if _ctx.engine().max_string_size() > 0 && len > _ctx.engine().max_string_size() { return Err(crate::ERR::ErrorDataTooLarge( "Length of string".to_string(), crate::Position::NONE, @@ -1145,10 +1196,10 @@ mod string_functions { let orig_len = string.chars().count(); - if len as usize > orig_len { + if len > orig_len { let p = string.make_mut(); - for _ in 0..(len as usize - orig_len) { + for _ in 0..(len - orig_len) { p.push(character); } @@ -1192,11 +1243,12 @@ mod string_functions { if len <= 0 { return Ok(()); } + let len = len.min(MAX_USIZE_INT) as usize; let _ctx = ctx; // Check if string will be over max size limit #[cfg(not(feature = "unchecked"))] - if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() { + if _ctx.engine().max_string_size() > 0 && len > _ctx.engine().max_string_size() { return Err(crate::ERR::ErrorDataTooLarge( "Length of string".to_string(), crate::Position::NONE, @@ -1207,16 +1259,16 @@ mod string_functions { let mut str_len = string.chars().count(); let padding_len = padding.chars().count(); - if len as usize > str_len { + if len > str_len { let p = string.make_mut(); - while str_len < len as usize { - if str_len + padding_len <= len as usize { + while str_len < len { + if str_len + padding_len <= len { p.push_str(padding); str_len += padding_len; } else { - p.extend(padding.chars().take(len as usize - str_len)); - str_len = len as usize; + p.extend(padding.chars().take(len - str_len)); + str_len = len; } } @@ -1263,7 +1315,16 @@ mod string_functions { #[rhai_fn(name = "split")] pub fn split_at(ctx: NativeCallContext, string: &mut ImmutableString, index: INT) -> Array { if index <= 0 { - let abs_index = index.unsigned_abs() as usize; + let abs_index = index.unsigned_abs(); + + if abs_index as u64 > MAX_USIZE_INT as u64 { + return vec![ + ctx.engine().get_interned_string("").into(), + string.as_str().into(), + ]; + } + + let abs_index = abs_index as usize; let num_chars = string.chars().count(); if abs_index > num_chars { vec![ @@ -1275,6 +1336,11 @@ mod string_functions { let prefix_len = prefix.len(); vec![prefix.into(), string[prefix_len..].into()] } + } else if index > MAX_USIZE_INT { + vec![ + string.as_str().into(), + ctx.engine().get_interned_string("").into(), + ] } else { let prefix: String = string.chars().take(index as usize).collect(); let prefix_len = prefix.len(); @@ -1341,7 +1407,8 @@ mod string_functions { /// ``` #[rhai_fn(name = "split")] pub fn splitn(string: &str, delimiter: &str, segments: INT) -> Array { - let pieces: usize = if segments < 1 { 1 } else { segments as usize }; + let segments = segments.min(MAX_USIZE_INT) as usize; + let pieces: usize = if segments < 1 { 1 } else { segments }; string.splitn(pieces, delimiter).map(Into::into).collect() } /// Split the string into segments based on a `delimiter` character, returning an array of the segments. @@ -1371,7 +1438,8 @@ mod string_functions { /// ``` #[rhai_fn(name = "split")] pub fn splitn_char(string: &str, delimiter: char, segments: INT) -> Array { - let pieces: usize = if segments < 1 { 1 } else { segments as usize }; + let segments = segments.min(MAX_USIZE_INT) as usize; + let pieces: usize = if segments < 1 { 1 } else { segments }; string.splitn(pieces, delimiter).map(Into::into).collect() } /// Split the string into segments based on a `delimiter` string, returning an array of the @@ -1402,7 +1470,8 @@ mod string_functions { /// ``` #[rhai_fn(name = "split_rev")] pub fn rsplitn(string: &str, delimiter: &str, segments: INT) -> Array { - let pieces: usize = if segments < 1 { 1 } else { segments as usize }; + let segments = segments.min(MAX_USIZE_INT) as usize; + let pieces: usize = if segments < 1 { 1 } else { segments }; string.rsplitn(pieces, delimiter).map(Into::into).collect() } /// Split the string into segments based on a `delimiter` character, returning an array of @@ -1433,7 +1502,8 @@ mod string_functions { /// ``` #[rhai_fn(name = "split_rev")] pub fn rsplitn_char(string: &str, delimiter: char, segments: INT) -> Array { - let pieces: usize = if segments < 1 { 1 } else { segments as usize }; + let segments = segments.min(MAX_USIZE_INT) as usize; + let pieces: usize = if segments < 1 { 1 } else { segments }; string.rsplitn(pieces, delimiter).map(Into::into).collect() } } diff --git a/src/parser.rs b/src/parser.rs index 8498b90d..216cd3ea 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -34,6 +34,10 @@ pub type ParseResult = Result; type FnLib = BTreeMap>; +const KEYWORD_SEMICOLON: &str = Token::SemiColon.literal_syntax(); + +const KEYWORD_CLOSE_BRACE: &str = Token::RightBrace.literal_syntax(); + /// Invalid variable name that acts as a search barrier in a [`Scope`]. const SCOPE_SEARCH_BARRIER_MARKER: &str = "$ BARRIER $"; @@ -41,8 +45,9 @@ const SCOPE_SEARCH_BARRIER_MARKER: &str = "$ BARRIER $"; const NEVER_ENDS: &str = "`Token`"; /// Unroll `switch` ranges no larger than this. -const SMALL_SWITCH_RANGE: usize = 16; +const SMALL_SWITCH_RANGE: INT = 16; +/// Number of string interners used: two additional for property getters/setters if not `no_object` const NUM_INTERNERS: usize = if cfg!(feature = "no_object") { 1 } else { 3 }; /// _(internals)_ A type that encapsulates the current state of the parser. @@ -899,13 +904,13 @@ impl Engine { let mut settings = settings; settings.pos = eat_token(input, Token::LeftBracket); - let mut arr = StaticVec::new_const(); + let mut array = StaticVec::new_const(); loop { const MISSING_RBRACKET: &str = "to end this array literal"; #[cfg(not(feature = "unchecked"))] - if self.max_array_size() > 0 && arr.len() >= self.max_array_size() { + if self.max_array_size() > 0 && array.len() >= self.max_array_size() { return Err(PERR::LiteralTooLarge( "Size of array literal".to_string(), self.max_array_size(), @@ -927,7 +932,7 @@ impl Engine { } _ => { let expr = self.parse_expr(input, state, lib, settings.level_up())?; - arr.push(expr); + array.push(expr); } } @@ -954,9 +959,9 @@ impl Engine { }; } - arr.shrink_to_fit(); + array.shrink_to_fit(); - Ok(Expr::Array(arr.into(), settings.pos)) + Ok(Expr::Array(array.into(), settings.pos)) } /// Parse a map literal. @@ -2010,7 +2015,7 @@ impl Engine { } } - let op_info = if let Some(op) = op { + let op_info = if let Some(ref op) = op { OpAssignment::new_op_assignment_from_token(op, op_pos) } else { OpAssignment::new_assignment(op_pos) @@ -2605,9 +2610,6 @@ impl Engine { inputs.shrink_to_fit(); tokens.shrink_to_fit(); - const KEYWORD_SEMICOLON: &str = Token::SemiColon.literal_syntax(); - const KEYWORD_CLOSE_BRACE: &str = Token::RightBrace.literal_syntax(); - let self_terminated = matches!( required_token.as_str(), // It is self-terminating if the last symbol is a block @@ -2912,7 +2914,7 @@ impl Engine { Ok(true) => (), Ok(false) => return Err(PERR::ForbiddenVariable(name.to_string()).into_err(pos)), Err(err) => match *err { - EvalAltResult::ErrorParsing(perr, pos) => return Err(perr.into_err(pos)), + EvalAltResult::ErrorParsing(e, pos) => return Err(e.into_err(pos)), _ => return Err(PERR::ForbiddenVariable(name.to_string()).into_err(pos)), }, } diff --git a/src/reify.rs b/src/reify.rs index bdbe2db8..c5e98bb3 100644 --- a/src/reify.rs +++ b/src/reify.rs @@ -11,6 +11,7 @@ #[macro_export] macro_rules! reify { ($old:ident, |$new:ident : $t:ty| $code:expr, || $fallback:expr) => {{ + #[allow(clippy::redundant_else)] if std::any::TypeId::of::<$t>() == std::any::Any::type_id(&$old) { // SAFETY: This is safe because we already checked to make sure the two types // are actually the same. diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 27333f42..1eb5bd93 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -2315,13 +2315,13 @@ impl InputStream for MultiInputsStream<'_> { if self.index >= self.streams.len() { // No more streams return None; - } else if let Some(ch) = self.streams[self.index].next() { + } + if let Some(ch) = self.streams[self.index].next() { // Next character in current stream return Some(ch); - } else { - // Jump to the next stream - self.index += 1; } + // Jump to the next stream + self.index += 1; } } fn peek_next(&mut self) -> Option { @@ -2333,13 +2333,13 @@ impl InputStream for MultiInputsStream<'_> { if self.index >= self.streams.len() { // No more streams return None; - } else if let Some(&ch) = self.streams[self.index].peek() { + } + if let Some(&ch) = self.streams[self.index].peek() { // Next character in current stream return Some(ch); - } else { - // Jump to the next stream - self.index += 1; } + // Jump to the next stream + self.index += 1; } } } diff --git a/src/types/dynamic.rs b/src/types/dynamic.rs index a318581b..29a88336 100644 --- a/src/types/dynamic.rs +++ b/src/types/dynamic.rs @@ -936,7 +936,7 @@ impl Dynamic { #[must_use] pub const fn from_float(value: crate::FLOAT) -> Self { Self(Union::Float( - crate::ast::FloatWrapper::new_const(value), + crate::ast::FloatWrapper::new(value), DEFAULT_TAG_VALUE, ReadWrite, ))