difftreelog
fix bounds type error syntax
in: master
1 file changed
crates/jrsonnet-evaluator/src/typed.rsdiffbeforeafterboth1use 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}