Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(remap): slice function collects subtypes #7092

Merged
merged 1 commit into from
Apr 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions lib/vrl/compiler/src/type_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,36 @@ impl TypeKind {
Object(_) => Kind::Object,
}
}

/// Collects the kinds into a single kind.
/// Array and objects may have different kinds for each key/index, this collects those
/// into a single kind.
pub fn collect_kinds(self) -> TypeKind {
match self {
TypeKind::Array(kinds) => {
let mut newkinds = BTreeMap::new();
newkinds.insert(
Index::Any,
kinds
.into_iter()
.fold(KindInfo::Unknown, |acc, (_, k)| acc.merge(k, false, true)),
);
TypeKind::Array(newkinds)
}

TypeKind::Object(kinds) => {
let mut newkinds = BTreeMap::new();
newkinds.insert(
Field::Any,
kinds
.into_iter()
.fold(KindInfo::Unknown, |acc, (_, k)| acc.merge(k, false, true)),
);
TypeKind::Object(newkinds)
}
_ => self,
}
}
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord)]
Expand Down Expand Up @@ -784,6 +814,20 @@ impl TypeDef {
self
}

/// Collects any subtypes that can contain multiple indexed types (array, object) and collects them into
/// a single type for all indexes.
/// Used for functions that cant determine which indexes of a collection have been used in the result.
pub fn collect_subtypes(mut self) -> Self {
self.kind = match self.kind {
KindInfo::Known(set) => {
KindInfo::Known(set.into_iter().map(|k| k.collect_kinds()).collect())
}
v => v,
};

self
}

#[inline]
pub fn is_unknown(&self) -> bool {
matches!(self.kind, KindInfo::Unknown)
Expand Down Expand Up @@ -934,6 +978,35 @@ mod tests {
use path::{self, Segment};
use std::str::FromStr;

#[test]
fn collect_subtypes() {
let kind = TypeKind::Array({
let mut set1 = BTreeSet::new();
set1.insert(TypeKind::Integer);
let mut set2 = BTreeSet::new();
set2.insert(TypeKind::Bytes);

let mut map = BTreeMap::new();
map.insert(Index::Index(1), KindInfo::Known(set1));
map.insert(Index::Index(2), KindInfo::Known(set2));
map
});

let kind = kind.collect_kinds();

let expected = TypeKind::Array({
let mut set = BTreeSet::new();
set.insert(TypeKind::Integer);
set.insert(TypeKind::Bytes);

let mut map = BTreeMap::new();
map.insert(Index::Any, KindInfo::Known(set));
map
});

assert_eq!(kind, expected);
}

mod kind_info {
use super::*;

Expand Down
30 changes: 15 additions & 15 deletions lib/vrl/stdlib/src/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ impl Expression for SliceFn {
let td = TypeDef::new().fallible();

match self.value.type_def(state) {
v if v.is_bytes() || v.is_array() => td.merge(v),
v if v.is_bytes() => td.merge(v),
v if v.is_array() => td.merge(v).collect_subtypes(),
_ => td.bytes().add_array_mapped::<(), Kind>(map! {
(): Kind::all(),
}),
Expand Down Expand Up @@ -218,34 +219,33 @@ mod tests {
start: 0
],
want: Ok(vec![0, 1, 2]),
tdef: TypeDef::new().fallible().array_mapped::<i32, Kind>(map! { 0: Kind::Integer,
1: Kind::Integer,
2: Kind::Integer
}),
tdef: TypeDef::new().fallible().array_mapped::<(), Kind>(map! { (): Kind::Integer }),
}

array_1 {
args: func_args![value: vec![0, 1, 2],
start: 1
],
want: Ok(vec![1, 2]),
// TODO: This is wrong! See https://github.com/timberio/vector/issues/6676
tdef: TypeDef::new().fallible().array_mapped::<i32, Kind>(map! { 0: Kind::Integer,
1: Kind::Integer,
2: Kind::Integer
}),
tdef: TypeDef::new().fallible().array_mapped::<(), Kind>(map! { (): Kind::Integer }),
}

array_minus_2 {
args: func_args![value: vec![0, 1, 2],
start: -2
],
want: Ok(vec![1, 2]),
// TODO: This is wrong! See https://github.com/timberio/vector/issues/6676
tdef: TypeDef::new().fallible().array_mapped::<i32, Kind>(map! { 0: Kind::Integer,
1: Kind::Integer,
2: Kind::Integer
}),
tdef: TypeDef::new().fallible().array_mapped::<(), Kind>(map! { (): Kind::Integer }),
}

array_mixed_types {
args: func_args![value: value!([0, "ook", true]),
start: 1
],
want: Ok(value!(["ook", true])),
tdef: TypeDef::new().fallible().array_mapped::<(), Kind>(
map! { (): Kind::Integer | Kind::Bytes | Kind::Boolean }
),
}

error_after_end {
Expand Down