From 172bc149969570fdee80e37465052fcc215fc0ef Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 26 Jun 2023 08:48:22 +0800 Subject: [PATCH 1/3] Bump version. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 821c0a15..18521034 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = [".", "codegen"] [package] name = "rhai" -version = "1.15.1" +version = "1.16.0" rust-version = "1.61.0" edition = "2018" resolver = "2" From 541844e1e11bdfa90402f1709ebc50de2186355e Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 27 Jun 2023 16:53:21 +0800 Subject: [PATCH 2/3] Remove unnecessary gates. --- src/types/dynamic.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/types/dynamic.rs b/src/types/dynamic.rs index 515f3694..18828774 100644 --- a/src/types/dynamic.rs +++ b/src/types/dynamic.rs @@ -246,10 +246,7 @@ impl Dynamic { #[inline(always)] #[must_use] pub const fn is_shared(&self) -> bool { - #[cfg(not(feature = "no_closure"))] - return matches!(self.0, Union::Shared(..)); - #[cfg(feature = "no_closure")] - return false; + matches!(self.0, Union::Shared(..)) } /// Is the value held by this [`Dynamic`] a particular type? /// From 2474c1fec1422084af1bd65f4c19015deeef72b0 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 27 Jun 2023 17:14:18 +0800 Subject: [PATCH 3/3] Fix bug. --- CHANGELOG.md | 9 +++++++++ src/func/call.rs | 28 ++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33ff513e..382ad3f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,15 @@ Rhai Release Notes ================== +Version 1.16.0 +============== + +Bug fixes +--------- + +* Fixes a panic when using `this` as the first parameter in a namespace-qualified function call. + + Version 1.15.1 ============== diff --git a/src/func/call.rs b/src/func/call.rs index 9e7e153d..72ff9fb6 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -1289,15 +1289,17 @@ impl Engine { // Call with blank scope #[cfg(not(feature = "no_closure"))] - let this_ptr_not_shared = this_ptr.as_ref().map_or(false, |v| !v.is_shared()); + let has_non_shared_this_ptr = this_ptr.as_ref().map_or(false, |v| !v.is_shared()); #[cfg(feature = "no_closure")] - let this_ptr_not_shared = true; + let has_non_shared_this_ptr = this_ptr.is_some(); // If the first argument is a variable, and there are no curried arguments, // convert to method-call style in order to leverage potential &mut first argument // and avoid cloning the value. match first_arg { - Some(_first_expr @ Expr::ThisPtr(pos)) if curry.is_empty() && this_ptr_not_shared => { + Some(_first_expr @ Expr::ThisPtr(pos)) + if curry.is_empty() && has_non_shared_this_ptr => + { // Turn it into a method call only if the object is not shared self.track_operation(global, *pos)?; @@ -1381,21 +1383,30 @@ impl Engine { let mut first_arg_value = None; #[cfg(not(feature = "no_closure"))] - let this_ptr_not_shared = this_ptr.as_ref().map_or(false, |v| !v.is_shared()); + let has_non_shared_this_ptr = this_ptr.as_ref().map_or(false, |v| !v.is_shared()); #[cfg(feature = "no_closure")] - let this_ptr_not_shared = true; + let has_non_shared_this_ptr = this_ptr.is_some(); // See if the first argument is a variable. // If so, convert to method-call style in order to leverage potential // &mut first argument and avoid cloning the value. match args_expr.get(0) { - Some(_first_expr @ Expr::ThisPtr(pos)) if this_ptr_not_shared => { + Some(_first_expr @ Expr::ThisPtr(pos)) if has_non_shared_this_ptr => { self.track_operation(global, *pos)?; #[cfg(feature = "debugging")] self.run_debugger(global, caches, scope, this_ptr.as_deref_mut(), _first_expr)?; - // Turn it into a method call only if the object is not shared + // The first value is a placeholder (for later if it needs to be cloned) + arg_values.push(Dynamic::UNIT); + + for expr in args_expr.iter().skip(1) { + let (value, ..) = + self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)?; + arg_values.push(value.flatten()); + } + + // func(x, ...) -> x.func(...) let (first, rest) = arg_values.split_first_mut().unwrap(); first_arg_value = Some(first); args.push(this_ptr.unwrap()); @@ -1407,7 +1418,7 @@ impl Engine { #[cfg(feature = "debugging")] self.run_debugger(global, caches, scope, this_ptr.as_deref_mut(), first_expr)?; - // func(x, ...) -> x.func(...) + // The first value is a placeholder (for later if it needs to be cloned) arg_values.push(Dynamic::UNIT); for expr in args_expr.iter().skip(1) { @@ -1423,6 +1434,7 @@ impl Engine { args.extend(arg_values.iter_mut()); } else { // Turn it into a method call only if the object is not shared and not a simple value + // func(x, ...) -> x.func(...) let (first, rest) = arg_values.split_first_mut().unwrap(); first_arg_value = Some(first); let obj_ref = target.take_ref().expect("ref");