Compare commits

..

3 Commits

Author SHA1 Message Date
David Peter
e956acf371 [ty] Public types: remove special-case for stub files 2025-10-01 16:28:37 +02:00
David Peter
439ffc1f15 Review comments 2025-10-01 16:26:57 +02:00
David Peter
b6e9af50f1 [ty] No union with Unknown for module-global symbols 2025-10-01 14:42:53 +02:00
23 changed files with 110 additions and 326 deletions

View File

@@ -932,7 +932,7 @@ jobs:
tool: cargo-codspeed
- name: "Build benchmarks"
run: cargo codspeed build --features "codspeed,instrumented" --no-default-features -p ruff_benchmark --bench formatter --bench lexer --bench linter --bench parser
run: cargo codspeed build --features "codspeed,instrumented" --no-default-features -p ruff_benchmark formatter lexer linter parser
- name: "Run benchmarks"
uses: CodSpeedHQ/action@653fdc30e6c40ffd9739e40c8a0576f4f4523ca1 # v4.0.1
@@ -967,7 +967,7 @@ jobs:
tool: cargo-codspeed
- name: "Build benchmarks"
run: cargo codspeed build --features "codspeed,instrumented" --no-default-features -p ruff_benchmark --bench ty
run: cargo codspeed build --features "codspeed,instrumented" --no-default-features -p ruff_benchmark ty
- name: "Run benchmarks"
uses: CodSpeedHQ/action@653fdc30e6c40ffd9739e40c8a0576f4f4523ca1 # v4.0.1

View File

@@ -1,48 +1,5 @@
# Changelog
## 0.13.3
Released on 2025-10-02.
### Preview features
- Display diffs for `ruff format --check` and add support for different output formats ([#20443](https://github.com/astral-sh/ruff/pull/20443))
- \[`pyflakes`\] Handle some common submodule import situations for `unused-import` (`F401`) ([#20200](https://github.com/astral-sh/ruff/pull/20200))
- \[`ruff`\] Do not flag `%r` + `repr()` combinations (`RUF065`) ([#20600](https://github.com/astral-sh/ruff/pull/20600))
### Bug fixes
- \[`cli`\] Add conflict between `--add-noqa` and `--diff` options ([#20642](https://github.com/astral-sh/ruff/pull/20642))
- \[`pylint`\] Exempt required imports from `PLR0402` ([#20381](https://github.com/astral-sh/ruff/pull/20381))
- \[`pylint`\] Fix missing `max-nested-blocks` in settings display ([#20574](https://github.com/astral-sh/ruff/pull/20574))
- \[`pyupgrade`\] Prevent infinite loop with `I002` and `UP026` ([#20634](https://github.com/astral-sh/ruff/pull/20634))
### Rule changes
- \[`flake8-simplify`\] Improve help message clarity (`SIM105`) ([#20548](https://github.com/astral-sh/ruff/pull/20548))
### Documentation
- Add the *The Basics* title back to CONTRIBUTING.md ([#20624](https://github.com/astral-sh/ruff/pull/20624))
- Fixed documentation for try_consider_else ([#20587](https://github.com/astral-sh/ruff/pull/20587))
- \[`isort`\] Clarify dependency between `order-by-type` and `case-sensitive` settings ([#20559](https://github.com/astral-sh/ruff/pull/20559))
- \[`pylint`\] Clarify fix safety to include left-hand hashability (`PLR6201`) ([#20518](https://github.com/astral-sh/ruff/pull/20518))
### Other changes
- \[`playground`\] Fix quick fixes for empty ranges in playground ([#20599](https://github.com/astral-sh/ruff/pull/20599))
### Contributors
- [@TaKO8Ki](https://github.com/TaKO8Ki)
- [@ntBre](https://github.com/ntBre)
- [@dylwil3](https://github.com/dylwil3)
- [@MichaReiser](https://github.com/MichaReiser)
- [@danparizher](https://github.com/danparizher)
- [@LilMonk](https://github.com/LilMonk)
- [@mgiovani](https://github.com/mgiovani)
- [@IDrokin117](https://github.com/IDrokin117)
## 0.13.2
Released on 2025-09-25.

6
Cargo.lock generated
View File

@@ -2738,7 +2738,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.13.3"
version = "0.13.2"
dependencies = [
"anyhow",
"argfile",
@@ -2994,7 +2994,7 @@ dependencies = [
[[package]]
name = "ruff_linter"
version = "0.13.3"
version = "0.13.2"
dependencies = [
"aho-corasick",
"anyhow",
@@ -3348,7 +3348,7 @@ dependencies = [
[[package]]
name = "ruff_wasm"
version = "0.13.3"
version = "0.13.2"
dependencies = [
"console_error_panic_hook",
"console_log",

View File

@@ -148,8 +148,8 @@ curl -LsSf https://astral.sh/ruff/install.sh | sh
powershell -c "irm https://astral.sh/ruff/install.ps1 | iex"
# For a specific version.
curl -LsSf https://astral.sh/ruff/0.13.3/install.sh | sh
powershell -c "irm https://astral.sh/ruff/0.13.3/install.ps1 | iex"
curl -LsSf https://astral.sh/ruff/0.13.2/install.sh | sh
powershell -c "irm https://astral.sh/ruff/0.13.2/install.ps1 | iex"
```
You can also install Ruff via [Homebrew](https://formulae.brew.sh/formula/ruff), [Conda](https://anaconda.org/conda-forge/ruff),
@@ -182,7 +182,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff
```yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.13.3
rev: v0.13.2
hooks:
# Run the linter.
- id: ruff-check

View File

@@ -31,7 +31,6 @@ extend-ignore-re = [
"typ",
# TODO: Remove this once the `TYP` redirects are removed from `rule_redirects.rs`
"TYP",
"ntBre"
]
[default.extend-identifiers]

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff"
version = "0.13.3"
version = "0.13.2"
publish = true
authors = { workspace = true }
edition = { workspace = true }

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_linter"
version = "0.13.3"
version = "0.13.2"
publish = false
authors = { workspace = true }
edition = { workspace = true }

View File

@@ -25,11 +25,9 @@ use crate::{AlwaysFixableViolation, Edit, Fix};
///
/// ## Fix safety
/// This rule's fix is marked as unsafe, as the use of a `set` literal will
/// error at runtime if either the element being tested for membership (the
/// left-hand side) or any element of the sequence (the right-hand side)
/// is unhashable (like lists or dictionaries). While Ruff will attempt to
/// infer the hashability of both sides and skip the fix when it can determine
/// that either side is unhashable, it may not always be able to do so.
/// error at runtime if the sequence contains unhashable elements (like lists
/// or dictionaries). While Ruff will attempt to infer the hashability of the
/// elements, it may not always be able to do so.
///
/// ## References
/// - [Whats New In Python 3.2](https://docs.python.org/3/whatsnew/3.2.html#optimizations)

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_wasm"
version = "0.13.3"
version = "0.13.2"
publish = false
authors = { workspace = true }
edition = { workspace = true }

View File

@@ -248,66 +248,3 @@ reveal_type(Public.a) # revealed: Unknown
# error: [unresolved-attribute]
Public.a = None
```
## In stub files
In stub files, we have a minor modification to the rules above: we do not union with `Unknown` for
undeclared symbols.
### Undeclared and bound
`mod.pyi`:
```pyi
MyInt = int
class C:
MyStr = str
```
```py
from mod import MyInt, C
reveal_type(MyInt) # revealed: <class 'int'>
reveal_type(C.MyStr) # revealed: <class 'str'>
```
### Undeclared and possibly unbound
`mod.pyi`:
```pyi
def flag() -> bool:
return True
if flag():
MyInt = int
class C:
MyStr = str
```
```py
# error: [possibly-missing-import]
# error: [possibly-missing-import]
from mod import MyInt, C
reveal_type(MyInt) # revealed: <class 'int'>
reveal_type(C.MyStr) # revealed: <class 'str'>
```
### Undeclared and unbound
`mod.pyi`:
```pyi
if False:
MyInt = int
```
```py
# error: [unresolved-import]
from mod import MyInt
reveal_type(MyInt) # revealed: Unknown
```

View File

@@ -139,7 +139,8 @@ reveal_type(f(A())) # revealed: A
reveal_type(f(*(A(),))) # revealed: A
reveal_type(f(B())) # revealed: A
reveal_type(f(*(B(),))) # revealed: A
# TODO: revealed: A
reveal_type(f(*(B(),))) # revealed: Unknown
# But, in this case, the arity check filters out the first overload, so we only have one match:
reveal_type(f(B(), 1)) # revealed: B
@@ -550,13 +551,16 @@ from overloaded import MyEnumSubclass, ActualEnum, f
def _(actual_enum: ActualEnum, my_enum_instance: MyEnumSubclass):
reveal_type(f(actual_enum)) # revealed: Both
reveal_type(f(*(actual_enum,))) # revealed: Both
# TODO: revealed: Both
reveal_type(f(*(actual_enum,))) # revealed: Unknown
reveal_type(f(ActualEnum.A)) # revealed: OnlyA
reveal_type(f(*(ActualEnum.A,))) # revealed: OnlyA
# TODO: revealed: OnlyA
reveal_type(f(*(ActualEnum.A,))) # revealed: Unknown
reveal_type(f(ActualEnum.B)) # revealed: OnlyB
reveal_type(f(*(ActualEnum.B,))) # revealed: OnlyB
# TODO: revealed: OnlyB
reveal_type(f(*(ActualEnum.B,))) # revealed: Unknown
reveal_type(f(my_enum_instance)) # revealed: MyEnumSubclass
reveal_type(f(*(my_enum_instance,))) # revealed: MyEnumSubclass
@@ -1093,10 +1097,12 @@ reveal_type(f(*(1,))) # revealed: str
def _(list_int: list[int], list_any: list[Any]):
reveal_type(f(list_int)) # revealed: int
reveal_type(f(*(list_int,))) # revealed: int
# TODO: revealed: int
reveal_type(f(*(list_int,))) # revealed: Unknown
reveal_type(f(list_any)) # revealed: int
reveal_type(f(*(list_any,))) # revealed: int
# TODO: revealed: int
reveal_type(f(*(list_any,))) # revealed: Unknown
```
### Single list argument (ambiguous)
@@ -1130,7 +1136,8 @@ def _(list_int: list[int], list_any: list[Any]):
# All materializations of `list[int]` are assignable to `list[int]`, so it matches the first
# overload.
reveal_type(f(list_int)) # revealed: int
reveal_type(f(*(list_int,))) # revealed: int
# TODO: revealed: int
reveal_type(f(*(list_int,))) # revealed: Unknown
# All materializations of `list[Any]` are assignable to `list[int]` and `list[Any]`, but the
# return type of first and second overloads are not equivalent, so the overload matching
@@ -1163,21 +1170,25 @@ reveal_type(f("a")) # revealed: str
reveal_type(f(*("a",))) # revealed: str
reveal_type(f((1, "b"))) # revealed: int
reveal_type(f(*((1, "b"),))) # revealed: int
# TODO: revealed: int
reveal_type(f(*((1, "b"),))) # revealed: Unknown
reveal_type(f((1, 2))) # revealed: int
reveal_type(f(*((1, 2),))) # revealed: int
# TODO: revealed: int
reveal_type(f(*((1, 2),))) # revealed: Unknown
def _(int_str: tuple[int, str], int_any: tuple[int, Any], any_any: tuple[Any, Any]):
# All materializations are assignable to first overload, so second and third overloads are
# eliminated
reveal_type(f(int_str)) # revealed: int
reveal_type(f(*(int_str,))) # revealed: int
# TODO: revealed: int
reveal_type(f(*(int_str,))) # revealed: Unknown
# All materializations are assignable to second overload, so the third overload is eliminated;
# the return type of first and second overload is equivalent
reveal_type(f(int_any)) # revealed: int
reveal_type(f(*(int_any,))) # revealed: int
# TODO: revealed: int
reveal_type(f(*(int_any,))) # revealed: Unknown
# All materializations of `tuple[Any, Any]` are assignable to the parameters of all the
# overloads, but the return types aren't equivalent, so the overload matching is ambiguous
@@ -1255,22 +1266,26 @@ def _(list_int: list[int], list_any: list[Any], int_str: tuple[int, str], int_an
# All materializations of both argument types are assignable to the first overload, so the
# second and third overloads are filtered out
reveal_type(f(list_int, int_str)) # revealed: A
reveal_type(f(*(list_int, int_str))) # revealed: A
# TODO: revealed: A
reveal_type(f(*(list_int, int_str))) # revealed: Unknown
# All materialization of first argument is assignable to first overload and for the second
# argument, they're assignable to the second overload, so the third overload is filtered out
reveal_type(f(list_int, int_any)) # revealed: A
reveal_type(f(*(list_int, int_any))) # revealed: A
# TODO: revealed: A
reveal_type(f(*(list_int, int_any))) # revealed: Unknown
# All materialization of first argument is assignable to second overload and for the second
# argument, they're assignable to the first overload, so the third overload is filtered out
reveal_type(f(list_any, int_str)) # revealed: A
reveal_type(f(*(list_any, int_str))) # revealed: A
# TODO: revealed: A
reveal_type(f(*(list_any, int_str))) # revealed: Unknown
# All materializations of both arguments are assignable to the second overload, so the third
# overload is filtered out
reveal_type(f(list_any, int_any)) # revealed: A
reveal_type(f(*(list_any, int_any))) # revealed: A
# TODO: revealed: A
reveal_type(f(*(list_any, int_any))) # revealed: Unknown
# All materializations of first argument is assignable to the second overload and for the second
# argument, they're assignable to the third overload, so no overloads are filtered out; the
@@ -1301,7 +1316,8 @@ from overloaded import f
def _(literal: LiteralString, string: str, any: Any):
reveal_type(f(literal)) # revealed: LiteralString
reveal_type(f(*(literal,))) # revealed: LiteralString
# TODO: revealed: LiteralString
reveal_type(f(*(literal,))) # revealed: Unknown
reveal_type(f(string)) # revealed: str
reveal_type(f(*(string,))) # revealed: str
@@ -1339,10 +1355,12 @@ from overloaded import f
def _(list_int: list[int], list_str: list[str], list_any: list[Any], any: Any):
reveal_type(f(list_int)) # revealed: A
reveal_type(f(*(list_int,))) # revealed: A
# TODO: revealed: A
reveal_type(f(*(list_int,))) # revealed: Unknown
reveal_type(f(list_str)) # revealed: str
reveal_type(f(*(list_str,))) # revealed: str
# TODO: Should be `str`
reveal_type(f(*(list_str,))) # revealed: Unknown
reveal_type(f(list_any)) # revealed: Unknown
reveal_type(f(*(list_any,))) # revealed: Unknown
@@ -1543,10 +1561,12 @@ def _(any: Any):
reveal_type(f(*(any,), flag=False)) # revealed: str
def _(args: tuple[Any, Literal[True]]):
reveal_type(f(*args)) # revealed: int
# TODO: revealed: int
reveal_type(f(*args)) # revealed: Unknown
def _(args: tuple[Any, Literal[False]]):
reveal_type(f(*args)) # revealed: str
# TODO: revealed: str
reveal_type(f(*args)) # revealed: Unknown
```
### Argument type expansion

View File

@@ -265,41 +265,6 @@ reveal_type(enum_members(Color))
reveal_type(Color.red)
```
Multiple aliases to the same member are also supported. This is a regression test for
<https://github.com/astral-sh/ty/issues/1293>:
```py
from ty_extensions import enum_members
class ManyAliases(Enum):
real_member = "real_member"
alias1 = "real_member"
alias2 = "real_member"
alias3 = "real_member"
other_member = "other_real_member"
# revealed: tuple[Literal["real_member"], Literal["other_member"]]
reveal_type(enum_members(ManyAliases))
reveal_type(ManyAliases.real_member) # revealed: Literal[ManyAliases.real_member]
reveal_type(ManyAliases.alias1) # revealed: Literal[ManyAliases.real_member]
reveal_type(ManyAliases.alias2) # revealed: Literal[ManyAliases.real_member]
reveal_type(ManyAliases.alias3) # revealed: Literal[ManyAliases.real_member]
reveal_type(ManyAliases.real_member.value) # revealed: Literal["real_member"]
reveal_type(ManyAliases.real_member.name) # revealed: Literal["real_member"]
reveal_type(ManyAliases.alias1.value) # revealed: Literal["real_member"]
reveal_type(ManyAliases.alias1.name) # revealed: Literal["real_member"]
reveal_type(ManyAliases.alias2.value) # revealed: Literal["real_member"]
reveal_type(ManyAliases.alias2.name) # revealed: Literal["real_member"]
reveal_type(ManyAliases.alias3.value) # revealed: Literal["real_member"]
reveal_type(ManyAliases.alias3.name) # revealed: Literal["real_member"]
```
### Using `auto()`
```toml

View File

@@ -530,17 +530,3 @@ age, name = team.employees[0]
reveal_type(age) # revealed: Age
reveal_type(name) # revealed: Name
```
## `~T` is never assignable to `T`
```py
from typing import TypeVar
from ty_extensions import Not
T = TypeVar("T")
def f(x: T, y: Not[T]) -> T:
x = y # error: [invalid-assignment]
y = x # error: [invalid-assignment]
return x
```

View File

@@ -543,14 +543,3 @@ def _(x: int):
reveal_type(C().implicit_self(x)) # revealed: tuple[C, int]
```
## `~T` is never assignable to `T`
```py
from ty_extensions import Not
def f[T](x: T, y: Not[T]) -> T:
x = y # error: [invalid-assignment]
y = x # error: [invalid-assignment]
return x
```

View File

@@ -840,14 +840,7 @@ fn place_by_id<'db>(
// not union with `Unknown`, because the symbol cannot be modified externally.
let scope_has_private_visibility = scope.scope(db).visibility().is_private();
// We generally trust undeclared places in stubs and do not union with `Unknown`.
let in_stub_file = scope.file(db).is_stub(db);
if is_considered_non_modifiable
|| is_module_global
|| scope_has_private_visibility
|| in_stub_file
{
if is_considered_non_modifiable || is_module_global || scope_has_private_visibility {
inferred.into()
} else {
// Widen the inferred type of undeclared public symbols by unioning with `Unknown`

View File

@@ -1567,7 +1567,7 @@ impl<'db> Type<'db> {
(Type::Intersection(intersection), Type::NonInferableTypeVar(_))
if intersection.negative(db).contains(&target) =>
{
ConstraintSet::from(false)
ConstraintSet::from(true)
}
// Two identical typevars must always solve to the same type, so they are always

View File

@@ -32,7 +32,7 @@ use crate::types::tuple::{TupleLength, TupleType};
use crate::types::{
BoundMethodType, ClassLiteral, DataclassParams, FieldInstance, KnownBoundMethodType,
KnownClass, KnownInstanceType, MemberLookupPolicy, PropertyInstanceType, SpecialFormType,
TrackedConstraintSet, TypeAliasType, TypeContext, TypeMapping, UnionBuilder, UnionType,
TrackedConstraintSet, TypeAliasType, TypeContext, TypeMapping, UnionType,
WrapperDescriptorKind, enums, ide_support, todo_type,
};
use ruff_db::diagnostic::{Annotation, Diagnostic, SubDiagnostic, SubDiagnosticSeverity};
@@ -1588,14 +1588,6 @@ impl<'db> CallableBinding<'db> {
arguments: &CallArguments<'_, 'db>,
matching_overload_indexes: &[usize],
) {
// The maximum number of parameters across all the overloads that are being considered
// for filtering.
let max_parameter_count = matching_overload_indexes
.iter()
.map(|&index| self.overloads[index].signature.parameters().len())
.max()
.unwrap_or(0);
// These are the parameter indexes that matches the arguments that participate in the
// filtering process.
//
@@ -1603,67 +1595,41 @@ impl<'db> CallableBinding<'db> {
// gradual equivalent to the parameter types at the same index for other overloads.
let mut participating_parameter_indexes = HashSet::new();
// The parameter types at each index for the first overload containing a parameter at
// that index.
let mut first_parameter_types: Vec<Option<Type<'db>>> = vec![None; max_parameter_count];
for argument_index in 0..arguments.len() {
for overload_index in matching_overload_indexes {
let overload = &self.overloads[*overload_index];
for &parameter_index in &overload.argument_matches[argument_index].parameters {
// TODO: For an unannotated `self` / `cls` parameter, the type should be
// `typing.Self` / `type[typing.Self]`
let current_parameter_type = overload.signature.parameters()[parameter_index]
.annotated_type()
.unwrap_or(Type::unknown());
let first_parameter_type = &mut first_parameter_types[parameter_index];
if let Some(first_parameter_type) = first_parameter_type {
if !first_parameter_type.is_equivalent_to(db, current_parameter_type) {
participating_parameter_indexes.insert(parameter_index);
}
} else {
*first_parameter_type = Some(current_parameter_type);
}
}
}
}
let mut union_argument_type_builders = std::iter::repeat_with(|| UnionBuilder::new(db))
.take(max_parameter_count)
.collect::<Vec<_>>();
for (argument_index, argument_type) in arguments.iter_types().enumerate() {
for overload_index in matching_overload_indexes {
let overload = &self.overloads[*overload_index];
for (parameter_index, variadic_argument_type) in
overload.argument_matches[argument_index].iter()
{
if !participating_parameter_indexes.contains(&parameter_index) {
continue;
}
union_argument_type_builders[parameter_index].add_in_place(
variadic_argument_type
.unwrap_or(argument_type)
.top_materialization(db),
);
}
}
}
// These only contain the top materialized argument types for the corresponding
// participating parameter indexes.
let top_materialized_argument_type = Type::heterogeneous_tuple(
db,
union_argument_type_builders
.into_iter()
.filter_map(|builder| {
if builder.is_empty() {
None
let mut top_materialized_argument_types = vec![];
for (argument_index, argument_type) in arguments.iter_types().enumerate() {
let mut first_parameter_type: Option<Type<'db>> = None;
let mut participating_parameter_index = None;
'overload: for overload_index in matching_overload_indexes {
let overload = &self.overloads[*overload_index];
for parameter_index in &overload.argument_matches[argument_index].parameters {
// TODO: For an unannotated `self` / `cls` parameter, the type should be
// `typing.Self` / `type[typing.Self]`
let current_parameter_type = overload.signature.parameters()[*parameter_index]
.annotated_type()
.unwrap_or(Type::unknown());
if let Some(first_parameter_type) = first_parameter_type {
if !first_parameter_type.is_equivalent_to(db, current_parameter_type) {
participating_parameter_index = Some(*parameter_index);
break 'overload;
}
} else {
Some(builder.build())
first_parameter_type = Some(current_parameter_type);
}
}),
);
}
}
if let Some(parameter_index) = participating_parameter_index {
participating_parameter_indexes.insert(parameter_index);
top_materialized_argument_types.push(argument_type.top_materialization(db));
}
}
let top_materialized_argument_type =
Type::heterogeneous_tuple(db, top_materialized_argument_types);
// A flag to indicate whether we've found the overload that makes the remaining overloads
// unmatched for the given argument types.
@@ -1674,22 +1640,15 @@ impl<'db> CallableBinding<'db> {
self.overloads[*current_index].mark_as_unmatched_overload();
continue;
}
let mut union_parameter_types = std::iter::repeat_with(|| UnionBuilder::new(db))
.take(max_parameter_count)
.collect::<Vec<_>>();
// The number of parameters that have been skipped because they don't participate in
// the filtering process. This is used to make sure the types are added to the
// corresponding parameter index in `union_parameter_types`.
let mut skipped_parameters = 0;
let mut parameter_types = Vec::with_capacity(arguments.len());
for argument_index in 0..arguments.len() {
// The parameter types at the current argument index.
let mut current_parameter_types = vec![];
for overload_index in &matching_overload_indexes[..=upto] {
let overload = &self.overloads[*overload_index];
for parameter_index in &overload.argument_matches[argument_index].parameters {
if !participating_parameter_indexes.contains(parameter_index) {
skipped_parameters += 1;
// This parameter doesn't participate in the filtering process.
continue;
}
// TODO: For an unannotated `self` / `cls` parameter, the type should be
@@ -1705,24 +1664,17 @@ impl<'db> CallableBinding<'db> {
parameter_type =
parameter_type.apply_specialization(db, inherited_specialization);
}
union_parameter_types[parameter_index.saturating_sub(skipped_parameters)]
.add_in_place(parameter_type);
current_parameter_types.push(parameter_type);
}
}
if current_parameter_types.is_empty() {
continue;
}
parameter_types.push(UnionType::from_elements(db, current_parameter_types));
}
let parameter_types = Type::heterogeneous_tuple(
db,
union_parameter_types.into_iter().filter_map(|builder| {
if builder.is_empty() {
None
} else {
Some(builder.build())
}
}),
);
if top_materialized_argument_type.is_assignable_to(db, parameter_types) {
if top_materialized_argument_type
.is_assignable_to(db, Type::heterogeneous_tuple(db, parameter_types))
{
filter_remaining_overloads = true;
}
}

View File

@@ -194,19 +194,12 @@ pub(crate) fn enum_metadata<'db>(
// we don't know if it's a duplicate or not.
if matches!(
value_ty,
Type::BooleanLiteral(_)
| Type::IntLiteral(_)
| Type::StringLiteral(_)
| Type::BytesLiteral(_)
Type::IntLiteral(_) | Type::StringLiteral(_) | Type::BytesLiteral(_)
) {
if let Some(canonical) = enum_values.get(&value_ty) {
// This is a duplicate value, create an alias to the canonical (first) member
aliases.insert(name.clone(), canonical.clone());
if let Some(previous) = enum_values.insert(value_ty, name.clone()) {
aliases.insert(name.clone(), previous);
return None;
}
// This is the first occurrence of this value, track it as the canonical member
enum_values.insert(value_ty, name.clone());
}
let declarations = use_def_map.end_of_scope_symbol_declarations(symbol_id);

View File

@@ -80,7 +80,7 @@ You can add the following configuration to `.gitlab-ci.yml` to run a `ruff forma
stage: build
interruptible: true
image:
name: ghcr.io/astral-sh/ruff:0.13.3-alpine
name: ghcr.io/astral-sh/ruff:0.13.2-alpine
before_script:
- cd $CI_PROJECT_DIR
- ruff --version
@@ -106,7 +106,7 @@ Ruff can be used as a [pre-commit](https://pre-commit.com) hook via [`ruff-pre-c
```yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.13.3
rev: v0.13.2
hooks:
# Run the linter.
- id: ruff-check
@@ -119,7 +119,7 @@ To enable lint fixes, add the `--fix` argument to the lint hook:
```yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.13.3
rev: v0.13.2
hooks:
# Run the linter.
- id: ruff-check
@@ -133,7 +133,7 @@ To avoid running on Jupyter Notebooks, remove `jupyter` from the list of allowed
```yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.13.3
rev: v0.13.2
hooks:
# Run the linter.
- id: ruff-check

View File

@@ -369,7 +369,7 @@ This tutorial has focused on Ruff's command-line interface, but Ruff can also be
```yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.13.3
rev: v0.13.2
hooks:
# Run the linter.
- id: ruff

View File

@@ -96,11 +96,6 @@ export default function Playground() {
file: FileId,
newName: string,
) => {
if (newName.startsWith("/")) {
setError("File names cannot start with '/'.");
return;
}
const handle = files.handles[file];
let newHandle: FileHandle | null = null;
if (handle == null) {

View File

@@ -4,7 +4,7 @@ build-backend = "maturin"
[project]
name = "ruff"
version = "0.13.3"
version = "0.13.2"
description = "An extremely fast Python linter and code formatter, written in Rust."
authors = [{ name = "Astral Software Inc.", email = "hey@astral.sh" }]
readme = "README.md"

View File

@@ -1,6 +1,6 @@
[project]
name = "scripts"
version = "0.13.3"
version = "0.13.2"
description = ""
authors = ["Charles Marsh <charlie.r.marsh@gmail.com>"]