diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index ea0a931f85..d88c0c8151 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -130,6 +130,8 @@ pub enum Type<'db> { Union(UnionType<'db>), Intersection(IntersectionType<'db>), IntLiteral(i64), + /// A boolean literal, either `True` or `False`. + BooleanLiteral(bool), // TODO protocols, callable types, overloads, generics, type vars } @@ -175,6 +177,7 @@ impl<'db> Type<'db> { // TODO raise error Type::Unknown } + Type::BooleanLiteral(_) => Type::Unknown, } } } diff --git a/crates/red_knot_python_semantic/src/types/display.rs b/crates/red_knot_python_semantic/src/types/display.rs index d2ff7eae0f..7de3f9ebf7 100644 --- a/crates/red_knot_python_semantic/src/types/display.rs +++ b/crates/red_knot_python_semantic/src/types/display.rs @@ -35,6 +35,9 @@ impl Display for DisplayType<'_> { Type::Union(union) => union.display(self.db).fmt(f), Type::Intersection(intersection) => intersection.display(self.db).fmt(f), Type::IntLiteral(n) => write!(f, "Literal[{n}]"), + Type::BooleanLiteral(boolean) => { + write!(f, "Literal[{}]", if *boolean { "True" } else { "False" }) + } } } } diff --git a/crates/red_knot_python_semantic/src/types/infer.rs b/crates/red_knot_python_semantic/src/types/infer.rs index c28fccc764..74a13eed4c 100644 --- a/crates/red_knot_python_semantic/src/types/infer.rs +++ b/crates/red_knot_python_semantic/src/types/infer.rs @@ -939,12 +939,10 @@ impl<'db> TypeInferenceBuilder<'db> { } #[allow(clippy::unused_self)] - fn infer_boolean_literal_expression( - &mut self, - _literal: &ast::ExprBooleanLiteral, - ) -> Type<'db> { - // TODO builtins.bool and boolean Literal types - Type::Unknown + fn infer_boolean_literal_expression(&mut self, literal: &ast::ExprBooleanLiteral) -> Type<'db> { + let ast::ExprBooleanLiteral { range: _, value } = literal; + + Type::BooleanLiteral(*value) } #[allow(clippy::unused_self)] @@ -1649,6 +1647,18 @@ mod tests { Ok(()) } + #[test] + fn boolean_literal() -> anyhow::Result<()> { + let mut db = setup_db(); + + db.write_file("src/a.py", "x = True\ny = False")?; + + assert_public_ty(&db, "src/a.py", "x", "Literal[True]"); + assert_public_ty(&db, "src/a.py", "y", "Literal[False]"); + + Ok(()) + } + #[test] fn resolve_union() -> anyhow::Result<()> { let mut db = setup_db();