diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index 360b9a5546..d9d8ac2e9e 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -4254,9 +4254,8 @@ impl<'db> Class<'db> { // (.., self.name, ..) = // [.., self.name, ..] = - let inferred_ty = infer_unpack_types(db, *unpack) - .get(*attribute_expression_id) - .expect("Failed to look up type of attribute in unpack assignment"); + let inferred_ty = + infer_unpack_types(db, *unpack).expression_type(*attribute_expression_id); union_of_inferred_types = union_of_inferred_types.add(inferred_ty); } } diff --git a/crates/red_knot_python_semantic/src/types/infer.rs b/crates/red_knot_python_semantic/src/types/infer.rs index 6f224b398d..3d4d9ad75b 100644 --- a/crates/red_knot_python_semantic/src/types/infer.rs +++ b/crates/red_knot_python_semantic/src/types/infer.rs @@ -2085,7 +2085,7 @@ impl<'db> TypeInferenceBuilder<'db> { } let name_ast_id = name.scoped_expression_id(self.db(), self.scope()); - unpacked.get(name_ast_id).unwrap_or(Type::unknown()) + unpacked.expression_type(name_ast_id) } TargetKind::Name => { if self.in_stub() && value.is_ellipsis_literal_expr() { @@ -2356,7 +2356,7 @@ impl<'db> TypeInferenceBuilder<'db> { self.context.extend(unpacked); } let name_ast_id = name.scoped_expression_id(self.db(), self.scope()); - unpacked.get(name_ast_id).unwrap_or(Type::unknown()) + unpacked.expression_type(name_ast_id) } TargetKind::Name => iterable_ty .iterate(self.db()) diff --git a/crates/red_knot_python_semantic/src/types/unpacker.rs b/crates/red_knot_python_semantic/src/types/unpacker.rs index f7782d4e6b..bd5baa982d 100644 --- a/crates/red_knot_python_semantic/src/types/unpacker.rs +++ b/crates/red_knot_python_semantic/src/types/unpacker.rs @@ -268,8 +268,14 @@ pub(crate) struct UnpackResult<'db> { } impl<'db> UnpackResult<'db> { - pub(crate) fn get(&self, expr_id: ScopedExpressionId) -> Option> { - self.targets.get(&expr_id).copied() + /// Returns the inferred type for a given sub-expression of the left-hand side target + /// of an unpacking assignment. + /// + /// Panics if a scoped expression ID is passed in that does not correspond to a sub- + /// expression of the target. + #[track_caller] + pub(crate) fn expression_type(&self, expr_id: ScopedExpressionId) -> Type<'db> { + self.targets[&expr_id] } }