method-ray 0.1.6 → 0.1.8
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -0
- data/ext/Cargo.toml +1 -1
- data/lib/methodray/version.rb +1 -1
- data/rust/Cargo.toml +1 -1
- data/rust/src/analyzer/assignments.rs +152 -0
- data/rust/src/analyzer/attributes.rs +2 -1
- data/rust/src/analyzer/blocks.rs +4 -3
- data/rust/src/analyzer/calls.rs +7 -3
- data/rust/src/analyzer/definitions.rs +10 -5
- data/rust/src/analyzer/dispatch.rs +265 -24
- data/rust/src/analyzer/exceptions.rs +521 -0
- data/rust/src/analyzer/install.rs +22 -1
- data/rust/src/analyzer/loops.rs +176 -0
- data/rust/src/analyzer/mod.rs +32 -0
- data/rust/src/analyzer/operators.rs +119 -27
- data/rust/src/analyzer/parameters.rs +60 -9
- data/rust/src/cache/rbs_cache.rs +0 -1
- data/rust/src/cli/commands.rs +3 -3
- data/rust/src/diagnostics/diagnostic.rs +0 -3
- data/rust/src/diagnostics/formatter.rs +0 -1
- data/rust/src/env/box_manager.rs +2 -4
- data/rust/src/env/global_env.rs +43 -5
- data/rust/src/env/local_env.rs +35 -1
- data/rust/src/env/method_registry.rs +140 -17
- data/rust/src/env/scope.rs +143 -164
- data/rust/src/env/vertex_manager.rs +0 -1
- data/rust/src/graph/box.rs +217 -84
- data/rust/src/graph/change_set.rs +14 -0
- data/rust/src/lsp/server.rs +1 -1
- data/rust/src/rbs/loader.rs +1 -2
- data/rust/src/source_map.rs +0 -1
- data/rust/src/types.rs +0 -1
- metadata +4 -1
data/rust/src/graph/box.rs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
1
3
|
use crate::env::GlobalEnv;
|
|
2
4
|
use crate::graph::change_set::ChangeSet;
|
|
3
5
|
use crate::graph::vertex::VertexId;
|
|
@@ -9,21 +11,48 @@ use crate::types::Type;
|
|
|
9
11
|
pub struct BoxId(pub usize);
|
|
10
12
|
|
|
11
13
|
/// Box trait: represents constraints such as method calls
|
|
12
|
-
#[allow(dead_code)]
|
|
13
14
|
pub trait BoxTrait: Send + Sync {
|
|
14
15
|
fn id(&self) -> BoxId;
|
|
15
16
|
fn run(&mut self, genv: &mut GlobalEnv, changes: &mut ChangeSet);
|
|
16
17
|
fn ret(&self) -> VertexId;
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
/// Propagate argument types to parameter vertices by adding edges
|
|
21
|
+
/// from each argument vertex to the corresponding parameter vertex.
|
|
22
|
+
fn propagate_arguments(
|
|
23
|
+
arg_vtxs: &[VertexId],
|
|
24
|
+
param_vtxs: Option<&[VertexId]>,
|
|
25
|
+
changes: &mut ChangeSet,
|
|
26
|
+
) {
|
|
27
|
+
for (arg_vtx, param_vtx) in arg_vtxs.iter().zip(param_vtxs.unwrap_or_default()) {
|
|
28
|
+
changes.add_edge(*arg_vtx, *param_vtx);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// Propagate keyword argument types to keyword parameter vertices by name
|
|
33
|
+
fn propagate_keyword_arguments(
|
|
34
|
+
kwarg_vtxs: Option<&HashMap<String, VertexId>>,
|
|
35
|
+
kw_param_vtxs: Option<&HashMap<String, VertexId>>,
|
|
36
|
+
changes: &mut ChangeSet,
|
|
37
|
+
) {
|
|
38
|
+
let (Some(args), Some(params)) = (kwarg_vtxs, kw_param_vtxs) else {
|
|
39
|
+
return;
|
|
40
|
+
};
|
|
41
|
+
for (name, arg_vtx) in args {
|
|
42
|
+
if let Some(¶m_vtx) = params.get(name) {
|
|
43
|
+
changes.add_edge(*arg_vtx, param_vtx);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
19
48
|
/// Box representing a method call
|
|
20
|
-
#[allow(dead_code)]
|
|
21
49
|
pub struct MethodCallBox {
|
|
22
50
|
id: BoxId,
|
|
23
51
|
recv: VertexId,
|
|
24
52
|
method_name: String,
|
|
25
53
|
ret: VertexId,
|
|
26
54
|
arg_vtxs: Vec<VertexId>,
|
|
55
|
+
kwarg_vtxs: Option<HashMap<String, VertexId>>,
|
|
27
56
|
location: Option<SourceLocation>, // Source code location
|
|
28
57
|
/// Number of times this box has been rescheduled
|
|
29
58
|
reschedule_count: u8,
|
|
@@ -39,6 +68,7 @@ impl MethodCallBox {
|
|
|
39
68
|
method_name: String,
|
|
40
69
|
ret: VertexId,
|
|
41
70
|
arg_vtxs: Vec<VertexId>,
|
|
71
|
+
kwarg_vtxs: Option<HashMap<String, VertexId>>,
|
|
42
72
|
location: Option<SourceLocation>,
|
|
43
73
|
) -> Self {
|
|
44
74
|
Self {
|
|
@@ -47,10 +77,94 @@ impl MethodCallBox {
|
|
|
47
77
|
method_name,
|
|
48
78
|
ret,
|
|
49
79
|
arg_vtxs,
|
|
80
|
+
kwarg_vtxs,
|
|
50
81
|
location,
|
|
51
82
|
reschedule_count: 0,
|
|
52
83
|
}
|
|
53
84
|
}
|
|
85
|
+
|
|
86
|
+
/// Reschedule this box for re-execution if the limit hasn't been reached.
|
|
87
|
+
/// Handles cases where the receiver has no types yet (e.g., block parameters
|
|
88
|
+
/// that get typed by a later box). If max reschedules are reached, the box
|
|
89
|
+
/// is silently dropped (receiver type remains unknown).
|
|
90
|
+
fn try_reschedule(&mut self, changes: &mut ChangeSet) {
|
|
91
|
+
if self.reschedule_count < MAX_RESCHEDULE_COUNT {
|
|
92
|
+
self.reschedule_count += 1;
|
|
93
|
+
changes.reschedule(self.id);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
fn process_recv_type(
|
|
98
|
+
&self,
|
|
99
|
+
recv_ty: &Type,
|
|
100
|
+
genv: &mut GlobalEnv,
|
|
101
|
+
changes: &mut ChangeSet,
|
|
102
|
+
) {
|
|
103
|
+
if let Some(method_info) = genv.resolve_method(recv_ty, &self.method_name) {
|
|
104
|
+
if let Some(return_vtx) = method_info.return_vertex {
|
|
105
|
+
// User-defined method: connect body's return vertex to call site
|
|
106
|
+
changes.add_edge(return_vtx, self.ret);
|
|
107
|
+
propagate_arguments(
|
|
108
|
+
&self.arg_vtxs,
|
|
109
|
+
method_info.param_vertices.as_deref(),
|
|
110
|
+
changes,
|
|
111
|
+
);
|
|
112
|
+
propagate_keyword_arguments(
|
|
113
|
+
self.kwarg_vtxs.as_ref(),
|
|
114
|
+
method_info.keyword_param_vertices.as_ref(),
|
|
115
|
+
changes,
|
|
116
|
+
);
|
|
117
|
+
} else {
|
|
118
|
+
// Builtin/RBS method: create source with fixed return type
|
|
119
|
+
let ret_src_id = genv.new_source(method_info.return_type.clone());
|
|
120
|
+
changes.add_edge(ret_src_id, self.ret);
|
|
121
|
+
}
|
|
122
|
+
} else if self.method_name == "new" {
|
|
123
|
+
self.handle_new_call(recv_ty, genv, changes);
|
|
124
|
+
} else if !matches!(recv_ty, Type::Singleton { .. }) {
|
|
125
|
+
// Singleton types with unresolved methods are silently skipped;
|
|
126
|
+
// these are typically RBS class methods not yet supported.
|
|
127
|
+
self.report_type_error(recv_ty, genv);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/// Handle `.new` calls: singleton(Foo)#new produces instance(Foo),
|
|
132
|
+
/// and propagates arguments to the `initialize` method's parameters.
|
|
133
|
+
fn handle_new_call(
|
|
134
|
+
&self,
|
|
135
|
+
recv_ty: &Type,
|
|
136
|
+
genv: &mut GlobalEnv,
|
|
137
|
+
changes: &mut ChangeSet,
|
|
138
|
+
) {
|
|
139
|
+
if let Type::Singleton { name } = recv_ty {
|
|
140
|
+
let instance_type = Type::instance(name.full_name());
|
|
141
|
+
|
|
142
|
+
let ret_src = genv.new_source(instance_type.clone());
|
|
143
|
+
changes.add_edge(ret_src, self.ret);
|
|
144
|
+
|
|
145
|
+
let init_info = genv.resolve_method(&instance_type, "initialize");
|
|
146
|
+
propagate_arguments(
|
|
147
|
+
&self.arg_vtxs,
|
|
148
|
+
init_info.and_then(|info| info.param_vertices.as_deref()),
|
|
149
|
+
changes,
|
|
150
|
+
);
|
|
151
|
+
propagate_keyword_arguments(
|
|
152
|
+
self.kwarg_vtxs.as_ref(),
|
|
153
|
+
init_info.and_then(|info| info.keyword_param_vertices.as_ref()),
|
|
154
|
+
changes,
|
|
155
|
+
);
|
|
156
|
+
} else {
|
|
157
|
+
self.report_type_error(recv_ty, genv);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
fn report_type_error(&self, recv_ty: &Type, genv: &mut GlobalEnv) {
|
|
162
|
+
genv.record_type_error(
|
|
163
|
+
recv_ty.clone(),
|
|
164
|
+
self.method_name.clone(),
|
|
165
|
+
self.location.clone(),
|
|
166
|
+
);
|
|
167
|
+
}
|
|
54
168
|
}
|
|
55
169
|
|
|
56
170
|
impl BoxTrait for MethodCallBox {
|
|
@@ -63,88 +177,17 @@ impl BoxTrait for MethodCallBox {
|
|
|
63
177
|
}
|
|
64
178
|
|
|
65
179
|
fn run(&mut self, genv: &mut GlobalEnv, changes: &mut ChangeSet) {
|
|
66
|
-
|
|
67
|
-
let recv_types: Vec<Type> = if let Some(recv_vertex) = genv.get_vertex(self.recv) {
|
|
68
|
-
// Vertex case: may have multiple types
|
|
69
|
-
recv_vertex.types.keys().cloned().collect()
|
|
70
|
-
} else if let Some(recv_source) = genv.get_source(self.recv) {
|
|
71
|
-
// Source case: has one fixed type (e.g., literals)
|
|
72
|
-
vec![recv_source.ty.clone()]
|
|
73
|
-
} else {
|
|
74
|
-
// Receiver not found
|
|
180
|
+
let Some(recv_types) = genv.get_receiver_types(self.recv) else {
|
|
75
181
|
return;
|
|
76
182
|
};
|
|
77
183
|
|
|
78
|
-
// If receiver has no types yet, reschedule this box for later
|
|
79
|
-
// This handles cases like block parameters that are typed later
|
|
80
184
|
if recv_types.is_empty() {
|
|
81
|
-
|
|
82
|
-
self.reschedule_count += 1;
|
|
83
|
-
changes.reschedule(self.id);
|
|
84
|
-
}
|
|
85
|
-
// If max reschedules reached, just skip (receiver type is unknown)
|
|
185
|
+
self.try_reschedule(changes);
|
|
86
186
|
return;
|
|
87
187
|
}
|
|
88
188
|
|
|
89
189
|
for recv_ty in recv_types {
|
|
90
|
-
|
|
91
|
-
if let Some(method_info) = genv.resolve_method(&recv_ty, &self.method_name) {
|
|
92
|
-
if let Some(return_vtx) = method_info.return_vertex {
|
|
93
|
-
// User-defined: edge from body's last expr → call site return
|
|
94
|
-
changes.add_edge(return_vtx, self.ret);
|
|
95
|
-
|
|
96
|
-
// Propagate argument types to parameter vertices
|
|
97
|
-
if let Some(param_vtxs) = &method_info.param_vertices {
|
|
98
|
-
for (i, param_vtx) in param_vtxs.iter().enumerate() {
|
|
99
|
-
if let Some(arg_vtx) = self.arg_vtxs.get(i) {
|
|
100
|
-
changes.add_edge(*arg_vtx, *param_vtx);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
} else {
|
|
105
|
-
// RBS/builtin: create Source with fixed return type
|
|
106
|
-
let ret_src_id = genv.new_source(method_info.return_type.clone());
|
|
107
|
-
changes.add_edge(ret_src_id, self.ret);
|
|
108
|
-
}
|
|
109
|
-
} else if self.method_name == "new" {
|
|
110
|
-
if let Type::Singleton { name } = &recv_ty {
|
|
111
|
-
// singleton(User)#new → instance(User)
|
|
112
|
-
let instance_type = Type::instance(name.full_name());
|
|
113
|
-
let ret_src = genv.new_source(instance_type.clone());
|
|
114
|
-
changes.add_edge(ret_src, self.ret);
|
|
115
|
-
|
|
116
|
-
// Propagate arguments to initialize parameters
|
|
117
|
-
if let Some(init_info) = genv.resolve_method(&instance_type, "initialize") {
|
|
118
|
-
if let Some(param_vtxs) = &init_info.param_vertices {
|
|
119
|
-
for (i, param_vtx) in param_vtxs.iter().enumerate() {
|
|
120
|
-
if let Some(arg_vtx) = self.arg_vtxs.get(i) {
|
|
121
|
-
changes.add_edge(*arg_vtx, *param_vtx);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
// Non-singleton .new: record error
|
|
129
|
-
genv.record_type_error(
|
|
130
|
-
recv_ty.clone(),
|
|
131
|
-
self.method_name.clone(),
|
|
132
|
-
self.location.clone(),
|
|
133
|
-
);
|
|
134
|
-
} else if matches!(&recv_ty, Type::Singleton { .. }) {
|
|
135
|
-
// Skip error for unknown class methods on Singleton types.
|
|
136
|
-
// User-defined class methods (def self.foo) are resolved by
|
|
137
|
-
// resolve_method above. Only unresolved methods reach here
|
|
138
|
-
// (e.g., RBS class methods not yet supported).
|
|
139
|
-
continue;
|
|
140
|
-
} else {
|
|
141
|
-
// Record type error for diagnostic reporting
|
|
142
|
-
genv.record_type_error(
|
|
143
|
-
recv_ty.clone(),
|
|
144
|
-
self.method_name.clone(),
|
|
145
|
-
self.location.clone(),
|
|
146
|
-
);
|
|
147
|
-
}
|
|
190
|
+
self.process_recv_type(&recv_ty, genv, changes);
|
|
148
191
|
}
|
|
149
192
|
}
|
|
150
193
|
}
|
|
@@ -154,7 +197,6 @@ impl BoxTrait for MethodCallBox {
|
|
|
154
197
|
/// When a method with a block is called (e.g., `str.each_char { |c| ... }`),
|
|
155
198
|
/// this box resolves the block parameter types from the method's RBS definition
|
|
156
199
|
/// and propagates them to the block parameter vertices.
|
|
157
|
-
#[allow(dead_code)]
|
|
158
200
|
pub struct BlockParameterTypeBox {
|
|
159
201
|
id: BoxId,
|
|
160
202
|
/// Receiver vertex of the method call
|
|
@@ -241,12 +283,7 @@ impl BoxTrait for BlockParameterTypeBox {
|
|
|
241
283
|
}
|
|
242
284
|
|
|
243
285
|
fn run(&mut self, genv: &mut GlobalEnv, changes: &mut ChangeSet) {
|
|
244
|
-
|
|
245
|
-
let recv_types: Vec<Type> = if let Some(recv_vertex) = genv.get_vertex(self.recv_vtx) {
|
|
246
|
-
recv_vertex.types.keys().cloned().collect()
|
|
247
|
-
} else if let Some(recv_source) = genv.get_source(self.recv_vtx) {
|
|
248
|
-
vec![recv_source.ty.clone()]
|
|
249
|
-
} else {
|
|
286
|
+
let Some(recv_types) = genv.get_receiver_types(self.recv_vtx) else {
|
|
250
287
|
return;
|
|
251
288
|
};
|
|
252
289
|
|
|
@@ -318,6 +355,7 @@ mod tests {
|
|
|
318
355
|
"upcase".to_string(),
|
|
319
356
|
ret_vtx,
|
|
320
357
|
vec![],
|
|
358
|
+
None,
|
|
321
359
|
None, // No location in test
|
|
322
360
|
);
|
|
323
361
|
|
|
@@ -350,6 +388,7 @@ mod tests {
|
|
|
350
388
|
"unknown_method".to_string(),
|
|
351
389
|
ret_vtx,
|
|
352
390
|
vec![],
|
|
391
|
+
None,
|
|
353
392
|
None, // No location in test
|
|
354
393
|
);
|
|
355
394
|
|
|
@@ -545,7 +584,7 @@ mod tests {
|
|
|
545
584
|
let body_src = genv.new_source(Type::string());
|
|
546
585
|
|
|
547
586
|
// Register user-defined method User#name with return_vertex
|
|
548
|
-
genv.register_user_method(Type::instance("User"), "name", body_src, vec![]);
|
|
587
|
+
genv.register_user_method(Type::instance("User"), "name", body_src, vec![], None);
|
|
549
588
|
|
|
550
589
|
// Simulate: user.name (receiver has type User)
|
|
551
590
|
let recv_vtx = genv.new_vertex();
|
|
@@ -561,6 +600,7 @@ mod tests {
|
|
|
561
600
|
ret_vtx,
|
|
562
601
|
vec![],
|
|
563
602
|
None,
|
|
603
|
+
None,
|
|
564
604
|
);
|
|
565
605
|
genv.register_box(box_id, Box::new(call_box));
|
|
566
606
|
|
|
@@ -591,6 +631,7 @@ mod tests {
|
|
|
591
631
|
inner_ret_vtx,
|
|
592
632
|
vec![],
|
|
593
633
|
None,
|
|
634
|
+
None,
|
|
594
635
|
);
|
|
595
636
|
genv.register_box(inner_box_id, Box::new(inner_call));
|
|
596
637
|
|
|
@@ -600,6 +641,7 @@ mod tests {
|
|
|
600
641
|
"format",
|
|
601
642
|
inner_ret_vtx,
|
|
602
643
|
vec![param_vtx],
|
|
644
|
+
None,
|
|
603
645
|
);
|
|
604
646
|
|
|
605
647
|
// 5. Simulate call: Formatter.new.format(42)
|
|
@@ -618,6 +660,7 @@ mod tests {
|
|
|
618
660
|
call_ret_vtx,
|
|
619
661
|
vec![arg_vtx],
|
|
620
662
|
None,
|
|
663
|
+
None,
|
|
621
664
|
);
|
|
622
665
|
genv.register_box(call_box_id, Box::new(call_box));
|
|
623
666
|
|
|
@@ -630,4 +673,94 @@ mod tests {
|
|
|
630
673
|
// Return type should be String (Integer#to_s -> String)
|
|
631
674
|
assert_eq!(genv.get_vertex(call_ret_vtx).unwrap().show(), "String");
|
|
632
675
|
}
|
|
676
|
+
|
|
677
|
+
#[test]
|
|
678
|
+
fn test_keyword_arg_propagation() {
|
|
679
|
+
let mut genv = GlobalEnv::new();
|
|
680
|
+
|
|
681
|
+
// Simulate: def greet(name:); name; end
|
|
682
|
+
let param_vtx = genv.new_vertex();
|
|
683
|
+
let mut kw_params = HashMap::new();
|
|
684
|
+
kw_params.insert("name".to_string(), param_vtx);
|
|
685
|
+
|
|
686
|
+
genv.register_user_method(
|
|
687
|
+
Type::instance("Greeter"),
|
|
688
|
+
"greet",
|
|
689
|
+
param_vtx, // return vertex = param (returns name)
|
|
690
|
+
vec![],
|
|
691
|
+
Some(kw_params),
|
|
692
|
+
);
|
|
693
|
+
|
|
694
|
+
// Simulate call: Greeter.new.greet(name: "Alice")
|
|
695
|
+
let recv_vtx = genv.new_vertex();
|
|
696
|
+
let recv_src = genv.new_source(Type::instance("Greeter"));
|
|
697
|
+
genv.add_edge(recv_src, recv_vtx);
|
|
698
|
+
|
|
699
|
+
let arg_vtx = genv.new_source(Type::string());
|
|
700
|
+
let mut kwarg_vtxs = HashMap::new();
|
|
701
|
+
kwarg_vtxs.insert("name".to_string(), arg_vtx);
|
|
702
|
+
|
|
703
|
+
let ret_vtx = genv.new_vertex();
|
|
704
|
+
let box_id = genv.alloc_box_id();
|
|
705
|
+
let call_box = MethodCallBox::new(
|
|
706
|
+
box_id,
|
|
707
|
+
recv_vtx,
|
|
708
|
+
"greet".to_string(),
|
|
709
|
+
ret_vtx,
|
|
710
|
+
vec![],
|
|
711
|
+
Some(kwarg_vtxs),
|
|
712
|
+
None,
|
|
713
|
+
);
|
|
714
|
+
genv.register_box(box_id, Box::new(call_box));
|
|
715
|
+
|
|
716
|
+
genv.run_all();
|
|
717
|
+
|
|
718
|
+
// param_vtx should have String type (propagated from keyword argument)
|
|
719
|
+
assert_eq!(genv.get_vertex(param_vtx).unwrap().show(), "String");
|
|
720
|
+
assert_eq!(genv.get_vertex(ret_vtx).unwrap().show(), "String");
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
#[test]
|
|
724
|
+
fn test_keyword_arg_name_mismatch_skipped() {
|
|
725
|
+
let mut genv = GlobalEnv::new();
|
|
726
|
+
|
|
727
|
+
let param_vtx = genv.new_vertex();
|
|
728
|
+
let mut kw_params = HashMap::new();
|
|
729
|
+
kw_params.insert("name".to_string(), param_vtx);
|
|
730
|
+
|
|
731
|
+
genv.register_user_method(
|
|
732
|
+
Type::instance("Greeter"),
|
|
733
|
+
"greet",
|
|
734
|
+
param_vtx,
|
|
735
|
+
vec![],
|
|
736
|
+
Some(kw_params),
|
|
737
|
+
);
|
|
738
|
+
|
|
739
|
+
let recv_vtx = genv.new_vertex();
|
|
740
|
+
let recv_src = genv.new_source(Type::instance("Greeter"));
|
|
741
|
+
genv.add_edge(recv_src, recv_vtx);
|
|
742
|
+
|
|
743
|
+
// Wrong keyword name: "title" instead of "name"
|
|
744
|
+
let arg_vtx = genv.new_source(Type::string());
|
|
745
|
+
let mut kwarg_vtxs = HashMap::new();
|
|
746
|
+
kwarg_vtxs.insert("title".to_string(), arg_vtx);
|
|
747
|
+
|
|
748
|
+
let ret_vtx = genv.new_vertex();
|
|
749
|
+
let box_id = genv.alloc_box_id();
|
|
750
|
+
let call_box = MethodCallBox::new(
|
|
751
|
+
box_id,
|
|
752
|
+
recv_vtx,
|
|
753
|
+
"greet".to_string(),
|
|
754
|
+
ret_vtx,
|
|
755
|
+
vec![],
|
|
756
|
+
Some(kwarg_vtxs),
|
|
757
|
+
None,
|
|
758
|
+
);
|
|
759
|
+
genv.register_box(box_id, Box::new(call_box));
|
|
760
|
+
|
|
761
|
+
genv.run_all();
|
|
762
|
+
|
|
763
|
+
// param_vtx should remain untyped (name mismatch → no propagation)
|
|
764
|
+
assert_eq!(genv.get_vertex(param_vtx).unwrap().show(), "untyped");
|
|
765
|
+
}
|
|
633
766
|
}
|
|
@@ -10,6 +10,12 @@ pub struct ChangeSet {
|
|
|
10
10
|
reschedule_boxes: Vec<BoxId>,
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
impl Default for ChangeSet {
|
|
14
|
+
fn default() -> Self {
|
|
15
|
+
Self::new()
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
13
19
|
impl ChangeSet {
|
|
14
20
|
pub fn new() -> Self {
|
|
15
21
|
Self {
|
|
@@ -75,6 +81,14 @@ pub enum EdgeUpdate {
|
|
|
75
81
|
mod tests {
|
|
76
82
|
use super::*;
|
|
77
83
|
|
|
84
|
+
#[test]
|
|
85
|
+
fn test_change_set_default() {
|
|
86
|
+
let mut cs = ChangeSet::default();
|
|
87
|
+
cs.add_edge(VertexId(1), VertexId(2));
|
|
88
|
+
let updates = cs.reinstall();
|
|
89
|
+
assert_eq!(updates.len(), 1);
|
|
90
|
+
}
|
|
91
|
+
|
|
78
92
|
#[test]
|
|
79
93
|
fn test_change_set_add() {
|
|
80
94
|
let mut cs = ChangeSet::new();
|
data/rust/src/lsp/server.rs
CHANGED
|
@@ -132,7 +132,7 @@ pub async fn run_server() {
|
|
|
132
132
|
let stdin = tokio::io::stdin();
|
|
133
133
|
let stdout = tokio::io::stdout();
|
|
134
134
|
|
|
135
|
-
let (service, socket) = LspService::new(
|
|
135
|
+
let (service, socket) = LspService::new(MethodRayServer::new);
|
|
136
136
|
|
|
137
137
|
Server::new(stdin, stdout, socket).serve(service).await;
|
|
138
138
|
}
|
data/rust/src/rbs/loader.rs
CHANGED
|
@@ -155,8 +155,7 @@ pub fn register_rbs_methods(genv: &mut GlobalEnv, ruby: &Ruby) -> Result<usize,
|
|
|
155
155
|
cache.to_method_infos()
|
|
156
156
|
} else {
|
|
157
157
|
eprintln!("Cache invalid, reloading from RBS...");
|
|
158
|
-
|
|
159
|
-
methods
|
|
158
|
+
load_and_cache_rbs_methods(ruby, methodray_version, &rbs_version)?
|
|
160
159
|
}
|
|
161
160
|
} else {
|
|
162
161
|
eprintln!("No cache found, loading from RBS...");
|
data/rust/src/source_map.rs
CHANGED
data/rust/src/types.rs
CHANGED
|
@@ -125,7 +125,6 @@ impl From<String> for QualifiedName {
|
|
|
125
125
|
|
|
126
126
|
/// Type system for graph-based type inference
|
|
127
127
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
|
128
|
-
#[allow(dead_code)]
|
|
129
128
|
pub enum Type {
|
|
130
129
|
/// Instance type: String, Integer, Api::User, etc.
|
|
131
130
|
Instance { name: QualifiedName },
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: method-ray
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- dak2
|
|
@@ -48,14 +48,17 @@ files:
|
|
|
48
48
|
- lib/methodray/commands.rb
|
|
49
49
|
- lib/methodray/version.rb
|
|
50
50
|
- rust/Cargo.toml
|
|
51
|
+
- rust/src/analyzer/assignments.rs
|
|
51
52
|
- rust/src/analyzer/attributes.rs
|
|
52
53
|
- rust/src/analyzer/blocks.rs
|
|
53
54
|
- rust/src/analyzer/calls.rs
|
|
54
55
|
- rust/src/analyzer/conditionals.rs
|
|
55
56
|
- rust/src/analyzer/definitions.rs
|
|
56
57
|
- rust/src/analyzer/dispatch.rs
|
|
58
|
+
- rust/src/analyzer/exceptions.rs
|
|
57
59
|
- rust/src/analyzer/install.rs
|
|
58
60
|
- rust/src/analyzer/literals.rs
|
|
61
|
+
- rust/src/analyzer/loops.rs
|
|
59
62
|
- rust/src/analyzer/mod.rs
|
|
60
63
|
- rust/src/analyzer/operators.rs
|
|
61
64
|
- rust/src/analyzer/parameters.rs
|