difftreelog
fix disallow field duplicates
in: master
5 files changed
crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/error.rs
+++ b/crates/jrsonnet-evaluator/src/error.rs
@@ -63,6 +63,8 @@
#[error("field name should be string, got {0}")]
FieldMustBeStringGot(ValType),
+ #[error("duplicate field name: {0}")]
+ DuplicateFieldName(IStr),
#[error("attempted to index array with string {0}")]
AttemptedIndexAnArrayWithString(IStr),
crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs
@@ -298,7 +298,7 @@
context_creator: context_creator.clone(),
value: value.clone(),
name,
- })));
+ })))?;
}
Member::Field(FieldMember {
name,
@@ -341,7 +341,7 @@
value: value.clone(),
params: params.clone(),
name,
- })));
+ })))?;
}
Member::BindStmt(_) => {}
Member::AssertStmt(stmt) => {
@@ -424,7 +424,7 @@
.bindable(TraceBox(Box::new(ObjCompBinding {
context: ctx,
value: obj.value.clone(),
- })));
+ })))?;
}
v => throw!(FieldMustBeStringGot(v.value_type())),
}
crates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/integrations/serde.rs
+++ b/crates/jrsonnet-evaluator/src/integrations/serde.rs
@@ -68,7 +68,7 @@
Value::Object(o) => {
let mut builder = ObjValueBuilder::with_capacity(o.len());
for (k, v) in o {
- builder.member((k as &str).into()).value(v.try_into()?);
+ builder.member((k as &str).into()).value(v.try_into()?)?;
}
Self::Obj(builder.build())
}
crates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/obj.rs
+++ b/crates/jrsonnet-evaluator/src/obj.rs
@@ -1,6 +1,11 @@
+use crate::function::CallLocation;
use crate::gc::{GcHashMap, GcHashSet, TraceBox};
use crate::operator::evaluate_add_op;
-use crate::{cc_ptr_eq, weak_ptr_eq, weak_raw, Bindable, LazyBinding, LazyVal, Result, Val};
+use crate::push_frame;
+use crate::{
+ cc_ptr_eq, error::Error::*, throw, weak_ptr_eq, weak_raw, Bindable, LazyBinding, LazyVal,
+ Result, Val,
+};
use gcmodule::{Cc, Trace, Weak};
use jrsonnet_interner::IStr;
use jrsonnet_parser::{ExprLocation, Visibility};
@@ -373,22 +378,29 @@
self.location = Some(location);
self
}
- pub fn value(self, value: Val) -> &'v mut ObjValueBuilder {
+ pub fn value(self, value: Val) -> Result<()> {
self.binding(LazyBinding::Bound(LazyVal::new_resolved(value)))
}
- pub fn bindable(self, bindable: TraceBox<dyn Bindable>) -> &'v mut ObjValueBuilder {
+ pub fn bindable(self, bindable: TraceBox<dyn Bindable>) -> Result<()> {
self.binding(LazyBinding::Bindable(Cc::new(bindable)))
}
- pub fn binding(self, binding: LazyBinding) -> &'v mut ObjValueBuilder {
- self.value.map.insert(
- self.name,
+ pub fn binding(self, binding: LazyBinding) -> Result<()> {
+ let old = self.value.map.insert(
+ self.name.clone(),
ObjMember {
add: self.add,
visibility: self.visibility,
invoke: binding,
- location: self.location,
+ location: self.location.clone(),
},
);
- self.value
+ if old.is_some() {
+ push_frame(
+ CallLocation(self.location.as_ref()),
+ || format!("field <{}> initializtion", self.name.clone()),
+ || throw!(DuplicateFieldName(self.name.clone())),
+ )?
+ }
+ Ok(())
}
}
crates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth459 if self.is_option() {459 if self.is_option() {460 quote! {460 quote! {461 if let Some(value) = self.#ident {461 if let Some(value) = self.#ident {462 out.member(#name.into()).value(value.try_into()?);462 out.member(#name.into()).value(value.try_into()?)?;463 }463 }464 }464 }465 } else {465 } else {466 quote! {466 quote! {467 out.member(#name.into()).value(self.#ident.try_into()?);467 out.member(#name.into()).value(self.#ident.try_into()?)?;468 }468 }469 }469 }470 } else if self.is_option() {470 } else if self.is_option() {