forked from EmmyLuaLs/emmylua-analyzer-rust
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpcall_test.rs
More file actions
178 lines (143 loc) · 4.22 KB
/
pcall_test.rs
File metadata and controls
178 lines (143 loc) · 4.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#[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"));
}
}