use std::fmt::Debug;
use std::hash::Hash;
use allocative::Allocative;
use dupe::Dupe;
use crate::codemap::Span;
use crate::typing::call_args::TyCallArgs;
use crate::typing::callable::TyCallable;
use crate::typing::custom::TyCustomImpl;
use crate::typing::error::TypingNoContextError;
use crate::typing::error::TypingNoContextOrInternalError;
use crate::typing::error::TypingOrInternalError;
use crate::typing::ParamSpec;
use crate::typing::Ty;
use crate::typing::TyBasic;
use crate::typing::TypingBinOp;
use crate::typing::TypingOracleCtx;
use crate::values::typing::type_compiled::alloc::TypeMatcherAlloc;
pub trait TyCustomFunctionImpl:
Debug + Eq + Ord + Hash + Allocative + Send + Sync + 'static
{
fn is_type(&self) -> bool {
false
}
fn validate_call(
&self,
span: Span,
args: &TyCallArgs,
oracle: TypingOracleCtx,
) -> Result<Ty, TypingOrInternalError>;
fn as_callable(&self) -> TyCallable;
fn as_function(&self) -> Option<&TyFunction> {
None
}
}
#[derive(
Allocative,
Eq,
PartialEq,
Hash,
Ord,
PartialOrd,
Debug,
derive_more::Display
)]
#[display(
"def({}) -> {}",
self.0.as_callable().params(),
self.0.as_callable().result(),
)]
pub struct TyCustomFunction<F: TyCustomFunctionImpl>(pub F);
impl<F: TyCustomFunctionImpl> TyCustomImpl for TyCustomFunction<F> {
fn as_name(&self) -> Option<&str> {
Some("function")
}
fn validate_call(
&self,
span: Span,
args: &TyCallArgs,
oracle: TypingOracleCtx,
) -> Result<Ty, TypingOrInternalError> {
self.0.validate_call(span, args, oracle)
}
fn as_callable(&self) -> Option<TyCallable> {
Some(self.0.as_callable())
}
fn as_function(&self) -> Option<&TyFunction> {
self.0.as_function()
}
fn bin_op(
&self,
bin_op: TypingBinOp,
_rhs: &TyBasic,
_ctx: &TypingOracleCtx,
) -> Result<Ty, TypingNoContextOrInternalError> {
match bin_op {
TypingBinOp::BitOr if self.0.is_type() => Ok(Ty::basic(TyBasic::Type)),
_ => Err(TypingNoContextOrInternalError::Typing),
}
}
fn index(
&self,
_item: &TyBasic,
_ctx: &TypingOracleCtx,
) -> Result<Ty, TypingNoContextOrInternalError> {
Ok(Ty::any())
}
fn attribute(&self, _attr: &str) -> Result<Ty, TypingNoContextError> {
Err(TypingNoContextError)
}
fn matcher<T: TypeMatcherAlloc>(&self, factory: T) -> T::Result {
factory.callable()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Allocative)]
pub struct TyFunction {
pub(crate) type_attr: Option<Ty>,
pub(crate) callable: TyCallable,
}
impl TyFunction {
pub fn new_with_type_attr(params: ParamSpec, result: Ty, type_attr: Ty) -> Self {
TyFunction {
type_attr: Some(type_attr),
callable: TyCallable::new(params, result),
}
}
pub fn new(params: ParamSpec, result: Ty) -> Self {
TyFunction {
type_attr: None,
callable: TyCallable::new(params, result),
}
}
pub fn callable(&self) -> &TyCallable {
&self.callable
}
}
impl TyCustomFunctionImpl for TyFunction {
fn is_type(&self) -> bool {
self.type_attr.is_some()
}
fn validate_call(
&self,
span: Span,
args: &TyCallArgs,
oracle: TypingOracleCtx,
) -> Result<Ty, TypingOrInternalError> {
oracle.validate_fn_call(span, &self.callable, args)
}
fn as_callable(&self) -> TyCallable {
self.callable.dupe()
}
fn as_function(&self) -> Option<&TyFunction> {
Some(self)
}
}