Typecheck KCL args via generics, not handwritten impls (#3025)

In KCL, arguments to functions are passed in the Args struct. This struct contains a list of args, but each arg could be any KCL type (they're stored in an enum of all possible types). To get args of the correct type, these enums are fallibly converted into the type expected for the matching parameter.

Until now, the fallible conversion was handwritten for nearly each function. This is unnecessary, I've replaced it with composable traits.
This commit is contained in:
Adam Chalmers
2024-07-19 20:30:13 -05:00
committed by GitHub
parent 6e7e6e96cf
commit e6a2ac9c4a
3 changed files with 315 additions and 737 deletions

View File

@ -620,7 +620,7 @@ impl MemoryItem {
.map(Some) .map(Some)
} }
fn as_user_val(&self) -> Option<&UserVal> { pub fn as_user_val(&self) -> Option<&UserVal> {
if let MemoryItem::UserVal(x) = self { if let MemoryItem::UserVal(x) = self {
Some(x) Some(x)
} else { } else {
@ -642,25 +642,17 @@ impl MemoryItem {
} }
/// If this value is of type function, return it. /// If this value is of type function, return it.
pub fn get_function(&self, source_ranges: Vec<SourceRange>) -> Result<FnAsArg<'_>, KclError> { pub fn get_function(&self) -> Option<FnAsArg<'_>> {
let MemoryItem::Function { let MemoryItem::Function {
func, func,
expression, expression,
meta: _, meta: _,
} = &self } = &self
else { else {
return Err(KclError::Semantic(KclErrorDetails { return None;
message: "not an in-memory function".to_string(),
source_ranges,
}));
}; };
let func = func.as_ref().ok_or_else(|| { let func = func.as_ref()?;
KclError::Semantic(KclErrorDetails { Some(FnAsArg {
message: format!("Not an in-memory function: {:?}", expression),
source_ranges,
})
})?;
Ok(FnAsArg {
func, func,
expr: expression.to_owned(), expr: expression.to_owned(),
}) })

File diff suppressed because it is too large Load Diff

View File

@ -1308,7 +1308,7 @@ async fn serial_test_stdlib_kcl_error_right_code_path() {
assert!(result.is_err()); assert!(result.is_err());
assert_eq!( assert_eq!(
result.err().unwrap().to_string(), result.err().unwrap().to_string(),
r#"type: KclErrorDetails { source_ranges: [SourceRange([157, 175])], message: "Expected a SketchGroup or SketchSurface as the third argument, found `[UserVal(UserVal { value: Array [Number(2), Number(2)], meta: [Metadata { source_range: SourceRange([164, 170]) }] }), UserVal(UserVal { value: Number(0.5), meta: [Metadata { source_range: SourceRange([172, 174]) }] })]`" }"# r#"semantic: KclErrorDetails { source_ranges: [SourceRange([157, 175])], message: "Expected an argument at index 2" }"#,
); );
} }
@ -1406,7 +1406,7 @@ const part = rectShape([0, 0], 20, 20)
assert!(result.is_err()); assert!(result.is_err());
assert_eq!( assert_eq!(
result.err().unwrap().to_string(), result.err().unwrap().to_string(),
r#"type: KclErrorDetails { source_ranges: [SourceRange([891, 940])], message: "Expected a [number, number] as the first argument, found `[UserVal(UserVal { value: String(\"XY\"), meta: [Metadata { source_range: SourceRange([898, 902]) }] }), UserVal(UserVal { value: Array [Number(-6.0), Number(6)], meta: [Metadata { source_range: SourceRange([904, 927]) }] }), UserVal(UserVal { value: Number(1), meta: [Metadata { source_range: SourceRange([760, 761]) }] })]`" }"# r#"semantic: KclErrorDetails { source_ranges: [SourceRange([891, 940])], message: "Argument at index 0 was supposed to be type [f64; 2] but wasn't" }"#,
); );
} }