mirror of
				https://github.com/astral-sh/ruff.git
				synced 2025-10-31 12:05:57 +00:00 
			
		
		
		
	[ty] Remove special casing for tuple addition (#19636)
	
		
			
	
		
	
	
		
	
		
			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 (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 (push) Blocked by required conditions
				
			CI / benchmarks-walltime (push) Blocked by required conditions
				
			[ty Playground] Release / publish (push) Waiting to run
				
			This commit is contained in:
		
							parent
							
								
									38049aae12
								
							
						
					
					
						commit
						7b4103bcb6
					
				
					 6 changed files with 58 additions and 29 deletions
				
			
		|  | @ -351,6 +351,41 @@ fn benchmark_many_tuple_assignments(criterion: &mut Criterion) { | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | fn benchmark_tuple_implicit_instance_attributes(criterion: &mut Criterion) { | ||||||
|  |     setup_rayon(); | ||||||
|  | 
 | ||||||
|  |     criterion.bench_function("ty_micro[many_tuple_assignments]", |b| { | ||||||
|  |         b.iter_batched_ref( | ||||||
|  |             || { | ||||||
|  |                 // This is a regression benchmark for a case that used to hang:
 | ||||||
|  |                 // https://github.com/astral-sh/ty/issues/765
 | ||||||
|  |                 setup_micro_case( | ||||||
|  |                     r#" | ||||||
|  |                     from typing import Any | ||||||
|  | 
 | ||||||
|  |                     class A: | ||||||
|  |                         foo: tuple[Any, ...] | ||||||
|  | 
 | ||||||
|  |                     class B(A): | ||||||
|  |                         def __init__(self, parent: "C", x: tuple[Any]): | ||||||
|  |                             self.foo = parent.foo + x | ||||||
|  | 
 | ||||||
|  |                     class C(A): | ||||||
|  |                         def __init__(self, parent: B, x: tuple[Any]): | ||||||
|  |                             self.foo = parent.foo + x | ||||||
|  |                     "#,
 | ||||||
|  |                 ) | ||||||
|  |             }, | ||||||
|  |             |case| { | ||||||
|  |                 let Case { db, .. } = case; | ||||||
|  |                 let result = db.check(); | ||||||
|  |                 assert_eq!(result.len(), 0); | ||||||
|  |             }, | ||||||
|  |             BatchSize::SmallInput, | ||||||
|  |         ); | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| fn benchmark_complex_constrained_attributes_1(criterion: &mut Criterion) { | fn benchmark_complex_constrained_attributes_1(criterion: &mut Criterion) { | ||||||
|     setup_rayon(); |     setup_rayon(); | ||||||
| 
 | 
 | ||||||
|  | @ -630,6 +665,7 @@ criterion_group!( | ||||||
|     micro, |     micro, | ||||||
|     benchmark_many_string_assignments, |     benchmark_many_string_assignments, | ||||||
|     benchmark_many_tuple_assignments, |     benchmark_many_tuple_assignments, | ||||||
|  |     benchmark_tuple_implicit_instance_attributes, | ||||||
|     benchmark_complex_constrained_attributes_1, |     benchmark_complex_constrained_attributes_1, | ||||||
|     benchmark_complex_constrained_attributes_2, |     benchmark_complex_constrained_attributes_2, | ||||||
|     benchmark_many_enum_members, |     benchmark_many_enum_members, | ||||||
|  |  | ||||||
|  | @ -13,7 +13,7 @@ reveal_type(x)  # revealed: int | float | ||||||
| 
 | 
 | ||||||
| x = (1, 2) | x = (1, 2) | ||||||
| x += (3, 4) | x += (3, 4) | ||||||
| reveal_type(x)  # revealed: tuple[Literal[1], Literal[2], Literal[3], Literal[4]] | reveal_type(x)  # revealed: tuple[Literal[1, 2, 3, 4], ...] | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ## Dunder methods | ## Dunder methods | ||||||
|  |  | ||||||
|  | @ -3,14 +3,14 @@ | ||||||
| ## Concatenation for heterogeneous tuples | ## Concatenation for heterogeneous tuples | ||||||
| 
 | 
 | ||||||
| ```py | ```py | ||||||
| reveal_type((1, 2) + (3, 4))  # revealed: tuple[Literal[1], Literal[2], Literal[3], Literal[4]] | reveal_type((1, 2) + (3, 4))  # revealed: tuple[Literal[1, 2, 3, 4], ...] | ||||||
| reveal_type(() + (1, 2))  # revealed: tuple[Literal[1], Literal[2]] | reveal_type(() + (1, 2))  # revealed: tuple[Literal[1, 2], ...] | ||||||
| reveal_type((1, 2) + ())  # revealed: tuple[Literal[1], Literal[2]] | reveal_type((1, 2) + ())  # revealed: tuple[Literal[1, 2], ...] | ||||||
| reveal_type(() + ())  # revealed: tuple[()] | reveal_type(() + ())  # revealed: tuple[()] | ||||||
| 
 | 
 | ||||||
| def _(x: tuple[int, str], y: tuple[None, tuple[int]]): | def _(x: tuple[int, str], y: tuple[None, tuple[int]]): | ||||||
|     reveal_type(x + y)  # revealed: tuple[int, str, None, tuple[int]] |     reveal_type(x + y)  # revealed: tuple[int | str | None | tuple[int], ...] | ||||||
|     reveal_type(y + x)  # revealed: tuple[None, tuple[int], int, str] |     reveal_type(y + x)  # revealed: tuple[None | tuple[int] | int | str, ...] | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ## Concatenation for homogeneous tuples | ## Concatenation for homogeneous tuples | ||||||
|  | @ -19,10 +19,10 @@ def _(x: tuple[int, str], y: tuple[None, tuple[int]]): | ||||||
| def _(x: tuple[int, ...], y: tuple[str, ...]): | def _(x: tuple[int, ...], y: tuple[str, ...]): | ||||||
|     reveal_type(x + x)  # revealed: tuple[int, ...] |     reveal_type(x + x)  # revealed: tuple[int, ...] | ||||||
|     reveal_type(x + y)  # revealed: tuple[int | str, ...] |     reveal_type(x + y)  # revealed: tuple[int | str, ...] | ||||||
|     reveal_type((1, 2) + x)  # revealed: tuple[Literal[1], Literal[2], *tuple[int, ...]] |     reveal_type((1, 2) + x)  # revealed: tuple[int, ...] | ||||||
|     reveal_type(x + (3, 4))  # revealed: tuple[*tuple[int, ...], Literal[3], Literal[4]] |     reveal_type(x + (3, 4))  # revealed: tuple[int, ...] | ||||||
|     reveal_type((1, 2) + x + (3, 4))  # revealed: tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[3], Literal[4]] |     reveal_type((1, 2) + x + (3, 4))  # revealed: tuple[int, ...] | ||||||
|     reveal_type((1, 2) + y + (3, 4) + x)  # revealed: tuple[Literal[1], Literal[2], *tuple[int | str, ...]] |     reveal_type((1, 2) + y + (3, 4) + x)  # revealed: tuple[int | str, ...] | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| We get the same results even when we use a legacy type alias, even though this involves first | We get the same results even when we use a legacy type alias, even though this involves first | ||||||
|  | @ -41,8 +41,8 @@ StrTuple = tuple[str, ...] | ||||||
| def _(one_two: OneTwo, x: IntTuple, y: StrTuple, three_four: ThreeFour): | def _(one_two: OneTwo, x: IntTuple, y: StrTuple, three_four: ThreeFour): | ||||||
|     reveal_type(x + x)  # revealed: tuple[int, ...] |     reveal_type(x + x)  # revealed: tuple[int, ...] | ||||||
|     reveal_type(x + y)  # revealed: tuple[int | str, ...] |     reveal_type(x + y)  # revealed: tuple[int | str, ...] | ||||||
|     reveal_type(one_two + x)  # revealed: tuple[Literal[1], Literal[2], *tuple[int, ...]] |     reveal_type(one_two + x)  # revealed: tuple[int, ...] | ||||||
|     reveal_type(x + three_four)  # revealed: tuple[*tuple[int, ...], Literal[3], Literal[4]] |     reveal_type(x + three_four)  # revealed: tuple[int, ...] | ||||||
|     reveal_type(one_two + x + three_four)  # revealed: tuple[Literal[1], Literal[2], *tuple[int, ...], Literal[3], Literal[4]] |     reveal_type(one_two + x + three_four)  # revealed: tuple[int, ...] | ||||||
|     reveal_type(one_two + y + three_four + x)  # revealed: tuple[Literal[1], Literal[2], *tuple[int | str, ...]] |     reveal_type(one_two + y + three_four + x)  # revealed: tuple[int | str, ...] | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  | @ -122,15 +122,14 @@ class A: | ||||||
|     __slots__ = () |     __slots__ = () | ||||||
|     __slots__ += ("a", "b") |     __slots__ += ("a", "b") | ||||||
| 
 | 
 | ||||||
| reveal_type(A.__slots__)  # revealed: tuple[Literal["a"], Literal["b"]] | reveal_type(A.__slots__)  # revealed: tuple[Literal["a", "b"], ...] | ||||||
| 
 | 
 | ||||||
| class B: | class B: | ||||||
|     __slots__ = ("c", "d") |     __slots__ = ("c", "d") | ||||||
| 
 | 
 | ||||||
| class C(  # error: [instance-layout-conflict] | # TODO: ideally this would trigger `[instance-layout-conflict]` | ||||||
|     A, | # (but it's also not high-priority) | ||||||
|     B, | class C(A, B): ... | ||||||
| ): ... |  | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ## Explicitly annotated `__slots__` | ## Explicitly annotated `__slots__` | ||||||
|  |  | ||||||
|  | @ -240,9 +240,7 @@ def homogeneous(t: tuple[str, ...]) -> None: | ||||||
|     reveal_type(t[-3])  # revealed: str |     reveal_type(t[-3])  # revealed: str | ||||||
|     reveal_type(t[-4])  # revealed: str |     reveal_type(t[-4])  # revealed: str | ||||||
| 
 | 
 | ||||||
| def mixed(s: tuple[str, ...]) -> None: | def mixed(t: tuple[Literal[1], Literal[2], Literal[3], *tuple[str, ...], Literal[8], Literal[9], Literal[10]]) -> None: | ||||||
|     t = (1, 2, 3) + s + (8, 9, 10) |  | ||||||
| 
 |  | ||||||
|     reveal_type(t[0])  # revealed: Literal[1] |     reveal_type(t[0])  # revealed: Literal[1] | ||||||
|     reveal_type(t[1])  # revealed: Literal[2] |     reveal_type(t[1])  # revealed: Literal[2] | ||||||
|     reveal_type(t[2])  # revealed: Literal[3] |     reveal_type(t[2])  # revealed: Literal[3] | ||||||
|  |  | ||||||
|  | @ -7061,8 +7061,10 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { | ||||||
|             // the result would then become Any or Unknown, respectively).
 |             // the result would then become Any or Unknown, respectively).
 | ||||||
|             (any @ Type::Dynamic(DynamicType::Any), _, _) |             (any @ Type::Dynamic(DynamicType::Any), _, _) | ||||||
|             | (_, any @ Type::Dynamic(DynamicType::Any), _) => Some(any), |             | (_, any @ Type::Dynamic(DynamicType::Any), _) => Some(any), | ||||||
|  | 
 | ||||||
|             (unknown @ Type::Dynamic(DynamicType::Unknown), _, _) |             (unknown @ Type::Dynamic(DynamicType::Unknown), _, _) | ||||||
|             | (_, unknown @ Type::Dynamic(DynamicType::Unknown), _) => Some(unknown), |             | (_, unknown @ Type::Dynamic(DynamicType::Unknown), _) => Some(unknown), | ||||||
|  | 
 | ||||||
|             ( |             ( | ||||||
|                 todo @ Type::Dynamic( |                 todo @ Type::Dynamic( | ||||||
|                     DynamicType::Todo(_) |                     DynamicType::Todo(_) | ||||||
|  | @ -7083,6 +7085,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { | ||||||
|                 ), |                 ), | ||||||
|                 _, |                 _, | ||||||
|             ) => Some(todo), |             ) => Some(todo), | ||||||
|  | 
 | ||||||
|             (Type::Never, _, _) | (_, Type::Never, _) => Some(Type::Never), |             (Type::Never, _, _) | (_, Type::Never, _) => Some(Type::Never), | ||||||
| 
 | 
 | ||||||
|             (Type::IntLiteral(n), Type::IntLiteral(m), ast::Operator::Add) => Some( |             (Type::IntLiteral(n), Type::IntLiteral(m), ast::Operator::Add) => Some( | ||||||
|  | @ -7235,13 +7238,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { | ||||||
|                     op, |                     op, | ||||||
|                 ), |                 ), | ||||||
| 
 | 
 | ||||||
|             (Type::Tuple(lhs), Type::Tuple(rhs), ast::Operator::Add) => { |  | ||||||
|                 Some(Type::tuple(TupleType::new( |  | ||||||
|                     self.db(), |  | ||||||
|                     lhs.tuple(self.db()).concat(self.db(), rhs.tuple(self.db())), |  | ||||||
|                 ))) |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // We've handled all of the special cases that we support for literals, so we need to
 |             // We've handled all of the special cases that we support for literals, so we need to
 | ||||||
|             // fall back on looking for dunder methods on one of the operand types.
 |             // fall back on looking for dunder methods on one of the operand types.
 | ||||||
|             ( |             ( | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Alex Waygood
						Alex Waygood