ruby-lsp 0.17.3 → 0.17.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +241 -91
  4. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +74 -102
  5. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +81 -19
  6. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +50 -2
  7. data/lib/ruby_indexer/test/classes_and_modules_test.rb +46 -0
  8. data/lib/ruby_indexer/test/index_test.rb +326 -27
  9. data/lib/ruby_indexer/test/instance_variables_test.rb +84 -7
  10. data/lib/ruby_indexer/test/method_test.rb +54 -24
  11. data/lib/ruby_indexer/test/rbs_indexer_test.rb +27 -2
  12. data/lib/ruby_lsp/document.rb +37 -8
  13. data/lib/ruby_lsp/global_state.rb +7 -3
  14. data/lib/ruby_lsp/internal.rb +1 -0
  15. data/lib/ruby_lsp/listeners/completion.rb +53 -14
  16. data/lib/ruby_lsp/listeners/definition.rb +11 -7
  17. data/lib/ruby_lsp/listeners/hover.rb +14 -7
  18. data/lib/ruby_lsp/listeners/signature_help.rb +5 -2
  19. data/lib/ruby_lsp/node_context.rb +6 -1
  20. data/lib/ruby_lsp/requests/completion.rb +5 -4
  21. data/lib/ruby_lsp/requests/completion_resolve.rb +8 -0
  22. data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +88 -0
  23. data/lib/ruby_lsp/requests/support/common.rb +19 -1
  24. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +12 -4
  25. data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +91 -0
  26. data/lib/ruby_lsp/requests/workspace_symbol.rb +1 -21
  27. data/lib/ruby_lsp/requests.rb +2 -0
  28. data/lib/ruby_lsp/server.rb +54 -15
  29. data/lib/ruby_lsp/test_helper.rb +1 -1
  30. data/lib/ruby_lsp/type_inferrer.rb +86 -0
  31. metadata +5 -2
@@ -93,30 +93,30 @@ module RubyIndexer
93
93
 
94
94
  def test_fuzzy_search
95
95
  @index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
96
- class Bar; end
96
+ class Zws; end
97
97
 
98
- module Foo
99
- class Bar
98
+ module Qtl
99
+ class Zws
100
100
  end
101
101
 
102
- class Baz
102
+ class Zwo
103
103
  class Something
104
104
  end
105
105
  end
106
106
  end
107
107
  RUBY
108
108
 
109
- result = @index.fuzzy_search("Bar")
110
- assert_equal(3, result.length)
111
- assert_equal(["Bar", "Backtrace", "Base"], result.map(&:name))
112
-
113
- result = @index.fuzzy_search("foobarsomeking")
114
- assert_equal(6, result.length)
115
- assert_equal(["Foo::Baz::Something", "Foo::Bar", "Foo::Baz", "Foo", "Base", "Bar"], result.map(&:name))
109
+ result = @index.fuzzy_search("Zws")
110
+ assert_equal(2, result.length)
111
+ assert_equal(["Zws", "Qtl::Zwo::Something"], result.map(&:name))
116
112
 
117
- result = @index.fuzzy_search("FooBaz")
113
+ result = @index.fuzzy_search("qtlzwssomeking")
118
114
  assert_equal(5, result.length)
119
- assert_equal(["Foo::Baz", "Foo::Bar", "Foo", "Foo::Baz::Something", "Float"], result.map(&:name))
115
+ assert_equal(["Qtl::Zwo::Something", "Qtl::Zws", "Qtl::Zwo", "Qtl", "Zws"], result.map(&:name))
116
+
117
+ result = @index.fuzzy_search("QltZwo")
118
+ assert_equal(4, result.length)
119
+ assert_equal(["Qtl::Zwo", "Qtl::Zws", "Qtl::Zwo::Something", "Qtl"], result.map(&:name))
120
120
  end
121
121
 
122
122
  def test_index_single_ignores_directories
@@ -140,25 +140,23 @@ module RubyIndexer
140
140
  end
141
141
 
142
142
  def test_searching_for_entries_based_on_prefix
143
- # For this test, it's easier if we don't include core classes and modules
144
- @index = Index.new
145
143
  @index.index_single(IndexablePath.new("/fake", "/fake/path/foo.rb"), <<~RUBY)
146
- class Foo::Bar
144
+ class Foo::Bizw
147
145
  end
148
146
  RUBY
149
147
  @index.index_single(IndexablePath.new("/fake", "/fake/path/other_foo.rb"), <<~RUBY)
150
- class Foo::Bar
148
+ class Foo::Bizw
151
149
  end
152
150
 
153
- class Foo::Baz
151
+ class Foo::Bizt
154
152
  end
155
153
  RUBY
156
154
 
157
155
  results = @index.prefix_search("Foo", []).map { |entries| entries.map(&:name) }
158
- assert_equal([["Foo::Bar", "Foo::Bar"], ["Foo::Baz"]], results)
156
+ assert_equal([["Foo::Bizw", "Foo::Bizw"], ["Foo::Bizt"]], results)
159
157
 
160
- results = @index.prefix_search("Ba", ["Foo"]).map { |entries| entries.map(&:name) }
161
- assert_equal([["Foo::Bar", "Foo::Bar"], ["Foo::Baz"]], results)
158
+ results = @index.prefix_search("Biz", ["Foo"]).map { |entries| entries.map(&:name) }
159
+ assert_equal([["Foo::Bizw", "Foo::Bizw"], ["Foo::Bizt"]], results)
162
160
  end
163
161
 
164
162
  def test_resolve_normalizes_top_level_names
@@ -291,16 +289,16 @@ module RubyIndexer
291
289
  index(<<~RUBY)
292
290
  module Foo
293
291
  module Bar
294
- def baz; end
292
+ def qzx; end
295
293
  end
296
294
  end
297
295
  RUBY
298
296
 
299
- entries = @index.prefix_search("ba")
297
+ entries = @index.prefix_search("qz")
300
298
  refute_empty(entries)
301
299
 
302
- entry = T.must(entries.first).first
303
- assert_equal("baz", entry.name)
300
+ entry = T.must(T.must(entries.first).first)
301
+ assert_equal("qzx", entry.name)
304
302
  end
305
303
 
306
304
  def test_indexing_prism_fixtures_succeeds
@@ -1145,8 +1143,32 @@ module RubyIndexer
1145
1143
  assert_nil(@index.resolve("RSpec", []))
1146
1144
  end
1147
1145
 
1146
+ def test_object_superclass_indexing_and_resolution_with_reopened_object_class
1147
+ index(<<~RUBY)
1148
+ class Object; end
1149
+ RUBY
1150
+
1151
+ entries = @index["Object"]
1152
+ assert_equal(2, entries.length)
1153
+ reopened_entry = entries.last
1154
+ assert_equal("::BasicObject", reopened_entry.parent_class)
1155
+ assert_equal(["Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Object"))
1156
+ end
1157
+
1158
+ def test_object_superclass_indexing_and_resolution_with_reopened_basic_object_class
1159
+ index(<<~RUBY)
1160
+ class BasicObject; end
1161
+ RUBY
1162
+
1163
+ entries = @index["BasicObject"]
1164
+ assert_equal(2, entries.length)
1165
+ reopened_entry = entries.last
1166
+ assert_nil(reopened_entry.parent_class)
1167
+ assert_equal(["BasicObject"], @index.linearized_ancestors_of("BasicObject"))
1168
+ end
1169
+
1148
1170
  def test_object_superclass_resolution
1149
- @index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
1171
+ index(<<~RUBY)
1150
1172
  module Foo
1151
1173
  class Object; end
1152
1174
 
@@ -1162,8 +1184,25 @@ module RubyIndexer
1162
1184
  )
1163
1185
  end
1164
1186
 
1187
+ def test_basic_object_superclass_resolution
1188
+ index(<<~RUBY)
1189
+ module Foo
1190
+ class BasicObject; end
1191
+
1192
+ class Bar; end
1193
+ class Baz < BasicObject; end
1194
+ end
1195
+ RUBY
1196
+
1197
+ assert_equal(["Foo::Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Foo::Bar"))
1198
+ assert_equal(
1199
+ ["Foo::Baz", "Foo::BasicObject", "Object", "Kernel", "BasicObject"],
1200
+ @index.linearized_ancestors_of("Foo::Baz"),
1201
+ )
1202
+ end
1203
+
1165
1204
  def test_top_level_object_superclass_resolution
1166
- @index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
1205
+ index(<<~RUBY)
1167
1206
  module Foo
1168
1207
  class Object; end
1169
1208
 
@@ -1173,5 +1212,265 @@ module RubyIndexer
1173
1212
 
1174
1213
  assert_equal(["Foo::Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Foo::Bar"))
1175
1214
  end
1215
+
1216
+ def test_top_level_basic_object_superclass_resolution
1217
+ index(<<~RUBY)
1218
+ module Foo
1219
+ class BasicObject; end
1220
+
1221
+ class Bar < ::BasicObject; end
1222
+ end
1223
+ RUBY
1224
+
1225
+ assert_equal(["Foo::Bar", "BasicObject"], @index.linearized_ancestors_of("Foo::Bar"))
1226
+ end
1227
+
1228
+ def test_resolving_method_inside_singleton_context
1229
+ @index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
1230
+ module Foo
1231
+ class Bar
1232
+ class << self
1233
+ class Baz
1234
+ class << self
1235
+ def found_me!; end
1236
+ end
1237
+ end
1238
+ end
1239
+ end
1240
+ end
1241
+ RUBY
1242
+
1243
+ entry = @index.resolve_method("found_me!", "Foo::Bar::<Class:Bar>::Baz::<Class:Baz>")&.first
1244
+ refute_nil(entry)
1245
+
1246
+ assert_equal("found_me!", T.must(entry).name)
1247
+ end
1248
+
1249
+ def test_resolving_constants_in_singleton_contexts
1250
+ @index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
1251
+ module Foo
1252
+ class Bar
1253
+ CONST = 3
1254
+
1255
+ class << self
1256
+ CONST = 2
1257
+
1258
+ class Baz
1259
+ CONST = 1
1260
+
1261
+ class << self
1262
+ end
1263
+ end
1264
+ end
1265
+ end
1266
+ end
1267
+ RUBY
1268
+
1269
+ entry = @index.resolve("CONST", ["Foo", "Bar", "<Class:Bar>", "Baz", "<Class:Baz>"])&.first
1270
+ refute_nil(entry)
1271
+ assert_equal(9, T.must(entry).location.start_line)
1272
+ end
1273
+
1274
+ def test_resolving_instance_variables_in_singleton_contexts
1275
+ @index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
1276
+ module Foo
1277
+ class Bar
1278
+ @a = 123
1279
+
1280
+ class << self
1281
+ def hello
1282
+ @b = 123
1283
+ end
1284
+
1285
+ @c = 123
1286
+ end
1287
+ end
1288
+ end
1289
+ RUBY
1290
+
1291
+ entry = @index.resolve_instance_variable("@a", "Foo::Bar::<Class:Bar>")&.first
1292
+ refute_nil(entry)
1293
+ assert_equal("@a", T.must(entry).name)
1294
+
1295
+ entry = @index.resolve_instance_variable("@b", "Foo::Bar::<Class:Bar>")&.first
1296
+ refute_nil(entry)
1297
+ assert_equal("@b", T.must(entry).name)
1298
+
1299
+ entry = @index.resolve_instance_variable("@c", "Foo::Bar::<Class:Bar>::<Class:<Class:Bar>>")&.first
1300
+ refute_nil(entry)
1301
+ assert_equal("@c", T.must(entry).name)
1302
+ end
1303
+
1304
+ def test_instance_variable_completion_in_singleton_contexts
1305
+ @index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"), <<~RUBY)
1306
+ module Foo
1307
+ class Bar
1308
+ @a = 123
1309
+
1310
+ class << self
1311
+ def hello
1312
+ @b = 123
1313
+ end
1314
+
1315
+ @c = 123
1316
+ end
1317
+ end
1318
+ end
1319
+ RUBY
1320
+
1321
+ entries = @index.instance_variable_completion_candidates("@", "Foo::Bar::<Class:Bar>").map(&:name)
1322
+ assert_includes(entries, "@a")
1323
+ assert_includes(entries, "@b")
1324
+
1325
+ assert_includes(
1326
+ @index.instance_variable_completion_candidates("@", "Foo::Bar::<Class:Bar>::<Class:<Class:Bar>>").map(&:name),
1327
+ "@c",
1328
+ )
1329
+ end
1330
+
1331
+ def test_singletons_are_excluded_from_prefix_search
1332
+ index(<<~RUBY)
1333
+ class Zwq
1334
+ class << self
1335
+ end
1336
+ end
1337
+ RUBY
1338
+
1339
+ assert_empty(@index.prefix_search("Zwq::<C"))
1340
+ end
1341
+
1342
+ def test_singletons_are_excluded_from_fuzzy_search
1343
+ index(<<~RUBY)
1344
+ class Zwq
1345
+ class << self
1346
+ end
1347
+ end
1348
+ RUBY
1349
+
1350
+ results = @index.fuzzy_search("Zwq")
1351
+ assert_equal(1, results.length)
1352
+ assert_equal("Zwq", results.first.name)
1353
+ end
1354
+
1355
+ def test_resolving_method_aliases
1356
+ index(<<~RUBY)
1357
+ class Foo
1358
+ def bar(a, b, c)
1359
+ end
1360
+
1361
+ alias double_alias bar
1362
+ end
1363
+
1364
+ class Bar < Foo
1365
+ def hello(b); end
1366
+
1367
+ alias baz bar
1368
+ alias_method :qux, :hello
1369
+ alias double double_alias
1370
+ end
1371
+ RUBY
1372
+
1373
+ # baz
1374
+ methods = @index.resolve_method("baz", "Bar")
1375
+ refute_nil(methods)
1376
+
1377
+ entry = T.must(methods.first)
1378
+ assert_kind_of(Entry::MethodAlias, entry)
1379
+ assert_equal("bar", entry.target.name)
1380
+ assert_equal("Foo", T.must(entry.target.owner).name)
1381
+
1382
+ # qux
1383
+ methods = @index.resolve_method("qux", "Bar")
1384
+ refute_nil(methods)
1385
+
1386
+ entry = T.must(methods.first)
1387
+ assert_kind_of(Entry::MethodAlias, entry)
1388
+ assert_equal("hello", entry.target.name)
1389
+ assert_equal("Bar", T.must(entry.target.owner).name)
1390
+
1391
+ # double
1392
+ methods = @index.resolve_method("double", "Bar")
1393
+ refute_nil(methods)
1394
+
1395
+ entry = T.must(methods.first)
1396
+ assert_kind_of(Entry::MethodAlias, entry)
1397
+
1398
+ target = entry.target
1399
+ assert_equal("double_alias", target.name)
1400
+ assert_kind_of(Entry::MethodAlias, target)
1401
+ assert_equal("Foo", T.must(target.owner).name)
1402
+
1403
+ final_target = target.target
1404
+ assert_equal("bar", final_target.name)
1405
+ assert_kind_of(Entry::Method, final_target)
1406
+ assert_equal("Foo", T.must(final_target.owner).name)
1407
+ end
1408
+
1409
+ def test_resolving_circular_method_aliases
1410
+ index(<<~RUBY)
1411
+ class Foo
1412
+ alias bar bar
1413
+ end
1414
+ RUBY
1415
+
1416
+ # It's not possible to resolve an alias that points to itself
1417
+ methods = @index.resolve_method("bar", "Foo")
1418
+ assert_nil(methods)
1419
+
1420
+ entry = T.must(@index["bar"].first)
1421
+ assert_kind_of(Entry::UnresolvedMethodAlias, entry)
1422
+ end
1423
+
1424
+ def test_unresolable_method_aliases
1425
+ index(<<~RUBY)
1426
+ class Foo
1427
+ alias bar baz
1428
+ end
1429
+ RUBY
1430
+
1431
+ # `baz` does not exist, so resolving `bar` is not possible
1432
+ methods = @index.resolve_method("bar", "Foo")
1433
+ assert_nil(methods)
1434
+
1435
+ entry = T.must(@index["bar"].first)
1436
+ assert_kind_of(Entry::UnresolvedMethodAlias, entry)
1437
+ end
1438
+
1439
+ def test_only_aliases_for_the_right_owner_are_resolved
1440
+ index(<<~RUBY)
1441
+ class Foo
1442
+ attr_reader :name
1443
+ alias_method :decorated_name, :name
1444
+ end
1445
+
1446
+ class Bar
1447
+ alias_method :decorated_name, :to_s
1448
+ end
1449
+ RUBY
1450
+
1451
+ methods = @index.resolve_method("decorated_name", "Foo")
1452
+ refute_nil(methods)
1453
+
1454
+ entry = T.must(methods.first)
1455
+ assert_kind_of(Entry::MethodAlias, entry)
1456
+
1457
+ target = entry.target
1458
+ assert_equal("name", target.name)
1459
+ assert_kind_of(Entry::Accessor, target)
1460
+ assert_equal("Foo", T.must(target.owner).name)
1461
+
1462
+ other_decorated_name = T.must(@index["decorated_name"].find { |e| e.is_a?(Entry::UnresolvedMethodAlias) })
1463
+ assert_kind_of(Entry::UnresolvedMethodAlias, other_decorated_name)
1464
+ end
1465
+
1466
+ def test_completion_does_not_include_unresolved_aliases
1467
+ index(<<~RUBY)
1468
+ class Foo
1469
+ alias_method :bar, :missing
1470
+ end
1471
+ RUBY
1472
+
1473
+ assert_empty(@index.method_completion_candidates("bar", "Foo"))
1474
+ end
1176
1475
  end
1177
1476
  end
@@ -20,7 +20,9 @@ module RubyIndexer
20
20
  assert_entry("@a", Entry::InstanceVariable, "/fake/path/foo.rb:4-6:4-8")
21
21
 
22
22
  entry = T.must(@index["@a"]&.first)
23
- assert_equal("Foo::Bar", T.must(entry.owner).name)
23
+ owner = T.must(entry.owner)
24
+ assert_instance_of(Entry::Class, owner)
25
+ assert_equal("Foo::Bar", owner.name)
24
26
  end
25
27
 
26
28
  def test_instance_variable_and_write
@@ -38,7 +40,9 @@ module RubyIndexer
38
40
  assert_entry("@a", Entry::InstanceVariable, "/fake/path/foo.rb:4-6:4-8")
39
41
 
40
42
  entry = T.must(@index["@a"]&.first)
41
- assert_equal("Foo::Bar", T.must(entry.owner).name)
43
+ owner = T.must(entry.owner)
44
+ assert_instance_of(Entry::Class, owner)
45
+ assert_equal("Foo::Bar", owner.name)
42
46
  end
43
47
 
44
48
  def test_instance_variable_operator_write
@@ -56,7 +60,9 @@ module RubyIndexer
56
60
  assert_entry("@a", Entry::InstanceVariable, "/fake/path/foo.rb:4-6:4-8")
57
61
 
58
62
  entry = T.must(@index["@a"]&.first)
59
- assert_equal("Foo::Bar", T.must(entry.owner).name)
63
+ owner = T.must(entry.owner)
64
+ assert_instance_of(Entry::Class, owner)
65
+ assert_equal("Foo::Bar", owner.name)
60
66
  end
61
67
 
62
68
  def test_instance_variable_or_write
@@ -74,7 +80,9 @@ module RubyIndexer
74
80
  assert_entry("@a", Entry::InstanceVariable, "/fake/path/foo.rb:4-6:4-8")
75
81
 
76
82
  entry = T.must(@index["@a"]&.first)
77
- assert_equal("Foo::Bar", T.must(entry.owner).name)
83
+ owner = T.must(entry.owner)
84
+ assert_instance_of(Entry::Class, owner)
85
+ assert_equal("Foo::Bar", owner.name)
78
86
  end
79
87
 
80
88
  def test_instance_variable_target
@@ -93,10 +101,14 @@ module RubyIndexer
93
101
  assert_entry("@b", Entry::InstanceVariable, "/fake/path/foo.rb:4-10:4-12")
94
102
 
95
103
  entry = T.must(@index["@a"]&.first)
96
- assert_equal("Foo::Bar", T.must(entry.owner).name)
104
+ owner = T.must(entry.owner)
105
+ assert_instance_of(Entry::Class, owner)
106
+ assert_equal("Foo::Bar", owner.name)
97
107
 
98
108
  entry = T.must(@index["@b"]&.first)
99
- assert_equal("Foo::Bar", T.must(entry.owner).name)
109
+ owner = T.must(entry.owner)
110
+ assert_instance_of(Entry::Class, owner)
111
+ assert_equal("Foo::Bar", owner.name)
100
112
  end
101
113
 
102
114
  def test_empty_name_instance_variables
@@ -118,6 +130,14 @@ module RubyIndexer
118
130
  module Foo
119
131
  class Bar
120
132
  @a = 123
133
+
134
+ class << self
135
+ def hello
136
+ @b = 123
137
+ end
138
+
139
+ @c = 123
140
+ end
121
141
  end
122
142
  end
123
143
  RUBY
@@ -125,7 +145,64 @@ module RubyIndexer
125
145
  assert_entry("@a", Entry::InstanceVariable, "/fake/path/foo.rb:2-4:2-6")
126
146
 
127
147
  entry = T.must(@index["@a"]&.first)
128
- assert_equal("Foo::Bar", T.must(entry.owner).name)
148
+ owner = T.must(entry.owner)
149
+ assert_instance_of(Entry::SingletonClass, owner)
150
+ assert_equal("Foo::Bar::<Class:Bar>", owner.name)
151
+
152
+ assert_entry("@b", Entry::InstanceVariable, "/fake/path/foo.rb:6-8:6-10")
153
+
154
+ entry = T.must(@index["@b"]&.first)
155
+ owner = T.must(entry.owner)
156
+ assert_instance_of(Entry::SingletonClass, owner)
157
+ assert_equal("Foo::Bar::<Class:Bar>", owner.name)
158
+
159
+ assert_entry("@c", Entry::InstanceVariable, "/fake/path/foo.rb:9-6:9-8")
160
+
161
+ entry = T.must(@index["@c"]&.first)
162
+ owner = T.must(entry.owner)
163
+ assert_instance_of(Entry::SingletonClass, owner)
164
+ assert_equal("Foo::Bar::<Class:Bar>::<Class:<Class:Bar>>", owner.name)
165
+ end
166
+
167
+ def test_top_level_instance_variables
168
+ index(<<~RUBY)
169
+ @a = 123
170
+ RUBY
171
+
172
+ entry = T.must(@index["@a"]&.first)
173
+ assert_nil(entry.owner)
174
+ end
175
+
176
+ def test_class_instance_variables_inside_self_method
177
+ index(<<~RUBY)
178
+ class Foo
179
+ def self.bar
180
+ @a = 123
181
+ end
182
+ end
183
+ RUBY
184
+
185
+ entry = T.must(@index["@a"]&.first)
186
+ owner = T.must(entry.owner)
187
+ assert_instance_of(Entry::SingletonClass, owner)
188
+ assert_equal("Foo::<Class:Foo>", owner.name)
189
+ end
190
+
191
+ def test_instance_variable_inside_dynamic_method_declaration
192
+ index(<<~RUBY)
193
+ class Foo
194
+ def something.bar
195
+ @a = 123
196
+ end
197
+ end
198
+ RUBY
199
+
200
+ # If the surrounding method is beind defined on any dynamic value that isn't `self`, then we attribute the
201
+ # instance variable to the wrong owner since there's no way to understand that statically
202
+ entry = T.must(@index["@a"]&.first)
203
+ owner = T.must(entry.owner)
204
+ assert_instance_of(Entry::Class, owner)
205
+ assert_equal("Foo", owner.name)
129
206
  end
130
207
  end
131
208
  end