mirror of https://github.com/astral-sh/ruff
[ty] Inlay Hint edit follow up (#21621)
<!-- Thank you for contributing to Ruff/ty! To help us out with reviewing, please consider the following: - Does this pull request include a summary of the change? (See below.) - Does this pull request include a descriptive title? (Please prefix with `[ty]` for ty pull requests.) - Does this pull request include references to any relevant issues? --> ## Summary Don't allow edits of some more invalid syntax types. ## Test Plan Add a test for `x = Literal['a']` (similar) to show we don't allow edits.
This commit is contained in:
parent
66d233134f
commit
88bfc32dfc
|
|
@ -6294,6 +6294,22 @@ mod tests {
|
|||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_literal_type_alias_inlay_hint() {
|
||||
let mut test = inlay_hint_test(
|
||||
"
|
||||
from typing import Literal
|
||||
|
||||
a = Literal['a', 'b', 'c']",
|
||||
);
|
||||
|
||||
assert_snapshot!(test.inlay_hints(), @r"
|
||||
from typing import Literal
|
||||
|
||||
a[: <typing.Literal special form>] = Literal['a', 'b', 'c']
|
||||
");
|
||||
}
|
||||
|
||||
struct InlayHintLocationDiagnostic {
|
||||
source: FileRange,
|
||||
target: FileRange,
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ use crate::types::constraints::{
|
|||
};
|
||||
use crate::types::context::{LintDiagnosticGuard, LintDiagnosticGuardBuilder};
|
||||
use crate::types::diagnostic::{INVALID_AWAIT, INVALID_TYPE_FORM, UNSUPPORTED_BOOL_CONVERSION};
|
||||
use crate::types::display::TupleSpecialization;
|
||||
pub use crate::types::display::{DisplaySettings, TypeDetail, TypeDisplayDetails};
|
||||
use crate::types::enums::{enum_metadata, is_single_member_enum};
|
||||
use crate::types::function::{
|
||||
|
|
@ -8233,97 +8232,7 @@ impl<'db> KnownInstanceType<'db> {
|
|||
|
||||
/// Return the repr of the symbol at runtime
|
||||
fn repr(self, db: &'db dyn Db) -> impl std::fmt::Display + 'db {
|
||||
struct KnownInstanceRepr<'db> {
|
||||
known_instance: KnownInstanceType<'db>,
|
||||
db: &'db dyn Db,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for KnownInstanceRepr<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self.known_instance {
|
||||
KnownInstanceType::SubscriptedProtocol(generic_context) => {
|
||||
f.write_str("typing.Protocol")?;
|
||||
generic_context.display(self.db).fmt(f)
|
||||
}
|
||||
KnownInstanceType::SubscriptedGeneric(generic_context) => {
|
||||
f.write_str("typing.Generic")?;
|
||||
generic_context.display(self.db).fmt(f)
|
||||
}
|
||||
KnownInstanceType::TypeAliasType(alias) => {
|
||||
if let Some(specialization) = alias.specialization(self.db) {
|
||||
f.write_str(alias.name(self.db))?;
|
||||
specialization
|
||||
.display_short(
|
||||
self.db,
|
||||
TupleSpecialization::No,
|
||||
DisplaySettings::default(),
|
||||
)
|
||||
.fmt(f)
|
||||
} else {
|
||||
f.write_str("typing.TypeAliasType")
|
||||
}
|
||||
}
|
||||
// This is a legacy `TypeVar` _outside_ of any generic class or function, so we render
|
||||
// it as an instance of `typing.TypeVar`. Inside of a generic class or function, we'll
|
||||
// have a `Type::TypeVar(_)`, which is rendered as the typevar's name.
|
||||
KnownInstanceType::TypeVar(typevar_instance) => {
|
||||
if typevar_instance.kind(self.db).is_paramspec() {
|
||||
f.write_str("typing.ParamSpec")
|
||||
} else {
|
||||
f.write_str("typing.TypeVar")
|
||||
}
|
||||
}
|
||||
KnownInstanceType::Deprecated(_) => f.write_str("warnings.deprecated"),
|
||||
KnownInstanceType::Field(field) => {
|
||||
f.write_str("dataclasses.Field")?;
|
||||
if let Some(default_ty) = field.default_type(self.db) {
|
||||
write!(f, "[{}]", default_ty.display(self.db))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
KnownInstanceType::ConstraintSet(tracked_set) => {
|
||||
let constraints = tracked_set.constraints(self.db);
|
||||
write!(
|
||||
f,
|
||||
"ty_extensions.ConstraintSet[{}]",
|
||||
constraints.display(self.db)
|
||||
)
|
||||
}
|
||||
KnownInstanceType::GenericContext(generic_context) => {
|
||||
write!(
|
||||
f,
|
||||
"ty_extensions.GenericContext{}",
|
||||
generic_context.display_full(self.db)
|
||||
)
|
||||
}
|
||||
KnownInstanceType::Specialization(specialization) => {
|
||||
// Normalize for consistent output across CI platforms
|
||||
write!(
|
||||
f,
|
||||
"ty_extensions.Specialization{}",
|
||||
specialization.display_full(self.db)
|
||||
)
|
||||
}
|
||||
KnownInstanceType::UnionType(_) => f.write_str("types.UnionType"),
|
||||
KnownInstanceType::Literal(_) => f.write_str("<typing.Literal special form>"),
|
||||
KnownInstanceType::Annotated(_) => {
|
||||
f.write_str("<typing.Annotated special form>")
|
||||
}
|
||||
KnownInstanceType::TypeGenericAlias(_) | KnownInstanceType::Callable(_) => {
|
||||
f.write_str("GenericAlias")
|
||||
}
|
||||
KnownInstanceType::LiteralStringAlias(_) => f.write_str("str"),
|
||||
KnownInstanceType::NewType(declaration) => {
|
||||
write!(f, "<NewType pseudo-class '{}'>", declaration.name(self.db))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KnownInstanceRepr {
|
||||
known_instance: self,
|
||||
db,
|
||||
}
|
||||
self.display_with(db, DisplaySettings::default())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -8368,6 +8277,10 @@ impl DynamicType<'_> {
|
|||
Self::Any
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_todo(&self) -> bool {
|
||||
matches!(self, Self::Todo(_) | Self::TodoUnpack)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for DynamicType<'_> {
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ use crate::types::tuple::TupleSpec;
|
|||
use crate::types::visitor::TypeVisitor;
|
||||
use crate::types::{
|
||||
BoundTypeVarIdentity, CallableType, IntersectionType, KnownBoundMethodType, KnownClass,
|
||||
MaterializationKind, Protocol, ProtocolInstanceType, SpecialFormType, StringLiteralType,
|
||||
SubclassOfInner, Type, UnionType, WrapperDescriptorKind, visitor,
|
||||
KnownInstanceType, MaterializationKind, Protocol, ProtocolInstanceType, SpecialFormType,
|
||||
StringLiteralType, SubclassOfInner, Type, UnionType, WrapperDescriptorKind, visitor,
|
||||
};
|
||||
|
||||
/// Settings for displaying types and signatures
|
||||
|
|
@ -582,7 +582,12 @@ impl Display for DisplayRepresentation<'_> {
|
|||
impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||
fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result {
|
||||
match self.ty {
|
||||
Type::Dynamic(dynamic) => write!(f.with_type(self.ty), "{dynamic}"),
|
||||
Type::Dynamic(dynamic) => {
|
||||
if dynamic.is_todo() {
|
||||
f.set_invalid_syntax();
|
||||
}
|
||||
write!(f.with_type(self.ty), "{dynamic}")
|
||||
}
|
||||
Type::Never => f.with_type(self.ty).write_str("Never"),
|
||||
Type::NominalInstance(instance) => {
|
||||
let class = instance.class(self.db);
|
||||
|
|
@ -687,9 +692,9 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
|||
Type::SpecialForm(special_form) => {
|
||||
write!(f.with_type(self.ty), "{special_form}")
|
||||
}
|
||||
Type::KnownInstance(known_instance) => {
|
||||
write!(f.with_type(self.ty), "{}", known_instance.repr(self.db))
|
||||
}
|
||||
Type::KnownInstance(known_instance) => known_instance
|
||||
.display_with(self.db, self.settings.clone())
|
||||
.fmt_detailed(f),
|
||||
Type::FunctionLiteral(function) => function
|
||||
.display_with(self.db, self.settings.clone())
|
||||
.fmt_detailed(f),
|
||||
|
|
@ -2133,6 +2138,111 @@ impl Display for DisplayStringLiteralType<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct DisplayKnownInstanceRepr<'db> {
|
||||
pub(crate) known_instance: KnownInstanceType<'db>,
|
||||
pub(crate) db: &'db dyn Db,
|
||||
}
|
||||
|
||||
impl<'db> KnownInstanceType<'db> {
|
||||
pub(crate) fn display_with(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
_settings: DisplaySettings<'db>,
|
||||
) -> DisplayKnownInstanceRepr<'db> {
|
||||
DisplayKnownInstanceRepr {
|
||||
known_instance: self,
|
||||
db,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DisplayKnownInstanceRepr<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
self.fmt_detailed(&mut TypeWriter::Formatter(f))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> FmtDetailed<'db> for DisplayKnownInstanceRepr<'db> {
|
||||
fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result {
|
||||
let ty = Type::KnownInstance(self.known_instance);
|
||||
match self.known_instance {
|
||||
KnownInstanceType::SubscriptedProtocol(generic_context) => {
|
||||
f.with_type(ty).write_str("typing.Protocol")?;
|
||||
f.write_str(&generic_context.display(self.db).to_string())
|
||||
}
|
||||
KnownInstanceType::SubscriptedGeneric(generic_context) => {
|
||||
f.with_type(ty).write_str("typing.Generic")?;
|
||||
f.write_str(&generic_context.display(self.db).to_string())
|
||||
}
|
||||
KnownInstanceType::TypeAliasType(alias) => {
|
||||
if let Some(specialization) = alias.specialization(self.db) {
|
||||
f.write_str(alias.name(self.db))?;
|
||||
f.write_str(
|
||||
&specialization
|
||||
.display_short(
|
||||
self.db,
|
||||
TupleSpecialization::No,
|
||||
DisplaySettings::default(),
|
||||
)
|
||||
.to_string(),
|
||||
)
|
||||
} else {
|
||||
f.with_type(ty).write_str("typing.TypeAliasType")
|
||||
}
|
||||
}
|
||||
// This is a legacy `TypeVar` _outside_ of any generic class or function, so we render
|
||||
// it as an instance of `typing.TypeVar`. Inside of a generic class or function, we'll
|
||||
// have a `Type::TypeVar(_)`, which is rendered as the typevar's name.
|
||||
KnownInstanceType::TypeVar(typevar_instance) => {
|
||||
if typevar_instance.kind(self.db).is_paramspec() {
|
||||
f.write_str("typing.ParamSpec")
|
||||
} else {
|
||||
f.write_str("typing.TypeVar")
|
||||
}
|
||||
}
|
||||
KnownInstanceType::Deprecated(_) => f.write_str("warnings.deprecated"),
|
||||
KnownInstanceType::Field(field) => {
|
||||
f.with_type(ty).write_str("dataclasses.Field")?;
|
||||
if let Some(default_ty) = field.default_type(self.db) {
|
||||
write!(f, "[{}]", default_ty.display(self.db))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
KnownInstanceType::ConstraintSet(tracked_set) => {
|
||||
let constraints = tracked_set.constraints(self.db);
|
||||
f.with_type(ty).write_str("ty_extensions.ConstraintSet")?;
|
||||
write!(f, "[{}]", constraints.display(self.db))
|
||||
}
|
||||
KnownInstanceType::GenericContext(generic_context) => {
|
||||
f.with_type(ty).write_str("ty_extensions.GenericContext")?;
|
||||
write!(f, "{}", generic_context.display_full(self.db))
|
||||
}
|
||||
KnownInstanceType::Specialization(specialization) => {
|
||||
// Normalize for consistent output across CI platforms
|
||||
f.with_type(ty).write_str("ty_extensions.Specialization")?;
|
||||
write!(f, "{}", specialization.display_full(self.db))
|
||||
}
|
||||
KnownInstanceType::UnionType(_) => f.with_type(ty).write_str("types.UnionType"),
|
||||
KnownInstanceType::Literal(_) => {
|
||||
f.set_invalid_syntax();
|
||||
f.write_str("<typing.Literal special form>")
|
||||
}
|
||||
KnownInstanceType::Annotated(_) => {
|
||||
f.set_invalid_syntax();
|
||||
f.write_str("<typing.Annotated special form>")
|
||||
}
|
||||
KnownInstanceType::TypeGenericAlias(_) | KnownInstanceType::Callable(_) => {
|
||||
f.with_type(ty).write_str("GenericAlias")
|
||||
}
|
||||
KnownInstanceType::LiteralStringAlias(_) => f.write_str("str"),
|
||||
KnownInstanceType::NewType(declaration) => {
|
||||
f.set_invalid_syntax();
|
||||
write!(f, "<NewType pseudo-class '{}'>", declaration.name(self.db))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use insta::assert_snapshot;
|
||||
|
|
|
|||
Loading…
Reference in New Issue