method-ray 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -0
  3. data/{rust → core}/Cargo.toml +1 -1
  4. data/core/src/analyzer/assignments.rs +499 -0
  5. data/{rust → core}/src/analyzer/attributes.rs +2 -1
  6. data/{rust → core}/src/analyzer/blocks.rs +140 -0
  7. data/{rust → core}/src/analyzer/calls.rs +7 -3
  8. data/{rust → core}/src/analyzer/definitions.rs +12 -7
  9. data/{rust → core}/src/analyzer/dispatch.rs +431 -13
  10. data/core/src/analyzer/exceptions.rs +622 -0
  11. data/{rust → core}/src/analyzer/install.rs +37 -1
  12. data/{rust → core}/src/analyzer/literals.rs +3 -17
  13. data/core/src/analyzer/loops.rs +301 -0
  14. data/{rust → core}/src/analyzer/mod.rs +4 -0
  15. data/{rust → core}/src/analyzer/operators.rs +119 -27
  16. data/{rust → core}/src/analyzer/parameters.rs +214 -5
  17. data/core/src/analyzer/super_calls.rs +285 -0
  18. data/{rust → core}/src/cache/rbs_cache.rs +0 -1
  19. data/{rust → core}/src/cli/commands.rs +3 -3
  20. data/{rust → core}/src/diagnostics/diagnostic.rs +0 -3
  21. data/{rust → core}/src/diagnostics/formatter.rs +0 -1
  22. data/{rust → core}/src/env/box_manager.rs +2 -4
  23. data/{rust → core}/src/env/global_env.rs +28 -7
  24. data/{rust → core}/src/env/local_env.rs +35 -1
  25. data/{rust → core}/src/env/method_registry.rs +117 -25
  26. data/{rust → core}/src/env/scope.rs +91 -4
  27. data/{rust → core}/src/env/vertex_manager.rs +0 -1
  28. data/{rust → core}/src/graph/box.rs +134 -8
  29. data/{rust → core}/src/graph/change_set.rs +14 -0
  30. data/{rust → core}/src/lsp/server.rs +1 -1
  31. data/{rust → core}/src/rbs/loader.rs +1 -2
  32. data/{rust → core}/src/source_map.rs +0 -1
  33. data/{rust → core}/src/types.rs +11 -1
  34. data/ext/Cargo.toml +2 -2
  35. data/lib/methodray/binary_locator.rb +2 -2
  36. data/lib/methodray/commands.rb +1 -1
  37. data/lib/methodray/version.rb +1 -1
  38. metadata +54 -50
  39. /data/{rust → core}/src/analyzer/conditionals.rs +0 -0
  40. /data/{rust → core}/src/analyzer/parentheses.rs +0 -0
  41. /data/{rust → core}/src/analyzer/returns.rs +0 -0
  42. /data/{rust → core}/src/analyzer/variables.rs +0 -0
  43. /data/{rust → core}/src/cache/mod.rs +0 -0
  44. /data/{rust → core}/src/checker.rs +0 -0
  45. /data/{rust → core}/src/cli/args.rs +0 -0
  46. /data/{rust → core}/src/cli/mod.rs +0 -0
  47. /data/{rust → core}/src/diagnostics/mod.rs +0 -0
  48. /data/{rust → core}/src/env/mod.rs +0 -0
  49. /data/{rust → core}/src/env/type_error.rs +0 -0
  50. /data/{rust → core}/src/graph/mod.rs +0 -0
  51. /data/{rust → core}/src/graph/vertex.rs +0 -0
  52. /data/{rust → core}/src/lib.rs +0 -0
  53. /data/{rust → core}/src/lsp/diagnostics.rs +0 -0
  54. /data/{rust → core}/src/lsp/main.rs +0 -0
  55. /data/{rust → core}/src/lsp/mod.rs +0 -0
  56. /data/{rust → core}/src/main.rs +0 -0
  57. /data/{rust → core}/src/parser.rs +0 -0
  58. /data/{rust → core}/src/rbs/converter.rs +0 -0
  59. /data/{rust → core}/src/rbs/error.rs +0 -0
  60. /data/{rust → core}/src/rbs/mod.rs +0 -0
@@ -128,6 +128,55 @@ fn install_block_parameter(genv: &mut GlobalEnv, lenv: &mut LocalEnv, name: Stri
128
128
  #[cfg(test)]
129
129
  mod tests {
130
130
  use super::*;
131
+ use crate::analyzer::install::AstInstaller;
132
+ use crate::env::LocalEnv;
133
+ use crate::parser::ParseSession;
134
+ use crate::types::Type;
135
+
136
+ fn get_type_show(genv: &GlobalEnv, vtx: VertexId) -> String {
137
+ if let Some(vertex) = genv.get_vertex(vtx) {
138
+ vertex.show()
139
+ } else if let Some(source) = genv.get_source(vtx) {
140
+ source.ty.show()
141
+ } else {
142
+ panic!("vertex {:?} not found as either Vertex or Source", vtx);
143
+ }
144
+ }
145
+
146
+ fn analyze_with_stdlib(source: &str) -> GlobalEnv {
147
+ let session = ParseSession::new();
148
+ let parse_result = session.parse_source(source, "test.rb").unwrap();
149
+ let root = parse_result.node();
150
+ let program = root.as_program_node().unwrap();
151
+
152
+ let mut genv = GlobalEnv::new();
153
+
154
+ // Register stdlib methods needed for block tests
155
+ genv.register_builtin_method_with_block(
156
+ Type::array(),
157
+ "each",
158
+ Type::array(),
159
+ Some(vec![Type::instance("Elem")]),
160
+ );
161
+ genv.register_builtin_method_with_block(
162
+ Type::string(),
163
+ "each_char",
164
+ Type::string(),
165
+ Some(vec![Type::string()]),
166
+ );
167
+ genv.register_builtin_method(Type::integer(), "even?", Type::instance("TrueClass"));
168
+ genv.register_builtin_method(Type::string(), "upcase", Type::string());
169
+
170
+ let mut lenv = LocalEnv::new();
171
+
172
+ let mut installer = AstInstaller::new(&mut genv, &mut lenv, source);
173
+ for stmt in &program.statements().body() {
174
+ installer.install_node(&stmt);
175
+ }
176
+ installer.finish();
177
+
178
+ genv
179
+ }
131
180
 
132
181
  #[test]
133
182
  fn test_enter_exit_block_scope() {
@@ -173,4 +222,95 @@ mod tests {
173
222
 
174
223
  exit_block_scope(&mut genv);
175
224
  }
225
+
226
+ #[test]
227
+ fn test_block_parameter_type_from_array() {
228
+ let source = r#"
229
+ class Foo
230
+ def bar
231
+ [1, 2, 3].each { |x| x.even? }
232
+ end
233
+ end
234
+ "#;
235
+ let genv = analyze_with_stdlib(source);
236
+ assert!(
237
+ genv.type_errors.is_empty(),
238
+ "x.even? should not produce type errors: {:?}",
239
+ genv.type_errors
240
+ );
241
+ // Verify bar returns Array (each returns its receiver)
242
+ let info = genv.resolve_method(&Type::instance("Foo"), "bar").unwrap();
243
+ let ret_vtx = info.return_vertex.unwrap();
244
+ assert_eq!(get_type_show(&genv, ret_vtx), "Array");
245
+ }
246
+
247
+ #[test]
248
+ fn test_block_external_variable_access() {
249
+ let source = r#"
250
+ class Foo
251
+ def bar
252
+ y = "hello"
253
+ [1].each { y.upcase }
254
+ end
255
+ end
256
+ "#;
257
+ let genv = analyze_with_stdlib(source);
258
+ assert!(
259
+ genv.type_errors.is_empty(),
260
+ "y.upcase should not produce type errors: {:?}",
261
+ genv.type_errors
262
+ );
263
+ }
264
+
265
+ #[test]
266
+ fn test_block_parameter_from_each_char() {
267
+ let source = r#"
268
+ class Foo
269
+ def bar
270
+ "hello".each_char { |c| c.upcase }
271
+ end
272
+ end
273
+ "#;
274
+ let genv = analyze_with_stdlib(source);
275
+ assert!(
276
+ genv.type_errors.is_empty(),
277
+ "c.upcase should not produce type errors: {:?}",
278
+ genv.type_errors
279
+ );
280
+ }
281
+
282
+ #[test]
283
+ fn test_block_body_does_not_affect_method_return() {
284
+ let source = r#"
285
+ class Foo
286
+ def bar
287
+ [1, 2].each { |x| "string" }
288
+ end
289
+ end
290
+ "#;
291
+ let genv = analyze_with_stdlib(source);
292
+ // each returns its receiver (Array), not the block body result (String)
293
+ let info = genv.resolve_method(&Type::instance("Foo"), "bar").unwrap();
294
+ let ret_vtx = info.return_vertex.unwrap();
295
+ assert_eq!(get_type_show(&genv, ret_vtx), "Array");
296
+ }
297
+
298
+ #[test]
299
+ fn test_nested_blocks() {
300
+ let source = r#"
301
+ class Foo
302
+ def bar
303
+ [1, 2].each { |x|
304
+ "hello".each_char { |c| c.upcase }
305
+ }
306
+ end
307
+ end
308
+ "#;
309
+ let genv = analyze_with_stdlib(source);
310
+ assert!(
311
+ genv.type_errors.is_empty(),
312
+ "nested block should not produce type errors: {:?}",
313
+ genv.type_errors
314
+ );
315
+ }
176
316
  }
@@ -5,6 +5,8 @@
5
5
  //! - Managing return value vertices
6
6
  //! - Attaching source location for error reporting
7
7
 
8
+ use std::collections::HashMap;
9
+
8
10
  use crate::env::GlobalEnv;
9
11
  use crate::graph::{MethodCallBox, VertexId};
10
12
  use crate::source_map::SourceLocation;
@@ -15,6 +17,7 @@ pub fn install_method_call(
15
17
  recv_vtx: VertexId,
16
18
  method_name: String,
17
19
  arg_vtxs: Vec<VertexId>,
20
+ kwarg_vtxs: Option<HashMap<String, VertexId>>,
18
21
  location: Option<SourceLocation>,
19
22
  ) -> VertexId {
20
23
  // Create Vertex for return value
@@ -22,7 +25,8 @@ pub fn install_method_call(
22
25
 
23
26
  // Create MethodCallBox with location and argument vertices
24
27
  let box_id = genv.alloc_box_id();
25
- let call_box = MethodCallBox::new(box_id, recv_vtx, method_name, ret_vtx, arg_vtxs, location);
28
+ let call_box =
29
+ MethodCallBox::new(box_id, recv_vtx, method_name, ret_vtx, arg_vtxs, kwarg_vtxs, location);
26
30
  genv.register_box(box_id, Box::new(call_box));
27
31
 
28
32
  ret_vtx
@@ -39,7 +43,7 @@ mod tests {
39
43
 
40
44
  let recv_vtx = genv.new_source(Type::string());
41
45
  let ret_vtx =
42
- install_method_call(&mut genv, recv_vtx, "upcase".to_string(), vec![], None);
46
+ install_method_call(&mut genv, recv_vtx, "upcase".to_string(), vec![], None, None);
43
47
 
44
48
  // Return vertex should exist
45
49
  assert!(genv.get_vertex(ret_vtx).is_some());
@@ -51,7 +55,7 @@ mod tests {
51
55
 
52
56
  let recv_vtx = genv.new_source(Type::string());
53
57
  let _ret_vtx =
54
- install_method_call(&mut genv, recv_vtx, "upcase".to_string(), vec![], None);
58
+ install_method_call(&mut genv, recv_vtx, "upcase".to_string(), vec![], None, None);
55
59
 
56
60
  // Box should be added
57
61
  assert_eq!(genv.box_count(), 1);
@@ -6,6 +6,8 @@
6
6
  //! - Method definition scope management (def baz ... end)
7
7
  //! - Extracting class/module names from AST nodes (including qualified names like Api::User)
8
8
 
9
+ use std::collections::HashMap;
10
+
9
11
  use crate::env::{GlobalEnv, LocalEnv};
10
12
  use crate::graph::{ChangeSet, VertexId};
11
13
  use crate::types::Type;
@@ -24,7 +26,8 @@ pub(crate) fn process_class_node(
24
26
  class_node: &ruby_prism::ClassNode,
25
27
  ) -> Option<VertexId> {
26
28
  let class_name = extract_class_name(class_node);
27
- install_class(genv, class_name);
29
+ let superclass = class_node.superclass().and_then(|sup| extract_constant_path(&sup));
30
+ install_class(genv, class_name, superclass.as_deref());
28
31
 
29
32
  if let Some(body) = class_node.body() {
30
33
  if let Some(statements) = body.as_statements_node() {
@@ -78,10 +81,10 @@ pub(crate) fn process_def_node(
78
81
  let merge_vtx = genv.scope_manager.current_method_return_vertex();
79
82
 
80
83
  // Process parameters BEFORE processing body
81
- let param_vtxs = if let Some(params_node) = def_node.parameters() {
84
+ let (param_vtxs, keyword_param_vtxs) = if let Some(params_node) = def_node.parameters() {
82
85
  install_parameters(genv, lenv, changes, source, &params_node)
83
86
  } else {
84
- vec![]
87
+ (vec![], HashMap::new())
85
88
  };
86
89
 
87
90
  let mut last_vtx = None;
@@ -108,11 +111,13 @@ pub(crate) fn process_def_node(
108
111
  } else {
109
112
  Type::instance(&name)
110
113
  };
114
+ let kw_params = (!keyword_param_vtxs.is_empty()).then_some(keyword_param_vtxs);
111
115
  genv.register_user_method(
112
116
  recv_type,
113
117
  &method_name,
114
118
  ret_vtx,
115
119
  param_vtxs,
120
+ kw_params,
116
121
  );
117
122
  }
118
123
  }
@@ -122,8 +127,8 @@ pub(crate) fn process_def_node(
122
127
  }
123
128
 
124
129
  /// Install class definition
125
- fn install_class(genv: &mut GlobalEnv, class_name: String) {
126
- genv.enter_class(class_name);
130
+ fn install_class(genv: &mut GlobalEnv, class_name: String, superclass: Option<&str>) {
131
+ genv.enter_class(class_name, superclass);
127
132
  }
128
133
 
129
134
  /// Install module definition
@@ -199,7 +204,7 @@ mod tests {
199
204
  fn test_enter_exit_class_scope() {
200
205
  let mut genv = GlobalEnv::new();
201
206
 
202
- install_class(&mut genv, "User".to_string());
207
+ install_class(&mut genv, "User".to_string(), None);
203
208
  assert_eq!(
204
209
  genv.scope_manager.current_class_name(),
205
210
  Some("User".to_string())
@@ -227,7 +232,7 @@ mod tests {
227
232
  fn test_nested_method_scope() {
228
233
  let mut genv = GlobalEnv::new();
229
234
 
230
- install_class(&mut genv, "User".to_string());
235
+ install_class(&mut genv, "User".to_string(), None);
231
236
  install_method(&mut genv, "greet".to_string());
232
237
 
233
238
  // Still in User class context