luaur-analysis 0.1.3

Luau type checker and type inference (Rust).
Documentation
use crate::functions::flatten_type_pack::flatten_type_pack_id;
use crate::functions::parse_pattern_string::parse_pattern_string;
use crate::records::type_checker::TypeChecker;
use crate::records::type_pack::TypePack;
use crate::records::union_type::UnionType;
use crate::records::with_predicate::WithPredicate;
use crate::type_aliases::scope_ptr_type_infer::ScopePtr;
use crate::type_aliases::type_pack_id::TypePackId;
use alloc::sync::Arc;
use alloc::vec;
use luaur_ast::records::ast_expr_call::AstExprCall;
use luaur_ast::records::ast_expr_constant_string::AstExprConstantString;
use luaur_ast::records::ast_node::AstNode;
use luaur_ast::rtti::ast_node_as;

pub fn magic_match_handle_old_solver(
    typechecker: &mut TypeChecker,
    scope: &ScopePtr,
    expr: &AstExprCall,
    with_predicate: WithPredicate<TypePackId>,
) -> Option<WithPredicate<TypePackId>> {
    let param_pack = with_predicate.r#type;
    let (params, _tail) = flatten_type_pack_id(param_pack);

    if params.len() < 2 || params.len() > 3 {
        return None;
    }

    let module = typechecker.current_module.as_ref()?;
    let arena = unsafe {
        &mut (*(Arc::as_ptr(module) as *mut crate::records::module::Module)).internal_types
    };

    let pattern_index = if expr.self_ { 0 } else { 1 };
    let pattern = if expr.args.size > pattern_index {
        let arg = unsafe { *expr.args.data.add(pattern_index) };
        unsafe { ast_node_as::<AstExprConstantString>(arg as *mut AstNode) }
    } else {
        core::ptr::null_mut()
    };

    if pattern.is_null() {
        return None;
    }

    let return_types = unsafe {
        parse_pattern_string(
            core::ptr::NonNull::new_unchecked(typechecker.builtin_types),
            (*pattern).value.data,
            (*pattern).value.size,
        )
    };

    if return_types.is_empty() {
        return None;
    }

    let first_location = unsafe { &(*(*expr.args.data.add(0))).base.location };
    typechecker.unify_type_id_type_id_scope_ptr_location(
        params[0],
        typechecker.string_type,
        scope,
        first_location,
    );

    let optional_number = arena.add_type(UnionType {
        options: vec![typechecker.nil_type, typechecker.number_type],
    });

    let init_index = if expr.self_ { 1 } else { 2 };
    if params.len() == 3 && expr.args.size > init_index {
        let location = unsafe { &(*(*expr.args.data.add(init_index))).base.location };
        typechecker.unify_type_id_type_id_scope_ptr_location(
            params[2],
            optional_number,
            scope,
            location,
        );
    }

    let return_list = arena.add_type_pack_t(TypePack {
        head: return_types,
        tail: None,
    });
    Some(WithPredicate::with_predicate_t(return_list))
}