Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion crates/ty_ide/src/goto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,8 @@ impl<'db> Definitions<'db> {
| ty_python_semantic::types::TypeDefinition::TypeVar(definition)
| ty_python_semantic::types::TypeDefinition::TypeAlias(definition)
| ty_python_semantic::types::TypeDefinition::SpecialForm(definition)
| ty_python_semantic::types::TypeDefinition::NewType(definition) => {
| ty_python_semantic::types::TypeDefinition::NewType(definition)
| ty_python_semantic::types::TypeDefinition::EnumMember(definition) => {
ResolvedDefinition::Definition(definition)
}
};
Expand Down
80 changes: 80 additions & 0 deletions crates/ty_ide/src/inlay_hints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2777,6 +2777,86 @@ Source with applied edits:
"#);
}

#[test]
fn test_enum_literal() {
let mut test = inlay_hint_test(
r#"
from enum import Enum

class Color(Enum):
RED = 1
BLUE = 2

x = Color.RED
"#,
);

assert_snapshot!(test.inlay_hints(), @r"

from enum import Enum

class Color(Enum):
RED = 1
BLUE = 2

x[: Literal[Color.RED]] = Color.RED

---------------------------------------------
info[inlay-hint-location]: Inlay Hint Target
--> stdlib/typing.pyi:487:1
|
487 | Literal: _SpecialForm
| ^^^^^^^
|
info: Source
--> main2.py:8:5
|
8 | x[: Literal[Color.RED]] = Color.RED
| ^^^^^^^
|

info[inlay-hint-location]: Inlay Hint Target
--> main.py:4:7
|
4 | class Color(Enum):
| ^^^^^
|
info: Source
--> main2.py:8:13
|
8 | x[: Literal[Color.RED]] = Color.RED
| ^^^^^
|

info[inlay-hint-location]: Inlay Hint Target
--> main.py:5:5
|
5 | RED = 1
| ^^^
|
info: Source
--> main2.py:8:19
|
8 | x[: Literal[Color.RED]] = Color.RED
| ^^^
|

---------------------------------------------
info[inlay-hint-edit]: Inlay hint edits
--> main.py:1:1
1 + from typing import Literal
2 |
3 | from enum import Enum
4 |
--------------------------------------------------------------------------------
6 | RED = 1
7 | BLUE = 2
8 |
- x = Color.RED
9 + x: Literal[Color.RED] = Color.RED
");
}

#[test]
fn test_simple_init_call() {
let mut test = inlay_hint_test(
Expand Down
40 changes: 28 additions & 12 deletions crates/ty_python_semantic/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6202,16 +6202,18 @@ impl<'db> Type<'db> {
KnownInstanceType::TypeAliasType(type_alias) => {
Some(TypeDefinition::TypeAlias(type_alias.definition(db)))
}
KnownInstanceType::NewType(newtype) => Some(TypeDefinition::NewType(newtype.definition(db))),
KnownInstanceType::NewType(newtype) => {
Some(TypeDefinition::NewType(newtype.definition(db)))
}
_ => None,
},

Self::SubclassOf(subclass_of_type) => match subclass_of_type.subclass_of() {
SubclassOfInner::Dynamic(_) => None,
SubclassOfInner::Class(class) => class.type_definition(db),
SubclassOfInner::TypeVar(bound_typevar) => {
Some(TypeDefinition::TypeVar(bound_typevar.typevar(db).definition(db)?))
}
SubclassOfInner::TypeVar(bound_typevar) => Some(TypeDefinition::TypeVar(
bound_typevar.typevar(db).definition(db)?,
)),
},

Self::TypeAlias(alias) => alias.value_type(db).definition(db),
Expand All @@ -6221,17 +6223,27 @@ impl<'db> Type<'db> {
.getter(db)
.and_then(|getter| getter.definition(db))
.or_else(|| property.setter(db).and_then(|setter| setter.definition(db)))
.or_else(|| property.deleter(db).and_then(|deleter| deleter.definition(db))),
.or_else(|| {
property
.deleter(db)
.and_then(|deleter| deleter.definition(db))
}),

Self::LiteralValue(literal) => literal
.as_enum()
.and_then(|enum_lit| enum_lit.definition(db))
.map(TypeDefinition::EnumMember)
.or_else(|| self.to_meta_type(db).definition(db)),

Self::LiteralValue(_)
// TODO: For enum literals, it would be even better to jump to the definition of the specific member
| Self::KnownBoundMethod(_)
Self::KnownBoundMethod(_)
| Self::WrapperDescriptor(_)
| Self::DataclassDecorator(_)
| Self::DataclassTransformer(_)
| Self::BoundSuper(_) => self.to_meta_type(db).definition(db),

Self::TypeVar(bound_typevar) => Some(TypeDefinition::TypeVar(bound_typevar.typevar(db).definition(db)?)),
Self::TypeVar(bound_typevar) => Some(TypeDefinition::TypeVar(
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't know why this formatting isn't failing on main

bound_typevar.typevar(db).definition(db)?,
)),

Self::ProtocolInstance(protocol) => match protocol.inner {
Protocol::FromClass(class) => class.type_definition(db),
Expand All @@ -6244,8 +6256,12 @@ impl<'db> Type<'db> {

Self::SpecialForm(special_form) => special_form.definition(db),
Self::Never => Type::SpecialForm(SpecialFormType::Never).definition(db),
Self::Dynamic(DynamicType::Any) => Type::SpecialForm(SpecialFormType::Any).definition(db),
Self::Dynamic(DynamicType::Unknown | DynamicType::UnknownGeneric(_)) => Type::SpecialForm(SpecialFormType::Unknown).definition(db),
Self::Dynamic(DynamicType::Any) => {
Type::SpecialForm(SpecialFormType::Any).definition(db)
}
Self::Dynamic(DynamicType::Unknown | DynamicType::UnknownGeneric(_)) => {
Type::SpecialForm(SpecialFormType::Unknown).definition(db)
}
Self::AlwaysTruthy => Type::SpecialForm(SpecialFormType::AlwaysTruthy).definition(db),
Self::AlwaysFalsy => Type::SpecialForm(SpecialFormType::AlwaysFalsy).definition(db),

Expand All @@ -6257,7 +6273,7 @@ impl<'db> Type<'db> {
| DynamicType::TodoStarredExpression
| DynamicType::TodoTypeVarTuple
| DynamicType::InvalidConcatenateUnknown
| DynamicType::UnspecializedTypeVar
| DynamicType::UnspecializedTypeVar,
)
| Self::Callable(_)
| Self::TypeIs(_)
Expand Down
13 changes: 9 additions & 4 deletions crates/ty_python_semantic/src/types/definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub enum TypeDefinition<'db> {
TypeAlias(Definition<'db>),
NewType(Definition<'db>),
SpecialForm(Definition<'db>),
EnumMember(Definition<'db>),
}

impl TypeDefinition<'_> {
Expand All @@ -30,7 +31,8 @@ impl TypeDefinition<'_> {
| Self::TypeVar(definition)
| Self::TypeAlias(definition)
| Self::SpecialForm(definition)
| Self::NewType(definition) => {
| Self::NewType(definition)
| Self::EnumMember(definition) => {
let module = parsed_module(db, definition.file(db)).load(db);
Some(definition.focus_range(db, &module))
}
Expand All @@ -50,7 +52,8 @@ impl TypeDefinition<'_> {
| Self::TypeVar(definition)
| Self::TypeAlias(definition)
| Self::SpecialForm(definition)
| Self::NewType(definition) => {
| Self::NewType(definition)
| Self::EnumMember(definition) => {
let module = parsed_module(db, definition.file(db)).load(db);
Some(definition.full_range(db, &module))
}
Expand All @@ -66,7 +69,8 @@ impl TypeDefinition<'_> {
| Self::TypeVar(definition)
| Self::TypeAlias(definition)
| Self::SpecialForm(definition)
| Self::NewType(definition) => Some(definition.file(db)),
| Self::NewType(definition)
| Self::EnumMember(definition) => Some(definition.file(db)),
}
}
}
Expand All @@ -81,7 +85,8 @@ impl<'db> TypeDefinition<'db> {
| Self::TypeVar(definition)
| Self::TypeAlias(definition)
| Self::SpecialForm(definition)
| Self::NewType(definition) => Some(definition),
| Self::NewType(definition)
| Self::EnumMember(definition) => Some(definition),
}
}
}
7 changes: 6 additions & 1 deletion crates/ty_python_semantic/src/types/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1227,7 +1227,12 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
.enum_class(self.db)
.display_with(self.db, self.settings.clone())
.fmt_detailed(f)?;
write!(f, ".{}", enum_literal.name(self.db))
f.write_char('.')?;
write!(
f.with_type(Type::enum_literal(enum_literal)),
"{}",
enum_literal.name(self.db)
)
}
},
Type::TypeVar(bound_typevar) => {
Expand Down
15 changes: 15 additions & 0 deletions crates/ty_python_semantic/src/types/literal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use ruff_python_ast::name::Name;
use crate::Db;
use crate::types::set_theoretic::RecursivelyDefined;
use crate::types::{ClassLiteral, KnownClass, Type};
use ty_python_core::definition::Definition;
use ty_python_core::{place_table, use_def_map};

/// A literal value. See [`LiteralValueTypeKind`] for details.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, salsa::Update, get_size2::GetSize)]
Expand Down Expand Up @@ -385,4 +387,17 @@ impl<'db> EnumLiteralType<'db> {
pub(crate) fn enum_class_instance(self, db: &'db dyn Db) -> Type<'db> {
self.enum_class(db).to_non_generic_instance(db)
}

pub(crate) fn definition(self, db: &'db dyn Db) -> Option<Definition<'db>> {
let ClassLiteral::Static(class) = self.enum_class(db) else {
return None;
};

let scope = class.body_scope(db);
let symbol_id = place_table(db, scope).symbol_id(self.name(db))?;

use_def_map(db, scope)
.end_of_scope_symbol_bindings(symbol_id)
.find_map(|binding| binding.binding.definition())
}
}
Loading