@@ -711,12 +711,43 @@ impl<'a> SemanticModel<'a> {
711
711
/// References from within an [`ast::Comprehension`] can produce incorrect
712
712
/// results when referring to a [`BindingKind::NamedExprAssignment`].
713
713
pub fn simulate_runtime_load ( & self , name : & ast:: ExprName ) -> Option < BindingId > {
714
- let symbol = name. id . as_str ( ) ;
715
- let range = name. range ;
714
+ self . simulate_runtime_load_at_location_in_scope ( name. id . as_str ( ) , name. range , self . scope_id )
715
+ }
716
+
717
+ /// Simulates a runtime load of the given symbol.
718
+ ///
719
+ /// This should not be run until after all the bindings have been visited.
720
+ ///
721
+ /// The main purpose of this method and what makes this different from
722
+ /// [`SemanticModel::lookup_symbol_in_scope`] is that it may be used to
723
+ /// perform speculative name lookups.
724
+ ///
725
+ /// In most cases a load can be accurately modeled simply by calling
726
+ /// [`SemanticModel::lookup_symbol`] at the right time during semantic
727
+ /// analysis, however for speculative lookups this is not the case,
728
+ /// since we're aiming to change the semantic meaning of our load.
729
+ /// E.g. we want to check what would happen if we changed a forward
730
+ /// reference to an immediate load or vice versa.
731
+ ///
732
+ /// Use caution when utilizing this method, since it was primarily designed
733
+ /// to work for speculative lookups from within type definitions, which
734
+ /// happen to share some nice properties, where attaching each binding
735
+ /// to a range in the source code and ordering those bindings based on
736
+ /// that range is a good enough approximation of which bindings are
737
+ /// available at runtime for which reference.
738
+ ///
739
+ /// References from within an [`ast::Comprehension`] can produce incorrect
740
+ /// results when referring to a [`BindingKind::NamedExprAssignment`].
741
+ pub fn simulate_runtime_load_at_location_in_scope (
742
+ & self ,
743
+ symbol : & str ,
744
+ symbol_range : TextRange ,
745
+ scope_id : ScopeId ,
746
+ ) -> Option < BindingId > {
716
747
let mut seen_function = false ;
717
748
let mut class_variables_visible = true ;
718
749
let mut source_order_sensitive_lookup = true ;
719
- for ( index, scope_id) in self . scopes . ancestor_ids ( self . scope_id ) . enumerate ( ) {
750
+ for ( index, scope_id) in self . scopes . ancestor_ids ( scope_id) . enumerate ( ) {
720
751
let scope = & self . scopes [ scope_id] ;
721
752
722
753
// Only once we leave a function scope and its enclosing type scope should
@@ -776,7 +807,7 @@ impl<'a> SemanticModel<'a> {
776
807
_ => binding. range ,
777
808
} ;
778
809
779
- if binding_range. ordering ( range ) . is_lt ( ) {
810
+ if binding_range. ordering ( symbol_range ) . is_lt ( ) {
780
811
return Some ( shadowed_id) ;
781
812
}
782
813
}
0 commit comments