From 3782ccf028a1e15d3836c53996a31bd793f1b3ab Mon Sep 17 00:00:00 2001 From: Douglas Creager Date: Mon, 19 May 2025 18:09:43 -0400 Subject: [PATCH] walk the scopes --- crates/ty_python_semantic/src/types.rs | 4 ++ .../ty_python_semantic/src/types/generics.rs | 9 ++++ crates/ty_python_semantic/src/types/infer.rs | 44 ++++++++++++++++++- 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index 7c64993ae8..8d7a71d235 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -6867,6 +6867,10 @@ impl<'db> FunctionType<'db> { } } + pub(crate) fn non_overloaded_signature(self, db: &'db dyn Db) -> Signature<'db> { + self.internal_signature(db, self.inherited_generic_context(db)) + } + /// Typed internally-visible signature for this function. /// /// This represents the annotations on the function itself, unmodified by decorators and diff --git a/crates/ty_python_semantic/src/types/generics.rs b/crates/ty_python_semantic/src/types/generics.rs index 35829c6c5c..7128a9e56b 100644 --- a/crates/ty_python_semantic/src/types/generics.rs +++ b/crates/ty_python_semantic/src/types/generics.rs @@ -105,6 +105,15 @@ impl<'db> GenericContext<'db> { Some(Self::new(db, variables, GenericContextOrigin::Inherited)) } + pub(crate) fn is_legacy(self, db: &'db dyn Db) -> bool { + matches!( + self.origin(db), + GenericContextOrigin::LegacyBase(_) + | GenericContextOrigin::Inherited + | GenericContextOrigin::LegacyGenericFunction + ) + } + pub(crate) fn len(self, db: &'db dyn Db) -> usize { self.variables(db).len() } diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs index 7359649a3f..dd6ac49831 100644 --- a/crates/ty_python_semantic/src/types/infer.rs +++ b/crates/ty_python_semantic/src/types/infer.rs @@ -355,6 +355,42 @@ pub(crate) fn enclosing_class_symbol<'db>( }) } +/// Returns in iterator of any generic context introduced by the given scope or any enclosing +/// scope. +pub(crate) fn enclosing_generic_contexts<'db>( + db: &'db dyn Db, + index: &SemanticIndex<'db>, + scope: ScopeId, +) -> impl Iterator> { + index + .ancestor_scopes(scope.file_scope_id(db)) + .filter_map(|(_, ancestor_scope)| match ancestor_scope.node() { + NodeWithScopeKind::Class(class) => { + binding_type(db, index.expect_single_definition(class.node())) + .into_class_literal()? + .generic_context(db) + } + NodeWithScopeKind::Function(function) => { + binding_type(db, index.expect_single_definition(function.node())) + .into_function_literal()? + .non_overloaded_signature(db) + .generic_context + } + _ => None, + }) +} + +/// Returns the legacy typevars that have been bound in the given scope or any enclosing scope. +pub(crate) fn bound_legacy_typevars<'db>( + db: &'db dyn Db, + index: &'db SemanticIndex<'db>, + scope: ScopeId, +) -> impl Iterator> { + enclosing_generic_contexts(db, index, scope) + .filter(|generic_context| generic_context.is_legacy(db)) + .flat_map(|generic_context| generic_context.variables(db).iter().copied()) +} + /// A region within which we can infer types. #[derive(Copy, Clone, Debug)] pub(crate) enum InferenceRegion<'db> { @@ -4233,7 +4269,7 @@ impl<'db> TypeInferenceBuilder<'db> { } fn infer_expression_impl(&mut self, expression: &ast::Expr) -> Type<'db> { - let ty = match expression { + let mut ty = match expression { ast::Expr::NoneLiteral(ast::ExprNoneLiteral { range: _ }) => Type::none(self.db()), ast::Expr::NumberLiteral(literal) => self.infer_number_literal_expression(literal), ast::Expr::BooleanLiteral(literal) => self.infer_boolean_literal_expression(literal), @@ -4274,6 +4310,12 @@ impl<'db> TypeInferenceBuilder<'db> { } }; + // If the expression resolves to a legacy typevar, we will have the TypeVarInstance that + // was created when the typevar was created, which will not have an associated definition. + // Walk the enclosing scopes, looking for the nearest generic context that binds the + // typevar. + if let Type::TypeVar(typevar) = f + self.store_expression_type(expression, ty); ty