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.rsdiffbeforeafterboth298 context_creator: context_creator.clone(),298 context_creator: context_creator.clone(),299 value: value.clone(),299 value: value.clone(),300 name,300 name,301 })));301 })))?;302 }302 }303 Member::Field(FieldMember {303 Member::Field(FieldMember {304 name,304 name,341 value: value.clone(),341 value: value.clone(),342 params: params.clone(),342 params: params.clone(),343 name,343 name,344 })));344 })))?;345 }345 }346 Member::BindStmt(_) => {}346 Member::BindStmt(_) => {}347 Member::AssertStmt(stmt) => {347 Member::AssertStmt(stmt) => {424 .bindable(TraceBox(Box::new(ObjCompBinding {424 .bindable(TraceBox(Box::new(ObjCompBinding {425 context: ctx,425 context: ctx,426 value: obj.value.clone(),426 value: obj.value.clone(),427 })));427 })))?;428 }428 }429 v => throw!(FieldMustBeStringGot(v.value_type())),429 v => throw!(FieldMustBeStringGot(v.value_type())),430 }430 }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.rsdiffbeforeafterboth--- a/crates/jrsonnet-macros/src/lib.rs
+++ b/crates/jrsonnet-macros/src/lib.rs
@@ -459,12 +459,12 @@
if self.is_option() {
quote! {
if let Some(value) = self.#ident {
- out.member(#name.into()).value(value.try_into()?);
+ out.member(#name.into()).value(value.try_into()?)?;
}
}
} else {
quote! {
- out.member(#name.into()).value(self.#ident.try_into()?);
+ out.member(#name.into()).value(self.#ident.try_into()?)?;
}
}
} else if self.is_option() {