diff --git a/crates/ty_python_semantic/resources/mdtest/boundness_declaredness/public.md b/crates/ty_python_semantic/resources/mdtest/boundness_declaredness/public.md index 5dc20fa1d48bae..fd596758babcdb 100644 --- a/crates/ty_python_semantic/resources/mdtest/boundness_declaredness/public.md +++ b/crates/ty_python_semantic/resources/mdtest/boundness_declaredness/public.md @@ -237,11 +237,11 @@ b: SomeUnknownName = 1 # error: [unresolved-reference] ```py from mod import a, b -reveal_type(a) # revealed: Unknown | Literal[1] +reveal_type(a) # revealed: int reveal_type(b) # revealed: Unknown # All external modifications of `a` are allowed: -a = None +a = None # error: [invalid-assignment] ``` ### Undeclared and possibly unbound @@ -265,11 +265,11 @@ if flag: # on top of this document. from mod import a, b -reveal_type(a) # revealed: Unknown | Literal[1] +reveal_type(a) # revealed: int reveal_type(b) # revealed: Unknown # All external modifications of `a` are allowed: -a = None +a = None # error: [invalid-assignment] ``` ### Undeclared and unbound diff --git a/crates/ty_python_semantic/resources/mdtest/del.md b/crates/ty_python_semantic/resources/mdtest/del.md index e0d8a495c2afaa..ece1b79d7cbdde 100644 --- a/crates/ty_python_semantic/resources/mdtest/del.md +++ b/crates/ty_python_semantic/resources/mdtest/del.md @@ -108,7 +108,7 @@ def foo(): global x def bar(): # allowed, refers to `x` in the global scope - reveal_type(x) # revealed: Unknown | Literal[1] + reveal_type(x) # revealed: int bar() del x # allowed, deletes `x` in the global scope (though we don't track that) ``` diff --git a/crates/ty_python_semantic/resources/mdtest/import/conditional.md b/crates/ty_python_semantic/resources/mdtest/import/conditional.md index d2896ae2cd27af..679a96ba2ea2a0 100644 --- a/crates/ty_python_semantic/resources/mdtest/import/conditional.md +++ b/crates/ty_python_semantic/resources/mdtest/import/conditional.md @@ -25,8 +25,8 @@ reveal_type(y) # error: [possibly-missing-import] "Member `y` of module `maybe_unbound` may be missing" from maybe_unbound import x, y -reveal_type(x) # revealed: Unknown | Literal[3] -reveal_type(y) # revealed: Unknown | Literal[3] +reveal_type(x) # revealed: int +reveal_type(y) # revealed: int ``` ## Maybe unbound annotated @@ -56,7 +56,7 @@ Importing an annotated name prefers the declared type over the inferred type: # error: [possibly-missing-import] "Member `y` of module `maybe_unbound_annotated` may be missing" from maybe_unbound_annotated import x, y -reveal_type(x) # revealed: Unknown | Literal[3] +reveal_type(x) # revealed: int reveal_type(y) # revealed: int ``` diff --git a/crates/ty_python_semantic/resources/mdtest/import/dunder_all.md b/crates/ty_python_semantic/resources/mdtest/import/dunder_all.md index 1fcdefb2ddbf37..d80301f8517a26 100644 --- a/crates/ty_python_semantic/resources/mdtest/import/dunder_all.md +++ b/crates/ty_python_semantic/resources/mdtest/import/dunder_all.md @@ -784,7 +784,7 @@ class A: ... from subexporter import * # TODO: Should we avoid including `Unknown` for this case? -reveal_type(__all__) # revealed: Unknown | list[Unknown | str] +reveal_type(__all__) # revealed: list[Unknown | str] __all__.append("B") diff --git a/crates/ty_python_semantic/resources/mdtest/import/module_getattr.md b/crates/ty_python_semantic/resources/mdtest/import/module_getattr.md index 8e947ab655b8da..7d1665ef9653cf 100644 --- a/crates/ty_python_semantic/resources/mdtest/import/module_getattr.md +++ b/crates/ty_python_semantic/resources/mdtest/import/module_getattr.md @@ -40,10 +40,10 @@ def __getattr__(name: str) -> int: import mixed_module # Explicit attribute should take precedence -reveal_type(mixed_module.explicit_attr) # revealed: Unknown | Literal["explicit"] +reveal_type(mixed_module.explicit_attr) # revealed: str # `__getattr__` should handle unknown attributes -reveal_type(mixed_module.dynamic_attr) # revealed: str +reveal_type(mixed_module.dynamic_attr) # revealed: int ``` `mixed_module.py`: @@ -51,8 +51,8 @@ reveal_type(mixed_module.dynamic_attr) # revealed: str ```py explicit_attr = "explicit" -def __getattr__(name: str) -> str: - return "dynamic" +def __getattr__(name: str) -> int: + return 1 ``` ## Precedence: submodules vs `__getattr__` diff --git a/crates/ty_python_semantic/resources/mdtest/import/namespace.md b/crates/ty_python_semantic/resources/mdtest/import/namespace.md index 3b5f63e9818b35..af7d1ab036a9d8 100644 --- a/crates/ty_python_semantic/resources/mdtest/import/namespace.md +++ b/crates/ty_python_semantic/resources/mdtest/import/namespace.md @@ -91,19 +91,23 @@ If there's a namespace package with the same name as a module, the module takes `foo.py`: ```py -x = "module" +class FromModule: ... + +x = FromModule ``` `foo/bar.py`: ```py -x = "namespace" +class FromNamespace: ... + +x = FromNamespace ``` ```py from foo import x -reveal_type(x) # revealed: Unknown | Literal["module"] +reveal_type(x) # revealed: import foo.bar # error: [unresolved-import] ``` diff --git a/crates/ty_python_semantic/resources/mdtest/import/star.md b/crates/ty_python_semantic/resources/mdtest/import/star.md index c66012b10396cb..ae7dc6bb9858b6 100644 --- a/crates/ty_python_semantic/resources/mdtest/import/star.md +++ b/crates/ty_python_semantic/resources/mdtest/import/star.md @@ -144,8 +144,8 @@ X = (Y := 3) + 4 ```py from exporter import * -reveal_type(X) # revealed: Unknown | Literal[7] -reveal_type(Y) # revealed: Unknown | Literal[3] +reveal_type(X) # revealed: int +reveal_type(Y) # revealed: int ``` ### Global-scope symbols defined in many other ways @@ -781,9 +781,9 @@ else: from exporter import * # error: [possibly-unresolved-reference] -reveal_type(A) # revealed: Unknown | Literal[1] +reveal_type(A) # revealed: int -reveal_type(B) # revealed: Unknown | Literal[2, 3] +reveal_type(B) # revealed: int ``` ### Reachability constraints in the importing module @@ -804,7 +804,7 @@ if coinflip(): from exporter import * # error: [possibly-unresolved-reference] -reveal_type(A) # revealed: Unknown | Literal[1] +reveal_type(A) # revealed: int ``` ### Reachability constraints in the exporting module *and* the importing module diff --git a/crates/ty_python_semantic/resources/mdtest/known_constants.md b/crates/ty_python_semantic/resources/mdtest/known_constants.md index db53b807dcac93..91b8b579a9ce12 100644 --- a/crates/ty_python_semantic/resources/mdtest/known_constants.md +++ b/crates/ty_python_semantic/resources/mdtest/known_constants.md @@ -95,7 +95,7 @@ TYPE_CHECKING: bool = ... ```py from constants import TYPE_CHECKING -reveal_type(TYPE_CHECKING) # revealed: Literal[True] +reveal_type(TYPE_CHECKING) # revealed: bool from stub import TYPE_CHECKING diff --git a/crates/ty_python_semantic/resources/mdtest/narrow/assignment.md b/crates/ty_python_semantic/resources/mdtest/narrow/assignment.md index 8f329502525389..f692c59835a1c4 100644 --- a/crates/ty_python_semantic/resources/mdtest/narrow/assignment.md +++ b/crates/ty_python_semantic/resources/mdtest/narrow/assignment.md @@ -34,7 +34,7 @@ class _: [reveal_type(a.z) for _ in range(1)] # revealed: Literal[0] def _(): - reveal_type(a.x) # revealed: Unknown | int | None + reveal_type(a.x) # revealed: int | None reveal_type(a.y) # revealed: Unknown | None reveal_type(a.z) # revealed: Unknown | None @@ -75,7 +75,7 @@ class _: if cond(): a = A() - reveal_type(a.x) # revealed: int | None | Unknown + reveal_type(a.x) # revealed: int | None reveal_type(a.y) # revealed: Unknown | None reveal_type(a.z) # revealed: Unknown | None @@ -295,10 +295,10 @@ class C: def _(): # error: [possibly-missing-attribute] - reveal_type(b.a.x[0]) # revealed: Unknown | int | None + reveal_type(b.a.x[0]) # revealed: int | None # error: [possibly-missing-attribute] - reveal_type(b.a.x) # revealed: Unknown | list[int | None] - reveal_type(b.a) # revealed: Unknown | A | None + reveal_type(b.a.x) # revealed: list[int | None] + reveal_type(b.a) # revealed: A | None ``` ## Invalid assignments are not used for narrowing diff --git a/crates/ty_python_semantic/resources/mdtest/narrow/complex_target.md b/crates/ty_python_semantic/resources/mdtest/narrow/complex_target.md index 5a61c9e8d299f0..479238d617cea2 100644 --- a/crates/ty_python_semantic/resources/mdtest/narrow/complex_target.md +++ b/crates/ty_python_semantic/resources/mdtest/narrow/complex_target.md @@ -167,11 +167,11 @@ if c.x is not None: if c.x is not None: def _(): - reveal_type(c.x) # revealed: Unknown | int | None + reveal_type(c.x) # revealed: int | None def _(): if c.x is not None: - reveal_type(c.x) # revealed: (Unknown & ~None) | int + reveal_type(c.x) # revealed: int ``` ## Subscript narrowing diff --git a/crates/ty_python_semantic/resources/mdtest/narrow/conditionals/nested.md b/crates/ty_python_semantic/resources/mdtest/narrow/conditionals/nested.md index dd10ff95859e01..f27b3deb08170d 100644 --- a/crates/ty_python_semantic/resources/mdtest/narrow/conditionals/nested.md +++ b/crates/ty_python_semantic/resources/mdtest/narrow/conditionals/nested.md @@ -86,7 +86,7 @@ class B: reveal_type(a.x) # revealed: Literal["a"] def f(): - reveal_type(a.x) # revealed: Unknown | str | None + reveal_type(a.x) # revealed: str | None [reveal_type(a.x) for _ in range(1)] # revealed: Literal["a"] @@ -96,7 +96,7 @@ class C: reveal_type(a.x) # revealed: str | None def g(): - reveal_type(a.x) # revealed: Unknown | str | None + reveal_type(a.x) # revealed: str | None [reveal_type(a.x) for _ in range(1)] # revealed: str | None @@ -109,7 +109,7 @@ class D: reveal_type(a.x) # revealed: Literal["a"] def h(): - reveal_type(a.x) # revealed: Unknown | str | None + reveal_type(a.x) # revealed: str | None # TODO: should be `str | None` [reveal_type(a.x) for _ in range(1)] # revealed: Literal["a"] @@ -190,7 +190,7 @@ def f(x: str | None): reveal_type(g) # revealed: str if a.x is not None: - reveal_type(a.x) # revealed: (Unknown & ~None) | str + reveal_type(a.x) # revealed: str if l[0] is not None: reveal_type(l[0]) # revealed: str @@ -206,7 +206,7 @@ def f(x: str | None): reveal_type(g) # revealed: str if a.x is not None: - reveal_type(a.x) # revealed: (Unknown & ~None) | str + reveal_type(a.x) # revealed: str if l[0] is not None: reveal_type(l[0]) # revealed: str @@ -382,12 +382,12 @@ def f(): if a.x is not None: def _(): # Lazy nested scope narrowing is not performed on attributes/subscripts because it's difficult to track their changes. - reveal_type(a.x) # revealed: Unknown | str | None + reveal_type(a.x) # revealed: str | None class D: - reveal_type(a.x) # revealed: (Unknown & ~None) | str + reveal_type(a.x) # revealed: str - [reveal_type(a.x) for _ in range(1)] # revealed: (Unknown & ~None) | str + [reveal_type(a.x) for _ in range(1)] # revealed: str if l[0] is not None: def _(): @@ -473,11 +473,11 @@ def f(): if a.x is not None: def _(): if a.x != 1: - reveal_type(a.x) # revealed: (Unknown & ~Literal[1]) | str | None + reveal_type(a.x) # revealed: str | None class D: if a.x != 1: - reveal_type(a.x) # revealed: (Unknown & ~Literal[1] & ~None) | str + reveal_type(a.x) # revealed: str if l[0] is not None: def _(): diff --git a/crates/ty_python_semantic/resources/mdtest/public_types.md b/crates/ty_python_semantic/resources/mdtest/public_types.md index 4a6ef1c6fb7e57..1f4d0a5ccac190 100644 --- a/crates/ty_python_semantic/resources/mdtest/public_types.md +++ b/crates/ty_python_semantic/resources/mdtest/public_types.md @@ -263,7 +263,7 @@ if flag(): x = 1 def f() -> None: - reveal_type(x) # revealed: Unknown | Literal[1, 2] + reveal_type(x) # revealed: int # Function only used inside this branch f() diff --git a/crates/ty_python_semantic/resources/mdtest/scopes/builtin.md b/crates/ty_python_semantic/resources/mdtest/scopes/builtin.md index ae684a22d92cd5..b1dd1fbef63ec6 100644 --- a/crates/ty_python_semantic/resources/mdtest/scopes/builtin.md +++ b/crates/ty_python_semantic/resources/mdtest/scopes/builtin.md @@ -29,8 +29,8 @@ if flag(): chr: int = 1 def _(): - # TODO: Should ideally be `Unknown | Literal[1] | (def abs(x: SupportsAbs[_T], /) -> _T)` - reveal_type(abs) # revealed: Unknown | Literal[1] + # TODO: Should ideally be `Literal[1] | (def abs(x: SupportsAbs[_T], /) -> _T)` + reveal_type(abs) # revealed: int # TODO: Should ideally be `int | (def chr(i: SupportsIndex, /) -> str)` reveal_type(chr) # revealed: int ``` diff --git a/crates/ty_python_semantic/resources/mdtest/scopes/eager.md b/crates/ty_python_semantic/resources/mdtest/scopes/eager.md index 286f2eb26163d4..d8fdd5e0c9ff09 100644 --- a/crates/ty_python_semantic/resources/mdtest/scopes/eager.md +++ b/crates/ty_python_semantic/resources/mdtest/scopes/eager.md @@ -12,7 +12,7 @@ Function definitions are evaluated lazily. x = 1 def f(): - reveal_type(x) # revealed: Unknown | Literal[1, 2] + reveal_type(x) # revealed: int x = 2 ``` @@ -283,7 +283,7 @@ x = 1 def _(): class C: - # revealed: Unknown | Literal[1] + # revealed: int [reveal_type(x) for _ in [1]] x = 2 ``` @@ -389,7 +389,7 @@ x = int class C: var: ClassVar[x] -reveal_type(C.var) # revealed: Unknown | int | str +reveal_type(C.var) # revealed: int | str x = str ``` diff --git a/crates/ty_python_semantic/resources/mdtest/scopes/global.md b/crates/ty_python_semantic/resources/mdtest/scopes/global.md index e7156e85de51d8..21479dc5f2f70c 100644 --- a/crates/ty_python_semantic/resources/mdtest/scopes/global.md +++ b/crates/ty_python_semantic/resources/mdtest/scopes/global.md @@ -8,7 +8,7 @@ A name reference to a never-defined symbol in a function is implicitly a global x = 1 def f(): - reveal_type(x) # revealed: Unknown | Literal[1] + reveal_type(x) # revealed: int ``` ## Explicit global in function @@ -18,7 +18,7 @@ x = 1 def f(): global x - reveal_type(x) # revealed: Unknown | Literal[1] + reveal_type(x) # revealed: int ``` ## Unassignable type in function @@ -201,7 +201,7 @@ x = 42 def f(): global x - reveal_type(x) # revealed: Unknown | Literal[42] + reveal_type(x) # revealed: int x = "56" reveal_type(x) # revealed: Literal["56"] ``` diff --git a/crates/ty_python_semantic/resources/mdtest/scopes/moduletype_attrs.md b/crates/ty_python_semantic/resources/mdtest/scopes/moduletype_attrs.md index 7c6c3e6d9ea32f..16240e81d966a2 100644 --- a/crates/ty_python_semantic/resources/mdtest/scopes/moduletype_attrs.md +++ b/crates/ty_python_semantic/resources/mdtest/scopes/moduletype_attrs.md @@ -73,10 +73,10 @@ __spec__ = 42 # error: [invalid-assignment] "Object of type `Literal[42]` is no ```py import module -reveal_type(module.__file__) # revealed: Unknown | None +reveal_type(module.__file__) # revealed: None reveal_type(module.__path__) # revealed: list[str] reveal_type(module.__doc__) # revealed: Unknown -reveal_type(module.__spec__) # revealed: Unknown | ModuleSpec | None +reveal_type(module.__spec__) # revealed: ModuleSpec | None # error: [unresolved-attribute] reveal_type(module.__warningregistry__) # revealed: Unknown diff --git a/crates/ty_python_semantic/resources/mdtest/scopes/unbound.md b/crates/ty_python_semantic/resources/mdtest/scopes/unbound.md index 43c8f5f5644e42..71b483cf87188e 100644 --- a/crates/ty_python_semantic/resources/mdtest/scopes/unbound.md +++ b/crates/ty_python_semantic/resources/mdtest/scopes/unbound.md @@ -17,7 +17,7 @@ class C: x = 2 # error: [possibly-missing-attribute] "Attribute `x` on type `` may be missing" -reveal_type(C.x) # revealed: Unknown | Literal[2] +reveal_type(C.x) # revealed: Unknown | int reveal_type(C.y) # revealed: Unknown | Literal[1] ``` @@ -37,7 +37,7 @@ class C: # Possibly unbound variables in enclosing scopes are considered bound. y = x -reveal_type(C.y) # revealed: Unknown | Literal[1, "abc"] +reveal_type(C.y) # revealed: Unknown | Literal[1] | str ``` ## Possibly unbound in class scope with multiple declarations diff --git a/crates/ty_python_semantic/resources/primer/bad.txt b/crates/ty_python_semantic/resources/primer/bad.txt index bfff92bd22c8aa..59fa3b5d6ede2a 100644 --- a/crates/ty_python_semantic/resources/primer/bad.txt +++ b/crates/ty_python_semantic/resources/primer/bad.txt @@ -1,2 +1 @@ spark # too many iterations (in `exported_names` query) -steam.py # hangs (single threaded) diff --git a/crates/ty_python_semantic/src/place.rs b/crates/ty_python_semantic/src/place.rs index 993075cd5da488..33a50d28b911e0 100644 --- a/crates/ty_python_semantic/src/place.rs +++ b/crates/ty_python_semantic/src/place.rs @@ -822,7 +822,11 @@ fn place_by_id<'db>( ) }); - if scope.file(db).is_stub(db) || scope.scope(db).visibility().is_private() { + if scope.node(db).scope_kind().is_module() { + inferred + .map_type(|ty| ty.promote_literals(db, false)) + .into() + } else if scope.file(db).is_stub(db) || scope.scope(db).visibility().is_private() { // We generally trust module-level undeclared places in stubs and do not union // with `Unknown`. If we don't do this, simple aliases like `IOError = OSError` in // stubs would result in `IOError` being a union of `OSError` and `Unknown`, which diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index a9111f35819dab..5a25adc46c5fd2 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -1171,20 +1171,37 @@ impl<'db> Type<'db> { /// Note that this function tries to promote literals to a more user-friendly form than their /// fallback instance type. For example, `def _() -> int` is promoted to `Callable[[], int]`, /// as opposed to `FunctionType`. - pub(crate) fn promote_literals(self, db: &'db dyn Db) -> Type<'db> { - self.apply_type_mapping(db, &TypeMapping::PromoteLiterals) + pub(crate) fn promote_literals( + self, + db: &'db dyn Db, + promote_modules_and_functions: bool, + ) -> Type<'db> { + self.apply_type_mapping( + db, + &TypeMapping::PromoteLiterals { + promote_modules_and_functions, + }, + ) } /// Like [`Type::promote_literals`], but does not recurse into nested types. - fn promote_literals_impl(self, db: &'db dyn Db) -> Type<'db> { + fn promote_literals_impl( + self, + db: &'db dyn Db, + promote_modules_and_functions: bool, + ) -> Type<'db> { match self { Type::StringLiteral(_) | Type::LiteralString => KnownClass::Str.to_instance(db), Type::BooleanLiteral(_) => KnownClass::Bool.to_instance(db), Type::IntLiteral(_) => KnownClass::Int.to_instance(db), Type::BytesLiteral(_) => KnownClass::Bytes.to_instance(db), - Type::ModuleLiteral(_) => KnownClass::ModuleType.to_instance(db), Type::EnumLiteral(literal) => literal.enum_class_instance(db), - Type::FunctionLiteral(literal) => Type::Callable(literal.into_callable_type(db)), + Type::ModuleLiteral(_) if promote_modules_and_functions => { + KnownClass::ModuleType.to_instance(db) + } + Type::FunctionLiteral(literal) if promote_modules_and_functions => { + Type::Callable(literal.into_callable_type(db)) + } _ => self, } } @@ -6037,7 +6054,7 @@ impl<'db> Type<'db> { self } } - TypeMapping::PromoteLiterals + TypeMapping::PromoteLiterals { .. } | TypeMapping::BindLegacyTypevars(_) | TypeMapping::MarkTypeVarsInferable(_) => self, TypeMapping::Materialize(materialization_kind) => { @@ -6059,7 +6076,7 @@ impl<'db> Type<'db> { self } } - TypeMapping::PromoteLiterals + TypeMapping::PromoteLiterals { .. } | TypeMapping::BindLegacyTypevars(_) | TypeMapping::BindSelf(_) | TypeMapping::ReplaceSelf { .. } @@ -6074,7 +6091,7 @@ impl<'db> Type<'db> { } TypeMapping::Specialization(_) | TypeMapping::PartialSpecialization(_) | - TypeMapping::PromoteLiterals | + TypeMapping::PromoteLiterals { .. } | TypeMapping::BindSelf(_) | TypeMapping::ReplaceSelf { .. } | TypeMapping::MarkTypeVarsInferable(_) | @@ -6085,7 +6102,7 @@ impl<'db> Type<'db> { let function = Type::FunctionLiteral(function.apply_type_mapping_impl(db, type_mapping, visitor)); match type_mapping { - TypeMapping::PromoteLiterals => function.promote_literals_impl(db), + TypeMapping::PromoteLiterals { promote_modules_and_functions } => function.promote_literals_impl(db, *promote_modules_and_functions), _ => function } } @@ -6193,7 +6210,7 @@ impl<'db> Type<'db> { TypeMapping::ReplaceSelf { .. } | TypeMapping::MarkTypeVarsInferable(_) | TypeMapping::Materialize(_) => self, - TypeMapping::PromoteLiterals => self.promote_literals_impl(db) + TypeMapping::PromoteLiterals { promote_modules_and_functions } => self.promote_literals_impl(db, *promote_modules_and_functions) } Type::Dynamic(_) => match type_mapping { @@ -6203,7 +6220,7 @@ impl<'db> Type<'db> { TypeMapping::BindSelf(_) | TypeMapping::ReplaceSelf { .. } | TypeMapping::MarkTypeVarsInferable(_) | - TypeMapping::PromoteLiterals => self, + TypeMapping::PromoteLiterals { .. } => self, TypeMapping::Materialize(materialization_kind) => match materialization_kind { MaterializationKind::Top => Type::object(), MaterializationKind::Bottom => Type::Never, @@ -6730,7 +6747,7 @@ pub enum TypeMapping<'a, 'db> { PartialSpecialization(PartialSpecialization<'a, 'db>), /// Replaces any literal types with their corresponding promoted type form (e.g. `Literal["string"]` /// to `str`, or `def _() -> int` to `Callable[[], int]`). - PromoteLiterals, + PromoteLiterals { promote_modules_and_functions: bool }, /// Binds a legacy typevar with the generic context (class, function, type alias) that it is /// being used in. BindLegacyTypevars(BindingContext<'db>), @@ -6763,7 +6780,7 @@ impl<'db> TypeMapping<'_, 'db> { match self { TypeMapping::Specialization(_) | TypeMapping::PartialSpecialization(_) - | TypeMapping::PromoteLiterals + | TypeMapping::PromoteLiterals { .. } | TypeMapping::BindLegacyTypevars(_) | TypeMapping::MarkTypeVarsInferable(_) | TypeMapping::Materialize(_) => context, diff --git a/crates/ty_python_semantic/src/types/call/bind.rs b/crates/ty_python_semantic/src/types/call/bind.rs index 59a38e303beed4..94348dffb0ef11 100644 --- a/crates/ty_python_semantic/src/types/call/bind.rs +++ b/crates/ty_python_semantic/src/types/call/bind.rs @@ -2498,9 +2498,12 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> { // The inherited generic context is used when inferring the specialization of a generic // class from a constructor call. In this case (only), we promote any typevars that are // inferred as a literal to the corresponding instance type. - builder - .build(gc) - .apply_type_mapping(self.db, &TypeMapping::PromoteLiterals) + builder.build(gc).apply_type_mapping( + self.db, + &TypeMapping::PromoteLiterals { + promote_modules_and_functions: true, + }, + ) }); } diff --git a/crates/ty_python_semantic/src/types/diagnostic.rs b/crates/ty_python_semantic/src/types/diagnostic.rs index ea7d54841c8f8f..de65181fa1c55e 100644 --- a/crates/ty_python_semantic/src/types/diagnostic.rs +++ b/crates/ty_python_semantic/src/types/diagnostic.rs @@ -2662,7 +2662,7 @@ pub(crate) fn report_undeclared_protocol_member( if definition.kind(db).is_unannotated_assignment() { let binding_type = binding_type(db, definition); - let suggestion = binding_type.promote_literals(db); + let suggestion = binding_type.promote_literals(db, true); if should_give_hint(db, suggestion) { diagnostic.set_primary_message(format_args!( diff --git a/crates/ty_python_semantic/src/types/infer/builder.rs b/crates/ty_python_semantic/src/types/infer/builder.rs index 204d14d5700ded..a45ad91e0b9192 100644 --- a/crates/ty_python_semantic/src/types/infer/builder.rs +++ b/crates/ty_python_semantic/src/types/infer/builder.rs @@ -5432,7 +5432,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { // Convert any element literals to their promoted type form to avoid excessively large // unions for large nested list literals, which the constraint solver struggles with. - let inferred_elt_ty = inferred_elt_ty.promote_literals(self.db()); + let inferred_elt_ty = inferred_elt_ty.promote_literals(self.db(), true); builder .infer(Type::TypeVar(*elt_ty), inferred_elt_ty)