Skip to content

Commit 20ae181

Browse files
authored
Merge pull request #157 from projectsyn/fix/flattening-errors-context
Add missing context to errors that occur while flattening values
2 parents 87f5e7e + e60683c commit 20ae181

4 files changed

Lines changed: 56 additions & 34 deletions

File tree

src/refs/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ impl ResolveState {
104104
"While looking up key '{key}' in reference '{r}' for parameter '{current_key}': {msg}"
105105
)
106106
}
107+
108+
pub(crate) fn render_flattening_error(&self, msg: &str) -> anyhow::Error {
109+
let current_key = self.current_key();
110+
anyhow!("In {current_key}: {msg}")
111+
}
107112
}
108113

109114
/// Maximum allowed recursion depth for Token::resolve(). We're fairly conservative with the value,
@@ -348,7 +353,7 @@ fn interpolate_string_or_valuelist(
348353
i.push(v);
349354
}
350355
// Finally we flatten the resulting ValueList into a single Value.
351-
Value::ValueList(i).flattened()
356+
Value::ValueList(i).flattened(state)
352357
}
353358
// Do nothing for other types
354359
_ => Ok(v.clone()),

src/types/mapping.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -405,13 +405,13 @@ impl Mapping {
405405
///
406406
/// Used in `Value::flattened()` to preserve const and override key information when flattening
407407
/// Mapping values.
408-
pub(super) fn flattened(&self) -> Result<Self> {
408+
pub(super) fn flattened(&self, state: &mut ResolveState) -> Result<Self> {
409409
let mut res = Self::new();
410410
for (k, v) in self {
411411
// Propagate key properties to the resulting mapping by using `insert_impl()`.
412412
res.insert_impl(
413413
k.clone(),
414-
v.flattened()?,
414+
v.flattened(state)?,
415415
self.is_const(k),
416416
self.is_override(k),
417417
)?;
@@ -436,7 +436,7 @@ impl Mapping {
436436
let mut st = state.clone();
437437
st.push_mapping_key(k)?;
438438
let mut v = v.interpolate(root, &mut st)?;
439-
v.flatten()?;
439+
v.flatten(&mut st)?;
440440
// Propagate key properties to the resulting mapping by using `insert_impl()`.
441441
res.insert_impl(k.clone(), v, self.is_const(k), self.is_override(k))?;
442442
}

src/types/value.rs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ impl Value {
575575
// done with a layer, any references that we saw there have been successfully
576576
// resolved, and don't matter for the next layer we're interpolating).
577577
let mut st = state.clone();
578-
r.merge(v.interpolate(root, &mut st)?)?;
578+
r.merge(v.interpolate(root, &mut st)?, &mut st)?;
579579
}
580580
// Depending on the structure of the ValueList, we may end up with a final
581581
// interpolated Value which contains more ValueLists due to mapping merges. Such
@@ -601,7 +601,7 @@ impl Value {
601601
///
602602
/// Note that this method will call [`Value::flatten()`] after merging two Mappings to ensure
603603
/// that the resulting Value doesn't contain any `ValueList` elements.
604-
fn merge(&mut self, other: Self) -> Result<()> {
604+
fn merge(&mut self, other: Self, state: &mut ResolveState) -> Result<()> {
605605
if other.is_null() {
606606
// Any value can be replaced by null,
607607
let _prev = std::mem::replace(self, other);
@@ -610,7 +610,7 @@ impl Value {
610610

611611
// If `other` is a ValueList, flatten it before trying to merge
612612
let other = if other.is_value_list() {
613-
other.flattened()?
613+
other.flattened(state)?
614614
} else {
615615
other
616616
};
@@ -624,21 +624,31 @@ impl Value {
624624
Self::Mapping(m) => match other {
625625
// merge mapping and mapping
626626
Self::Mapping(other) => m.merge(&other)?,
627-
_ => return Err(anyhow!("Can't merge {} over mapping", other.variant())),
627+
_ => {
628+
return Err(state.render_flattening_error(&format!(
629+
"Can't merge {} over mapping",
630+
other.variant()
631+
)))
632+
}
628633
},
629634
Self::Sequence(s) => match other {
630635
// merge sequence and sequence
631636
Self::Sequence(mut other) => s.append(&mut other),
632-
_ => return Err(anyhow!("Can't merge {} over sequence", other.variant())),
637+
_ => {
638+
return Err(state.render_flattening_error(&format!(
639+
"Can't merge {} over sequence",
640+
other.variant()
641+
)))
642+
}
633643
},
634644
Self::Literal(_) | Self::Bool(_) | Self::Number(_) => {
635645
if other.is_mapping() || other.is_sequence() {
636646
// We can't merge simple non-null types over mappings or sequences
637-
return Err(anyhow!(
647+
return Err(state.render_flattening_error(&format!(
638648
"Can't merge {} over {}",
639649
other.variant(),
640650
self.variant()
641-
));
651+
)));
642652
}
643653
// overwrite self with the value that's being merged
644654
let _prev = std::mem::replace(self, other);
@@ -666,42 +676,42 @@ impl Value {
666676
///
667677
/// Note that we don't recommend calling `flattened()` on arbitrary Values. Users should always
668678
/// prefer calling [`Value::rendered()`] or one of the in-place variations of that method.
669-
pub(crate) fn flattened(&self) -> Result<Self> {
679+
pub(crate) fn flattened(&self, state: &mut ResolveState) -> Result<Self> {
670680
match self {
671681
// Flatten ValueList by iterating over its elements and merging each element into a
672682
// base Value.
673683
Self::ValueList(l) => {
674684
// NOTE(sg): Empty ValueLists get flattened to Value::Null
675685
let mut base = Value::Null;
676686
for v in l {
677-
base.merge(v.clone())?;
687+
base.merge(v.clone(), state)?;
678688
}
679689
Ok(base)
680690
}
681691
// Flatten Mapping by flattening each value and inserting it into a new Mapping.
682-
Self::Mapping(m) => Ok(Self::Mapping(m.flattened()?)),
692+
Self::Mapping(m) => Ok(Self::Mapping(m.flattened(state)?)),
683693
// Flatten Sequence by flattening each element and inserting it into a new Sequence
684694
Self::Sequence(s) => {
685695
let mut n = Vec::with_capacity(s.len());
686696
for v in s {
687-
n.push(v.flattened()?);
697+
n.push(v.flattened(state)?);
688698
}
689699
Ok(Self::Sequence(n))
690700
}
691701
// Simple values are flattened as themselves
692702
Self::Null | Self::Bool(_) | Self::Literal(_) | Self::Number(_) => Ok(self.clone()),
693703
// Flattening an unparsed string is an error
694-
Self::String(_) => Err(anyhow!(
695-
"Can't flatten unparsed String, did you mean to call `rendered()`?"
704+
Self::String(_) => Err(state.render_flattening_error(
705+
"Can't flatten unparsed String, did you mean to call `rendered()`?",
696706
)),
697707
}
698708
}
699709

700710
/// Flattens the Value in-place.
701711
///
702712
/// See [`Value::flattened()`] for details.
703-
pub(super) fn flatten(&mut self) -> Result<()> {
704-
let _prev = std::mem::replace(self, self.flattened()?);
713+
pub(super) fn flatten(&mut self, state: &mut ResolveState) -> Result<()> {
714+
let _prev = std::mem::replace(self, self.flattened(state)?);
705715
Ok(())
706716
}
707717

@@ -718,7 +728,7 @@ impl Value {
718728
let mut v = self
719729
.interpolate(root, &mut state)
720730
.map_err(|e| anyhow!("While resolving references: {e}"))?;
721-
v.flatten()?;
731+
v.flatten(&mut state)?;
722732
Ok(v)
723733
}
724734

src/types/value/value_flattened_tests.rs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ use std::str::FromStr;
44

55
#[test]
66
fn test_flattened_null() {
7-
assert_eq!(Value::Null.flattened().unwrap(), Value::Null);
7+
assert_eq!(
8+
Value::Null.flattened(&mut ResolveState::default()).unwrap(),
9+
Value::Null
10+
);
811
}
912

1013
macro_rules! test_flattened_simple {
@@ -14,7 +17,7 @@ macro_rules! test_flattened_simple {
1417
#[test]
1518
fn [<test_flattened_simple_ $variant:snake>]() {
1619
let v = Value::$variant($val);
17-
let f = v.flattened().unwrap();
20+
let f = v.flattened(&mut ResolveState::default()).unwrap();
1821
assert_eq!(f, $expected);
1922
}
2023
}
@@ -31,10 +34,14 @@ test_flattened_simple! {
3134
}
3235

3336
#[test]
34-
#[should_panic(expected = "Can't flatten unparsed String, did you mean to call `rendered()`?")]
37+
#[should_panic(
38+
expected = "In test: Can't flatten unparsed String, did you mean to call `rendered()`?"
39+
)]
3540
fn test_flattened_string() {
3641
let v = Value::String("foo".into());
37-
v.flattened().unwrap();
42+
let mut st = ResolveState::default();
43+
st.push_mapping_key(&"test".into()).unwrap();
44+
v.flattened(&mut st).unwrap();
3845
}
3946

4047
#[test]
@@ -61,7 +68,7 @@ fn test_flattened_simple_value_list() {
6168
Value::Literal("foo".into()),
6269
Value::Literal("bar".into()),
6370
]);
64-
let f = v.flattened().unwrap();
71+
let f = v.flattened(&mut ResolveState::default()).unwrap();
6572
assert!(f.is_literal());
6673
assert_eq!(f, Value::Literal("bar".into()));
6774
}
@@ -73,7 +80,7 @@ fn test_flattened_mixed_value_list() {
7380
Value::Null,
7481
Value::Literal("bar".into()),
7582
]);
76-
let f = v.flattened().unwrap();
83+
let f = v.flattened(&mut ResolveState::default()).unwrap();
7784
assert!(f.is_literal());
7885
assert_eq!(f, Value::Literal("bar".into()));
7986
}
@@ -85,7 +92,7 @@ fn test_flattened_sequence_value_list() {
8592
Value::Sequence(vec!["baz".into(), "qux".into()]),
8693
Value::Sequence(vec!["foo".into()]),
8794
]);
88-
let f = v.flattened().unwrap();
95+
let f = v.flattened(&mut ResolveState::default()).unwrap();
8996
assert_eq!(
9097
f,
9198
Value::Sequence(vec![
@@ -106,7 +113,7 @@ fn test_flattened_mapping_value_list() {
106113
.into(),
107114
Mapping::from_str("{baz: baz, qux: qux}").unwrap().into(),
108115
]);
109-
let f = v.flattened().unwrap();
116+
let f = v.flattened(&mut ResolveState::default()).unwrap();
110117
assert!(f.is_mapping());
111118

112119
let m: serde_yaml::Mapping = f.as_mapping().unwrap().clone().into();
@@ -123,7 +130,7 @@ fn test_flattened_null_over_mapping() {
123130
.into(),
124131
Value::Null,
125132
]);
126-
let f = v.flattened().unwrap();
133+
let f = v.flattened(&mut ResolveState::default()).unwrap();
127134
assert!(f.is_null());
128135
assert_eq!(f, Value::Null);
129136
}
@@ -134,7 +141,7 @@ fn test_flattened_null_over_sequence() {
134141
Value::Sequence(vec!["foo".into(), "bar".into()]),
135142
Value::Null,
136143
]);
137-
let f = v.flattened().unwrap();
144+
let f = v.flattened(&mut ResolveState::default()).unwrap();
138145
assert!(f.is_null());
139146
assert_eq!(f, Value::Null);
140147
}
@@ -145,7 +152,7 @@ fn test_flattened_map_over_sequence_error() {
145152
Value::Sequence(vec!["foo".into(), "bar".into()]),
146153
Value::Mapping(Mapping::from_str("foo: foo").unwrap()),
147154
]);
148-
let f = v.flattened();
155+
let f = v.flattened(&mut ResolveState::default());
149156
assert!(f.is_err());
150157
}
151158

@@ -155,7 +162,7 @@ fn test_flattened_map_over_simple_value_error() {
155162
Value::Bool(true),
156163
Value::Mapping(Mapping::from_str("foo: foo").unwrap()),
157164
]);
158-
let f = v.flattened();
165+
let f = v.flattened(&mut ResolveState::default());
159166
assert!(f.is_err());
160167
}
161168

@@ -165,7 +172,7 @@ fn test_flattened_sequence_over_map_error() {
165172
Value::Mapping(Mapping::from_str("foo: foo").unwrap()),
166173
Value::Sequence(vec!["foo".into(), "bar".into()]),
167174
]);
168-
let f = v.flattened();
175+
let f = v.flattened(&mut ResolveState::default());
169176
assert!(f.is_err());
170177
}
171178

@@ -175,7 +182,7 @@ fn test_flattened_sequence_over_simple_value_error() {
175182
Value::Bool(true),
176183
Value::Sequence(vec!["foo".into(), "bar".into()]),
177184
]);
178-
let f = v.flattened();
185+
let f = v.flattened(&mut ResolveState::default());
179186
assert!(f.is_err());
180187
}
181188

0 commit comments

Comments
 (0)