More types stuff (#5901)

* parse union and fancy array types

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* type aliases

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Treat Helix and Face as primitive types

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* code motion: factor our execution::types module

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Tests for type coercion and subtyping

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Add Point2D/3D to std

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Rebasing and fixes

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
Nick Cameron
2025-03-21 10:56:55 +13:00
committed by GitHub
parent 9da8574103
commit 1d550da40b
47 changed files with 1773 additions and 1050 deletions

View File

@ -8,9 +8,10 @@ use crate::{
execution::{
annotations,
cad_op::{OpArg, OpKclValue, Operation},
kcl_value::{FunctionSource, NumericType, RuntimeType},
kcl_value::FunctionSource,
memory,
state::ModuleState,
types::{NumericType, RuntimeType},
BodyType, EnvironmentRef, ExecState, ExecutorContext, KclValue, Metadata, PlaneType, TagEngineInfo,
TagIdentifier,
},
@ -29,6 +30,8 @@ use crate::{
CompilationError,
};
use super::kcl_value::TypeDef;
enum StatementKind<'a> {
Declaration { name: &'a str },
Expression,
@ -304,8 +307,9 @@ impl ExecutorContext {
}));
}
};
let (t, props) = crate::std::std_ty(std_path, &ty.name.name);
let value = KclValue::Type {
value: Some(crate::std::std_ty(std_path, &ty.name.name)),
value: TypeDef::RustRepr(t, props),
meta: vec![metadata],
};
exec_state
@ -324,12 +328,40 @@ impl ExecutorContext {
}
// Do nothing for primitive types, they get special treatment and their declarations are just for documentation.
annotations::Impl::Primitive => {}
annotations::Impl::Kcl => {
return Err(KclError::Semantic(KclErrorDetails {
message: "User-defined types are not yet supported.".to_owned(),
source_ranges: vec![metadata.source_range],
}));
}
annotations::Impl::Kcl => match &ty.alias {
Some(alias) => {
let value = KclValue::Type {
value: TypeDef::Alias(
RuntimeType::from_parsed(
alias.inner.clone(),
exec_state,
metadata.source_range,
)
.map_err(|e| KclError::Semantic(e.into()))?,
),
meta: vec![metadata],
};
exec_state
.mut_stack()
.add(
format!("{}{}", memory::TYPE_PREFIX, ty.name.name),
value,
metadata.source_range,
)
.map_err(|_| {
KclError::Semantic(KclErrorDetails {
message: format!("Redefinition of type {}.", ty.name.name),
source_ranges: vec![metadata.source_range],
})
})?;
}
None => {
return Err(KclError::Semantic(KclErrorDetails {
message: "User-defined types are not yet supported.".to_owned(),
source_ranges: vec![metadata.source_range],
}))
}
},
}
last_expr = None;
@ -646,30 +678,28 @@ impl ExecutorContext {
let result = self
.execute_expr(&expr.expr, exec_state, metadata, &[], statement_kind)
.await?;
coerce(&result, &expr.ty, exec_state).ok_or_else(|| {
KclError::Semantic(KclErrorDetails {
message: format!(
"could not coerce {} value to type {}",
result.human_friendly_type(),
expr.ty
),
source_ranges: vec![expr.into()],
})
})?
coerce(&result, &expr.ty, exec_state, expr.into())?
}
};
Ok(item)
}
}
fn coerce(value: &KclValue, ty: &Node<Type>, exec_state: &mut ExecState) -> Option<KclValue> {
fn coerce(
value: &KclValue,
ty: &Node<Type>,
exec_state: &mut ExecState,
source_range: SourceRange,
) -> Result<KclValue, KclError> {
let ty = RuntimeType::from_parsed(ty.inner.clone(), exec_state, value.into())
.map_err(|e| {
exec_state.err(e);
})
.ok()??;
.map_err(|e| KclError::Semantic(e.into()))?;
value.coerce(&ty, exec_state)
value.coerce(&ty, exec_state).ok_or_else(|| {
KclError::Semantic(KclErrorDetails {
message: format!("could not coerce {} value to type {}", value.human_friendly_type(), ty),
source_ranges: vec![source_range],
})
})
}
impl BinaryPart {