rubydex 0.2.0 → 0.2.2
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/ext/rubydex/declaration.c +38 -0
- data/ext/rubydex/definition.c +27 -0
- data/ext/rubydex/graph.c +70 -17
- data/ext/rubydex/rubydex.c +2 -0
- data/ext/rubydex/signature.c +83 -0
- data/ext/rubydex/signature.h +23 -0
- data/lib/rubydex/declaration.rb +31 -0
- data/lib/rubydex/signature.rb +130 -0
- data/lib/rubydex/version.rb +1 -1
- data/lib/rubydex.rb +1 -0
- data/rbi/rubydex.rbi +41 -11
- data/rust/rubydex/src/diagnostic.rs +1 -0
- data/rust/rubydex/src/indexing/ruby_indexer.rs +75 -15
- data/rust/rubydex/src/indexing/ruby_indexer_tests.rs +2832 -2663
- data/rust/rubydex/src/model/declaration.rs +48 -0
- data/rust/rubydex/src/model/definitions.rs +41 -9
- data/rust/rubydex/src/model/graph.rs +276 -46
- data/rust/rubydex/src/query.rs +2073 -160
- data/rust/rubydex/src/resolution.rs +202 -71
- data/rust/rubydex/src/resolution_tests.rs +333 -1
- data/rust/rubydex-sys/src/declaration_api.rs +29 -33
- data/rust/rubydex-sys/src/graph_api.rs +89 -5
- data/rust/rubydex-sys/src/lib.rs +1 -0
- data/rust/rubydex-sys/src/signature_api.rs +209 -0
- metadata +6 -2
|
@@ -287,11 +287,8 @@ impl<'a> Resolver<'a> {
|
|
|
287
287
|
unreachable!("SelfReceiver methods should be routed to handle_definition_unit");
|
|
288
288
|
}
|
|
289
289
|
Some(Receiver::ConstantReceiver(name_id)) => {
|
|
290
|
-
let receiver_decl_id =
|
|
291
|
-
|
|
292
|
-
NameRef::Unresolved(_) => {
|
|
293
|
-
continue;
|
|
294
|
-
}
|
|
290
|
+
let Some(receiver_decl_id) = self.resolve_constant_receiver(*name_id, id) else {
|
|
291
|
+
continue;
|
|
295
292
|
};
|
|
296
293
|
|
|
297
294
|
let Some(singleton_id) = self.get_or_create_singleton_class(receiver_decl_id, true) else {
|
|
@@ -301,8 +298,8 @@ impl<'a> Resolver<'a> {
|
|
|
301
298
|
singleton_id
|
|
302
299
|
}
|
|
303
300
|
None => {
|
|
304
|
-
let
|
|
305
|
-
else {
|
|
301
|
+
let lexical = *method_definition.lexical_nesting_id();
|
|
302
|
+
let Some(resolved) = self.resolve_lexical_owner(lexical, id) else {
|
|
306
303
|
continue;
|
|
307
304
|
};
|
|
308
305
|
resolved
|
|
@@ -314,29 +311,35 @@ impl<'a> Resolver<'a> {
|
|
|
314
311
|
});
|
|
315
312
|
}
|
|
316
313
|
Definition::AttrAccessor(attr) => {
|
|
317
|
-
let
|
|
314
|
+
let lexical = *attr.lexical_nesting_id();
|
|
315
|
+
let str_id = *attr.str_id();
|
|
316
|
+
let Some(owner_id) = self.resolve_lexical_owner(lexical, id) else {
|
|
318
317
|
continue;
|
|
319
318
|
};
|
|
320
319
|
|
|
321
|
-
self.create_declaration(
|
|
320
|
+
self.create_declaration(str_id, id, owner_id, |name| {
|
|
322
321
|
Declaration::Method(Box::new(MethodDeclaration::new(name, owner_id)))
|
|
323
322
|
});
|
|
324
323
|
}
|
|
325
324
|
Definition::AttrReader(attr) => {
|
|
326
|
-
let
|
|
325
|
+
let lexical = *attr.lexical_nesting_id();
|
|
326
|
+
let str_id = *attr.str_id();
|
|
327
|
+
let Some(owner_id) = self.resolve_lexical_owner(lexical, id) else {
|
|
327
328
|
continue;
|
|
328
329
|
};
|
|
329
330
|
|
|
330
|
-
self.create_declaration(
|
|
331
|
+
self.create_declaration(str_id, id, owner_id, |name| {
|
|
331
332
|
Declaration::Method(Box::new(MethodDeclaration::new(name, owner_id)))
|
|
332
333
|
});
|
|
333
334
|
}
|
|
334
335
|
Definition::AttrWriter(attr) => {
|
|
335
|
-
let
|
|
336
|
+
let lexical = *attr.lexical_nesting_id();
|
|
337
|
+
let str_id = *attr.str_id();
|
|
338
|
+
let Some(owner_id) = self.resolve_lexical_owner(lexical, id) else {
|
|
336
339
|
continue;
|
|
337
340
|
};
|
|
338
341
|
|
|
339
|
-
self.create_declaration(
|
|
342
|
+
self.create_declaration(str_id, id, owner_id, |name| {
|
|
340
343
|
Declaration::Method(Box::new(MethodDeclaration::new(name, owner_id)))
|
|
341
344
|
});
|
|
342
345
|
}
|
|
@@ -377,11 +380,11 @@ impl<'a> Resolver<'a> {
|
|
|
377
380
|
.definition_id_to_declaration_id(*def_id)
|
|
378
381
|
.expect("SelfReceiver definition should have a declaration"),
|
|
379
382
|
Receiver::ConstantReceiver(name_id) => {
|
|
380
|
-
let Some(
|
|
383
|
+
let Some(receiver_decl_id) = self.resolve_constant_receiver(*name_id, id)
|
|
384
|
+
else {
|
|
381
385
|
continue;
|
|
382
386
|
};
|
|
383
|
-
|
|
384
|
-
*resolved.declaration_id()
|
|
387
|
+
receiver_decl_id
|
|
385
388
|
}
|
|
386
389
|
};
|
|
387
390
|
|
|
@@ -407,7 +410,8 @@ impl<'a> Resolver<'a> {
|
|
|
407
410
|
}
|
|
408
411
|
|
|
409
412
|
// If the method has no explicit receiver, we resolve the owner based on the lexical nesting
|
|
410
|
-
let Some(method_owner_id) = self.resolve_lexical_owner(*method.lexical_nesting_id())
|
|
413
|
+
let Some(method_owner_id) = self.resolve_lexical_owner(*method.lexical_nesting_id(), id)
|
|
414
|
+
else {
|
|
411
415
|
continue;
|
|
412
416
|
};
|
|
413
417
|
|
|
@@ -464,11 +468,14 @@ impl<'a> Resolver<'a> {
|
|
|
464
468
|
// If in a singleton class body directly, the owner is the singleton class's singleton class
|
|
465
469
|
// Like `class << Foo; @bar = 1; end`, where `@bar` is owned by `Foo::<Foo>::<<Foo>>`
|
|
466
470
|
Definition::SingletonClass(_) => {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
471
|
+
// The singleton's declaration may be missing (e.g. its receiver was
|
|
472
|
+
// just deleted). Re-queue and let the next resolve place `@bar` on
|
|
473
|
+
// the right owner instead of falling back to Object.
|
|
474
|
+
let Some(&singleton_class_decl_id) = self.graph.definition_id_to_declaration_id(nesting_id)
|
|
475
|
+
else {
|
|
476
|
+
self.graph.push_work(Unit::Definition(id));
|
|
477
|
+
continue;
|
|
478
|
+
};
|
|
472
479
|
let owner_id = self
|
|
473
480
|
.get_or_create_singleton_class(singleton_class_decl_id, true)
|
|
474
481
|
.expect("singleton class nesting should always be a namespace");
|
|
@@ -515,14 +522,15 @@ impl<'a> Resolver<'a> {
|
|
|
515
522
|
};
|
|
516
523
|
owner_id
|
|
517
524
|
}
|
|
518
|
-
Some(Receiver::ConstantReceiver(name_id)) =>
|
|
519
|
-
|
|
520
|
-
NameRef::Unresolved(_) => {
|
|
525
|
+
Some(Receiver::ConstantReceiver(name_id)) => {
|
|
526
|
+
let Some(resolved) = self.resolve_constant_receiver(*name_id, id) else {
|
|
521
527
|
continue;
|
|
522
|
-
}
|
|
523
|
-
|
|
528
|
+
};
|
|
529
|
+
resolved
|
|
530
|
+
}
|
|
524
531
|
None => {
|
|
525
|
-
let
|
|
532
|
+
let lexical = *alias.lexical_nesting_id();
|
|
533
|
+
let Some(resolved) = self.resolve_lexical_owner(lexical, id) else {
|
|
526
534
|
continue;
|
|
527
535
|
};
|
|
528
536
|
resolved
|
|
@@ -538,8 +546,63 @@ impl<'a> Resolver<'a> {
|
|
|
538
546
|
Declaration::GlobalVariable(Box::new(GlobalVariableDeclaration::new(name, *OBJECT_ID)))
|
|
539
547
|
});
|
|
540
548
|
}
|
|
541
|
-
Definition::ConstantVisibility(
|
|
542
|
-
//
|
|
549
|
+
Definition::ConstantVisibility(constant_visibility) => {
|
|
550
|
+
// Both `private_constant` and `public_constant` can only target direct members.
|
|
551
|
+
// Inheritance or surrounding lexical scopes are not taken into account.
|
|
552
|
+
let receiver = *constant_visibility.receiver();
|
|
553
|
+
let target = *constant_visibility.target();
|
|
554
|
+
let uri_id = *constant_visibility.uri_id();
|
|
555
|
+
let offset = constant_visibility.offset().clone();
|
|
556
|
+
let lexical_nesting_id = *constant_visibility.lexical_nesting_id();
|
|
557
|
+
let constant_name = self.graph.strings().get(&target).unwrap().as_str().to_string();
|
|
558
|
+
|
|
559
|
+
let owner_id = if let Some(receiver_name_id) = receiver {
|
|
560
|
+
let NameRef::Resolved(resolved_receiver) = self.graph.names().get(&receiver_name_id).unwrap()
|
|
561
|
+
else {
|
|
562
|
+
continue;
|
|
563
|
+
};
|
|
564
|
+
let Some(namespace_id) = self.resolve_to_namespace(*resolved_receiver.declaration_id()) else {
|
|
565
|
+
continue;
|
|
566
|
+
};
|
|
567
|
+
namespace_id
|
|
568
|
+
} else {
|
|
569
|
+
let Some(decl_id) = self.resolve_lexical_owner(lexical_nesting_id, id) else {
|
|
570
|
+
continue;
|
|
571
|
+
};
|
|
572
|
+
decl_id
|
|
573
|
+
};
|
|
574
|
+
|
|
575
|
+
let Some(Declaration::Namespace(namespace)) = self.graph.declarations().get(&owner_id) else {
|
|
576
|
+
continue;
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
if let Some(member) = namespace
|
|
580
|
+
.member(&target)
|
|
581
|
+
.and_then(|member_id| self.graph.declarations().get(member_id))
|
|
582
|
+
&& matches!(
|
|
583
|
+
member,
|
|
584
|
+
Declaration::Constant(_)
|
|
585
|
+
| Declaration::ConstantAlias(_)
|
|
586
|
+
| Declaration::Namespace(Namespace::Class(_) | Namespace::Module(_))
|
|
587
|
+
)
|
|
588
|
+
{
|
|
589
|
+
// `add_declaration` deduplicates by fully qualified name, so this appends
|
|
590
|
+
// the visibility definition to the existing constant declaration.
|
|
591
|
+
self.graph.add_declaration(id, member.name().to_string(), |name| {
|
|
592
|
+
Declaration::Constant(Box::new(ConstantDeclaration::new(name, owner_id)))
|
|
593
|
+
});
|
|
594
|
+
} else {
|
|
595
|
+
let diagnostic = Diagnostic::new(
|
|
596
|
+
Rule::UndefinedConstantVisibilityTarget,
|
|
597
|
+
uri_id,
|
|
598
|
+
offset,
|
|
599
|
+
format!(
|
|
600
|
+
"undefined constant `{constant_name}` for visibility change in `{}`",
|
|
601
|
+
namespace.name()
|
|
602
|
+
),
|
|
603
|
+
);
|
|
604
|
+
self.graph.add_document_diagnostic(uri_id, diagnostic);
|
|
605
|
+
}
|
|
543
606
|
}
|
|
544
607
|
Definition::MethodVisibility(_) => {
|
|
545
608
|
method_visibility_ids.push(id);
|
|
@@ -557,7 +620,8 @@ impl<'a> Resolver<'a> {
|
|
|
557
620
|
self.resolve_method_visibilities(method_visibility_ids);
|
|
558
621
|
}
|
|
559
622
|
|
|
560
|
-
/// Resolves retroactive method visibility changes (`private :foo`, `protected :foo`, `public :foo
|
|
623
|
+
/// Resolves retroactive method visibility changes (`private :foo`, `protected :foo`, `public :foo`,
|
|
624
|
+
/// `private_class_method :foo`, `public_class_method :foo`).
|
|
561
625
|
///
|
|
562
626
|
/// Runs as a second pass after all methods/attrs are declared, so `private :bar` works
|
|
563
627
|
/// regardless of whether `def bar` appeared before or after it in source.
|
|
@@ -573,11 +637,21 @@ impl<'a> Resolver<'a> {
|
|
|
573
637
|
let uri_id = *method_visibility.uri_id();
|
|
574
638
|
let offset = method_visibility.offset().clone();
|
|
575
639
|
let lexical_nesting_id = *method_visibility.lexical_nesting_id();
|
|
640
|
+
let is_singleton = method_visibility.flags().is_singleton_method_visibility();
|
|
576
641
|
|
|
577
|
-
let Some(
|
|
642
|
+
let Some(lexical_owner_id) = self.resolve_lexical_owner(lexical_nesting_id, id) else {
|
|
578
643
|
continue;
|
|
579
644
|
};
|
|
580
645
|
|
|
646
|
+
let owner_id = if is_singleton {
|
|
647
|
+
let Some(singleton_id) = self.get_or_create_singleton_class(lexical_owner_id, true) else {
|
|
648
|
+
continue;
|
|
649
|
+
};
|
|
650
|
+
singleton_id
|
|
651
|
+
} else {
|
|
652
|
+
lexical_owner_id
|
|
653
|
+
};
|
|
654
|
+
|
|
581
655
|
let Some(Declaration::Namespace(namespace)) = self.graph.declarations().get(&owner_id) else {
|
|
582
656
|
continue;
|
|
583
657
|
};
|
|
@@ -626,13 +700,20 @@ impl<'a> Resolver<'a> {
|
|
|
626
700
|
Rule::UndefinedMethodVisibilityTarget,
|
|
627
701
|
uri_id,
|
|
628
702
|
offset,
|
|
629
|
-
format!("undefined method `{method_name}` for visibility change
|
|
703
|
+
format!("undefined method `{owner_name}#{method_name}` for visibility change"),
|
|
630
704
|
);
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
.
|
|
635
|
-
.
|
|
705
|
+
if is_singleton {
|
|
706
|
+
// Document-scoped: the singleton class may be synthetic (created by this
|
|
707
|
+
// visibility resolution) and won't be cleaned up on file delete, so attaching
|
|
708
|
+
// the diagnostic to the declaration would leave it orphaned.
|
|
709
|
+
self.graph.add_document_diagnostic(uri_id, diagnostic);
|
|
710
|
+
} else {
|
|
711
|
+
self.graph
|
|
712
|
+
.declarations_mut()
|
|
713
|
+
.get_mut(&owner_id)
|
|
714
|
+
.unwrap()
|
|
715
|
+
.add_diagnostic(diagnostic);
|
|
716
|
+
}
|
|
636
717
|
}
|
|
637
718
|
}
|
|
638
719
|
|
|
@@ -640,6 +721,19 @@ impl<'a> Resolver<'a> {
|
|
|
640
721
|
self.graph.extend_work(pending_work);
|
|
641
722
|
}
|
|
642
723
|
|
|
724
|
+
/// Resolves a constant receiver for `handle_remaining_definitions`.
|
|
725
|
+
/// If the receiver name is unresolved, preserve the definition for a later
|
|
726
|
+
/// resolve cycle instead of dropping work during an incremental delete/re-add gap.
|
|
727
|
+
fn resolve_constant_receiver(&mut self, name_id: NameId, id: DefinitionId) -> Option<DeclarationId> {
|
|
728
|
+
match self.graph.names().get(&name_id).unwrap() {
|
|
729
|
+
NameRef::Resolved(resolved) => Some(*resolved.declaration_id()),
|
|
730
|
+
NameRef::Unresolved(_) => {
|
|
731
|
+
self.graph.push_work(Unit::Definition(id));
|
|
732
|
+
None
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
|
|
643
737
|
fn create_declaration<F>(
|
|
644
738
|
&mut self,
|
|
645
739
|
str_id: StringId,
|
|
@@ -689,37 +783,62 @@ impl<'a> Resolver<'a> {
|
|
|
689
783
|
}
|
|
690
784
|
|
|
691
785
|
/// Resolves owner from lexical nesting.
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
786
|
+
///
|
|
787
|
+
/// If the owner cannot be resolved yet, re-queues the current definition so
|
|
788
|
+
/// a later resolve cycle can retry instead of permanently dropping it.
|
|
789
|
+
fn resolve_lexical_owner(
|
|
790
|
+
&mut self,
|
|
791
|
+
lexical_nesting_id: Option<DefinitionId>,
|
|
792
|
+
definition_id: DefinitionId,
|
|
793
|
+
) -> Option<DeclarationId> {
|
|
794
|
+
let mut current_nesting = lexical_nesting_id;
|
|
696
795
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
let definition = self.graph.definitions().get(&id).unwrap();
|
|
702
|
-
return self.resolve_lexical_owner(*definition.lexical_nesting_id());
|
|
703
|
-
};
|
|
796
|
+
let resolved = loop {
|
|
797
|
+
let Some(id) = current_nesting else {
|
|
798
|
+
break Some(*OBJECT_ID);
|
|
799
|
+
};
|
|
704
800
|
|
|
705
|
-
|
|
801
|
+
// If no declaration exists yet for this definition, walk up the lexical chain.
|
|
802
|
+
// This handles the case where attr_* definitions inside methods are processed
|
|
803
|
+
// before the method definition itself. A SingletonClass with no declaration
|
|
804
|
+
// is an exception: returning the surrounding scope would attach its members to
|
|
805
|
+
// the wrong owner (e.g. `Object`) and never recover, so retry later instead.
|
|
806
|
+
let Some(declaration_id) = self.graph.definition_id_to_declaration_id(id) else {
|
|
807
|
+
let definition = self.graph.definitions().get(&id).unwrap();
|
|
808
|
+
if matches!(definition, Definition::SingletonClass(_)) {
|
|
809
|
+
break None;
|
|
810
|
+
}
|
|
811
|
+
current_nesting = *definition.lexical_nesting_id();
|
|
812
|
+
continue;
|
|
813
|
+
};
|
|
814
|
+
|
|
815
|
+
let decl = self.graph.declarations().get(declaration_id).unwrap();
|
|
816
|
+
|
|
817
|
+
// If the associated declaration is a namespace that can own things, we found the right owner. Otherwise, we might
|
|
818
|
+
// have found something nested inside something else (like a method), in which case we have to walk up until we find
|
|
819
|
+
// the appropriate owner.
|
|
820
|
+
if matches!(
|
|
821
|
+
decl,
|
|
822
|
+
Declaration::Namespace(Namespace::Class(_) | Namespace::Module(_) | Namespace::SingletonClass(_))
|
|
823
|
+
) {
|
|
824
|
+
break Some(*declaration_id);
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
if matches!(decl, Declaration::ConstantAlias(_)) {
|
|
828
|
+
// Follow the alias chain to find the target namespace. If the alias is unresolved,
|
|
829
|
+
// the definition cannot be properly owned yet and should be retried later.
|
|
830
|
+
break self.resolve_to_namespace(*declaration_id);
|
|
831
|
+
}
|
|
706
832
|
|
|
707
|
-
// If the associated declaration is a namespace that can own things, we found the right owner. Otherwise, we might
|
|
708
|
-
// have found something nested inside something else (like a method), in which case we have to recurse until we find
|
|
709
|
-
// the appropriate owner
|
|
710
|
-
if matches!(
|
|
711
|
-
decl,
|
|
712
|
-
Declaration::Namespace(Namespace::Class(_) | Namespace::Module(_) | Namespace::SingletonClass(_))
|
|
713
|
-
) {
|
|
714
|
-
Some(*declaration_id)
|
|
715
|
-
} else if matches!(decl, Declaration::ConstantAlias(_)) {
|
|
716
|
-
// Follow the alias chain to find the target namespace. If the alias is unresolved,
|
|
717
|
-
// the definition cannot be properly owned and should be skipped by the caller.
|
|
718
|
-
self.resolve_to_namespace(*declaration_id)
|
|
719
|
-
} else {
|
|
720
833
|
let definition = self.graph.definitions().get(&id).unwrap();
|
|
721
|
-
|
|
834
|
+
current_nesting = *definition.lexical_nesting_id();
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
if resolved.is_none() {
|
|
838
|
+
self.graph.push_work(Unit::Definition(definition_id));
|
|
722
839
|
}
|
|
840
|
+
|
|
841
|
+
resolved
|
|
723
842
|
}
|
|
724
843
|
|
|
725
844
|
/// Gets or creates a singleton class declaration for a given class/module declaration. For class `Foo`, this
|
|
@@ -1124,11 +1243,17 @@ impl<'a> Resolver<'a> {
|
|
|
1124
1243
|
let name_ref = self.graph.names().get(&name_id).unwrap();
|
|
1125
1244
|
let str_id = *name_ref.str();
|
|
1126
1245
|
|
|
1127
|
-
let outcome = match self.name_owner_id(name_id) {
|
|
1246
|
+
let outcome = match self.name_owner_id(name_id, singleton) {
|
|
1128
1247
|
// name_owner_id returns Unresolved(None) only when the parent scope is genuinely unknown
|
|
1129
1248
|
// (e.g., `class A::B::C` where `A` doesn't exist). This definition needs an owner, so
|
|
1130
1249
|
// create Todo placeholders for the missing parent chain. Todos get promoted when real
|
|
1131
1250
|
// definitions appear later.
|
|
1251
|
+
//
|
|
1252
|
+
// Singleton classes are the exception: `class << UndefinedReceiver` attaches via
|
|
1253
|
+
// `set_singleton_class_id`, not `add_member`, so a TODO receiver would never gain a
|
|
1254
|
+
// member. Emit Retry so the unit is preserved for a later resolve where the receiver
|
|
1255
|
+
// may exist.
|
|
1256
|
+
Outcome::Unresolved(None) if singleton => Outcome::Retry(None),
|
|
1132
1257
|
Outcome::Unresolved(None) => Outcome::Resolved(self.create_todo_for_parent(name_id), None),
|
|
1133
1258
|
other => other,
|
|
1134
1259
|
};
|
|
@@ -1200,7 +1325,11 @@ impl<'a> Resolver<'a> {
|
|
|
1200
1325
|
// Returns the owner declaration ID for a given name. If the name is simple and has no parent scope, then the owner is
|
|
1201
1326
|
// either the nesting or Object. If the name has a parent scope, we attempt to resolve the reference and that should be
|
|
1202
1327
|
// the name's owner. For aliases, resolves through to get the actual namespace.
|
|
1203
|
-
|
|
1328
|
+
//
|
|
1329
|
+
// When `preserve_retry` is true, Retry from resolve_constant_internal is NOT folded into
|
|
1330
|
+
// Unresolved(None). This is used by the singleton path so the unit can retry when the
|
|
1331
|
+
// receiver might resolve later rather than being dropped.
|
|
1332
|
+
fn name_owner_id(&mut self, name_id: NameId, preserve_retry: bool) -> Outcome {
|
|
1204
1333
|
let name_ref = self.graph.names().get(&name_id).unwrap();
|
|
1205
1334
|
|
|
1206
1335
|
if let Some(&parent_scope) = name_ref.parent_scope().as_ref() {
|
|
@@ -1210,7 +1339,8 @@ impl<'a> Resolver<'a> {
|
|
|
1210
1339
|
Outcome::Resolved(id, linearization) => self.resolve_to_primary_namespace(id, linearization),
|
|
1211
1340
|
// The parent scope is genuinely unknown — not a circular alias or pending
|
|
1212
1341
|
// linearization, but a name that doesn't exist anywhere in the graph.
|
|
1213
|
-
Outcome::
|
|
1342
|
+
Outcome::Unresolved(None) => Outcome::Unresolved(None),
|
|
1343
|
+
Outcome::Retry(None) if !preserve_retry => Outcome::Unresolved(None),
|
|
1214
1344
|
other => other,
|
|
1215
1345
|
}
|
|
1216
1346
|
} else if let Some(nesting_id) = name_ref.nesting()
|
|
@@ -1251,7 +1381,7 @@ impl<'a> Resolver<'a> {
|
|
|
1251
1381
|
// Object so it becomes top-level `A`. This way `module A; end` appearing later
|
|
1252
1382
|
// promotes it correctly. Using nesting would incorrectly create `SomeModule::A`.
|
|
1253
1383
|
let parent_owner_id = if parent_has_parent_scope {
|
|
1254
|
-
match self.name_owner_id(parent_scope) {
|
|
1384
|
+
match self.name_owner_id(parent_scope, false) {
|
|
1255
1385
|
Outcome::Resolved(id, _) => id,
|
|
1256
1386
|
_ => self.create_todo_for_parent(parent_scope),
|
|
1257
1387
|
}
|
|
@@ -1768,7 +1898,7 @@ impl<'a> Resolver<'a> {
|
|
|
1768
1898
|
singleton_methods.push(Unit::Definition(id));
|
|
1769
1899
|
}
|
|
1770
1900
|
_ => {
|
|
1771
|
-
others.push(id);
|
|
1901
|
+
others.push((id, (*definition.uri_id(), definition.offset())));
|
|
1772
1902
|
}
|
|
1773
1903
|
}
|
|
1774
1904
|
}
|
|
@@ -1808,14 +1938,15 @@ impl<'a> Resolver<'a> {
|
|
|
1808
1938
|
(depths.get(name_a).unwrap(), uri_a, offset_a).cmp(&(depths.get(name_b).unwrap(), uri_b, offset_b))
|
|
1809
1939
|
});
|
|
1810
1940
|
|
|
1941
|
+
others.sort_unstable_by_key(|(_, key)| *key);
|
|
1942
|
+
|
|
1811
1943
|
// Definitions first, then constant refs, then singleton methods, then ancestors
|
|
1812
1944
|
self.unit_queue.extend(definitions.into_iter().map(|(id, _)| id));
|
|
1813
1945
|
self.unit_queue.extend(const_refs.into_iter().map(|(id, _)| id));
|
|
1814
1946
|
self.unit_queue.extend(singleton_methods);
|
|
1815
1947
|
self.unit_queue.extend(ancestors.into_iter().map(Unit::Ancestors));
|
|
1816
1948
|
|
|
1817
|
-
others.
|
|
1818
|
-
others
|
|
1949
|
+
others.into_iter().map(|(id, _)| id).collect()
|
|
1819
1950
|
}
|
|
1820
1951
|
|
|
1821
1952
|
/// Returns the singleton parent ID for an attached object ID. A singleton class' parent depends on what the attached
|