git.delta.rocks / jrsonnet / refs/commits / 8a683442a5d7

difftreelog

fix bounds type error syntax

Yaroslav Bolyukin2021-07-12parent: #e23fa86.patch.diff
in: master

1 file changed

modifiedcrates/jrsonnet-evaluator/src/typed.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/typed.rs
1use std::{fmt::Display, rc::Rc};23use crate::{4	error::{Error, LocError, Result},5	push, Val,6};7use jrsonnet_gc::Trace;8use jrsonnet_parser::ExprLocation;9use jrsonnet_types::{ComplexValType, ValType};10use thiserror::Error;1112#[macro_export]13macro_rules! unwrap_type {14	($desc: expr, $value: expr, $typ: expr => $match: path) => {{15		use $crate::{push_stack_frame, typed::CheckType};16		push_stack_frame(None, $desc, || Ok($typ.check(&$value)?))?;17		match $value {18			$match(v) => v,19			_ => unreachable!(),20		}21	}};22}2324#[derive(Debug, Error, Clone, Trace)]25#[trivially_drop]26pub enum TypeError {27	#[error("expected {0}, got {1}")]28	ExpectedGot(ComplexValType, ValType),29	#[error("missing property {0} from {1:?}")]30	MissingProperty(Rc<str>, ComplexValType),31	#[error("every failed from {0}:\n{1}")]32	UnionFailed(ComplexValType, TypeLocErrorList),33	#[error("number out of bounds: {0} not in {1:?}..{2:?}")]34	BoundsFailed(f64, Option<f64>, Option<f64>),35}36impl From<TypeError> for LocError {37	fn from(e: TypeError) -> Self {38		Error::TypeError(e.into()).into()39	}40}4142#[derive(Debug, Clone, Trace)]43#[trivially_drop]44pub struct TypeLocError(Box<TypeError>, ValuePathStack);45impl From<TypeError> for TypeLocError {46	fn from(e: TypeError) -> Self {47		Self(Box::new(e), ValuePathStack(Vec::new()))48	}49}50impl From<TypeLocError> for LocError {51	fn from(e: TypeLocError) -> Self {52		Error::TypeError(e).into()53	}54}55impl Display for TypeLocError {56	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {57		write!(f, "{}", self.0)?;58		if !(self.1).0.is_empty() {59			write!(f, "at {}", self.1)?;60		}61		Ok(())62	}63}6465#[derive(Debug, Clone, Trace)]66#[trivially_drop]67pub struct TypeLocErrorList(Vec<TypeLocError>);68impl Display for TypeLocErrorList {69	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {70		use std::fmt::Write;71		let mut out = String::new();72		for (i, err) in self.0.iter().enumerate() {73			if i != 0 {74				writeln!(f)?;75			}76			out.clear();77			write!(out, "{}", err)?;7879			for (i, line) in out.lines().enumerate() {80				if line.trim().is_empty() {81					continue;82				}83				if i != 0 {84					writeln!(f)?;85					write!(f, "    ")?;86				} else {87					write!(f, "  - ")?;88				}89				write!(f, "{}", line)?;90			}91		}92		Ok(())93	}94}9596fn push_type(97	location: Option<&ExprLocation>,98	error_reason: impl Fn() -> String,99	path: impl Fn() -> ValuePathItem,100	item: impl Fn() -> Result<()>,101) -> Result<()> {102	push(location, error_reason, || match item() {103		Ok(_) => Ok(()),104		Err(mut e) => {105			if let Error::TypeError(e) = &mut e.error_mut() {106				(e.1).0.push(path())107			}108			Err(e)109		}110	})111}112113// TODO: check_fast for fast path of union type checking114pub trait CheckType {115	fn check(&self, value: &Val) -> Result<()>;116}117118impl CheckType for ValType {119	fn check(&self, value: &Val) -> Result<()> {120		let got = value.value_type();121		if got != *self {122			let loc_error: TypeLocError = TypeError::ExpectedGot((*self).into(), got).into();123			return Err(loc_error.into());124		}125		Ok(())126	}127}128129#[derive(Clone, Debug, Trace)]130#[trivially_drop]131enum ValuePathItem {132	Field(Rc<str>),133	Index(u64),134}135impl Display for ValuePathItem {136	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {137		match self {138			Self::Field(name) => write!(f, ".{}", name)?,139			Self::Index(idx) => write!(f, "[{}]", idx)?,140		}141		Ok(())142	}143}144145#[derive(Clone, Debug, Trace)]146#[trivially_drop]147struct ValuePathStack(Vec<ValuePathItem>);148impl Display for ValuePathStack {149	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {150		write!(f, "self")?;151		for elem in self.0.iter().rev() {152			write!(f, "{}", elem)?;153		}154		Ok(())155	}156}157158impl CheckType for ComplexValType {159	fn check(&self, value: &Val) -> Result<()> {160		match self {161			Self::Any => Ok(()),162			Self::Simple(s) => s.check(value),163			Self::Char => match value {164				Val::Str(s) if s.len() == 1 || s.chars().count() == 1 => Ok(()),165				v => Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()),166			},167			Self::BoundedNumber(from, to) => {168				if let Val::Num(n) = value {169					if from.map(|from| from > *n).unwrap_or(false)170						|| to.map(|to| to <= *n).unwrap_or(false)171					{172						return Err(TypeError::BoundsFailed(*n, *from, *to).into());173					}174					Ok(())175				} else {176					Err(TypeError::ExpectedGot(self.clone(), value.value_type()).into())177				}178			}179			Self::Array(elem_type) => match value {180				Val::Arr(a) => {181					for (i, item) in a.iter().enumerate() {182						push_type(183							None,184							|| format!("array index {}", i),185							|| ValuePathItem::Index(i as u64),186							|| elem_type.check(&item.clone()?),187						)?;188					}189					Ok(())190				}191				v => Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()),192			},193			Self::ArrayRef(elem_type) => match value {194				Val::Arr(a) => {195					for (i, item) in a.iter().enumerate() {196						push_type(197							None,198							|| format!("array index {}", i),199							|| ValuePathItem::Index(i as u64),200							|| elem_type.check(&item.clone()?),201						)?;202					}203					Ok(())204				}205				v => Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()),206			},207			Self::ObjectRef(elems) => match value {208				Val::Obj(obj) => {209					for (k, v) in elems.iter() {210						if let Some(got_v) = obj.get((*k).into())? {211							push_type(212								None,213								|| format!("property {}", k),214								|| ValuePathItem::Field((*k).into()),215								|| v.check(&got_v),216							)?217						} else {218							return Err(219								TypeError::MissingProperty((*k).into(), self.clone()).into()220							);221						}222					}223					Ok(())224				}225				v => Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()),226			},227			Self::Union(types) => {228				let mut errors = Vec::new();229				for ty in types.iter() {230					match ty.check(value) {231						Ok(()) => {232							return Ok(());233						}234						Err(e) => match e.error() {235							Error::TypeError(e) => errors.push(e.clone()),236							_ => return Err(e),237						},238					}239				}240				Err(TypeError::UnionFailed(self.clone(), TypeLocErrorList(errors)).into())241			}242			Self::UnionRef(types) => {243				let mut errors = Vec::new();244				for ty in types.iter() {245					match ty.check(value) {246						Ok(()) => {247							return Ok(());248						}249						Err(e) => match e.error() {250							Error::TypeError(e) => errors.push(e.clone()),251							_ => return Err(e),252						},253					}254				}255				Err(TypeError::UnionFailed(self.clone(), TypeLocErrorList(errors)).into())256			}257			Self::Sum(types) => {258				for ty in types.iter() {259					ty.check(value)?260				}261				Ok(())262			}263			Self::SumRef(types) => {264				for ty in types.iter() {265					ty.check(value)?266				}267				Ok(())268			}269		}270	}271}