emmylua_code_analysis 0.22.0

A library for analyzing lua code.
Documentation
#[cfg(test)]
mod test {
    use crate::{DiagnosticCode, VirtualWorkspace};

    const STACKED_PCALL_ALIAS_GUARDS: usize = 180;

    #[test]
    fn test_issue_263() {
        let mut ws = VirtualWorkspace::new_with_init_std_lib();

        ws.def(
            r#"
        ---@alias aaa fun(a: string, b: integer): integer

        ---@type aaa
        local a

        d, b = pcall(a, "", 1)
        "#,
        );

        let aaa_ty = ws.expr_ty("b");
        let expected = ws.ty("integer|string");
        assert_eq!(aaa_ty, expected);
    }

    #[test]
    fn test_issue_280() {
        let mut ws = VirtualWorkspace::new_with_init_std_lib();

        assert!(ws.check_code_for(
            DiagnosticCode::ParamTypeMismatch,
            r#"
        ---@class D11.AAA
        local AAA = {}

        ---@param a string
        ---@param b number
        function AAA:name(a, b)
        end

        ---@param a string
        ---@param b number
        function AAA:t(a, b)
            local ok, err = pcall(self.name, self, a, b)
        end
        "#
        ));
    }

    #[test]
    fn test_nested_pcall_higher_order_return_shape() {
        let mut ws = VirtualWorkspace::new_with_init_std_lib();

        ws.def(
            r#"
        ---@return integer
        local function f()
            return 1
        end

        ok, status, payload = pcall(pcall, f)
        "#,
        );

        assert_eq!(ws.expr_ty("status"), ws.ty("true|false|string"));
        assert_eq!(ws.expr_ty("payload"), ws.ty("string|integer|nil"));
    }

    #[test]
    fn test_pcall_return_overload_narrow_after_error_guard() {
        let mut ws = VirtualWorkspace::new_with_init_std_lib();

        ws.def(
            r#"
            ---@return integer
            local function foo()
                return 2
            end

            local ok, result = pcall(foo)

            if not ok then
                error(result)
            end

            a = result
            "#,
        );

        assert_eq!(ws.expr_ty("a"), ws.ty("integer"));
    }

    #[test]
    fn test_nested_pcall_like_without_return_overload() {
        let mut ws = VirtualWorkspace::new();

        ws.def(
            r#"
        ---@generic T, R
        ---@param f fun(...: T...): R...
        ---@param ... T...
        ---@return boolean, R...
        local function safe_call(f, ...)
            return true, f(...)
        end

        ---@return integer
        local function produce()
            return 1
        end

        ok, status, payload = safe_call(safe_call, produce)
        "#,
        );

        assert_eq!(ws.expr_ty("status"), ws.ty("boolean"));
        assert_eq!(ws.expr_ty("payload"), ws.ty("integer"));
    }

    #[test]
    fn test_nested_pcall_like_without_return_overload2() {
        let mut ws = VirtualWorkspace::new();

        ws.def(
            r#"
        ---@generic T, R, R1
        ---@param f sync fun(...: T...): R1, R...
        ---@param ... T...
        ---@return boolean, R1|string, R...
        local function pcall_like(f, ...) end

        ---@return integer
        local function produce()
            return 1
        end

        ok, status, payload = pcall_like(pcall_like, produce)
        "#,
        );

        assert_eq!(ws.expr_ty("ok"), ws.ty("boolean"));
        assert_eq!(ws.expr_ty("status"), ws.ty("boolean|string"));
        assert_eq!(ws.expr_ty("payload"), ws.ty("integer|string"));
    }

    #[test]
    fn test_pcall_stacked_alias_guards_build_semantic_model() {
        let mut ws = VirtualWorkspace::new_with_init_std_lib();
        let repeated_guards =
            "if failed then error(result) end\n".repeat(STACKED_PCALL_ALIAS_GUARDS);
        let block = format!(
            r#"
        ---@return integer
        local function foo()
            return 1
        end

        local ok, result = pcall(foo)
        local failed = ok == false

        {repeated_guards}
        narrowed = result
        "#,
        );

        let file_id = ws.def(&block);

        assert!(
            ws.analysis
                .compilation
                .get_semantic_model(file_id)
                .is_some(),
            "expected semantic model for stacked pcall alias guard repro"
        );
        assert_eq!(ws.expr_ty("narrowed"), ws.ty("integer"));
    }

    #[test]
    fn test_pcall_any_callable_splits_success_unknown_and_failure_string() {
        let mut ws = VirtualWorkspace::new_with_init_std_lib();

        ws.def(
            r#"
        ---@type any
        local x

        local ok, result = pcall(x)
        outside = result
        if ok then
            success = result
        else
            failure = result
        end
        "#,
        );

        assert_eq!(ws.expr_ty("outside"), ws.ty("unknown|string"));
        assert_eq!(ws.expr_ty("success"), ws.ty("unknown"));
        assert_eq!(ws.expr_ty("failure"), ws.ty("string"));
    }
}