mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 22:01:18 +00:00
[ty] Literal promotion refactor (#20646)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks instrumented (ruff) (push) Blocked by required conditions
CI / benchmarks instrumented (ty) (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks instrumented (ruff) (push) Blocked by required conditions
CI / benchmarks instrumented (ty) (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run
## Summary Not sure if this was the original intention, but it looks to me like the previous `Type::literal_promotion_type` was more of an implementation detail for the actual operation of promoting all literals in a possibly-nested position of a type. This is not a pure refactor, as I'm technically changing the behavior for that protocols diagnostic message suggestion. ## Test Plan New Markdown test
This commit is contained in:
parent
130a794c2b
commit
b483d3b0b9
4 changed files with 29 additions and 21 deletions
|
@ -893,8 +893,10 @@ class LotsOfBindings(Protocol):
|
||||||
match object():
|
match object():
|
||||||
case l: # error: [ambiguous-protocol-member]
|
case l: # error: [ambiguous-protocol-member]
|
||||||
...
|
...
|
||||||
|
# error: [ambiguous-protocol-member] "Consider adding an annotation, e.g. `m: int | str = ...`"
|
||||||
|
m = 1 if 1.2 > 3.4 else "a"
|
||||||
|
|
||||||
# revealed: frozenset[Literal["Nested", "NestedProtocol", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"]]
|
# revealed: frozenset[Literal["Nested", "NestedProtocol", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"]]
|
||||||
reveal_type(get_protocol_members(LotsOfBindings))
|
reveal_type(get_protocol_members(LotsOfBindings))
|
||||||
|
|
||||||
class Foo(Protocol):
|
class Foo(Protocol):
|
||||||
|
|
|
@ -1166,21 +1166,26 @@ impl<'db> Type<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If this type is a literal, promote it to a type that this literal is an instance of.
|
/// Promote (possibly nested) literals to types that these literals are instances of.
|
||||||
///
|
///
|
||||||
/// Note that this function tries to promote literals to a more user-friendly form than their
|
/// 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]`,
|
/// fallback instance type. For example, `def _() -> int` is promoted to `Callable[[], int]`,
|
||||||
/// as opposed to `FunctionType`.
|
/// as opposed to `FunctionType`.
|
||||||
pub(crate) fn literal_promotion_type(self, db: &'db dyn Db) -> Option<Type<'db>> {
|
pub(crate) fn promote_literals(self, db: &'db dyn Db) -> Type<'db> {
|
||||||
|
self.apply_type_mapping(db, &TypeMapping::PromoteLiterals)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like [`Type::promote_literals`], but does not recurse into nested types.
|
||||||
|
fn promote_literals_impl(self, db: &'db dyn Db) -> Type<'db> {
|
||||||
match self {
|
match self {
|
||||||
Type::StringLiteral(_) | Type::LiteralString => Some(KnownClass::Str.to_instance(db)),
|
Type::StringLiteral(_) | Type::LiteralString => KnownClass::Str.to_instance(db),
|
||||||
Type::BooleanLiteral(_) => Some(KnownClass::Bool.to_instance(db)),
|
Type::BooleanLiteral(_) => KnownClass::Bool.to_instance(db),
|
||||||
Type::IntLiteral(_) => Some(KnownClass::Int.to_instance(db)),
|
Type::IntLiteral(_) => KnownClass::Int.to_instance(db),
|
||||||
Type::BytesLiteral(_) => Some(KnownClass::Bytes.to_instance(db)),
|
Type::BytesLiteral(_) => KnownClass::Bytes.to_instance(db),
|
||||||
Type::ModuleLiteral(_) => Some(KnownClass::ModuleType.to_instance(db)),
|
Type::ModuleLiteral(_) => KnownClass::ModuleType.to_instance(db),
|
||||||
Type::EnumLiteral(literal) => Some(literal.enum_class_instance(db)),
|
Type::EnumLiteral(literal) => literal.enum_class_instance(db),
|
||||||
Type::FunctionLiteral(literal) => Some(Type::Callable(literal.into_callable_type(db))),
|
Type::FunctionLiteral(literal) => Type::Callable(literal.into_callable_type(db)),
|
||||||
_ => None,
|
_ => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6080,8 +6085,7 @@ impl<'db> Type<'db> {
|
||||||
let function = Type::FunctionLiteral(function.apply_type_mapping_impl(db, type_mapping, visitor));
|
let function = Type::FunctionLiteral(function.apply_type_mapping_impl(db, type_mapping, visitor));
|
||||||
|
|
||||||
match type_mapping {
|
match type_mapping {
|
||||||
TypeMapping::PromoteLiterals => function.literal_promotion_type(db)
|
TypeMapping::PromoteLiterals => function.promote_literals_impl(db),
|
||||||
.expect("function literal should have a promotion type"),
|
|
||||||
_ => function
|
_ => function
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6189,8 +6193,7 @@ impl<'db> Type<'db> {
|
||||||
TypeMapping::ReplaceSelf { .. } |
|
TypeMapping::ReplaceSelf { .. } |
|
||||||
TypeMapping::MarkTypeVarsInferable(_) |
|
TypeMapping::MarkTypeVarsInferable(_) |
|
||||||
TypeMapping::Materialize(_) => self,
|
TypeMapping::Materialize(_) => self,
|
||||||
TypeMapping::PromoteLiterals => self.literal_promotion_type(db)
|
TypeMapping::PromoteLiterals => self.promote_literals_impl(db)
|
||||||
.expect("literal type should have a promotion type"),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::Dynamic(_) => match type_mapping {
|
Type::Dynamic(_) => match type_mapping {
|
||||||
|
|
|
@ -2625,6 +2625,12 @@ pub(crate) fn report_undeclared_protocol_member(
|
||||||
SubclassOfInner::Dynamic(_) => return false,
|
SubclassOfInner::Dynamic(_) => return false,
|
||||||
},
|
},
|
||||||
Type::NominalInstance(instance) => instance.class(db),
|
Type::NominalInstance(instance) => instance.class(db),
|
||||||
|
Type::Union(union) => {
|
||||||
|
return union
|
||||||
|
.elements(db)
|
||||||
|
.iter()
|
||||||
|
.all(|elem| should_give_hint(db, *elem));
|
||||||
|
}
|
||||||
_ => return false,
|
_ => return false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2656,9 +2662,7 @@ pub(crate) fn report_undeclared_protocol_member(
|
||||||
if definition.kind(db).is_unannotated_assignment() {
|
if definition.kind(db).is_unannotated_assignment() {
|
||||||
let binding_type = binding_type(db, definition);
|
let binding_type = binding_type(db, definition);
|
||||||
|
|
||||||
let suggestion = binding_type
|
let suggestion = binding_type.promote_literals(db);
|
||||||
.literal_promotion_type(db)
|
|
||||||
.unwrap_or(binding_type);
|
|
||||||
|
|
||||||
if should_give_hint(db, suggestion) {
|
if should_give_hint(db, suggestion) {
|
||||||
diagnostic.set_primary_message(format_args!(
|
diagnostic.set_primary_message(format_args!(
|
||||||
|
|
|
@ -92,7 +92,7 @@ use crate::types::{
|
||||||
DynamicType, IntersectionBuilder, IntersectionType, KnownClass, KnownInstanceType,
|
DynamicType, IntersectionBuilder, IntersectionType, KnownClass, KnownInstanceType,
|
||||||
MemberLookupPolicy, MetaclassCandidate, PEP695TypeAliasType, Parameter, ParameterForm,
|
MemberLookupPolicy, MetaclassCandidate, PEP695TypeAliasType, Parameter, ParameterForm,
|
||||||
Parameters, SpecialFormType, SubclassOfType, TrackedConstraintSet, Truthiness, Type,
|
Parameters, SpecialFormType, SubclassOfType, TrackedConstraintSet, Truthiness, Type,
|
||||||
TypeAliasType, TypeAndQualifiers, TypeContext, TypeMapping, TypeQualifiers,
|
TypeAliasType, TypeAndQualifiers, TypeContext, TypeQualifiers,
|
||||||
TypeVarBoundOrConstraintsEvaluation, TypeVarDefaultEvaluation, TypeVarInstance, TypeVarKind,
|
TypeVarBoundOrConstraintsEvaluation, TypeVarDefaultEvaluation, TypeVarInstance, TypeVarKind,
|
||||||
UnionBuilder, UnionType, binding_type, todo_type,
|
UnionBuilder, UnionType, binding_type, todo_type,
|
||||||
};
|
};
|
||||||
|
@ -5432,8 +5432,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
|
|
||||||
// Convert any element literals to their promoted type form to avoid excessively large
|
// 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.
|
// unions for large nested list literals, which the constraint solver struggles with.
|
||||||
let inferred_elt_ty =
|
let inferred_elt_ty = inferred_elt_ty.promote_literals(self.db());
|
||||||
inferred_elt_ty.apply_type_mapping(self.db(), &TypeMapping::PromoteLiterals);
|
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.infer(Type::TypeVar(*elt_ty), inferred_elt_ty)
|
.infer(Type::TypeVar(*elt_ty), inferred_elt_ty)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue