[ty] fix non-deterministic overload function inference (#20966)

This commit is contained in:
Shunsuke Shibayama 2025-10-19 19:13:10 +09:00 committed by GitHub
parent 1f8297cfe6
commit 36d4b02fa9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -106,7 +106,7 @@ use crate::types::{
}; };
use crate::types::{ClassBase, add_inferred_python_version_hint_to_diagnostic}; use crate::types::{ClassBase, add_inferred_python_version_hint_to_diagnostic};
use crate::unpack::{EvaluationMode, UnpackPosition}; use crate::unpack::{EvaluationMode, UnpackPosition};
use crate::{Db, FxOrderSet, Program}; use crate::{Db, FxIndexSet, FxOrderSet, Program};
mod annotation_expression; mod annotation_expression;
mod type_expression; mod type_expression;
@ -257,8 +257,10 @@ pub(super) struct TypeInferenceBuilder<'db, 'ast> {
/// return x /// return x
/// ``` /// ```
/// ///
/// To keep the calculation deterministic, we use an `FxIndexSet` whose order is determined by the sequence of insertion calls.
///
/// [`check_overloaded_functions`]: TypeInferenceBuilder::check_overloaded_functions /// [`check_overloaded_functions`]: TypeInferenceBuilder::check_overloaded_functions
called_functions: FxHashSet<FunctionType<'db>>, called_functions: FxIndexSet<FunctionType<'db>>,
/// Whether we are in a context that binds unbound typevars. /// Whether we are in a context that binds unbound typevars.
typevar_binding_context: Option<Definition<'db>>, typevar_binding_context: Option<Definition<'db>>,
@ -312,7 +314,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
region, region,
scope, scope,
return_types_and_ranges: vec![], return_types_and_ranges: vec![],
called_functions: FxHashSet::default(), called_functions: FxIndexSet::default(),
deferred_state: DeferredExpressionState::None, deferred_state: DeferredExpressionState::None,
multi_inference_state: MultiInferenceState::Panic, multi_inference_state: MultiInferenceState::Panic,
expressions: FxHashMap::default(), expressions: FxHashMap::default(),
@ -949,7 +951,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
// Collect all the unique overloaded function places in this scope. This requires a set // Collect all the unique overloaded function places in this scope. This requires a set
// because an overloaded function uses the same place for each of the overloads and the // because an overloaded function uses the same place for each of the overloads and the
// implementation. // implementation.
let overloaded_function_places: FxHashSet<_> = self let overloaded_function_places: FxIndexSet<_> = self
.declarations .declarations
.iter() .iter()
.filter_map(|(definition, ty)| { .filter_map(|(definition, ty)| {
@ -971,7 +973,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
.index .index
.use_def_map(self.scope().file_scope_id(self.db())); .use_def_map(self.scope().file_scope_id(self.db()));
let mut public_functions = FxHashSet::default(); let mut public_functions = FxIndexSet::default();
for place in overloaded_function_places { for place in overloaded_function_places {
if let Place::Defined(Type::FunctionLiteral(function), _, Definedness::AlwaysDefined) = if let Place::Defined(Type::FunctionLiteral(function), _, Definedness::AlwaysDefined) =