From e63a14a9fa2bc97841d12927807aa0729e131ed0 Mon Sep 17 00:00:00 2001 From: Aria Desires Date: Wed, 19 Nov 2025 20:17:09 -0500 Subject: [PATCH 1/8] replace SignatureWriter with more generic TypeDetailsWriter --- .../ty_python_semantic/src/types/display.rs | 241 ++++++++++-------- 1 file changed, 139 insertions(+), 102 deletions(-) diff --git a/crates/ty_python_semantic/src/types/display.rs b/crates/ty_python_semantic/src/types/display.rs index 3a2c6423dd01aa..bbbdd6e7ded7d2 100644 --- a/crates/ty_python_semantic/src/types/display.rs +++ b/crates/ty_python_semantic/src/types/display.rs @@ -101,6 +101,122 @@ impl<'db> DisplaySettings<'db> { } } +enum TypeWriter<'a, 'b, 'db> { + Formatter(&'a mut Formatter<'b>), + Details(TypeDetailsWriter<'db>), +} + +/// Writer that builds a string with range tracking +struct TypeDetailsWriter<'db> { + label: String, + targets: Vec, + details: Vec>, +} +impl TypeDetailsWriter<'_> { + fn new() -> Self { + Self { + label: String::new(), + targets: Vec::new(), + details: Vec::new(), + } + } + + fn finish_signature_details(self) -> SignatureDisplayDetails { + let mut parameter_ranges = Vec::new(); + let mut parameter_names = Vec::new(); + let mut parameter_nesting = 0; + for (target, detail) in self.targets.into_iter().zip(self.details) { + match detail { + TypeDetail::SignatureStart => parameter_nesting += 1, + TypeDetail::SignatureEnd => parameter_nesting -= 1, + TypeDetail::Parameter(parameter) => { + if parameter_nesting <= 1 { + parameter_names.push(parameter); + parameter_ranges.push(target); + } + } + TypeDetail::Type(_) => { /* don't care */ } + } + } + + SignatureDisplayDetails { + label: self.label, + parameter_names, + parameter_ranges, + } + } +} + +impl<'a, 'b, 'db> TypeWriter<'a, 'b, 'db> { + fn with_detail<'c>(&'c mut self, detail: TypeDetail<'db>) -> TypeDetailGuard<'a, 'b, 'c, 'db> { + let start = match self { + TypeWriter::Formatter(_) => None, + TypeWriter::Details(details) => Some(details.label.len()), + }; + TypeDetailGuard { + start, + inner: self, + payload: Some(detail), + } + } +} +impl std::fmt::Write for TypeWriter<'_, '_, '_> { + fn write_str(&mut self, val: &str) -> fmt::Result { + match self { + TypeWriter::Formatter(formatter) => formatter.write_str(val), + TypeWriter::Details(formatter) => formatter.write_str(val), + } + } +} +impl std::fmt::Write for TypeDetailsWriter<'_> { + fn write_str(&mut self, val: &str) -> fmt::Result { + self.label.write_str(val) + } +} + +enum TypeDetail<'db> { + SignatureStart, + SignatureEnd, + Parameter(String), + Type(Type<'db>), +} + +struct TypeDetailGuard<'a, 'b, 'c, 'db> { + inner: &'c mut TypeWriter<'a, 'b, 'db>, + start: Option, + payload: Option>, +} + +impl Drop for TypeDetailGuard<'_, '_, '_, '_> { + fn drop(&mut self) { + // The fallibility here is primarily retrieving `TypeWriter::Details` + // everything else is ideally-never-fails pedantry (yay for pedantry!) + if let TypeWriter::Details(details) = &mut self.inner + && let Ok(end) = u32::try_from(details.label.len()) + && let Some(start) = self.start + && let Ok(start) = u32::try_from(start) + && let Some(len) = end.checked_sub(start) + && let Some(payload) = self.payload.take() + { + let target = TextRange::at(TextSize::new(start), TextSize::new(len)); + details.targets.push(target); + details.details.push(payload); + } + } +} + +impl<'a, 'b, 'db> std::ops::Deref for TypeDetailGuard<'a, 'b, '_, 'db> { + type Target = TypeWriter<'a, 'b, 'db>; + fn deref(&self) -> &Self::Target { + self.inner + } +} +impl std::ops::DerefMut for TypeDetailGuard<'_, '_, '_, '_> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.inner + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum QualificationLevel { ModuleName, @@ -1179,17 +1295,21 @@ pub(crate) struct DisplaySignature<'db> { impl DisplaySignature<'_> { /// Get detailed display information including component ranges pub(crate) fn to_string_parts(&self) -> SignatureDisplayDetails { - let mut writer = SignatureWriter::Details(SignatureDetailsWriter::new()); + let mut writer = TypeWriter::Details(TypeDetailsWriter::new()); self.write_signature(&mut writer).unwrap(); match writer { - SignatureWriter::Details(details) => details.finish(), - SignatureWriter::Formatter(_) => unreachable!("Expected Details variant"), + TypeWriter::Details(details) => details.finish_signature_details(), + TypeWriter::Formatter(_) => unreachable!("Expected Details variant"), } } /// Internal method to write signature with the signature writer - fn write_signature(&self, writer: &mut SignatureWriter) -> fmt::Result { + fn write_signature(&self, writer: &mut TypeWriter) -> fmt::Result { + // Immediately write a marker signaling we're starting a signature + let _ = writer.with_detail(TypeDetail::SignatureStart); + // When we exit this function, write a marker signaling we're ending a signature + let mut writer = writer.with_detail(TypeDetail::SignatureEnd); let multiline = self.settings.multiline && self.parameters.len() > 1; // Opening parenthesis writer.write_char('(')?; @@ -1233,10 +1353,15 @@ impl DisplaySignature<'_> { } // Write parameter with range tracking - let param_name = parameter.display_name(); - writer.write_parameter( - ¶meter.display_with(self.db, self.settings.singleline()), - param_name.as_deref(), + let param_name = parameter + .display_name() + .map(|name| name.to_string()) + .unwrap_or_default(); + let mut writer = writer.with_detail(TypeDetail::Parameter(param_name)); + write!( + &mut writer, + "{}", + parameter.display_with(self.db, self.settings.singleline()) )?; first = false; @@ -1258,7 +1383,11 @@ impl DisplaySignature<'_> { // Return type let return_ty = self.return_ty.unwrap_or_else(Type::unknown); - writer.write_return_type(&return_ty.display_with(self.db, self.settings.singleline()))?; + write!( + &mut writer, + " -> {}", + return_ty.display_with(self.db, self.settings.singleline()) + )?; Ok(()) } @@ -1266,102 +1395,10 @@ impl DisplaySignature<'_> { impl Display for DisplaySignature<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let mut writer = SignatureWriter::Formatter(f); + let mut writer = TypeWriter::Formatter(f); self.write_signature(&mut writer) } } - -/// Writer for building signature strings with different output targets -enum SignatureWriter<'a, 'b> { - /// Write directly to a formatter (for Display trait) - Formatter(&'a mut Formatter<'b>), - /// Build a string with range tracking (for `to_string_parts`) - Details(SignatureDetailsWriter), -} - -/// Writer that builds a string with range tracking -struct SignatureDetailsWriter { - label: String, - parameter_ranges: Vec, - parameter_names: Vec, -} - -impl SignatureDetailsWriter { - fn new() -> Self { - Self { - label: String::new(), - parameter_ranges: Vec::new(), - parameter_names: Vec::new(), - } - } - - fn finish(self) -> SignatureDisplayDetails { - SignatureDisplayDetails { - label: self.label, - parameter_ranges: self.parameter_ranges, - parameter_names: self.parameter_names, - } - } -} - -impl SignatureWriter<'_, '_> { - fn write_char(&mut self, c: char) -> fmt::Result { - match self { - SignatureWriter::Formatter(f) => f.write_char(c), - SignatureWriter::Details(details) => { - details.label.push(c); - Ok(()) - } - } - } - - fn write_str(&mut self, s: &str) -> fmt::Result { - match self { - SignatureWriter::Formatter(f) => f.write_str(s), - SignatureWriter::Details(details) => { - details.label.push_str(s); - Ok(()) - } - } - } - - fn write_parameter(&mut self, param: &T, param_name: Option<&str>) -> fmt::Result { - match self { - SignatureWriter::Formatter(f) => param.fmt(f), - SignatureWriter::Details(details) => { - let param_start = details.label.len(); - let param_display = param.to_string(); - details.label.push_str(¶m_display); - - // Use TextSize::try_from for safe conversion, falling back to empty range on overflow - let start = TextSize::try_from(param_start).unwrap_or_default(); - let length = TextSize::try_from(param_display.len()).unwrap_or_default(); - details.parameter_ranges.push(TextRange::at(start, length)); - - // Store the parameter name if available - if let Some(name) = param_name { - details.parameter_names.push(name.to_string()); - } else { - details.parameter_names.push(String::new()); - } - - Ok(()) - } - } - } - - fn write_return_type(&mut self, return_ty: &T) -> fmt::Result { - match self { - SignatureWriter::Formatter(f) => write!(f, " -> {return_ty}"), - SignatureWriter::Details(details) => { - let return_display = format!(" -> {return_ty}"); - details.label.push_str(&return_display); - Ok(()) - } - } - } -} - /// Details about signature display components, including ranges for parameters and return type #[derive(Debug, Clone)] pub(crate) struct SignatureDisplayDetails { From 3b7006e71c3f3e16a8d646a6e575ab469ab6e2d4 Mon Sep 17 00:00:00 2001 From: Aria Desires Date: Wed, 19 Nov 2025 22:54:12 -0500 Subject: [PATCH 2/8] introduce fmt_detailed everywhere --- .../ty_python_semantic/src/types/display.rs | 732 +++++++++++------- 1 file changed, 439 insertions(+), 293 deletions(-) diff --git a/crates/ty_python_semantic/src/types/display.rs b/crates/ty_python_semantic/src/types/display.rs index bbbdd6e7ded7d2..35006b54ccc193 100644 --- a/crates/ty_python_semantic/src/types/display.rs +++ b/crates/ty_python_semantic/src/types/display.rs @@ -361,8 +361,8 @@ pub struct DisplayType<'db> { settings: DisplaySettings<'db>, } -impl Display for DisplayType<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl<'db> DisplayType<'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { let representation = self.ty.representation(self.db, self.settings.clone()); match self.ty { Type::IntLiteral(_) @@ -370,13 +370,21 @@ impl Display for DisplayType<'_> { | Type::StringLiteral(_) | Type::BytesLiteral(_) | Type::EnumLiteral(_) => { - write!(f, "Literal[{representation}]") + f.write_str("Literal[")?; + representation.fmt_detailed(f)?; + f.write_str("]") } - _ => representation.fmt(f), + _ => representation.fmt_detailed(f), } } } +impl Display for DisplayType<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.fmt_detailed(&mut TypeWriter::Formatter(f)) + } +} + impl fmt::Debug for DisplayType<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { Display::fmt(self, f) @@ -445,8 +453,8 @@ struct ClassDisplay<'db> { settings: DisplaySettings<'db>, } -impl Display for ClassDisplay<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl<'db> ClassDisplay<'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { let qualification_level = self.settings.qualified.get(&**self.class.name(self.db)); if qualification_level.is_some() { for parent in self.class.qualified_name_components(self.db) { @@ -475,6 +483,12 @@ impl Display for ClassDisplay<'_> { } } +impl Display for ClassDisplay<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.fmt_detailed(&mut TypeWriter::Formatter(f)) + } +} + /// Writes the string representation of a type, which is the value displayed either as /// `Literal[]` or `Literal[, ]` for literal types or as `` for /// non literals @@ -486,35 +500,41 @@ struct DisplayRepresentation<'db> { impl Display for DisplayRepresentation<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.fmt_detailed(&mut TypeWriter::Formatter(f)) + } +} + +impl<'db> DisplayRepresentation<'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { match self.ty { - Type::Dynamic(dynamic) => dynamic.fmt(f), - Type::Never => f.write_str("Never"), + Type::Dynamic(dynamic) => write!(f, "{dynamic}"), + Type::Never => f.with_detail(TypeDetail::Type(self.ty)).write_str("Never"), Type::NominalInstance(instance) => { let class = instance.class(self.db); match (class, class.known(self.db)) { - (_, Some(KnownClass::NoneType)) => f.write_str("None"), - (_, Some(KnownClass::NoDefaultType)) => f.write_str("NoDefault"), + (_, Some(KnownClass::NoneType)) => f.with_detail(TypeDetail::Type(self.ty)).write_str("None"), + (_, Some(KnownClass::NoDefaultType)) => f.with_detail(TypeDetail::Type(self.ty)).write_str("NoDefault"), (ClassType::Generic(alias), Some(KnownClass::Tuple)) => alias .specialization(self.db) .tuple(self.db) .expect("Specialization::tuple() should always return `Some()` for `KnownClass::Tuple`") .display_with(self.db, self.settings.clone()) - .fmt(f), + .fmt_detailed(f), (ClassType::NonGeneric(class), _) => { - class.display_with(self.db, self.settings.clone()).fmt(f) + class.display_with(self.db, self.settings.clone()).fmt_detailed(f) }, - (ClassType::Generic(alias), _) => alias.display_with(self.db, self.settings.clone()).fmt(f), + (ClassType::Generic(alias), _) => alias.display_with(self.db, self.settings.clone()).fmt_detailed(f), } } Type::ProtocolInstance(protocol) => match protocol.inner { Protocol::FromClass(class) => match *class { - ClassType::NonGeneric(class) => { - class.display_with(self.db, self.settings.clone()).fmt(f) - } - ClassType::Generic(alias) => { - alias.display_with(self.db, self.settings.clone()).fmt(f) - } + ClassType::NonGeneric(class) => class + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f), + ClassType::Generic(alias) => alias + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f), }, Protocol::Synthesized(synthetic) => { f.write_str(" { }, Type::PropertyInstance(_) => f.write_str("property"), Type::ModuleLiteral(module) => { - write!(f, "", module.module(self.db).name(self.db)) + write!( + f.with_detail(TypeDetail::Type(self.ty)), + "", + module.module(self.db).name(self.db) + ) } Type::ClassLiteral(class) => write!( - f, + f.with_detail(TypeDetail::Type(self.ty)), "", class.display_with(self.db, self.settings.clone()) ), Type::GenericAlias(generic) => write!( - f, + f.with_detail(TypeDetail::Type(self.ty)), "", generic.display_with(self.db, self.settings.singleline()) ), Type::SubclassOf(subclass_of_ty) => match subclass_of_ty.subclass_of() { SubclassOfInner::Class(ClassType::NonGeneric(class)) => { - write!( - f, - "type[{}]", - class.display_with(self.db, self.settings.clone()) - ) + f.write_str("type[")?; + class + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f)?; + f.write_str("]") } SubclassOfInner::Class(ClassType::Generic(alias)) => { - write!( - f, - "type[{}]", - alias.display_with(self.db, self.settings.singleline()) - ) + f.write_str("type[")?; + alias + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f)?; + f.write_str("]") } SubclassOfInner::Dynamic(dynamic) => write!(f, "type[{dynamic}]"), }, - Type::SpecialForm(special_form) => special_form.fmt(f), - Type::KnownInstance(known_instance) => known_instance.repr(self.db).fmt(f), - Type::FunctionLiteral(function) => { - function.display_with(self.db, self.settings.clone()).fmt(f) - } - Type::Callable(callable) => { - callable.display_with(self.db, self.settings.clone()).fmt(f) - } + Type::SpecialForm(special_form) => write!(f, "{special_form}"), + Type::KnownInstance(known_instance) => write!(f, "{}", known_instance.repr(self.db)), + Type::FunctionLiteral(function) => function + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f), + Type::Callable(callable) => callable + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f), Type::BoundMethod(bound_method) => { let function = bound_method.function(self.db); let self_ty = bound_method.self_instance(self.db); @@ -583,16 +607,18 @@ impl Display for DisplayRepresentation<'_> { settings: self.settings.clone(), }; - write!( - f, - "bound method {instance}.{method}{type_parameters}{signature}", - method = function.name(self.db), - instance = self_ty.display_with(self.db, self.settings.singleline()), - type_parameters = type_parameters, - signature = signature - .bind_self(self.db, Some(typing_self_ty)) - .display_with(self.db, self.settings.clone()) - ) + f.write_str("bound method ")?; + self_ty + .display_with(self.db, self.settings.singleline()) + .fmt_detailed(f)?; + f.write_char('.')?; + f.with_detail(TypeDetail::Type(self.ty)) + .write_str(function.name(self.db))?; + type_parameters.fmt_detailed(f)?; + signature + .bind_self(self.db, Some(typing_self_ty)) + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f) } signatures => { // TODO: How to display overloads? @@ -600,13 +626,16 @@ impl Display for DisplayRepresentation<'_> { f.write_str("Overload[")?; } let separator = if self.settings.multiline { "\n" } else { ", " }; - let mut join = f.join(separator); + let mut is_first = true; for signature in signatures { - join.entry( - &signature - .bind_self(self.db, Some(typing_self_ty)) - .display_with(self.db, self.settings.clone()), - ); + if !is_first { + f.write_str(separator)?; + } + is_first = false; + signature + .bind_self(self.db, Some(typing_self_ty)) + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f)?; } if !self.settings.multiline { f.write_str("]")?; @@ -676,14 +705,16 @@ impl Display for DisplayRepresentation<'_> { Type::DataclassTransformer(_) => { f.write_str("") } - Type::Union(union) => union.display_with(self.db, self.settings.clone()).fmt(f), + Type::Union(union) => union + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f), Type::Intersection(intersection) => intersection .display_with(self.db, self.settings.clone()) - .fmt(f), - Type::IntLiteral(n) => n.fmt(f), + .fmt_detailed(f), + Type::IntLiteral(n) => write!(f, "{n}"), Type::BooleanLiteral(boolean) => f.write_str(if boolean { "True" } else { "False" }), Type::StringLiteral(string) => { - string.display_with(self.db, self.settings.clone()).fmt(f) + write!(f, "{}", string.display_with(self.db, self.settings.clone())) } Type::LiteralString => f.write_str("LiteralString"), Type::BytesLiteral(bytes) => { @@ -691,33 +722,35 @@ impl Display for DisplayRepresentation<'_> { escape.bytes_repr(TripleQuotes::No).write(f) } - Type::EnumLiteral(enum_literal) => write!( - f, - "{enum_class}.{literal_name}", - enum_class = enum_literal + Type::EnumLiteral(enum_literal) => { + enum_literal .enum_class(self.db) - .display_with(self.db, self.settings.clone()), - literal_name = enum_literal.name(self.db) - ), - Type::TypeVar(bound_typevar) => bound_typevar.identity(self.db).display(self.db).fmt(f), + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f)?; + write!(f, ".{}", enum_literal.name(self.db)) + } + Type::TypeVar(bound_typevar) => { + write!(f, "{}", bound_typevar.identity(self.db).display(self.db)) + } Type::AlwaysTruthy => f.write_str("AlwaysTruthy"), Type::AlwaysFalsy => f.write_str("AlwaysFalsy"), Type::BoundSuper(bound_super) => { - write!( - f, - "", - pivot = Type::from(bound_super.pivot_class(self.db)) - .display_with(self.db, self.settings.singleline()), - owner = Type::from(bound_super.owner(self.db)) - .display_with(self.db, self.settings.singleline()) - ) + f.write_str("") } Type::TypeIs(type_is) => { f.write_str("TypeIs[")?; type_is .return_type(self.db) .display_with(self.db, self.settings.singleline()) - .fmt(f)?; + .fmt_detailed(f)?; if let Some(name) = type_is.place_name(self.db) { f.write_str(" @ ")?; f.write_str(&name)?; @@ -729,17 +762,19 @@ impl Display for DisplayRepresentation<'_> { .class_literal(self.db) .0 .display_with(self.db, self.settings.clone()) - .fmt(f), + .fmt_detailed(f), Type::TypeAlias(alias) => { f.write_str(alias.name(self.db))?; match alias.specialization(self.db) { None => Ok(()), Some(specialization) => specialization .display_short(self.db, TupleSpecialization::No, self.settings.clone()) - .fmt(f), + .fmt_detailed(f), } } - Type::NewTypeInstance(newtype) => f.write_str(newtype.name(self.db)), + Type::NewTypeInstance(newtype) => f + .with_detail(TypeDetail::Type(self.ty)) + .write_str(newtype.name(self.db)), } } } @@ -769,11 +804,11 @@ impl Display for DisplayBoundTypeVarIdentity<'_> { } impl<'db> TupleSpec<'db> { - pub(crate) fn display_with( - &'db self, + pub(crate) fn display_with<'a>( + &'a self, db: &'db dyn Db, settings: DisplaySettings<'db>, - ) -> DisplayTuple<'db> { + ) -> DisplayTuple<'a, 'db> { DisplayTuple { tuple: self, db, @@ -782,14 +817,14 @@ impl<'db> TupleSpec<'db> { } } -pub(crate) struct DisplayTuple<'db> { - tuple: &'db TupleSpec<'db>, +pub(crate) struct DisplayTuple<'a, 'db> { + tuple: &'a TupleSpec<'db>, db: &'db dyn Db, settings: DisplaySettings<'db>, } -impl Display for DisplayTuple<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl<'db> DisplayTuple<'_, 'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { f.write_str("tuple[")?; match self.tuple { TupleSpec::Fixed(tuple) => { @@ -799,7 +834,7 @@ impl Display for DisplayTuple<'_> { } else { elements .display_with(self.db, self.settings.singleline()) - .fmt(f)?; + .fmt_detailed(f)?; } } @@ -822,7 +857,7 @@ impl Display for DisplayTuple<'_> { tuple .prefix .display_with(self.db, self.settings.singleline()) - .fmt(f)?; + .fmt_detailed(f)?; f.write_str(", ")?; } if !tuple.prefix.is_empty() || !tuple.suffix.is_empty() { @@ -831,7 +866,7 @@ impl Display for DisplayTuple<'_> { tuple .variable .display_with(self.db, self.settings.singleline()) - .fmt(f)?; + .fmt_detailed(f)?; f.write_str(", ...")?; if !tuple.prefix.is_empty() || !tuple.suffix.is_empty() { f.write_str("]")?; @@ -841,7 +876,7 @@ impl Display for DisplayTuple<'_> { tuple .suffix .display_with(self.db, self.settings.singleline()) - .fmt(f)?; + .fmt_detailed(f)?; } } } @@ -849,6 +884,12 @@ impl Display for DisplayTuple<'_> { } } +impl Display for DisplayTuple<'_, '_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.fmt_detailed(&mut TypeWriter::Formatter(f)) + } +} + impl<'db> OverloadLiteral<'db> { // Not currently used, but useful for debugging. #[expect(dead_code)] @@ -875,8 +916,8 @@ pub(crate) struct DisplayOverloadLiteral<'db> { settings: DisplaySettings<'db>, } -impl Display for DisplayOverloadLiteral<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl<'db> DisplayOverloadLiteral<'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { let signature = self.literal.signature(self.db); let type_parameters = DisplayOptionalGenericContext { generic_context: signature.generic_context.as_ref(), @@ -884,13 +925,18 @@ impl Display for DisplayOverloadLiteral<'_> { settings: self.settings.clone(), }; - write!( - f, - "def {name}{type_parameters}{signature}", - name = self.literal.name(self.db), - type_parameters = type_parameters, - signature = signature.display_with(self.db, self.settings.clone()) - ) + f.write_str("def ")?; + write!(f, "{}", self.literal.name(self.db))?; + type_parameters.fmt_detailed(f)?; + signature + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f) + } +} + +impl Display for DisplayOverloadLiteral<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.fmt_detailed(&mut TypeWriter::Formatter(f)) } } @@ -914,8 +960,8 @@ pub(crate) struct DisplayFunctionType<'db> { settings: DisplaySettings<'db>, } -impl Display for DisplayFunctionType<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl<'db> DisplayFunctionType<'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { let signature = self.ty.signature(self.db); match signature.overloads.as_slice() { @@ -926,13 +972,12 @@ impl Display for DisplayFunctionType<'_> { settings: self.settings.clone(), }; - write!( - f, - "def {name}{type_parameters}{signature}", - name = self.ty.name(self.db), - type_parameters = type_parameters, - signature = signature.display_with(self.db, self.settings.clone()) - ) + f.write_str("def ")?; + write!(f, "{}", self.ty.name(self.db))?; + type_parameters.fmt_detailed(f)?; + signature + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f) } signatures => { // TODO: How to display overloads? @@ -940,9 +985,15 @@ impl Display for DisplayFunctionType<'_> { f.write_str("Overload[")?; } let separator = if self.settings.multiline { "\n" } else { ", " }; - let mut join = f.join(separator); + let mut is_first = true; for signature in signatures { - join.entry(&signature.display_with(self.db, self.settings.clone())); + if !is_first { + f.write_str(separator)?; + } + is_first = false; + signature + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f)?; } if !self.settings.multiline { f.write_str("]")?; @@ -953,13 +1004,19 @@ impl Display for DisplayFunctionType<'_> { } } +impl Display for DisplayFunctionType<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.fmt_detailed(&mut TypeWriter::Formatter(f)) + } +} + impl<'db> GenericAlias<'db> { - pub(crate) fn display(&'db self, db: &'db dyn Db) -> DisplayGenericAlias<'db> { + pub(crate) fn display(self, db: &'db dyn Db) -> DisplayGenericAlias<'db> { self.display_with(db, DisplaySettings::default()) } pub(crate) fn display_with( - &'db self, + self, db: &'db dyn Db, settings: DisplaySettings<'db>, ) -> DisplayGenericAlias<'db> { @@ -979,10 +1036,12 @@ pub(crate) struct DisplayGenericAlias<'db> { settings: DisplaySettings<'db>, } -impl Display for DisplayGenericAlias<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl<'db> DisplayGenericAlias<'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { if let Some(tuple) = self.specialization.tuple(self.db) { - tuple.display_with(self.db, self.settings.clone()).fmt(f) + tuple + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f) } else { let prefix = match self.specialization.materialization_kind(self.db) { None => "", @@ -993,28 +1052,34 @@ impl Display for DisplayGenericAlias<'_> { None => "", Some(_) => "]", }; - write!( - f, - "{prefix}{origin}{specialization}{suffix}", - prefix = prefix, - origin = self.origin.display_with(self.db, self.settings.clone()), - specialization = self.specialization.display_short( + f.write_str(prefix)?; + self.origin + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f)?; + self.specialization + .display_short( self.db, TupleSpecialization::from_class(self.db, self.origin), - self.settings.clone() - ), - suffix = suffix, - ) + self.settings.clone(), + ) + .fmt_detailed(f)?; + f.write_str(suffix) } } } +impl Display for DisplayGenericAlias<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.fmt_detailed(&mut TypeWriter::Formatter(f)) + } +} + impl<'db> GenericContext<'db> { - pub fn display(&'db self, db: &'db dyn Db) -> DisplayGenericContext<'db> { + pub fn display<'a>(&'a self, db: &'db dyn Db) -> DisplayGenericContext<'a, 'db> { Self::display_with(self, db, DisplaySettings::default()) } - pub fn display_full(&'db self, db: &'db dyn Db) -> DisplayGenericContext<'db> { + pub fn display_full<'a>(&'a self, db: &'db dyn Db) -> DisplayGenericContext<'a, 'db> { DisplayGenericContext { generic_context: self, db, @@ -1023,11 +1088,11 @@ impl<'db> GenericContext<'db> { } } - pub fn display_with( - &'db self, + pub fn display_with<'a>( + &'a self, db: &'db dyn Db, settings: DisplaySettings<'db>, - ) -> DisplayGenericContext<'db> { + ) -> DisplayGenericContext<'a, 'db> { DisplayGenericContext { generic_context: self, db, @@ -1037,34 +1102,48 @@ impl<'db> GenericContext<'db> { } } -struct DisplayOptionalGenericContext<'db> { - generic_context: Option<&'db GenericContext<'db>>, +struct DisplayOptionalGenericContext<'a, 'db> { + generic_context: Option<&'a GenericContext<'db>>, db: &'db dyn Db, settings: DisplaySettings<'db>, } -impl Display for DisplayOptionalGenericContext<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl<'db> DisplayOptionalGenericContext<'_, 'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { if let Some(generic_context) = self.generic_context { generic_context .display_with(self.db, self.settings.clone()) - .fmt(f) + .fmt_detailed(f) } else { Ok(()) } } } -pub struct DisplayGenericContext<'db> { - generic_context: &'db GenericContext<'db>, +impl Display for DisplayOptionalGenericContext<'_, '_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.fmt_detailed(&mut TypeWriter::Formatter(f)) + } +} + +pub struct DisplayGenericContext<'a, 'db> { + generic_context: &'a GenericContext<'db>, db: &'db dyn Db, #[expect(dead_code)] settings: DisplaySettings<'db>, full: bool, } -impl DisplayGenericContext<'_> { - fn fmt_normal(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl<'db> DisplayGenericContext<'_, 'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { + if self.full { + self.fmt_full(f) + } else { + self.fmt_normal(f) + } + } + + fn fmt_normal(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { let variables = self.generic_context.variables(self.db); let non_implicit_variables: Vec<_> = variables @@ -1085,26 +1164,22 @@ impl DisplayGenericContext<'_> { f.write_char(']') } - fn fmt_full(&self, f: &mut Formatter<'_>) -> fmt::Result { + fn fmt_full(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { let variables = self.generic_context.variables(self.db); f.write_char('[')?; for (idx, bound_typevar) in variables.enumerate() { if idx > 0 { f.write_str(", ")?; } - bound_typevar.identity(self.db).display(self.db).fmt(f)?; + write!(f, "{}", bound_typevar.identity(self.db).display(self.db))?; } f.write_char(']') } } -impl Display for DisplayGenericContext<'_> { +impl Display for DisplayGenericContext<'_, '_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - if self.full { - self.fmt_full(f) - } else { - self.fmt_normal(f) - } + self.fmt_detailed(&mut TypeWriter::Formatter(f)) } } @@ -1148,15 +1223,24 @@ pub struct DisplaySpecialization<'db> { full: bool, } -impl DisplaySpecialization<'_> { - fn fmt_normal(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl<'db> DisplaySpecialization<'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { + if self.full { + self.fmt_full(f) + } else { + self.fmt_normal(f) + } + } + + fn fmt_normal(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { f.write_char('[')?; let types = self.specialization.types(self.db); for (idx, ty) in types.iter().enumerate() { if idx > 0 { f.write_str(", ")?; } - ty.display_with(self.db, self.settings.clone()).fmt(f)?; + ty.display_with(self.db, self.settings.clone()) + .fmt_detailed(f)?; } if self.tuple_specialization.is_yes() { f.write_str(", ...")?; @@ -1164,7 +1248,7 @@ impl DisplaySpecialization<'_> { f.write_char(']') } - fn fmt_full(&self, f: &mut Formatter<'_>) -> fmt::Result { + fn fmt_full(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { f.write_char('[')?; let variables = self .specialization @@ -1175,12 +1259,10 @@ impl DisplaySpecialization<'_> { if idx > 0 { f.write_str(", ")?; } - write!( - f, - "{} = {}", - bound_typevar.identity(self.db).display(self.db), - ty.display_with(self.db, self.settings.clone()), - )?; + write!(f, "{}", bound_typevar.identity(self.db).display(self.db))?; + f.write_str(" = ")?; + ty.display_with(self.db, self.settings.clone()) + .fmt_detailed(f)?; } f.write_char(']') } @@ -1188,11 +1270,7 @@ impl DisplaySpecialization<'_> { impl Display for DisplaySpecialization<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - if self.full { - self.fmt_full(f) - } else { - self.fmt_normal(f) - } + self.fmt_detailed(&mut TypeWriter::Formatter(f)) } } @@ -1217,15 +1295,15 @@ impl TupleSpecialization { } impl<'db> CallableType<'db> { - pub(crate) fn display(&'db self, db: &'db dyn Db) -> DisplayCallableType<'db> { + pub(crate) fn display<'a>(&'a self, db: &'db dyn Db) -> DisplayCallableType<'a, 'db> { Self::display_with(self, db, DisplaySettings::default()) } - pub(crate) fn display_with( - &'db self, + pub(crate) fn display_with<'a>( + &'a self, db: &'db dyn Db, settings: DisplaySettings<'db>, - ) -> DisplayCallableType<'db> { + ) -> DisplayCallableType<'a, 'db> { DisplayCallableType { signatures: self.signatures(db), db, @@ -1234,29 +1312,34 @@ impl<'db> CallableType<'db> { } } -pub(crate) struct DisplayCallableType<'db> { - signatures: &'db CallableSignature<'db>, +pub(crate) struct DisplayCallableType<'a, 'db> { + signatures: &'a CallableSignature<'db>, db: &'db dyn Db, settings: DisplaySettings<'db>, } -impl Display for DisplayCallableType<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl<'db> DisplayCallableType<'_, 'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { match self.signatures.overloads.as_slice() { [signature] => signature .display_with(self.db, self.settings.clone()) - .fmt(f), + .fmt_detailed(f), signatures => { // TODO: How to display overloads? if !self.settings.multiline { f.write_str("Overload[")?; } let separator = if self.settings.multiline { "\n" } else { ", " }; - let mut join = f.join(separator); + let mut is_first = true; for signature in signatures { - join.entry(&signature.display_with(self.db, self.settings.clone())); + if !is_first { + f.write_str(separator)?; + } + is_first = false; + signature + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f)?; } - join.finish()?; if !self.settings.multiline { f.write_char(']')?; } @@ -1266,16 +1349,22 @@ impl Display for DisplayCallableType<'_> { } } +impl Display for DisplayCallableType<'_, '_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.fmt_detailed(&mut TypeWriter::Formatter(f)) + } +} + impl<'db> Signature<'db> { - pub(crate) fn display(&'db self, db: &'db dyn Db) -> DisplaySignature<'db> { + pub(crate) fn display<'a>(&'a self, db: &'db dyn Db) -> DisplaySignature<'a, 'db> { Self::display_with(self, db, DisplaySettings::default()) } - pub(crate) fn display_with( - &'db self, + pub(crate) fn display_with<'a>( + &'a self, db: &'db dyn Db, settings: DisplaySettings<'db>, - ) -> DisplaySignature<'db> { + ) -> DisplaySignature<'a, 'db> { DisplaySignature { parameters: self.parameters(), return_ty: self.return_ty, @@ -1285,41 +1374,40 @@ impl<'db> Signature<'db> { } } -pub(crate) struct DisplaySignature<'db> { - parameters: &'db Parameters<'db>, +pub(crate) struct DisplaySignature<'a, 'db> { + parameters: &'a Parameters<'db>, return_ty: Option>, db: &'db dyn Db, settings: DisplaySettings<'db>, } -impl DisplaySignature<'_> { +impl<'db> DisplaySignature<'_, 'db> { /// Get detailed display information including component ranges pub(crate) fn to_string_parts(&self) -> SignatureDisplayDetails { - let mut writer = TypeWriter::Details(TypeDetailsWriter::new()); - self.write_signature(&mut writer).unwrap(); + let mut f = TypeWriter::Details(TypeDetailsWriter::new()); + self.fmt_detailed(&mut f).unwrap(); - match writer { + match f { TypeWriter::Details(details) => details.finish_signature_details(), TypeWriter::Formatter(_) => unreachable!("Expected Details variant"), } } - /// Internal method to write signature with the signature writer - fn write_signature(&self, writer: &mut TypeWriter) -> fmt::Result { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { // Immediately write a marker signaling we're starting a signature - let _ = writer.with_detail(TypeDetail::SignatureStart); + let _ = f.with_detail(TypeDetail::SignatureStart); // When we exit this function, write a marker signaling we're ending a signature - let mut writer = writer.with_detail(TypeDetail::SignatureEnd); + let mut f = f.with_detail(TypeDetail::SignatureEnd); let multiline = self.settings.multiline && self.parameters.len() > 1; // Opening parenthesis - writer.write_char('(')?; + f.write_char('(')?; if multiline { - writer.write_str("\n ")?; + f.write_str("\n ")?; } if self.parameters.is_gradual() { // We represent gradual form as `...` in the signature, internally the parameters still // contain `(*args, **kwargs)` parameters. - writer.write_str("...")?; + f.write_str("...")?; } else { let mut star_added = false; let mut needs_slash = false; @@ -1330,9 +1418,9 @@ impl DisplaySignature<'_> { // Handle special separators if !star_added && parameter.is_keyword_only() { if !first { - writer.write_str(arg_separator)?; + f.write_str(arg_separator)?; } - writer.write_char('*')?; + f.write_char('*')?; star_added = true; first = false; } @@ -1340,16 +1428,16 @@ impl DisplaySignature<'_> { needs_slash = true; } else if needs_slash { if !first { - writer.write_str(arg_separator)?; + f.write_str(arg_separator)?; } - writer.write_char('/')?; + f.write_char('/')?; needs_slash = false; first = false; } // Add comma before parameter if not first if !first { - writer.write_str(arg_separator)?; + f.write_str(arg_separator)?; } // Write parameter with range tracking @@ -1357,48 +1445,42 @@ impl DisplaySignature<'_> { .display_name() .map(|name| name.to_string()) .unwrap_or_default(); - let mut writer = writer.with_detail(TypeDetail::Parameter(param_name)); - write!( - &mut writer, - "{}", - parameter.display_with(self.db, self.settings.singleline()) - )?; + parameter + .display_with(self.db, self.settings.singleline()) + .fmt_detailed(&mut f.with_detail(TypeDetail::Parameter(param_name)))?; first = false; } if needs_slash { if !first { - writer.write_str(arg_separator)?; + f.write_str(arg_separator)?; } - writer.write_char('/')?; + f.write_char('/')?; } } if multiline { - writer.write_char('\n')?; + f.write_char('\n')?; } // Closing parenthesis - writer.write_char(')')?; + f.write_char(')')?; // Return type let return_ty = self.return_ty.unwrap_or_else(Type::unknown); - write!( - &mut writer, - " -> {}", - return_ty.display_with(self.db, self.settings.singleline()) - )?; - - Ok(()) + f.write_str(" -> ")?; + return_ty + .display_with(self.db, self.settings.singleline()) + .fmt_detailed(&mut f) } } -impl Display for DisplaySignature<'_> { +impl Display for DisplaySignature<'_, '_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let mut writer = TypeWriter::Formatter(f); - self.write_signature(&mut writer) + self.fmt_detailed(&mut TypeWriter::Formatter(f)) } } + /// Details about signature display components, including ranges for parameters and return type #[derive(Debug, Clone)] pub(crate) struct SignatureDisplayDetails { @@ -1411,11 +1493,11 @@ pub(crate) struct SignatureDisplayDetails { } impl<'db> Parameter<'db> { - fn display_with( - &'db self, + fn display_with<'a>( + &'a self, db: &'db dyn Db, settings: DisplaySettings<'db>, - ) -> DisplayParameter<'db> { + ) -> DisplayParameter<'a, 'db> { DisplayParameter { param: self, db, @@ -1424,50 +1506,51 @@ impl<'db> Parameter<'db> { } } -struct DisplayParameter<'db> { - param: &'db Parameter<'db>, +struct DisplayParameter<'a, 'db> { + param: &'a Parameter<'db>, db: &'db dyn Db, settings: DisplaySettings<'db>, } -impl Display for DisplayParameter<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl<'db> DisplayParameter<'_, 'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { if let Some(name) = self.param.display_name() { f.write_str(&name)?; if let Some(annotated_type) = self.param.annotated_type() { if self.param.should_annotation_be_displayed() { - write!( - f, - ": {}", - annotated_type.display_with(self.db, self.settings.clone()) - )?; + f.write_str(": ")?; + annotated_type + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f)?; } } // Default value can only be specified if `name` is given. if let Some(default_ty) = self.param.default_type() { if self.param.annotated_type().is_some() { - write!( - f, - " = {}", - default_ty.display_with(self.db, self.settings.clone()) - )?; + f.write_str(" = ")?; } else { - write!( - f, - "={}", - default_ty.display_with(self.db, self.settings.clone()) - )?; + f.write_str("=")?; } + default_ty + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f)?; } } else if let Some(ty) = self.param.annotated_type() { // This case is specifically for the `Callable` signature where name and default value // cannot be provided. - ty.display_with(self.db, self.settings.clone()).fmt(f)?; + ty.display_with(self.db, self.settings.clone()) + .fmt_detailed(f)?; } Ok(()) } } +impl Display for DisplayParameter<'_, '_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.fmt_detailed(&mut TypeWriter::Formatter(f)) + } +} + #[derive(Debug, Copy, Clone)] struct TruncationPolicy { max: usize, @@ -1507,11 +1590,11 @@ impl Display for DisplayOmitted { } impl<'db> UnionType<'db> { - fn display_with( - &'db self, + fn display_with<'a>( + &'a self, db: &'db dyn Db, settings: DisplaySettings<'db>, - ) -> DisplayUnionType<'db> { + ) -> DisplayUnionType<'a, 'db> { DisplayUnionType { db, ty: self, @@ -1520,8 +1603,8 @@ impl<'db> UnionType<'db> { } } -struct DisplayUnionType<'db> { - ty: &'db UnionType<'db>, +struct DisplayUnionType<'a, 'db> { + ty: &'a UnionType<'db>, db: &'db dyn Db, settings: DisplaySettings<'db>, } @@ -1531,8 +1614,8 @@ const UNION_POLICY: TruncationPolicy = TruncationPolicy { max_when_elided: 3, }; -impl Display for DisplayUnionType<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl<'db> DisplayUnionType<'_, 'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { fn is_condensable(ty: Type<'_>) -> bool { matches!( ty, @@ -1557,7 +1640,15 @@ impl Display for DisplayUnionType<'_> { assert_ne!(total_entries, 0); - let mut join = f.join(" | "); + let mut is_first = true; + let mut write_join = |f: &mut TypeWriter<'_, '_, 'db>| { + if !is_first { + f.write_str(" | ") + } else { + is_first = false; + Ok(()) + } + }; let display_limit = UNION_POLICY.display_limit(total_entries, self.settings.preserve_full_unions); @@ -1573,40 +1664,55 @@ impl Display for DisplayUnionType<'_> { if is_condensable(*element) { if let Some(condensed_types) = condensed_types.take() { displayed_entries += 1; - join.entry(&DisplayLiteralGroup { - literals: condensed_types, - db: self.db, - settings: self.settings.singleline(), - }); + write_join(f)?; + write!( + f, + "{}", + DisplayLiteralGroup { + literals: condensed_types, + db: self.db, + settings: self.settings.singleline(), + } + )?; } } else { displayed_entries += 1; - join.entry(&DisplayMaybeParenthesizedType { + write_join(f)?; + DisplayMaybeParenthesizedType { ty: *element, db: self.db, settings: self.settings.singleline(), - }); + } + .fmt_detailed(f)?; } } if !self.settings.preserve_full_unions { let omitted_entries = total_entries.saturating_sub(displayed_entries); if omitted_entries > 0 { - join.entry(&DisplayOmitted { - count: omitted_entries, - singular: "union element", - plural: "union elements", - }); + write_join(f)?; + write!( + f, + "{}", + DisplayOmitted { + count: omitted_entries, + singular: "union element", + plural: "union elements", + } + )?; } } - - join.finish()?; - Ok(()) } } -impl fmt::Debug for DisplayUnionType<'_> { +impl Display for DisplayUnionType<'_, '_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.fmt_detailed(&mut TypeWriter::Formatter(f)) + } +} + +impl fmt::Debug for DisplayUnionType<'_, '_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { Display::fmt(self, f) } @@ -1655,11 +1761,11 @@ impl Display for DisplayLiteralGroup<'_> { } impl<'db> IntersectionType<'db> { - fn display_with( - &'db self, + fn display_with<'a>( + &'a self, db: &'db dyn Db, settings: DisplaySettings<'db>, - ) -> DisplayIntersectionType<'db> { + ) -> DisplayIntersectionType<'a, 'db> { DisplayIntersectionType { db, ty: self, @@ -1668,14 +1774,14 @@ impl<'db> IntersectionType<'db> { } } -struct DisplayIntersectionType<'db> { - ty: &'db IntersectionType<'db>, +struct DisplayIntersectionType<'a, 'db> { + ty: &'a IntersectionType<'db>, db: &'db dyn Db, settings: DisplaySettings<'db>, } -impl Display for DisplayIntersectionType<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl<'db> DisplayIntersectionType<'_, 'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { let tys = self .ty .positive(self.db) @@ -1697,11 +1803,26 @@ impl Display for DisplayIntersectionType<'_> { negated: true, }), ); - f.join(" & ").entries(tys).finish() + + let mut first = true; + for ty in tys { + if !first { + f.write_str(" & ")?; + } + first = false; + ty.fmt_detailed(f)?; + } + Ok(()) + } +} + +impl Display for DisplayIntersectionType<'_, '_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.fmt_detailed(&mut TypeWriter::Formatter(f)) } } -impl fmt::Debug for DisplayIntersectionType<'_> { +impl fmt::Debug for DisplayIntersectionType<'_, '_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { Display::fmt(self, f) } @@ -1714,8 +1835,8 @@ struct DisplayMaybeNegatedType<'db> { settings: DisplaySettings<'db>, } -impl Display for DisplayMaybeNegatedType<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl<'db> DisplayMaybeNegatedType<'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { if self.negated { f.write_str("~")?; } @@ -1724,7 +1845,13 @@ impl Display for DisplayMaybeNegatedType<'_> { db: self.db, settings: self.settings.clone(), } - .fmt(f) + .fmt_detailed(f) + } +} + +impl Display for DisplayMaybeNegatedType<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.fmt_detailed(&mut TypeWriter::Formatter(f)) } } @@ -1734,14 +1861,14 @@ struct DisplayMaybeParenthesizedType<'db> { settings: DisplaySettings<'db>, } -impl Display for DisplayMaybeParenthesizedType<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let write_parentheses = |f: &mut Formatter<'_>| { - write!( - f, - "({})", - self.ty.display_with(self.db, self.settings.clone()) - ) +impl<'db> DisplayMaybeParenthesizedType<'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { + let write_parentheses = |f: &mut TypeWriter<'_, '_, 'db>| { + f.write_char('(')?; + self.ty + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f)?; + f.write_char(')') }; match self.ty { Type::Callable(_) @@ -1752,11 +1879,20 @@ impl Display for DisplayMaybeParenthesizedType<'_> { Type::Intersection(intersection) if !intersection.has_one_element(self.db) => { write_parentheses(f) } - _ => self.ty.display_with(self.db, self.settings.clone()).fmt(f), + _ => self + .ty + .display_with(self.db, self.settings.clone()) + .fmt_detailed(f), } } } +impl Display for DisplayMaybeParenthesizedType<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.fmt_detailed(&mut TypeWriter::Formatter(f)) + } +} + pub(crate) trait TypeArrayDisplay<'db> { fn display_with( &self, @@ -1813,21 +1949,31 @@ pub(crate) struct DisplayTypeArray<'b, 'db> { settings: DisplaySettings<'db>, } +impl<'db> DisplayTypeArray<'_, 'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { + let mut is_first = true; + for ty in self.types { + if !is_first { + f.write_str(", ")?; + } + is_first = false; + + ty.display_with(self.db, self.settings.singleline()) + .fmt_detailed(f)?; + } + Ok(()) + } +} + impl Display for DisplayTypeArray<'_, '_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.join(", ") - .entries( - self.types - .iter() - .map(|ty| ty.display_with(self.db, self.settings.singleline())), - ) - .finish() + self.fmt_detailed(&mut TypeWriter::Formatter(f)) } } impl<'db> StringLiteralType<'db> { fn display_with( - &'db self, + self, db: &'db dyn Db, settings: DisplaySettings<'db>, ) -> DisplayStringLiteralType<'db> { From 9554c0f5dbf0df8dac373c3256012f10186bcde6 Mon Sep 17 00:00:00 2001 From: Aria Desires Date: Wed, 19 Nov 2025 23:53:43 -0500 Subject: [PATCH 3/8] introduce goto-type for inlay hints --- crates/ty_ide/src/inlay_hints.rs | 48 +++++++++++++-- crates/ty_python_semantic/src/types.rs | 2 +- .../ty_python_semantic/src/types/display.rs | 60 +++++++++++++++++-- 3 files changed, 100 insertions(+), 10 deletions(-) diff --git a/crates/ty_ide/src/inlay_hints.rs b/crates/ty_ide/src/inlay_hints.rs index 7e1e12322802ce..8bddf3b711419c 100644 --- a/crates/ty_ide/src/inlay_hints.rs +++ b/crates/ty_ide/src/inlay_hints.rs @@ -1,6 +1,6 @@ use std::{fmt, vec}; -use crate::{Db, NavigationTarget}; +use crate::{Db, HasNavigationTargets, NavigationTarget}; use ruff_db::files::File; use ruff_db::parsed::parsed_module; use ruff_python_ast::visitor::source_order::{self, SourceOrderVisitor, TraversalSignal}; @@ -19,10 +19,48 @@ pub struct InlayHint { impl InlayHint { fn variable_type(position: TextSize, ty: Type, db: &dyn Db) -> Self { - let label_parts = vec![ - ": ".into(), - InlayHintLabelPart::new(ty.display(db).to_string()), - ]; + // Render the type to a string, and get subspans for all the types that make it up + let details = ty.display(db).to_string_parts(); + + // Ok so the idea here is that we potentially have a random soup of spans here, + // and each byte of the string can have at most one target associate with it. + // Thankfully, they were generally pushed in print order, with the inner smaller types + // appearing before the outer bigger ones. + // + // So we record where we are in the string, and every time we find a type, we + // check if it's further along in the string. If it is, great, we give it the + // span for its range, and then advance where we are. + let mut offset = 0; + let mut label_parts = vec![": ".into()]; + for (target, detail) in details.targets.iter().zip(&details.details) { + match detail { + ty_python_semantic::types::TypeDetail::Type(ty) => { + let start = target.start().to_usize(); + let end = target.end().to_usize(); + // If we skipped over some bytes, push them with no target + if start > offset { + label_parts.push(details.label[offset..start].into()); + } + // Ok, this is the first type that claimed these bytes, give it the target + if start >= offset { + let target = ty.navigation_targets(db).into_iter().next(); + label_parts.push( + InlayHintLabelPart::new(&details.label[start..end]).with_target(target), + ); + offset = end; + } + } + ty_python_semantic::types::TypeDetail::SignatureStart + | ty_python_semantic::types::TypeDetail::SignatureEnd + | ty_python_semantic::types::TypeDetail::Parameter(_) => { + // Don't care about these + } + } + } + // "flush" the rest of the label without any target + if offset < details.label.len() { + label_parts.push(details.label[offset..details.label.len()].into()); + } Self { position, diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index 67a598ab617e01..13b116bdadd24e 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -50,8 +50,8 @@ use crate::types::constraints::{ }; use crate::types::context::{LintDiagnosticGuard, LintDiagnosticGuardBuilder}; use crate::types::diagnostic::{INVALID_AWAIT, INVALID_TYPE_FORM, UNSUPPORTED_BOOL_CONVERSION}; -pub use crate::types::display::DisplaySettings; 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::{ DataclassTransformerFlags, DataclassTransformerParams, FunctionDecorators, FunctionSpans, diff --git a/crates/ty_python_semantic/src/types/display.rs b/crates/ty_python_semantic/src/types/display.rs index 35006b54ccc193..4d0e16434a119b 100644 --- a/crates/ty_python_semantic/src/types/display.rs +++ b/crates/ty_python_semantic/src/types/display.rs @@ -101,18 +101,31 @@ impl<'db> DisplaySettings<'db> { } } +/// Details about a type's formatting +/// +/// The `targets` and `details` are 1:1 (you can `zip` them) +pub struct TypeDisplayDetails<'db> { + /// The fully formatted type + pub label: String, + /// Ranges in the label + pub targets: Vec, + /// Metadata for each range + pub details: Vec>, +} + +/// Abstraction over "are we doing normal formatting, or tracking ranges with metadata?" enum TypeWriter<'a, 'b, 'db> { Formatter(&'a mut Formatter<'b>), Details(TypeDetailsWriter<'db>), } - /// Writer that builds a string with range tracking struct TypeDetailsWriter<'db> { label: String, targets: Vec, details: Vec>, } -impl TypeDetailsWriter<'_> { + +impl<'db> TypeDetailsWriter<'db> { fn new() -> Self { Self { label: String::new(), @@ -121,7 +134,20 @@ impl TypeDetailsWriter<'_> { } } + /// Produce type info + fn finish_type_details(self) -> TypeDisplayDetails<'db> { + TypeDisplayDetails { + label: self.label, + targets: self.targets, + details: self.details, + } + } + + /// Produce function signature info fn finish_signature_details(self) -> SignatureDisplayDetails { + // We use SignatureStart and SignatureEnd to delimit nested function signatures inside + // this function signature. We only care about the parameters of the outermost function + // which should introduce it's own SignatureStart and SignatureEnd let mut parameter_ranges = Vec::new(); let mut parameter_names = Vec::new(); let mut parameter_nesting = 0; @@ -131,6 +157,7 @@ impl TypeDetailsWriter<'_> { TypeDetail::SignatureEnd => parameter_nesting -= 1, TypeDetail::Parameter(parameter) => { if parameter_nesting <= 1 { + // We found parameters at the top-level, record them parameter_names.push(parameter); parameter_ranges.push(target); } @@ -148,6 +175,10 @@ impl TypeDetailsWriter<'_> { } impl<'a, 'b, 'db> TypeWriter<'a, 'b, 'db> { + /// Indicate the given detail is about to start being written to this Writer + /// + /// This creates a scoped guard that when Dropped will record the given detail + /// as spanning from when it was introduced to when it was dropped. fn with_detail<'c>(&'c mut self, detail: TypeDetail<'db>) -> TypeDetailGuard<'a, 'b, 'c, 'db> { let start = match self { TypeWriter::Formatter(_) => None, @@ -174,13 +205,23 @@ impl std::fmt::Write for TypeDetailsWriter<'_> { } } -enum TypeDetail<'db> { +pub enum TypeDetail<'db> { + /// Dummy item to indicate a function signature's parameters have started SignatureStart, + /// Dummy item to indicate a function signature's parameters have ended SignatureEnd, + /// A function signature's parameter Parameter(String), + /// A type Type(Type<'db>), } +/// Look on my Works, ye Mighty, and despair! +/// +/// It's quite important that we avoid conflating any of these lifetimes, or else the +/// borrowchecker will throw a ton of confusing errors about things not living long +/// enough. If you get those kinds of errors, it's probably because you introduced +/// something like `&'db self`, which, while convenient, and sometimes works, is imprecise. struct TypeDetailGuard<'a, 'b, 'c, 'db> { inner: &'c mut TypeWriter<'a, 'b, 'db>, start: Option, @@ -362,6 +403,16 @@ pub struct DisplayType<'db> { } impl<'db> DisplayType<'db> { + pub fn to_string_parts(&self) -> TypeDisplayDetails<'db> { + let mut f = TypeWriter::Details(TypeDetailsWriter::new()); + self.fmt_detailed(&mut f).unwrap(); + + match f { + TypeWriter::Details(details) => details.finish_type_details(), + TypeWriter::Formatter(_) => unreachable!("Expected Details variant"), + } + } + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { let representation = self.ty.representation(self.db, self.settings.clone()); match self.ty { @@ -462,7 +513,8 @@ impl<'db> ClassDisplay<'db> { f.write_char('.')?; } } - f.write_str(self.class.name(self.db))?; + f.with_detail(TypeDetail::Type(Type::ClassLiteral(self.class))) + .write_str(self.class.name(self.db))?; if qualification_level == Some(&QualificationLevel::FileAndLineNumber) { let file = self.class.file(self.db); let path = file.path(self.db); From 813ba0d92567e1481413277584c9cf50bf53bbdc Mon Sep 17 00:00:00 2001 From: Aria Desires Date: Wed, 19 Nov 2025 23:56:24 -0500 Subject: [PATCH 4/8] resolve snapshots --- crates/ty_ide/src/inlay_hints.rs | 1675 ++++++++++++++++++++- crates/ty_server/tests/e2e/inlay_hints.rs | 15 +- 2 files changed, 1670 insertions(+), 20 deletions(-) diff --git a/crates/ty_ide/src/inlay_hints.rs b/crates/ty_ide/src/inlay_hints.rs index 8bddf3b711419c..f9d0294b63e4fd 100644 --- a/crates/ty_ide/src/inlay_hints.rs +++ b/crates/ty_ide/src/inlay_hints.rs @@ -584,7 +584,7 @@ mod tests { ", ); - assert_snapshot!(test.inlay_hints(), @r" + assert_snapshot!(test.inlay_hints(), @r#" def i(x: int, /) -> int: return x @@ -592,7 +592,45 @@ mod tests { y[: Literal[1]] = x z[: int] = i(1) w[: int] = z - "); + + --------------------------------------------- + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:7:2 + | + 5 | x = 1 + 6 | y = x + 7 | z = i(1) + | ^ + 8 | w = z + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:8:2 + | + 6 | y = x + 7 | z = i(1) + 8 | w = z + | ^ + | + "#); } #[test] @@ -621,6 +659,81 @@ mod tests { x2[: Literal[1]], y2[: Literal["abc"]] = (x1, y1) x3[: int], y3[: str] = (i(1), s('abc')) x4[: int], y4[: str] = (x3, y3) + + --------------------------------------------- + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:9:3 + | + 7 | x1, y1 = (1, 'abc') + 8 | x2, y2 = (x1, y1) + 9 | x3, y3 = (i(1), s('abc')) + | ^ + 10 | x4, y4 = (x3, y3) + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:915:7 + | + 914 | @disjoint_base + 915 | class str(Sequence[str]): + | ^^^ + 916 | """str(object='') -> str + 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str + | + info: Source + --> main.py:9:7 + | + 7 | x1, y1 = (1, 'abc') + 8 | x2, y2 = (x1, y1) + 9 | x3, y3 = (i(1), s('abc')) + | ^ + 10 | x4, y4 = (x3, y3) + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:10:3 + | + 8 | x2, y2 = (x1, y1) + 9 | x3, y3 = (i(1), s('abc')) + 10 | x4, y4 = (x3, y3) + | ^ + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:915:7 + | + 914 | @disjoint_base + 915 | class str(Sequence[str]): + | ^^^ + 916 | """str(object='') -> str + 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str + | + info: Source + --> main.py:10:7 + | + 8 | x2, y2 = (x1, y1) + 9 | x3, y3 = (i(1), s('abc')) + 10 | x4, y4 = (x3, y3) + | ^ + | "#); } @@ -650,6 +763,81 @@ mod tests { x2[: Literal[1]], y2[: Literal["abc"]] = x1, y1 x3[: int], y3[: str] = i(1), s('abc') x4[: int], y4[: str] = x3, y3 + + --------------------------------------------- + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:9:3 + | + 7 | x1, y1 = 1, 'abc' + 8 | x2, y2 = x1, y1 + 9 | x3, y3 = i(1), s('abc') + | ^ + 10 | x4, y4 = x3, y3 + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:915:7 + | + 914 | @disjoint_base + 915 | class str(Sequence[str]): + | ^^^ + 916 | """str(object='') -> str + 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str + | + info: Source + --> main.py:9:7 + | + 7 | x1, y1 = 1, 'abc' + 8 | x2, y2 = x1, y1 + 9 | x3, y3 = i(1), s('abc') + | ^ + 10 | x4, y4 = x3, y3 + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:10:3 + | + 8 | x2, y2 = x1, y1 + 9 | x3, y3 = i(1), s('abc') + 10 | x4, y4 = x3, y3 + | ^ + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:915:7 + | + 914 | @disjoint_base + 915 | class str(Sequence[str]): + | ^^^ + 916 | """str(object='') -> str + 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str + | + info: Source + --> main.py:10:7 + | + 8 | x2, y2 = x1, y1 + 9 | x3, y3 = i(1), s('abc') + 10 | x4, y4 = x3, y3 + | ^ + | "#); } @@ -679,6 +867,81 @@ mod tests { y[: tuple[Literal[1], Literal["abc"]]] = x z[: tuple[int, str]] = (i(1), s('abc')) w[: tuple[int, str]] = z + + --------------------------------------------- + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:9:2 + | + 7 | x = (1, 'abc') + 8 | y = x + 9 | z = (i(1), s('abc')) + | ^ + 10 | w = z + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:915:7 + | + 914 | @disjoint_base + 915 | class str(Sequence[str]): + | ^^^ + 916 | """str(object='') -> str + 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str + | + info: Source + --> main.py:9:2 + | + 7 | x = (1, 'abc') + 8 | y = x + 9 | z = (i(1), s('abc')) + | ^ + 10 | w = z + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:10:2 + | + 8 | y = x + 9 | z = (i(1), s('abc')) + 10 | w = z + | ^ + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:915:7 + | + 914 | @disjoint_base + 915 | class str(Sequence[str]): + | ^^^ + 916 | """str(object='') -> str + 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str + | + info: Source + --> main.py:10:2 + | + 8 | y = x + 9 | z = (i(1), s('abc')) + 10 | w = z + | ^ + | "#); } @@ -707,6 +970,117 @@ mod tests { x2[: Literal[1]], (y2[: Literal["abc"]], z2[: Literal[2]]) = (x1, (y1, z1)) x3[: int], (y3[: str], z3[: int]) = (i(1), (s('abc'), i(2))) x4[: int], (y4[: str], z4[: int]) = (x3, (y3, z3)) + --------------------------------------------- + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:9:3 + | + 7 | x1, (y1, z1) = (1, ('abc', 2)) + 8 | x2, (y2, z2) = (x1, (y1, z1)) + 9 | x3, (y3, z3) = (i(1), (s('abc'), i(2))) + | ^ + 10 | x4, (y4, z4) = (x3, (y3, z3)) + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:915:7 + | + 914 | @disjoint_base + 915 | class str(Sequence[str]): + | ^^^ + 916 | """str(object='') -> str + 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str + | + info: Source + --> main.py:9:8 + | + 7 | x1, (y1, z1) = (1, ('abc', 2)) + 8 | x2, (y2, z2) = (x1, (y1, z1)) + 9 | x3, (y3, z3) = (i(1), (s('abc'), i(2))) + | ^ + 10 | x4, (y4, z4) = (x3, (y3, z3)) + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:9:12 + | + 7 | x1, (y1, z1) = (1, ('abc', 2)) + 8 | x2, (y2, z2) = (x1, (y1, z1)) + 9 | x3, (y3, z3) = (i(1), (s('abc'), i(2))) + | ^ + 10 | x4, (y4, z4) = (x3, (y3, z3)) + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:10:3 + | + 8 | x2, (y2, z2) = (x1, (y1, z1)) + 9 | x3, (y3, z3) = (i(1), (s('abc'), i(2))) + 10 | x4, (y4, z4) = (x3, (y3, z3)) + | ^ + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:915:7 + | + 914 | @disjoint_base + 915 | class str(Sequence[str]): + | ^^^ + 916 | """str(object='') -> str + 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str + | + info: Source + --> main.py:10:8 + | + 8 | x2, (y2, z2) = (x1, (y1, z1)) + 9 | x3, (y3, z3) = (i(1), (s('abc'), i(2))) + 10 | x4, (y4, z4) = (x3, (y3, z3)) + | ^ + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:10:12 + | + 8 | x2, (y2, z2) = (x1, (y1, z1)) + 9 | x3, (y3, z3) = (i(1), (s('abc'), i(2))) + 10 | x4, (y4, z4) = (x3, (y3, z3)) + | ^ + | "#); } @@ -723,7 +1097,7 @@ mod tests { w = z", ); - assert_snapshot!(test.inlay_hints(), @r" + assert_snapshot!(test.inlay_hints(), @r#" def i(x: int, /) -> int: return x @@ -731,7 +1105,25 @@ mod tests { y[: Literal[1]] = x z: int = i(1) w[: int] = z - "); + --------------------------------------------- + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:8:2 + | + 6 | y = x + 7 | z: int = i(1) + 8 | w = z + | ^ + | + "#); } #[test] @@ -744,12 +1136,31 @@ mod tests { z = x", ); - assert_snapshot!(test.inlay_hints(), @r" + assert_snapshot!(test.inlay_hints(), @r#" def i(x: int, /) -> int: return x x[: int] = i(1) z = x - "); + --------------------------------------------- + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:4:2 + | + 2 | def i(x: int, /) -> int: + 3 | return x + 4 | x = i(1) + | ^ + 5 | z = x + | + "#); } #[test] @@ -766,7 +1177,7 @@ mod tests { ", ); - assert_snapshot!(test.inlay_hints(), @r" + assert_snapshot!(test.inlay_hints(), @r#" class A: def __init__(self, y): self.x[: int] = int(1) @@ -776,6 +1187,43 @@ mod tests { a.y[: int] = int(3) --------------------------------------------- + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:4:15 + | + 2 | class A: + 3 | def __init__(self, y): + 4 | self.x = int(1) + | ^ + 5 | self.y = y + | + + info[inlay-hint-location]: Inlay Hint Target + --> main.py:2:7 + | + 2 | class A: + | ^ + 3 | def __init__(self, y): + 4 | self.x = int(1) + | + info: Source + --> main.py:7:2 + | + 5 | self.y = y + 6 | + 7 | a = A(2) + | ^ + 8 | a.y = int(3) + | + info[inlay-hint-location]: Inlay Hint Target --> main.py:3:24 | @@ -794,7 +1242,24 @@ mod tests { | ^ 8 | a.y = int(3) | - "); + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:8:4 + | + 7 | a = A(2) + 8 | a.y = int(3) + | ^ + | + "#); } #[test] @@ -959,6 +1424,457 @@ mod tests { i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] j[: list[Unknown | int | float]] = [+1, +2.0] k[: list[Unknown | int | float]] = [-1, -2.0] + + --------------------------------------------- + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:2802:7 + | + 2801 | @disjoint_base + 2802 | class list(MutableSequence[_T]): + | ^^^^ + 2803 | """Built-in mutable sequence. + | + info: Source + --> main.py:2:2 + | + 2 | a = [1, 2] + | ^ + 3 | b = [1.0, 2.0] + 4 | c = [True, False] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:2:2 + | + 2 | a = [1, 2] + | ^ + 3 | b = [1.0, 2.0] + 4 | c = [True, False] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:2802:7 + | + 2801 | @disjoint_base + 2802 | class list(MutableSequence[_T]): + | ^^^^ + 2803 | """Built-in mutable sequence. + | + info: Source + --> main.py:3:2 + | + 2 | a = [1, 2] + 3 | b = [1.0, 2.0] + | ^ + 4 | c = [True, False] + 5 | d = [None, None] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:661:7 + | + 660 | @disjoint_base + 661 | class float: + | ^^^^^ + 662 | """Convert a string or number to a floating-point number, if possible.""" + | + info: Source + --> main.py:3:2 + | + 2 | a = [1, 2] + 3 | b = [1.0, 2.0] + | ^ + 4 | c = [True, False] + 5 | d = [None, None] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:2802:7 + | + 2801 | @disjoint_base + 2802 | class list(MutableSequence[_T]): + | ^^^^ + 2803 | """Built-in mutable sequence. + | + info: Source + --> main.py:4:2 + | + 2 | a = [1, 2] + 3 | b = [1.0, 2.0] + 4 | c = [True, False] + | ^ + 5 | d = [None, None] + 6 | e = ["hel", "lo"] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:2591:7 + | + 2590 | @final + 2591 | class bool(int): + | ^^^^ + 2592 | """Returns True when the argument is true, False otherwise. + 2593 | The builtins True and False are the only two instances of the class bool. + | + info: Source + --> main.py:4:2 + | + 2 | a = [1, 2] + 3 | b = [1.0, 2.0] + 4 | c = [True, False] + | ^ + 5 | d = [None, None] + 6 | e = ["hel", "lo"] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:2802:7 + | + 2801 | @disjoint_base + 2802 | class list(MutableSequence[_T]): + | ^^^^ + 2803 | """Built-in mutable sequence. + | + info: Source + --> main.py:5:2 + | + 3 | b = [1.0, 2.0] + 4 | c = [True, False] + 5 | d = [None, None] + | ^ + 6 | e = ["hel", "lo"] + 7 | f = ['the', 're'] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/types.pyi:950:11 + | + 948 | if sys.version_info >= (3, 10): + 949 | @final + 950 | class NoneType: + | ^^^^^^^^ + 951 | """The type of the None singleton.""" + | + info: Source + --> main.py:5:2 + | + 3 | b = [1.0, 2.0] + 4 | c = [True, False] + 5 | d = [None, None] + | ^ + 6 | e = ["hel", "lo"] + 7 | f = ['the', 're'] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:2802:7 + | + 2801 | @disjoint_base + 2802 | class list(MutableSequence[_T]): + | ^^^^ + 2803 | """Built-in mutable sequence. + | + info: Source + --> main.py:6:2 + | + 4 | c = [True, False] + 5 | d = [None, None] + 6 | e = ["hel", "lo"] + | ^ + 7 | f = ['the', 're'] + 8 | g = [f"{ft}", f"{ft}"] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:915:7 + | + 914 | @disjoint_base + 915 | class str(Sequence[str]): + | ^^^ + 916 | """str(object='') -> str + 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str + | + info: Source + --> main.py:6:2 + | + 4 | c = [True, False] + 5 | d = [None, None] + 6 | e = ["hel", "lo"] + | ^ + 7 | f = ['the', 're'] + 8 | g = [f"{ft}", f"{ft}"] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:2802:7 + | + 2801 | @disjoint_base + 2802 | class list(MutableSequence[_T]): + | ^^^^ + 2803 | """Built-in mutable sequence. + | + info: Source + --> main.py:7:2 + | + 5 | d = [None, None] + 6 | e = ["hel", "lo"] + 7 | f = ['the', 're'] + | ^ + 8 | g = [f"{ft}", f"{ft}"] + 9 | h = [t"wow %d", t"wow %d"] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:915:7 + | + 914 | @disjoint_base + 915 | class str(Sequence[str]): + | ^^^ + 916 | """str(object='') -> str + 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str + | + info: Source + --> main.py:7:2 + | + 5 | d = [None, None] + 6 | e = ["hel", "lo"] + 7 | f = ['the', 're'] + | ^ + 8 | g = [f"{ft}", f"{ft}"] + 9 | h = [t"wow %d", t"wow %d"] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:2802:7 + | + 2801 | @disjoint_base + 2802 | class list(MutableSequence[_T]): + | ^^^^ + 2803 | """Built-in mutable sequence. + | + info: Source + --> main.py:8:2 + | + 6 | e = ["hel", "lo"] + 7 | f = ['the', 're'] + 8 | g = [f"{ft}", f"{ft}"] + | ^ + 9 | h = [t"wow %d", t"wow %d"] + 10 | i = [b'\x01', b'\x02'] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:915:7 + | + 914 | @disjoint_base + 915 | class str(Sequence[str]): + | ^^^ + 916 | """str(object='') -> str + 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str + | + info: Source + --> main.py:8:2 + | + 6 | e = ["hel", "lo"] + 7 | f = ['the', 're'] + 8 | g = [f"{ft}", f"{ft}"] + | ^ + 9 | h = [t"wow %d", t"wow %d"] + 10 | i = [b'\x01', b'\x02'] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:2802:7 + | + 2801 | @disjoint_base + 2802 | class list(MutableSequence[_T]): + | ^^^^ + 2803 | """Built-in mutable sequence. + | + info: Source + --> main.py:9:2 + | + 7 | f = ['the', 're'] + 8 | g = [f"{ft}", f"{ft}"] + 9 | h = [t"wow %d", t"wow %d"] + | ^ + 10 | i = [b'\x01', b'\x02'] + 11 | j = [+1, +2.0] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/string/templatelib.pyi:10:7 + | + 9 | @final + 10 | class Template: # TODO: consider making `Template` generic on `TypeVarTuple` + | ^^^^^^^^ + 11 | """Template object""" + | + info: Source + --> main.py:9:2 + | + 7 | f = ['the', 're'] + 8 | g = [f"{ft}", f"{ft}"] + 9 | h = [t"wow %d", t"wow %d"] + | ^ + 10 | i = [b'\x01', b'\x02'] + 11 | j = [+1, +2.0] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:2802:7 + | + 2801 | @disjoint_base + 2802 | class list(MutableSequence[_T]): + | ^^^^ + 2803 | """Built-in mutable sequence. + | + info: Source + --> main.py:10:2 + | + 8 | g = [f"{ft}", f"{ft}"] + 9 | h = [t"wow %d", t"wow %d"] + 10 | i = [b'\x01', b'\x02'] + | ^ + 11 | j = [+1, +2.0] + 12 | k = [-1, -2.0] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:1448:7 + | + 1447 | @disjoint_base + 1448 | class bytes(Sequence[int]): + | ^^^^^ + 1449 | """bytes(iterable_of_ints) -> bytes + 1450 | bytes(string, encoding[, errors]) -> bytes + | + info: Source + --> main.py:10:2 + | + 8 | g = [f"{ft}", f"{ft}"] + 9 | h = [t"wow %d", t"wow %d"] + 10 | i = [b'\x01', b'\x02'] + | ^ + 11 | j = [+1, +2.0] + 12 | k = [-1, -2.0] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:2802:7 + | + 2801 | @disjoint_base + 2802 | class list(MutableSequence[_T]): + | ^^^^ + 2803 | """Built-in mutable sequence. + | + info: Source + --> main.py:11:2 + | + 9 | h = [t"wow %d", t"wow %d"] + 10 | i = [b'\x01', b'\x02'] + 11 | j = [+1, +2.0] + | ^ + 12 | k = [-1, -2.0] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:11:2 + | + 9 | h = [t"wow %d", t"wow %d"] + 10 | i = [b'\x01', b'\x02'] + 11 | j = [+1, +2.0] + | ^ + 12 | k = [-1, -2.0] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:661:7 + | + 660 | @disjoint_base + 661 | class float: + | ^^^^^ + 662 | """Convert a string or number to a floating-point number, if possible.""" + | + info: Source + --> main.py:11:2 + | + 9 | h = [t"wow %d", t"wow %d"] + 10 | i = [b'\x01', b'\x02'] + 11 | j = [+1, +2.0] + | ^ + 12 | k = [-1, -2.0] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:2802:7 + | + 2801 | @disjoint_base + 2802 | class list(MutableSequence[_T]): + | ^^^^ + 2803 | """Built-in mutable sequence. + | + info: Source + --> main.py:12:2 + | + 10 | i = [b'\x01', b'\x02'] + 11 | j = [+1, +2.0] + 12 | k = [-1, -2.0] + | ^ + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:12:2 + | + 10 | i = [b'\x01', b'\x02'] + 11 | j = [+1, +2.0] + 12 | k = [-1, -2.0] + | ^ + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:661:7 + | + 660 | @disjoint_base + 661 | class float: + | ^^^^^ + 662 | """Convert a string or number to a floating-point number, if possible.""" + | + info: Source + --> main.py:12:2 + | + 10 | i = [b'\x01', b'\x02'] + 11 | j = [+1, +2.0] + 12 | k = [-1, -2.0] + | ^ + | "#); } @@ -986,6 +1902,132 @@ mod tests { y[: tuple[MyClass, MyClass]] = (MyClass(), MyClass()) a[: MyClass], b[: MyClass] = MyClass(), MyClass() c[: MyClass], d[: MyClass] = (MyClass(), MyClass()) + + --------------------------------------------- + info[inlay-hint-location]: Inlay Hint Target + --> main.py:2:7 + | + 2 | class MyClass: + | ^^^^^^^ + 3 | def __init__(self): + 4 | self.x: int = 1 + | + info: Source + --> main.py:6:2 + | + 4 | self.x: int = 1 + 5 | + 6 | x = MyClass() + | ^ + 7 | y = (MyClass(), MyClass()) + 8 | a, b = MyClass(), MyClass() + | + + info[inlay-hint-location]: Inlay Hint Target + --> main.py:2:7 + | + 2 | class MyClass: + | ^^^^^^^ + 3 | def __init__(self): + 4 | self.x: int = 1 + | + info: Source + --> main.py:7:2 + | + 6 | x = MyClass() + 7 | y = (MyClass(), MyClass()) + | ^ + 8 | a, b = MyClass(), MyClass() + 9 | c, d = (MyClass(), MyClass()) + | + + info[inlay-hint-location]: Inlay Hint Target + --> main.py:2:7 + | + 2 | class MyClass: + | ^^^^^^^ + 3 | def __init__(self): + 4 | self.x: int = 1 + | + info: Source + --> main.py:7:2 + | + 6 | x = MyClass() + 7 | y = (MyClass(), MyClass()) + | ^ + 8 | a, b = MyClass(), MyClass() + 9 | c, d = (MyClass(), MyClass()) + | + + info[inlay-hint-location]: Inlay Hint Target + --> main.py:2:7 + | + 2 | class MyClass: + | ^^^^^^^ + 3 | def __init__(self): + 4 | self.x: int = 1 + | + info: Source + --> main.py:8:2 + | + 6 | x = MyClass() + 7 | y = (MyClass(), MyClass()) + 8 | a, b = MyClass(), MyClass() + | ^ + 9 | c, d = (MyClass(), MyClass()) + | + + info[inlay-hint-location]: Inlay Hint Target + --> main.py:2:7 + | + 2 | class MyClass: + | ^^^^^^^ + 3 | def __init__(self): + 4 | self.x: int = 1 + | + info: Source + --> main.py:8:5 + | + 6 | x = MyClass() + 7 | y = (MyClass(), MyClass()) + 8 | a, b = MyClass(), MyClass() + | ^ + 9 | c, d = (MyClass(), MyClass()) + | + + info[inlay-hint-location]: Inlay Hint Target + --> main.py:2:7 + | + 2 | class MyClass: + | ^^^^^^^ + 3 | def __init__(self): + 4 | self.x: int = 1 + | + info: Source + --> main.py:9:2 + | + 7 | y = (MyClass(), MyClass()) + 8 | a, b = MyClass(), MyClass() + 9 | c, d = (MyClass(), MyClass()) + | ^ + | + + info[inlay-hint-location]: Inlay Hint Target + --> main.py:2:7 + | + 2 | class MyClass: + | ^^^^^^^ + 3 | def __init__(self): + 4 | self.x: int = 1 + | + info: Source + --> main.py:9:5 + | + 7 | y = (MyClass(), MyClass()) + 8 | a, b = MyClass(), MyClass() + 9 | c, d = (MyClass(), MyClass()) + | ^ + | "); } @@ -1017,6 +2059,83 @@ mod tests { c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b"))) --------------------------------------------- + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:2802:7 + | + 2801 | @disjoint_base + 2802 | class list(MutableSequence[_T]): + | ^^^^ + 2803 | """Built-in mutable sequence. + | + info: Source + --> main.py:4:15 + | + 2 | class MyClass[T, U]: + 3 | def __init__(self, x: list[T], y: tuple[U, U]): + 4 | self.x = x + | ^ + 5 | self.y = y + | + + info[inlay-hint-location]: Inlay Hint Target + --> main.py:2:7 + | + 2 | class MyClass[T, U]: + | ^^^^^^^ + 3 | def __init__(self, x: list[T], y: tuple[U, U]): + 4 | self.x = x + | + info: Source + --> main.py:7:2 + | + 5 | self.y = y + 6 | + 7 | x = MyClass([42], ("a", "b")) + | ^ + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:7:2 + | + 5 | self.y = y + 6 | + 7 | x = MyClass([42], ("a", "b")) + | ^ + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:915:7 + | + 914 | @disjoint_base + 915 | class str(Sequence[str]): + | ^^^ + 916 | """str(object='') -> str + 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str + | + info: Source + --> main.py:7:2 + | + 5 | self.y = y + 6 | + 7 | x = MyClass([42], ("a", "b")) + | ^ + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + | + info[inlay-hint-location]: Inlay Hint Target --> main.py:3:24 | @@ -1047,15 +2166,127 @@ mod tests { 5 | self.y = y | info: Source - --> main.py:7:19 - | - 5 | self.y = y - 6 | - 7 | x = MyClass([42], ("a", "b")) - | ^ - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - | + --> main.py:7:19 + | + 5 | self.y = y + 6 | + 7 | x = MyClass([42], ("a", "b")) + | ^ + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + | + + info[inlay-hint-location]: Inlay Hint Target + --> main.py:2:7 + | + 2 | class MyClass[T, U]: + | ^^^^^^^ + 3 | def __init__(self, x: list[T], y: tuple[U, U]): + 4 | self.x = x + | + info: Source + --> main.py:8:2 + | + 7 | x = MyClass([42], ("a", "b")) + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | ^ + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:8:2 + | + 7 | x = MyClass([42], ("a", "b")) + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | ^ + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:915:7 + | + 914 | @disjoint_base + 915 | class str(Sequence[str]): + | ^^^ + 916 | """str(object='') -> str + 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str + | + info: Source + --> main.py:8:2 + | + 7 | x = MyClass([42], ("a", "b")) + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | ^ + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | + + info[inlay-hint-location]: Inlay Hint Target + --> main.py:2:7 + | + 2 | class MyClass[T, U]: + | ^^^^^^^ + 3 | def __init__(self, x: list[T], y: tuple[U, U]): + 4 | self.x = x + | + info: Source + --> main.py:8:2 + | + 7 | x = MyClass([42], ("a", "b")) + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | ^ + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:8:2 + | + 7 | x = MyClass([42], ("a", "b")) + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | ^ + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:915:7 + | + 914 | @disjoint_base + 915 | class str(Sequence[str]): + | ^^^ + 916 | """str(object='') -> str + 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str + | + info: Source + --> main.py:8:2 + | + 7 | x = MyClass([42], ("a", "b")) + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | ^ + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | info[inlay-hint-location]: Inlay Hint Target --> main.py:3:24 @@ -1133,6 +2364,118 @@ mod tests { 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) | + info[inlay-hint-location]: Inlay Hint Target + --> main.py:2:7 + | + 2 | class MyClass[T, U]: + | ^^^^^^^ + 3 | def __init__(self, x: list[T], y: tuple[U, U]): + 4 | self.x = x + | + info: Source + --> main.py:9:2 + | + 7 | x = MyClass([42], ("a", "b")) + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + | ^ + 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:9:2 + | + 7 | x = MyClass([42], ("a", "b")) + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + | ^ + 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:915:7 + | + 914 | @disjoint_base + 915 | class str(Sequence[str]): + | ^^^ + 916 | """str(object='') -> str + 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str + | + info: Source + --> main.py:9:2 + | + 7 | x = MyClass([42], ("a", "b")) + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + | ^ + 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | + + info[inlay-hint-location]: Inlay Hint Target + --> main.py:2:7 + | + 2 | class MyClass[T, U]: + | ^^^^^^^ + 3 | def __init__(self, x: list[T], y: tuple[U, U]): + 4 | self.x = x + | + info: Source + --> main.py:9:5 + | + 7 | x = MyClass([42], ("a", "b")) + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + | ^ + 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:9:5 + | + 7 | x = MyClass([42], ("a", "b")) + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + | ^ + 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:915:7 + | + 914 | @disjoint_base + 915 | class str(Sequence[str]): + | ^^^ + 916 | """str(object='') -> str + 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str + | + info: Source + --> main.py:9:5 + | + 7 | x = MyClass([42], ("a", "b")) + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + | ^ + 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | + info[inlay-hint-location]: Inlay Hint Target --> main.py:3:24 | @@ -1209,6 +2552,112 @@ mod tests { 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) | + info[inlay-hint-location]: Inlay Hint Target + --> main.py:2:7 + | + 2 | class MyClass[T, U]: + | ^^^^^^^ + 3 | def __init__(self, x: list[T], y: tuple[U, U]): + 4 | self.x = x + | + info: Source + --> main.py:10:2 + | + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | ^ + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:10:2 + | + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | ^ + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:915:7 + | + 914 | @disjoint_base + 915 | class str(Sequence[str]): + | ^^^ + 916 | """str(object='') -> str + 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str + | + info: Source + --> main.py:10:2 + | + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | ^ + | + + info[inlay-hint-location]: Inlay Hint Target + --> main.py:2:7 + | + 2 | class MyClass[T, U]: + | ^^^^^^^ + 3 | def __init__(self, x: list[T], y: tuple[U, U]): + 4 | self.x = x + | + info: Source + --> main.py:10:5 + | + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | ^ + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:10:5 + | + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | ^ + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:915:7 + | + 914 | @disjoint_base + 915 | class str(Sequence[str]): + | ^^^ + 916 | """str(object='') -> str + 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str + | + info: Source + --> main.py:10:5 + | + 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + | ^ + | + info[inlay-hint-location]: Inlay Hint Target --> main.py:3:24 | @@ -1400,6 +2849,26 @@ mod tests { foo(val.x) foo([x=]val.y) --------------------------------------------- + info[inlay-hint-location]: Inlay Hint Target + --> main.py:3:7 + | + 2 | def foo(x: int): pass + 3 | class MyClass: + | ^^^^^^^ + 4 | def __init__(self): + 5 | self.x: int = 1 + | + info: Source + --> main.py:7:4 + | + 5 | self.x: int = 1 + 6 | self.y: int = 2 + 7 | val = MyClass() + | ^ + 8 | + 9 | foo(val.x) + | + info[inlay-hint-location]: Inlay Hint Target --> main.py:2:9 | @@ -1445,6 +2914,26 @@ mod tests { foo(x.x) foo([x=]x.y) --------------------------------------------- + info[inlay-hint-location]: Inlay Hint Target + --> main.py:3:7 + | + 2 | def foo(x: int): pass + 3 | class MyClass: + | ^^^^^^^ + 4 | def __init__(self): + 5 | self.x: int = 1 + | + info: Source + --> main.py:7:2 + | + 5 | self.x: int = 1 + 6 | self.y: int = 2 + 7 | x = MyClass() + | ^ + 8 | + 9 | foo(x.x) + | + info[inlay-hint-location]: Inlay Hint Target --> main.py:2:9 | @@ -1493,6 +2982,26 @@ mod tests { foo(val.x()) foo([x=]val.y()) --------------------------------------------- + info[inlay-hint-location]: Inlay Hint Target + --> main.py:3:7 + | + 2 | def foo(x: int): pass + 3 | class MyClass: + | ^^^^^^^ + 4 | def __init__(self): + 5 | def x() -> int: + | + info: Source + --> main.py:9:4 + | + 7 | def y() -> int: + 8 | return 2 + 9 | val = MyClass() + | ^ + 10 | + 11 | foo(val.x()) + | + info[inlay-hint-location]: Inlay Hint Target --> main.py:2:9 | @@ -1545,6 +3054,26 @@ mod tests { foo(val.x()[0]) foo([x=]val.y()[1]) --------------------------------------------- + info[inlay-hint-location]: Inlay Hint Target + --> main.py:5:7 + | + 4 | def foo(x: int): pass + 5 | class MyClass: + | ^^^^^^^ + 6 | def __init__(self): + 7 | def x() -> List[int]: + | + info: Source + --> main.py:11:4 + | + 9 | def y() -> List[int]: + 10 | return 2 + 11 | val = MyClass() + | ^ + 12 | + 13 | foo(val.x()[0]) + | + info[inlay-hint-location]: Inlay Hint Target --> main.py:4:9 | @@ -1577,7 +3106,7 @@ mod tests { foo(y[0])", ); - assert_snapshot!(test.inlay_hints(), @r" + assert_snapshot!(test.inlay_hints(), @r#" def foo(x: int): pass x[: list[Unknown | int]] = [1] y[: list[Unknown | int]] = [2] @@ -1585,6 +3114,80 @@ mod tests { foo(x[0]) foo([x=]y[0]) --------------------------------------------- + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:2802:7 + | + 2801 | @disjoint_base + 2802 | class list(MutableSequence[_T]): + | ^^^^ + 2803 | """Built-in mutable sequence. + | + info: Source + --> main.py:3:2 + | + 2 | def foo(x: int): pass + 3 | x = [1] + | ^ + 4 | y = [2] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:3:2 + | + 2 | def foo(x: int): pass + 3 | x = [1] + | ^ + 4 | y = [2] + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:2802:7 + | + 2801 | @disjoint_base + 2802 | class list(MutableSequence[_T]): + | ^^^^ + 2803 | """Built-in mutable sequence. + | + info: Source + --> main.py:4:2 + | + 2 | def foo(x: int): pass + 3 | x = [1] + 4 | y = [2] + | ^ + 5 | + 6 | foo(x[0]) + | + + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main.py:4:2 + | + 2 | def foo(x: int): pass + 3 | x = [1] + 4 | y = [2] + | ^ + 5 | + 6 | foo(x[0]) + | + info[inlay-hint-location]: Inlay Hint Target --> main.py:2:9 | @@ -1600,7 +3203,7 @@ mod tests { 7 | foo(y[0]) | ^ | - "); + "#); } #[test] @@ -1751,6 +3354,23 @@ mod tests { 5 | f = Foo(1) | + info[inlay-hint-location]: Inlay Hint Target + --> main.py:2:7 + | + 2 | class Foo: + | ^^^ + 3 | def __init__(self, x: int): pass + 4 | Foo(1) + | + info: Source + --> main.py:5:2 + | + 3 | def __init__(self, x: int): pass + 4 | Foo(1) + 5 | f = Foo(1) + | ^ + | + info[inlay-hint-location]: Inlay Hint Target --> main.py:3:24 | @@ -1806,6 +3426,23 @@ mod tests { 5 | f = Foo(1) | + info[inlay-hint-location]: Inlay Hint Target + --> main.py:2:7 + | + 2 | class Foo: + | ^^^ + 3 | def __new__(cls, x: int): pass + 4 | Foo(1) + | + info: Source + --> main.py:5:2 + | + 3 | def __new__(cls, x: int): pass + 4 | Foo(1) + 5 | f = Foo(1) + | ^ + | + info[inlay-hint-location]: Inlay Hint Target --> main.py:3:22 | diff --git a/crates/ty_server/tests/e2e/inlay_hints.rs b/crates/ty_server/tests/e2e/inlay_hints.rs index 42152a73511e2d..4444912feb488f 100644 --- a/crates/ty_server/tests/e2e/inlay_hints.rs +++ b/crates/ty_server/tests/e2e/inlay_hints.rs @@ -47,7 +47,20 @@ y = foo(1) "value": ": " }, { - "value": "int" + "value": "int", + "location": { + "uri": "file:///Users/gankra/.cache/ty/vendored/typeshed/f8cdc0bd526301e873cd952eb0d457bdf2554e57/stdlib/builtins.pyi", + "range": { + "start": { + "line": 347, + "character": 6 + }, + "end": { + "line": 347, + "character": 9 + } + } + } } ], "kind": 1 From 13fecff48afe8065b05e012e7f0cc5301bd244c4 Mon Sep 17 00:00:00 2001 From: Aria Desires Date: Thu, 20 Nov 2025 00:01:32 -0500 Subject: [PATCH 5/8] fixup --- crates/ty_server/tests/e2e/inlay_hints.rs | 2 +- crates/ty_server/tests/e2e/main.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/ty_server/tests/e2e/inlay_hints.rs b/crates/ty_server/tests/e2e/inlay_hints.rs index 4444912feb488f..8e16ce0c4e609c 100644 --- a/crates/ty_server/tests/e2e/inlay_hints.rs +++ b/crates/ty_server/tests/e2e/inlay_hints.rs @@ -49,7 +49,7 @@ y = foo(1) { "value": "int", "location": { - "uri": "file:///Users/gankra/.cache/ty/vendored/typeshed/f8cdc0bd526301e873cd952eb0d457bdf2554e57/stdlib/builtins.pyi", + "uri": "file://ty/vendored/typeshed/f8cdc0bd526301e873cd952eb0d457bdf2554e57/stdlib/builtins.pyi", "range": { "start": { "line": 347, diff --git a/crates/ty_server/tests/e2e/main.rs b/crates/ty_server/tests/e2e/main.rs index 97f0d69573522f..a0066acf427ef8 100644 --- a/crates/ty_server/tests/e2e/main.rs +++ b/crates/ty_server/tests/e2e/main.rs @@ -1198,6 +1198,7 @@ impl TestContext { r#"The system cannot find the file specified."#, "No such file or directory", ); + settings.add_filter(r"file://[^\s]*/\.cache/", "file://"); let settings_scope = settings.bind_to_scope(); From 89ca8c3e674a8d86d4bb115c00af5fb300e9efb3 Mon Sep 17 00:00:00 2001 From: Aria Desires Date: Thu, 20 Nov 2025 08:36:42 -0500 Subject: [PATCH 6/8] Show better details in inlay hint tests --- crates/ty_ide/src/inlay_hints.rs | 1578 +++++++++++++++--------------- 1 file changed, 791 insertions(+), 787 deletions(-) diff --git a/crates/ty_ide/src/inlay_hints.rs b/crates/ty_ide/src/inlay_hints.rs index f9d0294b63e4fd..241d705c66bd82 100644 --- a/crates/ty_ide/src/inlay_hints.rs +++ b/crates/ty_ide/src/inlay_hints.rs @@ -489,7 +489,7 @@ mod tests { /// [`inlay_hints_with_settings`] to generate hints with custom settings. /// /// [`inlay_hints_with_settings`]: Self::inlay_hints_with_settings - fn inlay_hints(&self) -> String { + fn inlay_hints(&mut self) -> String { self.inlay_hints_with_settings(&InlayHintSettings { variable_types: true, call_argument_names: true, @@ -501,40 +501,44 @@ mod tests { } /// Returns the inlay hints for the given test case with custom settings. - fn inlay_hints_with_settings(&self, settings: &InlayHintSettings) -> String { + fn inlay_hints_with_settings(&mut self, settings: &InlayHintSettings) -> String { let hints = inlay_hints(&self.db, self.file, self.range, settings); let mut buf = source_text(&self.db, self.file).as_str().to_string(); - let mut diagnostics = Vec::new(); + let mut tbd_diagnostics = Vec::new(); let mut offset = 0; for hint in hints { + let end_position = hint.position.to_usize() + offset; let mut hint_str = "[".to_string(); - let end_position = (hint.position.to_u32() as usize) + offset; - for part in hint.label.parts() { - hint_str.push_str(part.text()); - - if let Some(target) = part.target() { - let label_range = TextRange::at(hint.position, TextSize::ZERO); - - let label_file_range = FileRange::new(self.file, label_range); - - diagnostics - .push(InlayHintLocationDiagnostic::new(label_file_range, target)); + if let Some(target) = part.target().cloned() { + let part_position = u32::try_from(end_position + hint_str.len()).unwrap(); + let part_len = u32::try_from(part.text().len()).unwrap(); + let label_range = + TextRange::at(TextSize::new(part_position), TextSize::new(part_len)); + tbd_diagnostics.push((label_range, target)); } + hint_str.push_str(part.text()); } hint_str.push(']'); - offset += hint_str.len(); buf.insert_str(end_position, &hint_str); } + self.db.write_file("main2.py", &buf).unwrap(); + let inlayed_file = + system_path_to_file(&self.db, "main2.py").expect("newly written file to existing"); + + let diagnostics = tbd_diagnostics.into_iter().map(|(label_range, target)| { + InlayHintLocationDiagnostic::new(FileRange::new(inlayed_file, label_range), &target) + }); + let mut rendered_diagnostics = self.render_diagnostics(diagnostics); if !rendered_diagnostics.is_empty() { @@ -572,7 +576,7 @@ mod tests { #[test] fn test_assign_statement() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def i(x: int, /) -> int: return x @@ -604,13 +608,13 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:7:2 + --> main2.py:7:5 | 5 | x = 1 - 6 | y = x - 7 | z = i(1) - | ^ - 8 | w = z + 6 | y[: Literal[1]] = x + 7 | z[: int] = i(1) + | ^^^ + 8 | w[: int] = z | info[inlay-hint-location]: Inlay Hint Target @@ -623,19 +627,19 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:8:2 + --> main2.py:8:5 | - 6 | y = x - 7 | z = i(1) - 8 | w = z - | ^ + 6 | y[: Literal[1]] = x + 7 | z[: int] = i(1) + 8 | w[: int] = z + | ^^^ | "#); } #[test] fn test_unpacked_tuple_assignment() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def i(x: int, /) -> int: return x @@ -671,13 +675,13 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:9:3 + --> main2.py:9:6 | 7 | x1, y1 = (1, 'abc') - 8 | x2, y2 = (x1, y1) - 9 | x3, y3 = (i(1), s('abc')) - | ^ - 10 | x4, y4 = (x3, y3) + 8 | x2[: Literal[1]], y2[: Literal["abc"]] = (x1, y1) + 9 | x3[: int], y3[: str] = (i(1), s('abc')) + | ^^^ + 10 | x4[: int], y4[: str] = (x3, y3) | info[inlay-hint-location]: Inlay Hint Target @@ -690,13 +694,13 @@ mod tests { 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str | info: Source - --> main.py:9:7 + --> main2.py:9:17 | 7 | x1, y1 = (1, 'abc') - 8 | x2, y2 = (x1, y1) - 9 | x3, y3 = (i(1), s('abc')) - | ^ - 10 | x4, y4 = (x3, y3) + 8 | x2[: Literal[1]], y2[: Literal["abc"]] = (x1, y1) + 9 | x3[: int], y3[: str] = (i(1), s('abc')) + | ^^^ + 10 | x4[: int], y4[: str] = (x3, y3) | info[inlay-hint-location]: Inlay Hint Target @@ -709,12 +713,12 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:10:3 + --> main2.py:10:6 | - 8 | x2, y2 = (x1, y1) - 9 | x3, y3 = (i(1), s('abc')) - 10 | x4, y4 = (x3, y3) - | ^ + 8 | x2[: Literal[1]], y2[: Literal["abc"]] = (x1, y1) + 9 | x3[: int], y3[: str] = (i(1), s('abc')) + 10 | x4[: int], y4[: str] = (x3, y3) + | ^^^ | info[inlay-hint-location]: Inlay Hint Target @@ -727,19 +731,19 @@ mod tests { 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str | info: Source - --> main.py:10:7 + --> main2.py:10:17 | - 8 | x2, y2 = (x1, y1) - 9 | x3, y3 = (i(1), s('abc')) - 10 | x4, y4 = (x3, y3) - | ^ + 8 | x2[: Literal[1]], y2[: Literal["abc"]] = (x1, y1) + 9 | x3[: int], y3[: str] = (i(1), s('abc')) + 10 | x4[: int], y4[: str] = (x3, y3) + | ^^^ | "#); } #[test] fn test_multiple_assignment() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def i(x: int, /) -> int: return x @@ -775,13 +779,13 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:9:3 + --> main2.py:9:6 | 7 | x1, y1 = 1, 'abc' - 8 | x2, y2 = x1, y1 - 9 | x3, y3 = i(1), s('abc') - | ^ - 10 | x4, y4 = x3, y3 + 8 | x2[: Literal[1]], y2[: Literal["abc"]] = x1, y1 + 9 | x3[: int], y3[: str] = i(1), s('abc') + | ^^^ + 10 | x4[: int], y4[: str] = x3, y3 | info[inlay-hint-location]: Inlay Hint Target @@ -794,13 +798,13 @@ mod tests { 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str | info: Source - --> main.py:9:7 + --> main2.py:9:17 | 7 | x1, y1 = 1, 'abc' - 8 | x2, y2 = x1, y1 - 9 | x3, y3 = i(1), s('abc') - | ^ - 10 | x4, y4 = x3, y3 + 8 | x2[: Literal[1]], y2[: Literal["abc"]] = x1, y1 + 9 | x3[: int], y3[: str] = i(1), s('abc') + | ^^^ + 10 | x4[: int], y4[: str] = x3, y3 | info[inlay-hint-location]: Inlay Hint Target @@ -813,12 +817,12 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:10:3 + --> main2.py:10:6 | - 8 | x2, y2 = x1, y1 - 9 | x3, y3 = i(1), s('abc') - 10 | x4, y4 = x3, y3 - | ^ + 8 | x2[: Literal[1]], y2[: Literal["abc"]] = x1, y1 + 9 | x3[: int], y3[: str] = i(1), s('abc') + 10 | x4[: int], y4[: str] = x3, y3 + | ^^^ | info[inlay-hint-location]: Inlay Hint Target @@ -831,19 +835,19 @@ mod tests { 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str | info: Source - --> main.py:10:7 + --> main2.py:10:17 | - 8 | x2, y2 = x1, y1 - 9 | x3, y3 = i(1), s('abc') - 10 | x4, y4 = x3, y3 - | ^ + 8 | x2[: Literal[1]], y2[: Literal["abc"]] = x1, y1 + 9 | x3[: int], y3[: str] = i(1), s('abc') + 10 | x4[: int], y4[: str] = x3, y3 + | ^^^ | "#); } #[test] fn test_tuple_assignment() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def i(x: int, /) -> int: return x @@ -879,13 +883,13 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:9:2 + --> main2.py:9:11 | 7 | x = (1, 'abc') - 8 | y = x - 9 | z = (i(1), s('abc')) - | ^ - 10 | w = z + 8 | y[: tuple[Literal[1], Literal["abc"]]] = x + 9 | z[: tuple[int, str]] = (i(1), s('abc')) + | ^^^ + 10 | w[: tuple[int, str]] = z | info[inlay-hint-location]: Inlay Hint Target @@ -898,13 +902,13 @@ mod tests { 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str | info: Source - --> main.py:9:2 + --> main2.py:9:16 | 7 | x = (1, 'abc') - 8 | y = x - 9 | z = (i(1), s('abc')) - | ^ - 10 | w = z + 8 | y[: tuple[Literal[1], Literal["abc"]]] = x + 9 | z[: tuple[int, str]] = (i(1), s('abc')) + | ^^^ + 10 | w[: tuple[int, str]] = z | info[inlay-hint-location]: Inlay Hint Target @@ -917,12 +921,12 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:10:2 + --> main2.py:10:11 | - 8 | y = x - 9 | z = (i(1), s('abc')) - 10 | w = z - | ^ + 8 | y[: tuple[Literal[1], Literal["abc"]]] = x + 9 | z[: tuple[int, str]] = (i(1), s('abc')) + 10 | w[: tuple[int, str]] = z + | ^^^ | info[inlay-hint-location]: Inlay Hint Target @@ -935,19 +939,19 @@ mod tests { 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str | info: Source - --> main.py:10:2 + --> main2.py:10:16 | - 8 | y = x - 9 | z = (i(1), s('abc')) - 10 | w = z - | ^ + 8 | y[: tuple[Literal[1], Literal["abc"]]] = x + 9 | z[: tuple[int, str]] = (i(1), s('abc')) + 10 | w[: tuple[int, str]] = z + | ^^^ | "#); } #[test] fn test_nested_tuple_assignment() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def i(x: int, /) -> int: return x @@ -981,13 +985,13 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:9:3 + --> main2.py:9:6 | 7 | x1, (y1, z1) = (1, ('abc', 2)) - 8 | x2, (y2, z2) = (x1, (y1, z1)) - 9 | x3, (y3, z3) = (i(1), (s('abc'), i(2))) - | ^ - 10 | x4, (y4, z4) = (x3, (y3, z3)) + 8 | x2[: Literal[1]], (y2[: Literal["abc"]], z2[: Literal[2]]) = (x1, (y1, z1)) + 9 | x3[: int], (y3[: str], z3[: int]) = (i(1), (s('abc'), i(2))) + | ^^^ + 10 | x4[: int], (y4[: str], z4[: int]) = (x3, (y3, z3)) | info[inlay-hint-location]: Inlay Hint Target @@ -1000,13 +1004,13 @@ mod tests { 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str | info: Source - --> main.py:9:8 + --> main2.py:9:18 | 7 | x1, (y1, z1) = (1, ('abc', 2)) - 8 | x2, (y2, z2) = (x1, (y1, z1)) - 9 | x3, (y3, z3) = (i(1), (s('abc'), i(2))) - | ^ - 10 | x4, (y4, z4) = (x3, (y3, z3)) + 8 | x2[: Literal[1]], (y2[: Literal["abc"]], z2[: Literal[2]]) = (x1, (y1, z1)) + 9 | x3[: int], (y3[: str], z3[: int]) = (i(1), (s('abc'), i(2))) + | ^^^ + 10 | x4[: int], (y4[: str], z4[: int]) = (x3, (y3, z3)) | info[inlay-hint-location]: Inlay Hint Target @@ -1019,13 +1023,13 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:9:12 + --> main2.py:9:29 | 7 | x1, (y1, z1) = (1, ('abc', 2)) - 8 | x2, (y2, z2) = (x1, (y1, z1)) - 9 | x3, (y3, z3) = (i(1), (s('abc'), i(2))) - | ^ - 10 | x4, (y4, z4) = (x3, (y3, z3)) + 8 | x2[: Literal[1]], (y2[: Literal["abc"]], z2[: Literal[2]]) = (x1, (y1, z1)) + 9 | x3[: int], (y3[: str], z3[: int]) = (i(1), (s('abc'), i(2))) + | ^^^ + 10 | x4[: int], (y4[: str], z4[: int]) = (x3, (y3, z3)) | info[inlay-hint-location]: Inlay Hint Target @@ -1038,12 +1042,12 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:10:3 + --> main2.py:10:6 | - 8 | x2, (y2, z2) = (x1, (y1, z1)) - 9 | x3, (y3, z3) = (i(1), (s('abc'), i(2))) - 10 | x4, (y4, z4) = (x3, (y3, z3)) - | ^ + 8 | x2[: Literal[1]], (y2[: Literal["abc"]], z2[: Literal[2]]) = (x1, (y1, z1)) + 9 | x3[: int], (y3[: str], z3[: int]) = (i(1), (s('abc'), i(2))) + 10 | x4[: int], (y4[: str], z4[: int]) = (x3, (y3, z3)) + | ^^^ | info[inlay-hint-location]: Inlay Hint Target @@ -1056,12 +1060,12 @@ mod tests { 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str | info: Source - --> main.py:10:8 + --> main2.py:10:18 | - 8 | x2, (y2, z2) = (x1, (y1, z1)) - 9 | x3, (y3, z3) = (i(1), (s('abc'), i(2))) - 10 | x4, (y4, z4) = (x3, (y3, z3)) - | ^ + 8 | x2[: Literal[1]], (y2[: Literal["abc"]], z2[: Literal[2]]) = (x1, (y1, z1)) + 9 | x3[: int], (y3[: str], z3[: int]) = (i(1), (s('abc'), i(2))) + 10 | x4[: int], (y4[: str], z4[: int]) = (x3, (y3, z3)) + | ^^^ | info[inlay-hint-location]: Inlay Hint Target @@ -1074,19 +1078,19 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:10:12 + --> main2.py:10:29 | - 8 | x2, (y2, z2) = (x1, (y1, z1)) - 9 | x3, (y3, z3) = (i(1), (s('abc'), i(2))) - 10 | x4, (y4, z4) = (x3, (y3, z3)) - | ^ + 8 | x2[: Literal[1]], (y2[: Literal["abc"]], z2[: Literal[2]]) = (x1, (y1, z1)) + 9 | x3[: int], (y3[: str], z3[: int]) = (i(1), (s('abc'), i(2))) + 10 | x4[: int], (y4[: str], z4[: int]) = (x3, (y3, z3)) + | ^^^ | "#); } #[test] fn test_assign_statement_with_type_annotation() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def i(x: int, /) -> int: return x @@ -1116,19 +1120,19 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:8:2 + --> main2.py:8:5 | - 6 | y = x + 6 | y[: Literal[1]] = x 7 | z: int = i(1) - 8 | w = z - | ^ + 8 | w[: int] = z + | ^^^ | "#); } #[test] fn test_assign_statement_out_of_range() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def i(x: int, /) -> int: return x @@ -1152,12 +1156,12 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:4:2 + --> main2.py:4:5 | 2 | def i(x: int, /) -> int: 3 | return x - 4 | x = i(1) - | ^ + 4 | x[: int] = i(1) + | ^^^ 5 | z = x | "#); @@ -1165,7 +1169,7 @@ mod tests { #[test] fn test_assign_attribute_of_instance() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " class A: def __init__(self, y): @@ -1197,13 +1201,13 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:4:15 + --> main2.py:4:18 | 2 | class A: 3 | def __init__(self, y): - 4 | self.x = int(1) - | ^ - 5 | self.y = y + 4 | self.x[: int] = int(1) + | ^^^ + 5 | self.y[: Unknown] = y | info[inlay-hint-location]: Inlay Hint Target @@ -1215,13 +1219,13 @@ mod tests { 4 | self.x = int(1) | info: Source - --> main.py:7:2 + --> main2.py:7:5 | - 5 | self.y = y + 5 | self.y[: Unknown] = y 6 | - 7 | a = A(2) - | ^ - 8 | a.y = int(3) + 7 | a[: A] = A([y=]2) + | ^ + 8 | a.y[: int] = int(3) | info[inlay-hint-location]: Inlay Hint Target @@ -1234,13 +1238,13 @@ mod tests { 5 | self.y = y | info: Source - --> main.py:7:7 + --> main2.py:7:13 | - 5 | self.y = y + 5 | self.y[: Unknown] = y 6 | - 7 | a = A(2) - | ^ - 8 | a.y = int(3) + 7 | a[: A] = A([y=]2) + | ^ + 8 | a.y[: int] = int(3) | info[inlay-hint-location]: Inlay Hint Target @@ -1253,18 +1257,18 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:8:4 + --> main2.py:8:7 | - 7 | a = A(2) - 8 | a.y = int(3) - | ^ + 7 | a[: A] = A([y=]2) + 8 | a.y[: int] = int(3) + | ^^^ | "#); } #[test] fn test_many_literals() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( r#" a = 1 b = 1.0 @@ -1297,7 +1301,7 @@ mod tests { #[test] fn test_many_literals_tuple() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( r#" a = (1, 2) b = (1.0, 2.0) @@ -1330,7 +1334,7 @@ mod tests { #[test] fn test_many_literals_unpacked_tuple() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( r#" a1, a2 = (1, 2) b1, b2 = (1.0, 2.0) @@ -1363,7 +1367,7 @@ mod tests { #[test] fn test_many_literals_multiple() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( r#" a1, a2 = 1, 2 b1, b2 = 1.0, 2.0 @@ -1396,7 +1400,7 @@ mod tests { #[test] fn test_many_literals_list() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( r#" a = [1, 2] b = [1.0, 2.0] @@ -1435,12 +1439,12 @@ mod tests { 2803 | """Built-in mutable sequence. | info: Source - --> main.py:2:2 + --> main2.py:2:5 | - 2 | a = [1, 2] - | ^ - 3 | b = [1.0, 2.0] - 4 | c = [True, False] + 2 | a[: list[Unknown | int]] = [1, 2] + | ^^^^ + 3 | b[: list[Unknown | float]] = [1.0, 2.0] + 4 | c[: list[Unknown | bool]] = [True, False] | info[inlay-hint-location]: Inlay Hint Target @@ -1453,12 +1457,12 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:2:2 + --> main2.py:2:20 | - 2 | a = [1, 2] - | ^ - 3 | b = [1.0, 2.0] - 4 | c = [True, False] + 2 | a[: list[Unknown | int]] = [1, 2] + | ^^^ + 3 | b[: list[Unknown | float]] = [1.0, 2.0] + 4 | c[: list[Unknown | bool]] = [True, False] | info[inlay-hint-location]: Inlay Hint Target @@ -1470,13 +1474,13 @@ mod tests { 2803 | """Built-in mutable sequence. | info: Source - --> main.py:3:2 + --> main2.py:3:5 | - 2 | a = [1, 2] - 3 | b = [1.0, 2.0] - | ^ - 4 | c = [True, False] - 5 | d = [None, None] + 2 | a[: list[Unknown | int]] = [1, 2] + 3 | b[: list[Unknown | float]] = [1.0, 2.0] + | ^^^^ + 4 | c[: list[Unknown | bool]] = [True, False] + 5 | d[: list[Unknown | None]] = [None, None] | info[inlay-hint-location]: Inlay Hint Target @@ -1488,13 +1492,13 @@ mod tests { 662 | """Convert a string or number to a floating-point number, if possible.""" | info: Source - --> main.py:3:2 + --> main2.py:3:20 | - 2 | a = [1, 2] - 3 | b = [1.0, 2.0] - | ^ - 4 | c = [True, False] - 5 | d = [None, None] + 2 | a[: list[Unknown | int]] = [1, 2] + 3 | b[: list[Unknown | float]] = [1.0, 2.0] + | ^^^^^ + 4 | c[: list[Unknown | bool]] = [True, False] + 5 | d[: list[Unknown | None]] = [None, None] | info[inlay-hint-location]: Inlay Hint Target @@ -1506,14 +1510,14 @@ mod tests { 2803 | """Built-in mutable sequence. | info: Source - --> main.py:4:2 + --> main2.py:4:5 | - 2 | a = [1, 2] - 3 | b = [1.0, 2.0] - 4 | c = [True, False] - | ^ - 5 | d = [None, None] - 6 | e = ["hel", "lo"] + 2 | a[: list[Unknown | int]] = [1, 2] + 3 | b[: list[Unknown | float]] = [1.0, 2.0] + 4 | c[: list[Unknown | bool]] = [True, False] + | ^^^^ + 5 | d[: list[Unknown | None]] = [None, None] + 6 | e[: list[Unknown | str]] = ["hel", "lo"] | info[inlay-hint-location]: Inlay Hint Target @@ -1526,14 +1530,14 @@ mod tests { 2593 | The builtins True and False are the only two instances of the class bool. | info: Source - --> main.py:4:2 + --> main2.py:4:20 | - 2 | a = [1, 2] - 3 | b = [1.0, 2.0] - 4 | c = [True, False] - | ^ - 5 | d = [None, None] - 6 | e = ["hel", "lo"] + 2 | a[: list[Unknown | int]] = [1, 2] + 3 | b[: list[Unknown | float]] = [1.0, 2.0] + 4 | c[: list[Unknown | bool]] = [True, False] + | ^^^^ + 5 | d[: list[Unknown | None]] = [None, None] + 6 | e[: list[Unknown | str]] = ["hel", "lo"] | info[inlay-hint-location]: Inlay Hint Target @@ -1545,14 +1549,14 @@ mod tests { 2803 | """Built-in mutable sequence. | info: Source - --> main.py:5:2 + --> main2.py:5:5 | - 3 | b = [1.0, 2.0] - 4 | c = [True, False] - 5 | d = [None, None] - | ^ - 6 | e = ["hel", "lo"] - 7 | f = ['the', 're'] + 3 | b[: list[Unknown | float]] = [1.0, 2.0] + 4 | c[: list[Unknown | bool]] = [True, False] + 5 | d[: list[Unknown | None]] = [None, None] + | ^^^^ + 6 | e[: list[Unknown | str]] = ["hel", "lo"] + 7 | f[: list[Unknown | str]] = ['the', 're'] | info[inlay-hint-location]: Inlay Hint Target @@ -1565,14 +1569,14 @@ mod tests { 951 | """The type of the None singleton.""" | info: Source - --> main.py:5:2 + --> main2.py:5:20 | - 3 | b = [1.0, 2.0] - 4 | c = [True, False] - 5 | d = [None, None] - | ^ - 6 | e = ["hel", "lo"] - 7 | f = ['the', 're'] + 3 | b[: list[Unknown | float]] = [1.0, 2.0] + 4 | c[: list[Unknown | bool]] = [True, False] + 5 | d[: list[Unknown | None]] = [None, None] + | ^^^^ + 6 | e[: list[Unknown | str]] = ["hel", "lo"] + 7 | f[: list[Unknown | str]] = ['the', 're'] | info[inlay-hint-location]: Inlay Hint Target @@ -1584,14 +1588,14 @@ mod tests { 2803 | """Built-in mutable sequence. | info: Source - --> main.py:6:2 + --> main2.py:6:5 | - 4 | c = [True, False] - 5 | d = [None, None] - 6 | e = ["hel", "lo"] - | ^ - 7 | f = ['the', 're'] - 8 | g = [f"{ft}", f"{ft}"] + 4 | c[: list[Unknown | bool]] = [True, False] + 5 | d[: list[Unknown | None]] = [None, None] + 6 | e[: list[Unknown | str]] = ["hel", "lo"] + | ^^^^ + 7 | f[: list[Unknown | str]] = ['the', 're'] + 8 | g[: list[Unknown | str]] = [f"{ft}", f"{ft}"] | info[inlay-hint-location]: Inlay Hint Target @@ -1604,14 +1608,14 @@ mod tests { 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str | info: Source - --> main.py:6:2 + --> main2.py:6:20 | - 4 | c = [True, False] - 5 | d = [None, None] - 6 | e = ["hel", "lo"] - | ^ - 7 | f = ['the', 're'] - 8 | g = [f"{ft}", f"{ft}"] + 4 | c[: list[Unknown | bool]] = [True, False] + 5 | d[: list[Unknown | None]] = [None, None] + 6 | e[: list[Unknown | str]] = ["hel", "lo"] + | ^^^ + 7 | f[: list[Unknown | str]] = ['the', 're'] + 8 | g[: list[Unknown | str]] = [f"{ft}", f"{ft}"] | info[inlay-hint-location]: Inlay Hint Target @@ -1623,14 +1627,14 @@ mod tests { 2803 | """Built-in mutable sequence. | info: Source - --> main.py:7:2 + --> main2.py:7:5 | - 5 | d = [None, None] - 6 | e = ["hel", "lo"] - 7 | f = ['the', 're'] - | ^ - 8 | g = [f"{ft}", f"{ft}"] - 9 | h = [t"wow %d", t"wow %d"] + 5 | d[: list[Unknown | None]] = [None, None] + 6 | e[: list[Unknown | str]] = ["hel", "lo"] + 7 | f[: list[Unknown | str]] = ['the', 're'] + | ^^^^ + 8 | g[: list[Unknown | str]] = [f"{ft}", f"{ft}"] + 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] | info[inlay-hint-location]: Inlay Hint Target @@ -1643,14 +1647,14 @@ mod tests { 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str | info: Source - --> main.py:7:2 + --> main2.py:7:20 | - 5 | d = [None, None] - 6 | e = ["hel", "lo"] - 7 | f = ['the', 're'] - | ^ - 8 | g = [f"{ft}", f"{ft}"] - 9 | h = [t"wow %d", t"wow %d"] + 5 | d[: list[Unknown | None]] = [None, None] + 6 | e[: list[Unknown | str]] = ["hel", "lo"] + 7 | f[: list[Unknown | str]] = ['the', 're'] + | ^^^ + 8 | g[: list[Unknown | str]] = [f"{ft}", f"{ft}"] + 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] | info[inlay-hint-location]: Inlay Hint Target @@ -1662,14 +1666,14 @@ mod tests { 2803 | """Built-in mutable sequence. | info: Source - --> main.py:8:2 + --> main2.py:8:5 | - 6 | e = ["hel", "lo"] - 7 | f = ['the', 're'] - 8 | g = [f"{ft}", f"{ft}"] - | ^ - 9 | h = [t"wow %d", t"wow %d"] - 10 | i = [b'\x01', b'\x02'] + 6 | e[: list[Unknown | str]] = ["hel", "lo"] + 7 | f[: list[Unknown | str]] = ['the', 're'] + 8 | g[: list[Unknown | str]] = [f"{ft}", f"{ft}"] + | ^^^^ + 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] + 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] | info[inlay-hint-location]: Inlay Hint Target @@ -1682,14 +1686,14 @@ mod tests { 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str | info: Source - --> main.py:8:2 + --> main2.py:8:20 | - 6 | e = ["hel", "lo"] - 7 | f = ['the', 're'] - 8 | g = [f"{ft}", f"{ft}"] - | ^ - 9 | h = [t"wow %d", t"wow %d"] - 10 | i = [b'\x01', b'\x02'] + 6 | e[: list[Unknown | str]] = ["hel", "lo"] + 7 | f[: list[Unknown | str]] = ['the', 're'] + 8 | g[: list[Unknown | str]] = [f"{ft}", f"{ft}"] + | ^^^ + 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] + 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] | info[inlay-hint-location]: Inlay Hint Target @@ -1701,14 +1705,14 @@ mod tests { 2803 | """Built-in mutable sequence. | info: Source - --> main.py:9:2 + --> main2.py:9:5 | - 7 | f = ['the', 're'] - 8 | g = [f"{ft}", f"{ft}"] - 9 | h = [t"wow %d", t"wow %d"] - | ^ - 10 | i = [b'\x01', b'\x02'] - 11 | j = [+1, +2.0] + 7 | f[: list[Unknown | str]] = ['the', 're'] + 8 | g[: list[Unknown | str]] = [f"{ft}", f"{ft}"] + 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] + | ^^^^ + 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 11 | j[: list[Unknown | int | float]] = [+1, +2.0] | info[inlay-hint-location]: Inlay Hint Target @@ -1720,14 +1724,14 @@ mod tests { 11 | """Template object""" | info: Source - --> main.py:9:2 + --> main2.py:9:20 | - 7 | f = ['the', 're'] - 8 | g = [f"{ft}", f"{ft}"] - 9 | h = [t"wow %d", t"wow %d"] - | ^ - 10 | i = [b'\x01', b'\x02'] - 11 | j = [+1, +2.0] + 7 | f[: list[Unknown | str]] = ['the', 're'] + 8 | g[: list[Unknown | str]] = [f"{ft}", f"{ft}"] + 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] + | ^^^^^^^^ + 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 11 | j[: list[Unknown | int | float]] = [+1, +2.0] | info[inlay-hint-location]: Inlay Hint Target @@ -1739,14 +1743,14 @@ mod tests { 2803 | """Built-in mutable sequence. | info: Source - --> main.py:10:2 + --> main2.py:10:5 | - 8 | g = [f"{ft}", f"{ft}"] - 9 | h = [t"wow %d", t"wow %d"] - 10 | i = [b'\x01', b'\x02'] - | ^ - 11 | j = [+1, +2.0] - 12 | k = [-1, -2.0] + 8 | g[: list[Unknown | str]] = [f"{ft}", f"{ft}"] + 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] + 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + | ^^^^ + 11 | j[: list[Unknown | int | float]] = [+1, +2.0] + 12 | k[: list[Unknown | int | float]] = [-1, -2.0] | info[inlay-hint-location]: Inlay Hint Target @@ -1759,14 +1763,14 @@ mod tests { 1450 | bytes(string, encoding[, errors]) -> bytes | info: Source - --> main.py:10:2 + --> main2.py:10:20 | - 8 | g = [f"{ft}", f"{ft}"] - 9 | h = [t"wow %d", t"wow %d"] - 10 | i = [b'\x01', b'\x02'] - | ^ - 11 | j = [+1, +2.0] - 12 | k = [-1, -2.0] + 8 | g[: list[Unknown | str]] = [f"{ft}", f"{ft}"] + 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] + 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + | ^^^^^ + 11 | j[: list[Unknown | int | float]] = [+1, +2.0] + 12 | k[: list[Unknown | int | float]] = [-1, -2.0] | info[inlay-hint-location]: Inlay Hint Target @@ -1778,13 +1782,13 @@ mod tests { 2803 | """Built-in mutable sequence. | info: Source - --> main.py:11:2 + --> main2.py:11:5 | - 9 | h = [t"wow %d", t"wow %d"] - 10 | i = [b'\x01', b'\x02'] - 11 | j = [+1, +2.0] - | ^ - 12 | k = [-1, -2.0] + 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] + 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 11 | j[: list[Unknown | int | float]] = [+1, +2.0] + | ^^^^ + 12 | k[: list[Unknown | int | float]] = [-1, -2.0] | info[inlay-hint-location]: Inlay Hint Target @@ -1797,13 +1801,13 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:11:2 + --> main2.py:11:20 | - 9 | h = [t"wow %d", t"wow %d"] - 10 | i = [b'\x01', b'\x02'] - 11 | j = [+1, +2.0] - | ^ - 12 | k = [-1, -2.0] + 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] + 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 11 | j[: list[Unknown | int | float]] = [+1, +2.0] + | ^^^ + 12 | k[: list[Unknown | int | float]] = [-1, -2.0] | info[inlay-hint-location]: Inlay Hint Target @@ -1815,13 +1819,13 @@ mod tests { 662 | """Convert a string or number to a floating-point number, if possible.""" | info: Source - --> main.py:11:2 + --> main2.py:11:26 | - 9 | h = [t"wow %d", t"wow %d"] - 10 | i = [b'\x01', b'\x02'] - 11 | j = [+1, +2.0] - | ^ - 12 | k = [-1, -2.0] + 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] + 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 11 | j[: list[Unknown | int | float]] = [+1, +2.0] + | ^^^^^ + 12 | k[: list[Unknown | int | float]] = [-1, -2.0] | info[inlay-hint-location]: Inlay Hint Target @@ -1833,12 +1837,12 @@ mod tests { 2803 | """Built-in mutable sequence. | info: Source - --> main.py:12:2 + --> main2.py:12:5 | - 10 | i = [b'\x01', b'\x02'] - 11 | j = [+1, +2.0] - 12 | k = [-1, -2.0] - | ^ + 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 11 | j[: list[Unknown | int | float]] = [+1, +2.0] + 12 | k[: list[Unknown | int | float]] = [-1, -2.0] + | ^^^^ | info[inlay-hint-location]: Inlay Hint Target @@ -1851,12 +1855,12 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:12:2 + --> main2.py:12:20 | - 10 | i = [b'\x01', b'\x02'] - 11 | j = [+1, +2.0] - 12 | k = [-1, -2.0] - | ^ + 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 11 | j[: list[Unknown | int | float]] = [+1, +2.0] + 12 | k[: list[Unknown | int | float]] = [-1, -2.0] + | ^^^ | info[inlay-hint-location]: Inlay Hint Target @@ -1868,19 +1872,19 @@ mod tests { 662 | """Convert a string or number to a floating-point number, if possible.""" | info: Source - --> main.py:12:2 + --> main2.py:12:26 | - 10 | i = [b'\x01', b'\x02'] - 11 | j = [+1, +2.0] - 12 | k = [-1, -2.0] - | ^ + 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 11 | j[: list[Unknown | int | float]] = [+1, +2.0] + 12 | k[: list[Unknown | int | float]] = [-1, -2.0] + | ^^^^^ | "#); } #[test] fn test_simple_init_call() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( r#" class MyClass: def __init__(self): @@ -1913,14 +1917,14 @@ mod tests { 4 | self.x: int = 1 | info: Source - --> main.py:6:2 + --> main2.py:6:5 | 4 | self.x: int = 1 5 | - 6 | x = MyClass() - | ^ - 7 | y = (MyClass(), MyClass()) - 8 | a, b = MyClass(), MyClass() + 6 | x[: MyClass] = MyClass() + | ^^^^^^^ + 7 | y[: tuple[MyClass, MyClass]] = (MyClass(), MyClass()) + 8 | a[: MyClass], b[: MyClass] = MyClass(), MyClass() | info[inlay-hint-location]: Inlay Hint Target @@ -1932,13 +1936,13 @@ mod tests { 4 | self.x: int = 1 | info: Source - --> main.py:7:2 + --> main2.py:7:11 | - 6 | x = MyClass() - 7 | y = (MyClass(), MyClass()) - | ^ - 8 | a, b = MyClass(), MyClass() - 9 | c, d = (MyClass(), MyClass()) + 6 | x[: MyClass] = MyClass() + 7 | y[: tuple[MyClass, MyClass]] = (MyClass(), MyClass()) + | ^^^^^^^ + 8 | a[: MyClass], b[: MyClass] = MyClass(), MyClass() + 9 | c[: MyClass], d[: MyClass] = (MyClass(), MyClass()) | info[inlay-hint-location]: Inlay Hint Target @@ -1950,13 +1954,13 @@ mod tests { 4 | self.x: int = 1 | info: Source - --> main.py:7:2 + --> main2.py:7:20 | - 6 | x = MyClass() - 7 | y = (MyClass(), MyClass()) - | ^ - 8 | a, b = MyClass(), MyClass() - 9 | c, d = (MyClass(), MyClass()) + 6 | x[: MyClass] = MyClass() + 7 | y[: tuple[MyClass, MyClass]] = (MyClass(), MyClass()) + | ^^^^^^^ + 8 | a[: MyClass], b[: MyClass] = MyClass(), MyClass() + 9 | c[: MyClass], d[: MyClass] = (MyClass(), MyClass()) | info[inlay-hint-location]: Inlay Hint Target @@ -1968,13 +1972,13 @@ mod tests { 4 | self.x: int = 1 | info: Source - --> main.py:8:2 + --> main2.py:8:5 | - 6 | x = MyClass() - 7 | y = (MyClass(), MyClass()) - 8 | a, b = MyClass(), MyClass() - | ^ - 9 | c, d = (MyClass(), MyClass()) + 6 | x[: MyClass] = MyClass() + 7 | y[: tuple[MyClass, MyClass]] = (MyClass(), MyClass()) + 8 | a[: MyClass], b[: MyClass] = MyClass(), MyClass() + | ^^^^^^^ + 9 | c[: MyClass], d[: MyClass] = (MyClass(), MyClass()) | info[inlay-hint-location]: Inlay Hint Target @@ -1986,13 +1990,13 @@ mod tests { 4 | self.x: int = 1 | info: Source - --> main.py:8:5 + --> main2.py:8:19 | - 6 | x = MyClass() - 7 | y = (MyClass(), MyClass()) - 8 | a, b = MyClass(), MyClass() - | ^ - 9 | c, d = (MyClass(), MyClass()) + 6 | x[: MyClass] = MyClass() + 7 | y[: tuple[MyClass, MyClass]] = (MyClass(), MyClass()) + 8 | a[: MyClass], b[: MyClass] = MyClass(), MyClass() + | ^^^^^^^ + 9 | c[: MyClass], d[: MyClass] = (MyClass(), MyClass()) | info[inlay-hint-location]: Inlay Hint Target @@ -2004,12 +2008,12 @@ mod tests { 4 | self.x: int = 1 | info: Source - --> main.py:9:2 + --> main2.py:9:5 | - 7 | y = (MyClass(), MyClass()) - 8 | a, b = MyClass(), MyClass() - 9 | c, d = (MyClass(), MyClass()) - | ^ + 7 | y[: tuple[MyClass, MyClass]] = (MyClass(), MyClass()) + 8 | a[: MyClass], b[: MyClass] = MyClass(), MyClass() + 9 | c[: MyClass], d[: MyClass] = (MyClass(), MyClass()) + | ^^^^^^^ | info[inlay-hint-location]: Inlay Hint Target @@ -2021,19 +2025,19 @@ mod tests { 4 | self.x: int = 1 | info: Source - --> main.py:9:5 + --> main2.py:9:19 | - 7 | y = (MyClass(), MyClass()) - 8 | a, b = MyClass(), MyClass() - 9 | c, d = (MyClass(), MyClass()) - | ^ + 7 | y[: tuple[MyClass, MyClass]] = (MyClass(), MyClass()) + 8 | a[: MyClass], b[: MyClass] = MyClass(), MyClass() + 9 | c[: MyClass], d[: MyClass] = (MyClass(), MyClass()) + | ^^^^^^^ | "); } #[test] fn test_generic_init_call() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( r#" class MyClass[T, U]: def __init__(self, x: list[T], y: tuple[U, U]): @@ -2068,13 +2072,13 @@ mod tests { 2803 | """Built-in mutable sequence. | info: Source - --> main.py:4:15 + --> main2.py:4:18 | 2 | class MyClass[T, U]: 3 | def __init__(self, x: list[T], y: tuple[U, U]): - 4 | self.x = x - | ^ - 5 | self.y = y + 4 | self.x[: list[T@MyClass]] = x + | ^^^^ + 5 | self.y[: tuple[U@MyClass, U@MyClass]] = y | info[inlay-hint-location]: Inlay Hint Target @@ -2086,14 +2090,14 @@ mod tests { 4 | self.x = x | info: Source - --> main.py:7:2 + --> main2.py:7:5 | - 5 | self.y = y + 5 | self.y[: tuple[U@MyClass, U@MyClass]] = y 6 | - 7 | x = MyClass([42], ("a", "b")) - | ^ - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + | ^^^^^^^ + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… | info[inlay-hint-location]: Inlay Hint Target @@ -2106,14 +2110,14 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:7:2 + --> main2.py:7:23 | - 5 | self.y = y + 5 | self.y[: tuple[U@MyClass, U@MyClass]] = y 6 | - 7 | x = MyClass([42], ("a", "b")) - | ^ - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + | ^^^ + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… | info[inlay-hint-location]: Inlay Hint Target @@ -2126,14 +2130,14 @@ mod tests { 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str | info: Source - --> main.py:7:2 + --> main2.py:7:28 | - 5 | self.y = y + 5 | self.y[: tuple[U@MyClass, U@MyClass]] = y 6 | - 7 | x = MyClass([42], ("a", "b")) - | ^ - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + | ^^^ + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… | info[inlay-hint-location]: Inlay Hint Target @@ -2146,14 +2150,14 @@ mod tests { 5 | self.y = y | info: Source - --> main.py:7:13 + --> main2.py:7:45 | - 5 | self.y = y + 5 | self.y[: tuple[U@MyClass, U@MyClass]] = y 6 | - 7 | x = MyClass([42], ("a", "b")) - | ^ - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + | ^ + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… | info[inlay-hint-location]: Inlay Hint Target @@ -2166,14 +2170,14 @@ mod tests { 5 | self.y = y | info: Source - --> main.py:7:19 + --> main2.py:7:55 | - 5 | self.y = y + 5 | self.y[: tuple[U@MyClass, U@MyClass]] = y 6 | - 7 | x = MyClass([42], ("a", "b")) - | ^ - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + | ^ + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… | info[inlay-hint-location]: Inlay Hint Target @@ -2185,13 +2189,13 @@ mod tests { 4 | self.x = x | info: Source - --> main.py:8:2 + --> main2.py:8:11 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + | ^^^^^^^ + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2204,13 +2208,13 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:8:2 + --> main2.py:8:29 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + | ^^^ + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2223,13 +2227,13 @@ mod tests { 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str | info: Source - --> main.py:8:2 + --> main2.py:8:34 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + | ^^^ + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2241,13 +2245,13 @@ mod tests { 4 | self.x = x | info: Source - --> main.py:8:2 + --> main2.py:8:40 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + | ^^^^^^^ + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2260,13 +2264,13 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:8:2 + --> main2.py:8:58 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + | ^^^ + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2279,13 +2283,13 @@ mod tests { 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str | info: Source - --> main.py:8:2 + --> main2.py:8:63 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + | ^^^ + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2298,13 +2302,13 @@ mod tests { 5 | self.y = y | info: Source - --> main.py:8:14 + --> main2.py:8:82 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + | ^ + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2317,13 +2321,13 @@ mod tests { 5 | self.y = y | info: Source - --> main.py:8:20 + --> main2.py:8:92 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + | ^ + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2336,13 +2340,13 @@ mod tests { 5 | self.y = y | info: Source - --> main.py:8:41 + --> main2.py:8:117 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + | ^ + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2355,13 +2359,13 @@ mod tests { 5 | self.y = y | info: Source - --> main.py:8:47 + --> main2.py:8:127 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + | ^ + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2373,13 +2377,13 @@ mod tests { 4 | self.x = x | info: Source - --> main.py:9:2 + --> main2.py:9:5 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - | ^ - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + | ^^^^^^^ + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2392,13 +2396,13 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:9:2 + --> main2.py:9:23 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - | ^ - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + | ^^^ + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2411,13 +2415,13 @@ mod tests { 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str | info: Source - --> main.py:9:2 + --> main2.py:9:28 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - | ^ - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + | ^^^ + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2429,13 +2433,13 @@ mod tests { 4 | self.x = x | info: Source - --> main.py:9:5 + --> main2.py:9:39 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - | ^ - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + | ^^^^^^^ + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2448,13 +2452,13 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:9:5 + --> main2.py:9:57 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - | ^ - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + | ^^^ + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2467,13 +2471,13 @@ mod tests { 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str | info: Source - --> main.py:9:5 + --> main2.py:9:62 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - | ^ - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + | ^^^ + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2486,13 +2490,13 @@ mod tests { 5 | self.y = y | info: Source - --> main.py:9:16 + --> main2.py:9:79 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - | ^ - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + | ^ + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2505,13 +2509,13 @@ mod tests { 5 | self.y = y | info: Source - --> main.py:9:22 + --> main2.py:9:89 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - | ^ - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + | ^ + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2524,13 +2528,13 @@ mod tests { 5 | self.y = y | info: Source - --> main.py:9:43 + --> main2.py:9:114 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - | ^ - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + | ^ + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2543,13 +2547,13 @@ mod tests { 5 | self.y = y | info: Source - --> main.py:9:49 + --> main2.py:9:124 | - 7 | x = MyClass([42], ("a", "b")) - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - | ^ - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) + 7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")) + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + | ^ + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… | info[inlay-hint-location]: Inlay Hint Target @@ -2561,12 +2565,12 @@ mod tests { 4 | self.x = x | info: Source - --> main.py:10:2 + --> main2.py:10:5 | - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… + | ^^^^^^^ | info[inlay-hint-location]: Inlay Hint Target @@ -2579,12 +2583,12 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:10:2 + --> main2.py:10:23 | - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… + | ^^^ | info[inlay-hint-location]: Inlay Hint Target @@ -2597,12 +2601,12 @@ mod tests { 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str | info: Source - --> main.py:10:2 + --> main2.py:10:28 | - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… + | ^^^ | info[inlay-hint-location]: Inlay Hint Target @@ -2614,12 +2618,12 @@ mod tests { 4 | self.x = x | info: Source - --> main.py:10:5 + --> main2.py:10:39 | - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… + | ^^^^^^^ | info[inlay-hint-location]: Inlay Hint Target @@ -2632,12 +2636,12 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:10:5 + --> main2.py:10:57 | - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… + | ^^^ | info[inlay-hint-location]: Inlay Hint Target @@ -2650,12 +2654,12 @@ mod tests { 917 | str(bytes_or_buffer[, encoding[, errors]]) -> str | info: Source - --> main.py:10:5 + --> main2.py:10:62 | - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… + | ^^^ | info[inlay-hint-location]: Inlay Hint Target @@ -2668,12 +2672,12 @@ mod tests { 5 | self.y = y | info: Source - --> main.py:10:17 + --> main2.py:10:80 | - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… + | ^ | info[inlay-hint-location]: Inlay Hint Target @@ -2686,12 +2690,12 @@ mod tests { 5 | self.y = y | info: Source - --> main.py:10:23 + --> main2.py:10:90 | - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… + | ^ | info[inlay-hint-location]: Inlay Hint Target @@ -2704,12 +2708,12 @@ mod tests { 5 | self.y = y | info: Source - --> main.py:10:44 + --> main2.py:10:115 | - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… + | ^ | info[inlay-hint-location]: Inlay Hint Target @@ -2722,19 +2726,19 @@ mod tests { 5 | self.y = y | info: Source - --> main.py:10:50 + --> main2.py:10:125 | - 8 | y = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - 9 | a, b = MyClass([42], ("a", "b")), MyClass([42], ("a", "b")) - 10 | c, d = (MyClass([42], ("a", "b")), MyClass([42], ("a", "b"))) - | ^ + 8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",… + 9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b… + 10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "… + | ^ | "#); } #[test] fn test_disabled_variable_types() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def i(x: int, /) -> int: return x @@ -2759,7 +2763,7 @@ mod tests { #[test] fn test_function_call_with_positional_or_keyword_parameter() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(x: int): pass foo(1)", @@ -2777,18 +2781,18 @@ mod tests { 3 | foo(1) | info: Source - --> main.py:3:5 + --> main2.py:3:6 | 2 | def foo(x: int): pass - 3 | foo(1) - | ^ + 3 | foo([x=]1) + | ^ | "); } #[test] fn test_function_call_with_positional_or_keyword_parameter_redundant_name() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(x: int): pass x = 1 @@ -2813,19 +2817,19 @@ mod tests { 4 | y = 2 | info: Source - --> main.py:6:5 + --> main2.py:6:6 | 4 | y = 2 5 | foo(x) - 6 | foo(y) - | ^ + 6 | foo([x=]y) + | ^ | "); } #[test] fn test_function_call_with_positional_or_keyword_parameter_redundant_attribute() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(x: int): pass class MyClass: @@ -2859,12 +2863,12 @@ mod tests { 5 | self.x: int = 1 | info: Source - --> main.py:7:4 + --> main2.py:7:7 | 5 | self.x: int = 1 6 | self.y: int = 2 - 7 | val = MyClass() - | ^ + 7 | val[: MyClass] = MyClass() + | ^^^^^^^ 8 | 9 | foo(val.x) | @@ -2878,11 +2882,11 @@ mod tests { 4 | def __init__(self): | info: Source - --> main.py:10:5 + --> main2.py:10:6 | 9 | foo(val.x) - 10 | foo(val.y) - | ^ + 10 | foo([x=]val.y) + | ^ | "); } @@ -2890,7 +2894,7 @@ mod tests { #[test] fn test_function_call_with_positional_or_keyword_parameter_redundant_attribute_not() { // This one checks that we don't allow elide `x=` for `x.y` - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(x: int): pass class MyClass: @@ -2924,12 +2928,12 @@ mod tests { 5 | self.x: int = 1 | info: Source - --> main.py:7:2 + --> main2.py:7:5 | 5 | self.x: int = 1 6 | self.y: int = 2 - 7 | x = MyClass() - | ^ + 7 | x[: MyClass] = MyClass() + | ^^^^^^^ 8 | 9 | foo(x.x) | @@ -2943,18 +2947,18 @@ mod tests { 4 | def __init__(self): | info: Source - --> main.py:10:5 + --> main2.py:10:6 | 9 | foo(x.x) - 10 | foo(x.y) - | ^ + 10 | foo([x=]x.y) + | ^ | "); } #[test] fn test_function_call_with_positional_or_keyword_parameter_redundant_call() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(x: int): pass class MyClass: @@ -2992,12 +2996,12 @@ mod tests { 5 | def x() -> int: | info: Source - --> main.py:9:4 + --> main2.py:9:7 | 7 | def y() -> int: 8 | return 2 - 9 | val = MyClass() - | ^ + 9 | val[: MyClass] = MyClass() + | ^^^^^^^ 10 | 11 | foo(val.x()) | @@ -3011,18 +3015,18 @@ mod tests { 4 | def __init__(self): | info: Source - --> main.py:12:5 + --> main2.py:12:6 | 11 | foo(val.x()) - 12 | foo(val.y()) - | ^ + 12 | foo([x=]val.y()) + | ^ | "); } #[test] fn test_function_call_with_positional_or_keyword_parameter_redundant_complex() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " from typing import List @@ -3064,12 +3068,12 @@ mod tests { 7 | def x() -> List[int]: | info: Source - --> main.py:11:4 + --> main2.py:11:7 | 9 | def y() -> List[int]: 10 | return 2 - 11 | val = MyClass() - | ^ + 11 | val[: MyClass] = MyClass() + | ^^^^^^^ 12 | 13 | foo(val.x()[0]) | @@ -3085,18 +3089,18 @@ mod tests { 6 | def __init__(self): | info: Source - --> main.py:14:5 + --> main2.py:14:6 | 13 | foo(val.x()[0]) - 14 | foo(val.y()[1]) - | ^ + 14 | foo([x=]val.y()[1]) + | ^ | "); } #[test] fn test_function_call_with_positional_or_keyword_parameter_redundant_subscript() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(x: int): pass x = [1] @@ -3123,12 +3127,12 @@ mod tests { 2803 | """Built-in mutable sequence. | info: Source - --> main.py:3:2 + --> main2.py:3:5 | 2 | def foo(x: int): pass - 3 | x = [1] - | ^ - 4 | y = [2] + 3 | x[: list[Unknown | int]] = [1] + | ^^^^ + 4 | y[: list[Unknown | int]] = [2] | info[inlay-hint-location]: Inlay Hint Target @@ -3141,12 +3145,12 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:3:2 + --> main2.py:3:20 | 2 | def foo(x: int): pass - 3 | x = [1] - | ^ - 4 | y = [2] + 3 | x[: list[Unknown | int]] = [1] + | ^^^ + 4 | y[: list[Unknown | int]] = [2] | info[inlay-hint-location]: Inlay Hint Target @@ -3158,12 +3162,12 @@ mod tests { 2803 | """Built-in mutable sequence. | info: Source - --> main.py:4:2 + --> main2.py:4:5 | 2 | def foo(x: int): pass - 3 | x = [1] - 4 | y = [2] - | ^ + 3 | x[: list[Unknown | int]] = [1] + 4 | y[: list[Unknown | int]] = [2] + | ^^^^ 5 | 6 | foo(x[0]) | @@ -3178,12 +3182,12 @@ mod tests { 350 | int(x, base=10) -> integer | info: Source - --> main.py:4:2 + --> main2.py:4:20 | 2 | def foo(x: int): pass - 3 | x = [1] - 4 | y = [2] - | ^ + 3 | x[: list[Unknown | int]] = [1] + 4 | y[: list[Unknown | int]] = [2] + | ^^^ 5 | 6 | foo(x[0]) | @@ -3197,18 +3201,18 @@ mod tests { 4 | y = [2] | info: Source - --> main.py:7:5 + --> main2.py:7:6 | 6 | foo(x[0]) - 7 | foo(y[0]) - | ^ + 7 | foo([x=]y[0]) + | ^ | "#); } #[test] fn test_function_call_with_positional_only_parameter() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(x: int, /): pass foo(1)", @@ -3222,7 +3226,7 @@ mod tests { #[test] fn test_function_call_with_variadic_parameter() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(*args: int): pass foo(1)", @@ -3236,7 +3240,7 @@ mod tests { #[test] fn test_function_call_with_keyword_variadic_parameter() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(**kwargs: int): pass foo(x=1)", @@ -3250,7 +3254,7 @@ mod tests { #[test] fn test_function_call_with_keyword_only_parameter() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(*, x: int): pass foo(x=1)", @@ -3264,7 +3268,7 @@ mod tests { #[test] fn test_function_call_positional_only_and_positional_or_keyword_parameters() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(x: int, /, y: int): pass foo(1, 2)", @@ -3282,18 +3286,18 @@ mod tests { 3 | foo(1, 2) | info: Source - --> main.py:3:8 + --> main2.py:3:9 | 2 | def foo(x: int, /, y: int): pass - 3 | foo(1, 2) - | ^ + 3 | foo(1, [y=]2) + | ^ | "); } #[test] fn test_function_call_positional_only_and_variadic_parameters() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(x: int, /, *args: int): pass foo(1, 2, 3)", @@ -3307,7 +3311,7 @@ mod tests { #[test] fn test_function_call_positional_only_and_keyword_variadic_parameters() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(x: int, /, **kwargs: int): pass foo(1, x=2)", @@ -3321,7 +3325,7 @@ mod tests { #[test] fn test_class_constructor_call_init() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " class Foo: def __init__(self, x: int): pass @@ -3345,13 +3349,13 @@ mod tests { 5 | f = Foo(1) | info: Source - --> main.py:4:5 + --> main2.py:4:6 | 2 | class Foo: 3 | def __init__(self, x: int): pass - 4 | Foo(1) - | ^ - 5 | f = Foo(1) + 4 | Foo([x=]1) + | ^ + 5 | f[: Foo] = Foo([x=]1) | info[inlay-hint-location]: Inlay Hint Target @@ -3363,12 +3367,12 @@ mod tests { 4 | Foo(1) | info: Source - --> main.py:5:2 + --> main2.py:5:5 | 3 | def __init__(self, x: int): pass - 4 | Foo(1) - 5 | f = Foo(1) - | ^ + 4 | Foo([x=]1) + 5 | f[: Foo] = Foo([x=]1) + | ^^^ | info[inlay-hint-location]: Inlay Hint Target @@ -3381,19 +3385,19 @@ mod tests { 5 | f = Foo(1) | info: Source - --> main.py:5:9 + --> main2.py:5:17 | 3 | def __init__(self, x: int): pass - 4 | Foo(1) - 5 | f = Foo(1) - | ^ + 4 | Foo([x=]1) + 5 | f[: Foo] = Foo([x=]1) + | ^ | "); } #[test] fn test_class_constructor_call_new() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " class Foo: def __new__(cls, x: int): pass @@ -3417,13 +3421,13 @@ mod tests { 5 | f = Foo(1) | info: Source - --> main.py:4:5 + --> main2.py:4:6 | 2 | class Foo: 3 | def __new__(cls, x: int): pass - 4 | Foo(1) - | ^ - 5 | f = Foo(1) + 4 | Foo([x=]1) + | ^ + 5 | f[: Foo] = Foo([x=]1) | info[inlay-hint-location]: Inlay Hint Target @@ -3435,12 +3439,12 @@ mod tests { 4 | Foo(1) | info: Source - --> main.py:5:2 + --> main2.py:5:5 | 3 | def __new__(cls, x: int): pass - 4 | Foo(1) - 5 | f = Foo(1) - | ^ + 4 | Foo([x=]1) + 5 | f[: Foo] = Foo([x=]1) + | ^^^ | info[inlay-hint-location]: Inlay Hint Target @@ -3453,19 +3457,19 @@ mod tests { 5 | f = Foo(1) | info: Source - --> main.py:5:9 + --> main2.py:5:17 | 3 | def __new__(cls, x: int): pass - 4 | Foo(1) - 5 | f = Foo(1) - | ^ + 4 | Foo([x=]1) + 5 | f[: Foo] = Foo([x=]1) + | ^ | "); } #[test] fn test_class_constructor_call_meta_class_call() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " class MetaFoo: def __call__(self, x: int): pass @@ -3491,19 +3495,19 @@ mod tests { 5 | pass | info: Source - --> main.py:6:5 + --> main2.py:6:6 | 4 | class Foo(metaclass=MetaFoo): 5 | pass - 6 | Foo(1) - | ^ + 6 | Foo([x=]1) + | ^ | "); } #[test] fn test_callable_call() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " from typing import Callable def foo(x: Callable[[int], int]): @@ -3519,7 +3523,7 @@ mod tests { #[test] fn test_instance_method_call() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " class Foo: def bar(self, y: int): pass @@ -3540,19 +3544,19 @@ mod tests { 4 | Foo().bar(2) | info: Source - --> main.py:4:11 + --> main2.py:4:12 | 2 | class Foo: 3 | def bar(self, y: int): pass - 4 | Foo().bar(2) - | ^ + 4 | Foo().bar([y=]2) + | ^ | "); } #[test] fn test_class_method_call() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " class Foo: @classmethod @@ -3576,19 +3580,19 @@ mod tests { 5 | Foo.bar(2) | info: Source - --> main.py:5:9 + --> main2.py:5:10 | 3 | @classmethod 4 | def bar(cls, y: int): pass - 5 | Foo.bar(2) - | ^ + 5 | Foo.bar([y=]2) + | ^ | "); } #[test] fn test_static_method_call() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " class Foo: @staticmethod @@ -3612,19 +3616,19 @@ mod tests { 5 | Foo.bar(2) | info: Source - --> main.py:5:9 + --> main2.py:5:10 | 3 | @staticmethod 4 | def bar(y: int): pass - 5 | Foo.bar(2) - | ^ + 5 | Foo.bar([y=]2) + | ^ | "); } #[test] fn test_function_call_with_union_type() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(x: int | str): pass foo(1) @@ -3645,12 +3649,12 @@ mod tests { 4 | foo('abc') | info: Source - --> main.py:3:5 + --> main2.py:3:6 | 2 | def foo(x: int | str): pass - 3 | foo(1) - | ^ - 4 | foo('abc') + 3 | foo([x=]1) + | ^ + 4 | foo([x=]'abc') | info[inlay-hint-location]: Inlay Hint Target @@ -3662,19 +3666,19 @@ mod tests { 4 | foo('abc') | info: Source - --> main.py:4:5 + --> main2.py:4:6 | 2 | def foo(x: int | str): pass - 3 | foo(1) - 4 | foo('abc') - | ^ + 3 | foo([x=]1) + 4 | foo([x=]'abc') + | ^ | "); } #[test] fn test_function_call_multiple_positional_arguments() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(x: int, y: str, z: bool): pass foo(1, 'hello', True)", @@ -3692,11 +3696,11 @@ mod tests { 3 | foo(1, 'hello', True) | info: Source - --> main.py:3:5 + --> main2.py:3:6 | 2 | def foo(x: int, y: str, z: bool): pass - 3 | foo(1, 'hello', True) - | ^ + 3 | foo([x=]1, [y=]'hello', [z=]True) + | ^ | info[inlay-hint-location]: Inlay Hint Target @@ -3707,11 +3711,11 @@ mod tests { 3 | foo(1, 'hello', True) | info: Source - --> main.py:3:8 + --> main2.py:3:13 | 2 | def foo(x: int, y: str, z: bool): pass - 3 | foo(1, 'hello', True) - | ^ + 3 | foo([x=]1, [y=]'hello', [z=]True) + | ^ | info[inlay-hint-location]: Inlay Hint Target @@ -3722,18 +3726,18 @@ mod tests { 3 | foo(1, 'hello', True) | info: Source - --> main.py:3:17 + --> main2.py:3:26 | 2 | def foo(x: int, y: str, z: bool): pass - 3 | foo(1, 'hello', True) - | ^ + 3 | foo([x=]1, [y=]'hello', [z=]True) + | ^ | "); } #[test] fn test_function_call_mixed_positional_and_keyword() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(x: int, y: str, z: bool): pass foo(1, z=True, y='hello')", @@ -3751,18 +3755,18 @@ mod tests { 3 | foo(1, z=True, y='hello') | info: Source - --> main.py:3:5 + --> main2.py:3:6 | 2 | def foo(x: int, y: str, z: bool): pass - 3 | foo(1, z=True, y='hello') - | ^ + 3 | foo([x=]1, z=True, y='hello') + | ^ | "); } #[test] fn test_function_call_with_default_parameters() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(x: int, y: str = 'default', z: bool = False): pass foo(1) @@ -3785,13 +3789,13 @@ mod tests { 4 | foo(1, 'custom') | info: Source - --> main.py:3:5 + --> main2.py:3:6 | 2 | def foo(x: int, y: str = 'default', z: bool = False): pass - 3 | foo(1) - | ^ - 4 | foo(1, 'custom') - 5 | foo(1, 'custom', True) + 3 | foo([x=]1) + | ^ + 4 | foo([x=]1, [y=]'custom') + 5 | foo([x=]1, [y=]'custom', [z=]True) | info[inlay-hint-location]: Inlay Hint Target @@ -3803,13 +3807,13 @@ mod tests { 4 | foo(1, 'custom') | info: Source - --> main.py:4:5 + --> main2.py:4:6 | 2 | def foo(x: int, y: str = 'default', z: bool = False): pass - 3 | foo(1) - 4 | foo(1, 'custom') - | ^ - 5 | foo(1, 'custom', True) + 3 | foo([x=]1) + 4 | foo([x=]1, [y=]'custom') + | ^ + 5 | foo([x=]1, [y=]'custom', [z=]True) | info[inlay-hint-location]: Inlay Hint Target @@ -3821,13 +3825,13 @@ mod tests { 4 | foo(1, 'custom') | info: Source - --> main.py:4:8 + --> main2.py:4:13 | 2 | def foo(x: int, y: str = 'default', z: bool = False): pass - 3 | foo(1) - 4 | foo(1, 'custom') - | ^ - 5 | foo(1, 'custom', True) + 3 | foo([x=]1) + 4 | foo([x=]1, [y=]'custom') + | ^ + 5 | foo([x=]1, [y=]'custom', [z=]True) | info[inlay-hint-location]: Inlay Hint Target @@ -3839,12 +3843,12 @@ mod tests { 4 | foo(1, 'custom') | info: Source - --> main.py:5:5 + --> main2.py:5:6 | - 3 | foo(1) - 4 | foo(1, 'custom') - 5 | foo(1, 'custom', True) - | ^ + 3 | foo([x=]1) + 4 | foo([x=]1, [y=]'custom') + 5 | foo([x=]1, [y=]'custom', [z=]True) + | ^ | info[inlay-hint-location]: Inlay Hint Target @@ -3856,12 +3860,12 @@ mod tests { 4 | foo(1, 'custom') | info: Source - --> main.py:5:8 + --> main2.py:5:13 | - 3 | foo(1) - 4 | foo(1, 'custom') - 5 | foo(1, 'custom', True) - | ^ + 3 | foo([x=]1) + 4 | foo([x=]1, [y=]'custom') + 5 | foo([x=]1, [y=]'custom', [z=]True) + | ^ | info[inlay-hint-location]: Inlay Hint Target @@ -3873,19 +3877,19 @@ mod tests { 4 | foo(1, 'custom') | info: Source - --> main.py:5:18 + --> main2.py:5:27 | - 3 | foo(1) - 4 | foo(1, 'custom') - 5 | foo(1, 'custom', True) - | ^ + 3 | foo([x=]1) + 4 | foo([x=]1, [y=]'custom') + 5 | foo([x=]1, [y=]'custom', [z=]True) + | ^ | "); } #[test] fn test_nested_function_calls() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(x: int) -> int: return x * 2 @@ -3920,12 +3924,12 @@ mod tests { 10 | baz(foo(5), bar(bar('test')), True) | info: Source - --> main.py:10:5 + --> main2.py:10:6 | 8 | def baz(a: int, b: str, c: bool): pass 9 | - 10 | baz(foo(5), bar(bar('test')), True) - | ^ + 10 | baz([a=]foo([x=]5), [b=]bar([y=]bar([y=]'test')), [c=]True) + | ^ | info[inlay-hint-location]: Inlay Hint Target @@ -3936,12 +3940,12 @@ mod tests { 3 | return x * 2 | info: Source - --> main.py:10:9 + --> main2.py:10:14 | 8 | def baz(a: int, b: str, c: bool): pass 9 | - 10 | baz(foo(5), bar(bar('test')), True) - | ^ + 10 | baz([a=]foo([x=]5), [b=]bar([y=]bar([y=]'test')), [c=]True) + | ^ | info[inlay-hint-location]: Inlay Hint Target @@ -3955,12 +3959,12 @@ mod tests { 10 | baz(foo(5), bar(bar('test')), True) | info: Source - --> main.py:10:13 + --> main2.py:10:22 | 8 | def baz(a: int, b: str, c: bool): pass 9 | - 10 | baz(foo(5), bar(bar('test')), True) - | ^ + 10 | baz([a=]foo([x=]5), [b=]bar([y=]bar([y=]'test')), [c=]True) + | ^ | info[inlay-hint-location]: Inlay Hint Target @@ -3973,12 +3977,12 @@ mod tests { 6 | return y | info: Source - --> main.py:10:17 + --> main2.py:10:30 | 8 | def baz(a: int, b: str, c: bool): pass 9 | - 10 | baz(foo(5), bar(bar('test')), True) - | ^ + 10 | baz([a=]foo([x=]5), [b=]bar([y=]bar([y=]'test')), [c=]True) + | ^ | info[inlay-hint-location]: Inlay Hint Target @@ -3991,12 +3995,12 @@ mod tests { 6 | return y | info: Source - --> main.py:10:21 + --> main2.py:10:38 | 8 | def baz(a: int, b: str, c: bool): pass 9 | - 10 | baz(foo(5), bar(bar('test')), True) - | ^ + 10 | baz([a=]foo([x=]5), [b=]bar([y=]bar([y=]'test')), [c=]True) + | ^ | info[inlay-hint-location]: Inlay Hint Target @@ -4010,19 +4014,19 @@ mod tests { 10 | baz(foo(5), bar(bar('test')), True) | info: Source - --> main.py:10:31 + --> main2.py:10:52 | 8 | def baz(a: int, b: str, c: bool): pass 9 | - 10 | baz(foo(5), bar(bar('test')), True) - | ^ + 10 | baz([a=]foo([x=]5), [b=]bar([y=]bar([y=]'test')), [c=]True) + | ^ | "); } #[test] fn test_method_chaining() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " class A: def foo(self, value: int) -> 'A': @@ -4052,12 +4056,12 @@ mod tests { 5 | def bar(self, name: str) -> 'A': | info: Source - --> main.py:8:9 + --> main2.py:8:10 | 6 | return self 7 | def baz(self): pass - 8 | A().foo(42).bar('test').baz() - | ^ + 8 | A().foo([value=]42).bar([name=]'test').baz() + | ^^^^^ | info[inlay-hint-location]: Inlay Hint Target @@ -4071,19 +4075,19 @@ mod tests { 7 | def baz(self): pass | info: Source - --> main.py:8:17 + --> main2.py:8:26 | 6 | return self 7 | def baz(self): pass - 8 | A().foo(42).bar('test').baz() - | ^ + 8 | A().foo([value=]42).bar([name=]'test').baz() + | ^^^^ | "); } #[test] fn test_nexted_keyword_function_calls() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(x: str) -> str: return x @@ -4108,19 +4112,19 @@ mod tests { 4 | def bar(y: int): pass | info: Source - --> main.py:5:11 + --> main2.py:5:12 | 3 | return x 4 | def bar(y: int): pass - 5 | bar(y=foo('test')) - | ^ + 5 | bar(y=foo([x=]'test')) + | ^ | "); } #[test] fn test_lambda_function_calls() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " foo = lambda x: x * 2 bar = lambda a, b: a + b @@ -4138,7 +4142,7 @@ mod tests { #[test] fn test_complex_parameter_combinations() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(a: int, b: str, /, c: float, d: bool = True, *, e: int, f: str = 'default'): pass foo(1, 'pos', 3.14, False, e=42) @@ -4159,12 +4163,12 @@ mod tests { 4 | foo(1, 'pos', 3.14, e=42, f='custom') | info: Source - --> main.py:3:15 + --> main2.py:3:16 | 2 | def foo(a: int, b: str, /, c: float, d: bool = True, *, e: int, f: str = 'default'): pass - 3 | foo(1, 'pos', 3.14, False, e=42) - | ^ - 4 | foo(1, 'pos', 3.14, e=42, f='custom') + 3 | foo(1, 'pos', [c=]3.14, [d=]False, e=42) + | ^ + 4 | foo(1, 'pos', [c=]3.14, e=42, f='custom') | info[inlay-hint-location]: Inlay Hint Target @@ -4176,12 +4180,12 @@ mod tests { 4 | foo(1, 'pos', 3.14, e=42, f='custom') | info: Source - --> main.py:3:21 + --> main2.py:3:26 | 2 | def foo(a: int, b: str, /, c: float, d: bool = True, *, e: int, f: str = 'default'): pass - 3 | foo(1, 'pos', 3.14, False, e=42) - | ^ - 4 | foo(1, 'pos', 3.14, e=42, f='custom') + 3 | foo(1, 'pos', [c=]3.14, [d=]False, e=42) + | ^ + 4 | foo(1, 'pos', [c=]3.14, e=42, f='custom') | info[inlay-hint-location]: Inlay Hint Target @@ -4193,12 +4197,12 @@ mod tests { 4 | foo(1, 'pos', 3.14, e=42, f='custom') | info: Source - --> main.py:4:15 + --> main2.py:4:16 | 2 | def foo(a: int, b: str, /, c: float, d: bool = True, *, e: int, f: str = 'default'): pass - 3 | foo(1, 'pos', 3.14, False, e=42) - 4 | foo(1, 'pos', 3.14, e=42, f='custom') - | ^ + 3 | foo(1, 'pos', [c=]3.14, [d=]False, e=42) + 4 | foo(1, 'pos', [c=]3.14, e=42, f='custom') + | ^ | "); } @@ -4232,19 +4236,19 @@ mod tests { 3 | pass | info: Source - --> main.py:4:5 + --> main2.py:4:6 | 2 | from foo import bar 3 | - 4 | bar(1) - | ^ + 4 | bar([x=]1) + | ^ | "); } #[test] fn test_overloaded_function_calls() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " from typing import overload @@ -4282,13 +4286,13 @@ mod tests { 7 | def foo(x: str) -> int: ... | info: Source - --> main.py:11:5 + --> main2.py:11:6 | 9 | return x 10 | - 11 | foo(42) - | ^ - 12 | foo('hello') + 11 | foo([x=]42) + | ^ + 12 | foo([x=]'hello') | info[inlay-hint-location]: Inlay Hint Target @@ -4301,18 +4305,18 @@ mod tests { 7 | def foo(x: str) -> int: ... | info: Source - --> main.py:12:5 + --> main2.py:12:6 | - 11 | foo(42) - 12 | foo('hello') - | ^ + 11 | foo([x=]42) + 12 | foo([x=]'hello') + | ^ | "); } #[test] fn test_disabled_function_argument_names() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(x: int): pass foo(1)", @@ -4329,7 +4333,7 @@ mod tests { #[test] fn test_function_call_out_of_range() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(x: int): pass def bar(y: int): pass @@ -4352,12 +4356,12 @@ mod tests { 4 | foo(1) | info: Source - --> main.py:4:5 + --> main2.py:4:6 | 2 | def foo(x: int): pass 3 | def bar(y: int): pass - 4 | foo(1) - | ^ + 4 | foo([x=]1) + | ^ 5 | bar(2) | "); @@ -4365,7 +4369,7 @@ mod tests { #[test] fn test_function_call_with_argument_name_starting_with_underscore() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo(_x: int, y: int): pass foo(1, 2)", @@ -4383,18 +4387,18 @@ mod tests { 3 | foo(1, 2) | info: Source - --> main.py:3:8 + --> main2.py:3:9 | 2 | def foo(_x: int, y: int): pass - 3 | foo(1, 2) - | ^ + 3 | foo(1, [y=]2) + | ^ | "); } #[test] fn test_function_call_different_formatting() { - let test = inlay_hint_test( + let mut test = inlay_hint_test( " def foo( x: int, @@ -4422,12 +4426,12 @@ mod tests { 5 | ): ... | info: Source - --> main.py:7:5 + --> main2.py:7:6 | 5 | ): ... 6 | - 7 | foo(1, 2) - | ^ + 7 | foo([x=]1, [y=]2) + | ^ | info[inlay-hint-location]: Inlay Hint Target @@ -4440,12 +4444,12 @@ mod tests { 5 | ): ... | info: Source - --> main.py:7:8 + --> main2.py:7:13 | 5 | ): ... 6 | - 7 | foo(1, 2) - | ^ + 7 | foo([x=]1, [y=]2) + | ^ | "); } From e4695a24176938031598db52a550a0685daa804e Mon Sep 17 00:00:00 2001 From: Aria Desires Date: Thu, 20 Nov 2025 09:08:22 -0500 Subject: [PATCH 7/8] proper typeshed filter --- .../ty_python_semantic/src/types/display.rs | 198 ++++++++++-------- crates/ty_server/tests/e2e/inlay_hints.rs | 2 +- crates/ty_server/tests/e2e/main.rs | 2 +- 3 files changed, 117 insertions(+), 85 deletions(-) diff --git a/crates/ty_python_semantic/src/types/display.rs b/crates/ty_python_semantic/src/types/display.rs index 4d0e16434a119b..c3bb7fa5105afd 100644 --- a/crates/ty_python_semantic/src/types/display.rs +++ b/crates/ty_python_semantic/src/types/display.rs @@ -11,7 +11,7 @@ use ruff_db::files::FilePath; use ruff_db::source::line_index; use ruff_python_ast::str::{Quote, TripleQuotes}; use ruff_python_literal::escape::AsciiEscape; -use ruff_text_size::{TextRange, TextSize}; +use ruff_text_size::{TextLen, TextRange, TextSize}; use rustc_hash::{FxHashMap, FxHashSet}; use crate::Db; @@ -182,7 +182,7 @@ impl<'a, 'b, 'db> TypeWriter<'a, 'b, 'db> { fn with_detail<'c>(&'c mut self, detail: TypeDetail<'db>) -> TypeDetailGuard<'a, 'b, 'c, 'db> { let start = match self { TypeWriter::Formatter(_) => None, - TypeWriter::Details(details) => Some(details.label.len()), + TypeWriter::Details(details) => Some(details.label.text_len()), }; TypeDetailGuard { start, @@ -190,7 +190,17 @@ impl<'a, 'b, 'db> TypeWriter<'a, 'b, 'db> { payload: Some(detail), } } + + fn join<'c>(&'c mut self, separator: &'static str) -> Join<'a, 'b, 'c, 'db> { + Join { + fmt: self, + separator, + result: Ok(()), + seen_first: false, + } + } } + impl std::fmt::Write for TypeWriter<'_, '_, '_> { fn write_str(&mut self, val: &str) -> fmt::Result { match self { @@ -205,6 +215,46 @@ impl std::fmt::Write for TypeDetailsWriter<'_> { } } +trait FmtDetailed<'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result; +} + +struct Join<'a, 'b, 'c, 'db> { + fmt: &'c mut TypeWriter<'a, 'b, 'db>, + separator: &'static str, + result: fmt::Result, + seen_first: bool, +} + +impl<'db> Join<'_, '_, '_, 'db> { + fn entry(&mut self, item: &dyn FmtDetailed<'db>) -> &mut Self { + if self.seen_first { + self.result = self + .result + .and_then(|()| self.fmt.write_str(self.separator)); + } else { + self.seen_first = true; + } + self.result = self.result.and_then(|()| item.fmt_detailed(self.fmt)); + self + } + + fn entries(&mut self, items: I) -> &mut Self + where + I: IntoIterator, + F: FmtDetailed<'db>, + { + for item in items { + self.entry(&item); + } + self + } + + fn finish(&mut self) -> fmt::Result { + self.result + } +} + pub enum TypeDetail<'db> { /// Dummy item to indicate a function signature's parameters have started SignatureStart, @@ -224,7 +274,7 @@ pub enum TypeDetail<'db> { /// something like `&'db self`, which, while convenient, and sometimes works, is imprecise. struct TypeDetailGuard<'a, 'b, 'c, 'db> { inner: &'c mut TypeWriter<'a, 'b, 'db>, - start: Option, + start: Option, payload: Option>, } @@ -233,13 +283,10 @@ impl Drop for TypeDetailGuard<'_, '_, '_, '_> { // The fallibility here is primarily retrieving `TypeWriter::Details` // everything else is ideally-never-fails pedantry (yay for pedantry!) if let TypeWriter::Details(details) = &mut self.inner - && let Ok(end) = u32::try_from(details.label.len()) && let Some(start) = self.start - && let Ok(start) = u32::try_from(start) - && let Some(len) = end.checked_sub(start) && let Some(payload) = self.payload.take() { - let target = TextRange::at(TextSize::new(start), TextSize::new(len)); + let target = TextRange::new(start, details.label.text_len()); details.targets.push(target); details.details.push(payload); } @@ -412,7 +459,9 @@ impl<'db> DisplayType<'db> { TypeWriter::Formatter(_) => unreachable!("Expected Details variant"), } } +} +impl<'db> FmtDetailed<'db> for DisplayType<'db> { fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { let representation = self.ty.representation(self.db, self.settings.clone()); match self.ty { @@ -504,7 +553,7 @@ struct ClassDisplay<'db> { settings: DisplaySettings<'db>, } -impl<'db> ClassDisplay<'db> { +impl<'db> FmtDetailed<'db> for ClassDisplay<'db> { fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { let qualification_level = self.settings.qualified.get(&**self.class.name(self.db)); if qualification_level.is_some() { @@ -556,7 +605,7 @@ impl Display for DisplayRepresentation<'_> { } } -impl<'db> DisplayRepresentation<'db> { +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, "{dynamic}"), @@ -678,17 +727,15 @@ impl<'db> DisplayRepresentation<'db> { f.write_str("Overload[")?; } let separator = if self.settings.multiline { "\n" } else { ", " }; - let mut is_first = true; + let mut join = f.join(separator); for signature in signatures { - if !is_first { - f.write_str(separator)?; - } - is_first = false; - signature - .bind_self(self.db, Some(typing_self_ty)) - .display_with(self.db, self.settings.clone()) - .fmt_detailed(f)?; + join.entry( + &signature + .bind_self(self.db, Some(typing_self_ty)) + .display_with(self.db, self.settings.clone()), + ); } + join.finish()?; if !self.settings.multiline { f.write_str("]")?; } @@ -875,7 +922,7 @@ pub(crate) struct DisplayTuple<'a, 'db> { settings: DisplaySettings<'db>, } -impl<'db> DisplayTuple<'_, 'db> { +impl<'db> FmtDetailed<'db> for DisplayTuple<'_, 'db> { fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { f.write_str("tuple[")?; match self.tuple { @@ -968,7 +1015,7 @@ pub(crate) struct DisplayOverloadLiteral<'db> { settings: DisplaySettings<'db>, } -impl<'db> DisplayOverloadLiteral<'db> { +impl<'db> FmtDetailed<'db> for DisplayOverloadLiteral<'db> { fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { let signature = self.literal.signature(self.db); let type_parameters = DisplayOptionalGenericContext { @@ -1012,7 +1059,7 @@ pub(crate) struct DisplayFunctionType<'db> { settings: DisplaySettings<'db>, } -impl<'db> DisplayFunctionType<'db> { +impl<'db> FmtDetailed<'db> for DisplayFunctionType<'db> { fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { let signature = self.ty.signature(self.db); @@ -1037,16 +1084,11 @@ impl<'db> DisplayFunctionType<'db> { f.write_str("Overload[")?; } let separator = if self.settings.multiline { "\n" } else { ", " }; - let mut is_first = true; + let mut join = f.join(separator); for signature in signatures { - if !is_first { - f.write_str(separator)?; - } - is_first = false; - signature - .display_with(self.db, self.settings.clone()) - .fmt_detailed(f)?; + join.entry(&signature.display_with(self.db, self.settings.clone())); } + join.finish()?; if !self.settings.multiline { f.write_str("]")?; } @@ -1088,7 +1130,7 @@ pub(crate) struct DisplayGenericAlias<'db> { settings: DisplaySettings<'db>, } -impl<'db> DisplayGenericAlias<'db> { +impl<'db> FmtDetailed<'db> for DisplayGenericAlias<'db> { fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { if let Some(tuple) = self.specialization.tuple(self.db) { tuple @@ -1160,7 +1202,7 @@ struct DisplayOptionalGenericContext<'a, 'db> { settings: DisplaySettings<'db>, } -impl<'db> DisplayOptionalGenericContext<'_, 'db> { +impl<'db> FmtDetailed<'db> for DisplayOptionalGenericContext<'_, 'db> { fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { if let Some(generic_context) = self.generic_context { generic_context @@ -1187,14 +1229,6 @@ pub struct DisplayGenericContext<'a, 'db> { } impl<'db> DisplayGenericContext<'_, 'db> { - fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { - if self.full { - self.fmt_full(f) - } else { - self.fmt_normal(f) - } - } - fn fmt_normal(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { let variables = self.generic_context.variables(self.db); @@ -1229,6 +1263,16 @@ impl<'db> DisplayGenericContext<'_, 'db> { } } +impl<'db> FmtDetailed<'db> for DisplayGenericContext<'_, 'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { + if self.full { + self.fmt_full(f) + } else { + self.fmt_normal(f) + } + } +} + impl Display for DisplayGenericContext<'_, '_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_detailed(&mut TypeWriter::Formatter(f)) @@ -1276,14 +1320,6 @@ pub struct DisplaySpecialization<'db> { } impl<'db> DisplaySpecialization<'db> { - fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { - if self.full { - self.fmt_full(f) - } else { - self.fmt_normal(f) - } - } - fn fmt_normal(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { f.write_char('[')?; let types = self.specialization.types(self.db); @@ -1320,6 +1356,16 @@ impl<'db> DisplaySpecialization<'db> { } } +impl<'db> FmtDetailed<'db> for DisplaySpecialization<'db> { + fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { + if self.full { + self.fmt_full(f) + } else { + self.fmt_normal(f) + } + } +} + impl Display for DisplaySpecialization<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_detailed(&mut TypeWriter::Formatter(f)) @@ -1370,7 +1416,7 @@ pub(crate) struct DisplayCallableType<'a, 'db> { settings: DisplaySettings<'db>, } -impl<'db> DisplayCallableType<'_, 'db> { +impl<'db> FmtDetailed<'db> for DisplayCallableType<'_, 'db> { fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { match self.signatures.overloads.as_slice() { [signature] => signature @@ -1382,16 +1428,11 @@ impl<'db> DisplayCallableType<'_, 'db> { f.write_str("Overload[")?; } let separator = if self.settings.multiline { "\n" } else { ", " }; - let mut is_first = true; + let mut join = f.join(separator); for signature in signatures { - if !is_first { - f.write_str(separator)?; - } - is_first = false; - signature - .display_with(self.db, self.settings.clone()) - .fmt_detailed(f)?; + join.entry(&signature.display_with(self.db, self.settings.clone())); } + join.finish()?; if !self.settings.multiline { f.write_char(']')?; } @@ -1433,7 +1474,7 @@ pub(crate) struct DisplaySignature<'a, 'db> { settings: DisplaySettings<'db>, } -impl<'db> DisplaySignature<'_, 'db> { +impl DisplaySignature<'_, '_> { /// Get detailed display information including component ranges pub(crate) fn to_string_parts(&self) -> SignatureDisplayDetails { let mut f = TypeWriter::Details(TypeDetailsWriter::new()); @@ -1444,7 +1485,9 @@ impl<'db> DisplaySignature<'_, 'db> { TypeWriter::Formatter(_) => unreachable!("Expected Details variant"), } } +} +impl<'db> FmtDetailed<'db> for DisplaySignature<'_, 'db> { fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { // Immediately write a marker signaling we're starting a signature let _ = f.with_detail(TypeDetail::SignatureStart); @@ -1564,7 +1607,7 @@ struct DisplayParameter<'a, 'db> { settings: DisplaySettings<'db>, } -impl<'db> DisplayParameter<'_, 'db> { +impl<'db> FmtDetailed<'db> for DisplayParameter<'_, 'db> { fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { if let Some(name) = self.param.display_name() { f.write_str(&name)?; @@ -1666,7 +1709,7 @@ const UNION_POLICY: TruncationPolicy = TruncationPolicy { max_when_elided: 3, }; -impl<'db> DisplayUnionType<'_, 'db> { +impl<'db> FmtDetailed<'db> for DisplayUnionType<'_, 'db> { fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { fn is_condensable(ty: Type<'_>) -> bool { matches!( @@ -1692,6 +1735,7 @@ impl<'db> DisplayUnionType<'_, 'db> { assert_ne!(total_entries, 0); + // Done manually because we have a mix of FmtDetailed and Display let mut is_first = true; let mut write_join = |f: &mut TypeWriter<'_, '_, 'db>| { if !is_first { @@ -1832,7 +1876,7 @@ struct DisplayIntersectionType<'a, 'db> { settings: DisplaySettings<'db>, } -impl<'db> DisplayIntersectionType<'_, 'db> { +impl<'db> FmtDetailed<'db> for DisplayIntersectionType<'_, 'db> { fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { let tys = self .ty @@ -1856,15 +1900,7 @@ impl<'db> DisplayIntersectionType<'_, 'db> { }), ); - let mut first = true; - for ty in tys { - if !first { - f.write_str(" & ")?; - } - first = false; - ty.fmt_detailed(f)?; - } - Ok(()) + f.join(" & ").entries(tys).finish() } } @@ -1887,7 +1923,7 @@ struct DisplayMaybeNegatedType<'db> { settings: DisplaySettings<'db>, } -impl<'db> DisplayMaybeNegatedType<'db> { +impl<'db> FmtDetailed<'db> for DisplayMaybeNegatedType<'db> { fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { if self.negated { f.write_str("~")?; @@ -1913,7 +1949,7 @@ struct DisplayMaybeParenthesizedType<'db> { settings: DisplaySettings<'db>, } -impl<'db> DisplayMaybeParenthesizedType<'db> { +impl<'db> FmtDetailed<'db> for DisplayMaybeParenthesizedType<'db> { fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { let write_parentheses = |f: &mut TypeWriter<'_, '_, 'db>| { f.write_char('(')?; @@ -2001,19 +2037,15 @@ pub(crate) struct DisplayTypeArray<'b, 'db> { settings: DisplaySettings<'db>, } -impl<'db> DisplayTypeArray<'_, 'db> { +impl<'db> FmtDetailed<'db> for DisplayTypeArray<'_, 'db> { fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result { - let mut is_first = true; - for ty in self.types { - if !is_first { - f.write_str(", ")?; - } - is_first = false; - - ty.display_with(self.db, self.settings.singleline()) - .fmt_detailed(f)?; - } - Ok(()) + f.join(", ") + .entries( + self.types + .iter() + .map(|ty| ty.display_with(self.db, self.settings.singleline())), + ) + .finish() } } diff --git a/crates/ty_server/tests/e2e/inlay_hints.rs b/crates/ty_server/tests/e2e/inlay_hints.rs index 8e16ce0c4e609c..3ee77ed7e4fb6d 100644 --- a/crates/ty_server/tests/e2e/inlay_hints.rs +++ b/crates/ty_server/tests/e2e/inlay_hints.rs @@ -49,7 +49,7 @@ y = foo(1) { "value": "int", "location": { - "uri": "file://ty/vendored/typeshed/f8cdc0bd526301e873cd952eb0d457bdf2554e57/stdlib/builtins.pyi", + "uri": "file:///stdlib/builtins.pyi", "range": { "start": { "line": 347, diff --git a/crates/ty_server/tests/e2e/main.rs b/crates/ty_server/tests/e2e/main.rs index a0066acf427ef8..086d24dcc59276 100644 --- a/crates/ty_server/tests/e2e/main.rs +++ b/crates/ty_server/tests/e2e/main.rs @@ -1198,7 +1198,7 @@ impl TestContext { r#"The system cannot find the file specified."#, "No such file or directory", ); - settings.add_filter(r"file://[^\s]*/\.cache/", "file://"); + settings.add_filter(r"file://.*/stdlib/", "file:///stdlib/"); let settings_scope = settings.bind_to_scope(); From 6bbea1aad73c7d83b49fc361f7f48fd86816a06b Mon Sep 17 00:00:00 2001 From: Aria Desires Date: Thu, 20 Nov 2025 09:31:43 -0500 Subject: [PATCH 8/8] help --- crates/ty_ide/src/inlay_hints.rs | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/crates/ty_ide/src/inlay_hints.rs b/crates/ty_ide/src/inlay_hints.rs index 241d705c66bd82..15201b032ae482 100644 --- a/crates/ty_ide/src/inlay_hints.rs +++ b/crates/ty_ide/src/inlay_hints.rs @@ -570,7 +570,10 @@ mod tests { write!(buf, "{}", diag.display(&self.db, &config)).unwrap(); } - buf + // Windows path normalization for typeshed references + // "hey why is \x08 getting clobbered to /x08?" + // no it's not I don't know what you're talking about + buf.replace('\\', "/") } } @@ -1673,7 +1676,7 @@ mod tests { 8 | g[: list[Unknown | str]] = [f"{ft}", f"{ft}"] | ^^^^ 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] - 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 10 | i[: list[Unknown | bytes]] = [b'/x01', b'/x02'] | info[inlay-hint-location]: Inlay Hint Target @@ -1693,7 +1696,7 @@ mod tests { 8 | g[: list[Unknown | str]] = [f"{ft}", f"{ft}"] | ^^^ 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] - 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 10 | i[: list[Unknown | bytes]] = [b'/x01', b'/x02'] | info[inlay-hint-location]: Inlay Hint Target @@ -1711,7 +1714,7 @@ mod tests { 8 | g[: list[Unknown | str]] = [f"{ft}", f"{ft}"] 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] | ^^^^ - 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 10 | i[: list[Unknown | bytes]] = [b'/x01', b'/x02'] 11 | j[: list[Unknown | int | float]] = [+1, +2.0] | @@ -1730,7 +1733,7 @@ mod tests { 8 | g[: list[Unknown | str]] = [f"{ft}", f"{ft}"] 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] | ^^^^^^^^ - 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 10 | i[: list[Unknown | bytes]] = [b'/x01', b'/x02'] 11 | j[: list[Unknown | int | float]] = [+1, +2.0] | @@ -1747,7 +1750,7 @@ mod tests { | 8 | g[: list[Unknown | str]] = [f"{ft}", f"{ft}"] 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] - 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 10 | i[: list[Unknown | bytes]] = [b'/x01', b'/x02'] | ^^^^ 11 | j[: list[Unknown | int | float]] = [+1, +2.0] 12 | k[: list[Unknown | int | float]] = [-1, -2.0] @@ -1767,7 +1770,7 @@ mod tests { | 8 | g[: list[Unknown | str]] = [f"{ft}", f"{ft}"] 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] - 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 10 | i[: list[Unknown | bytes]] = [b'/x01', b'/x02'] | ^^^^^ 11 | j[: list[Unknown | int | float]] = [+1, +2.0] 12 | k[: list[Unknown | int | float]] = [-1, -2.0] @@ -1785,7 +1788,7 @@ mod tests { --> main2.py:11:5 | 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] - 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 10 | i[: list[Unknown | bytes]] = [b'/x01', b'/x02'] 11 | j[: list[Unknown | int | float]] = [+1, +2.0] | ^^^^ 12 | k[: list[Unknown | int | float]] = [-1, -2.0] @@ -1804,7 +1807,7 @@ mod tests { --> main2.py:11:20 | 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] - 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 10 | i[: list[Unknown | bytes]] = [b'/x01', b'/x02'] 11 | j[: list[Unknown | int | float]] = [+1, +2.0] | ^^^ 12 | k[: list[Unknown | int | float]] = [-1, -2.0] @@ -1822,7 +1825,7 @@ mod tests { --> main2.py:11:26 | 9 | h[: list[Unknown | Template]] = [t"wow %d", t"wow %d"] - 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 10 | i[: list[Unknown | bytes]] = [b'/x01', b'/x02'] 11 | j[: list[Unknown | int | float]] = [+1, +2.0] | ^^^^^ 12 | k[: list[Unknown | int | float]] = [-1, -2.0] @@ -1839,7 +1842,7 @@ mod tests { info: Source --> main2.py:12:5 | - 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 10 | i[: list[Unknown | bytes]] = [b'/x01', b'/x02'] 11 | j[: list[Unknown | int | float]] = [+1, +2.0] 12 | k[: list[Unknown | int | float]] = [-1, -2.0] | ^^^^ @@ -1857,7 +1860,7 @@ mod tests { info: Source --> main2.py:12:20 | - 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 10 | i[: list[Unknown | bytes]] = [b'/x01', b'/x02'] 11 | j[: list[Unknown | int | float]] = [+1, +2.0] 12 | k[: list[Unknown | int | float]] = [-1, -2.0] | ^^^ @@ -1874,7 +1877,7 @@ mod tests { info: Source --> main2.py:12:26 | - 10 | i[: list[Unknown | bytes]] = [b'\x01', b'\x02'] + 10 | i[: list[Unknown | bytes]] = [b'/x01', b'/x02'] 11 | j[: list[Unknown | int | float]] = [+1, +2.0] 12 | k[: list[Unknown | int | float]] = [-1, -2.0] | ^^^^^