Do not promote module literals
This commit is contained in:
@@ -823,7 +823,9 @@ fn place_by_id<'db>(
|
||||
});
|
||||
|
||||
if scope.node(db).scope_kind().is_module() {
|
||||
inferred.map_type(|ty| ty.promote_literals(db)).into()
|
||||
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
|
||||
|
||||
@@ -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,
|
||||
@@ -6227,12 +6244,6 @@ impl<'db> Type<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Replaces any literal types with their corresponding promoted type form (e.g. `Literal["string"]`
|
||||
/// to `str`, or `def _() -> int` to `Callable[[], int]`).
|
||||
pub(crate) fn promote_literals(self, db: &'db dyn Db) -> Type<'db> {
|
||||
self.apply_type_mapping(db, &TypeMapping::PromoteLiterals)
|
||||
}
|
||||
|
||||
/// Locates any legacy `TypeVar`s in this type, and adds them to a set. This is used to build
|
||||
/// up a generic context from any legacy `TypeVar`s that appear in a function parameter list or
|
||||
/// `Generic` specialization.
|
||||
@@ -6736,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>),
|
||||
@@ -6769,7 +6780,7 @@ impl<'db> TypeMapping<'_, 'db> {
|
||||
match self {
|
||||
TypeMapping::Specialization(_)
|
||||
| TypeMapping::PartialSpecialization(_)
|
||||
| TypeMapping::PromoteLiterals
|
||||
| TypeMapping::PromoteLiterals { .. }
|
||||
| TypeMapping::BindLegacyTypevars(_)
|
||||
| TypeMapping::MarkTypeVarsInferable(_)
|
||||
| TypeMapping::Materialize(_) => context,
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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!(
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user