diff options
| author | Chayim Refael Friedman <chayimfr@gmail.com> | 2025-03-08 20:38:47 +0200 |
|---|---|---|
| committer | Chayim Refael Friedman <chayimfr@gmail.com> | 2025-03-12 23:34:16 +0200 |
| commit | f335d00263fd429d12fd844134df54657357de56 (patch) | |
| tree | f0a6868055073d9a8c4940a198ab3f61567a8771 /src | |
| parent | 8148fa9324c274ae4be0e8f62a2d42adb8a371ff (diff) | |
| download | rust-f335d00263fd429d12fd844134df54657357de56.tar.gz rust-f335d00263fd429d12fd844134df54657357de56.zip | |
Lower Return Type Notation (`Type::method(..): Send`)
We do it the way rustc does it, by only marking segments with it, and not the whole path. This will allow extending where it is allowed in the future.
Diffstat (limited to 'src')
5 files changed, 125 insertions, 80 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs index 6f1650adeb6..682f21ab3b4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs @@ -872,7 +872,7 @@ fn copy_generic_args( args, has_self_type: generic_args.has_self_type, bindings, - desugared_from_fn: generic_args.desugared_from_fn, + parenthesized: generic_args.parenthesized, } }) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs index 713e7389736..8f170fb983a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs @@ -79,6 +79,19 @@ thin_vec_with_header_struct! { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum GenericArgsParentheses { + No, + /// Bounds of the form `Type::method(..): Send` or `impl Trait<method(..): Send>`, + /// aka. Return Type Notation or RTN. + ReturnTypeNotation, + /// `Fn`-family parenthesized traits, e.g. `impl Fn(u32) -> String`. + /// + /// This is desugared into one generic argument containing a tuple of all arguments, + /// and an associated type binding for `Output` for the return type. + ParenSugar, +} + /// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This /// also includes bindings of associated types, like in `Iterator<Item = Foo>`. #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -92,9 +105,8 @@ pub struct GenericArgs { pub has_self_type: bool, /// Associated type bindings like in `Iterator<Item = T>`. pub bindings: Box<[AssociatedTypeBinding]>, - /// Whether these generic args were desugared from `Trait(Arg) -> Output` - /// parenthesis notation typically used for the `Fn` traits. - pub desugared_from_fn: bool, + /// Whether these generic args were written with parentheses and how. + pub parenthesized: GenericArgsParentheses, } /// An associated type binding like in `Iterator<Item = T>`. @@ -326,7 +338,16 @@ impl GenericArgs { args: Box::default(), has_self_type: false, bindings: Box::default(), - desugared_from_fn: false, + parenthesized: GenericArgsParentheses::No, + } + } + + pub(crate) fn return_type_notation() -> GenericArgs { + GenericArgs { + args: Box::default(), + has_self_type: false, + bindings: Box::default(), + parenthesized: GenericArgsParentheses::ReturnTypeNotation, } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs index 7a6d6973298..c6ea3c4d710 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs @@ -13,7 +13,10 @@ use stdx::thin_vec::EmptyOptimizedThinVec; use syntax::ast::{self, AstNode, HasGenericArgs, HasTypeBounds}; use crate::{ - path::{AssociatedTypeBinding, GenericArg, GenericArgs, ModPath, Path, PathKind}, + path::{ + AssociatedTypeBinding, GenericArg, GenericArgs, GenericArgsParentheses, ModPath, Path, + PathKind, + }, type_ref::{LifetimeRef, TypeBound, TypeRef}, }; @@ -73,6 +76,9 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< segment.parenthesized_arg_list(), segment.ret_type(), ) + }) + .or_else(|| { + segment.return_type_syntax().map(|_| GenericArgs::return_type_notation()) }); if args.is_some() { generic_args.resize(segments.len(), None); @@ -126,7 +132,7 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< has_self_type: true, bindings: it.bindings.clone(), - desugared_from_fn: it.desugared_from_fn, + parenthesized: it.parenthesized, }, None => GenericArgs { args: Box::new([self_type]), @@ -281,7 +287,12 @@ pub(super) fn lower_generic_args( let name = name_ref.as_name(); let args = assoc_type_arg .generic_arg_list() - .and_then(|args| lower_generic_args(lower_ctx, args)); + .and_then(|args| lower_generic_args(lower_ctx, args)) + .or_else(|| { + assoc_type_arg + .return_type_syntax() + .map(|_| GenericArgs::return_type_notation()) + }); let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it)); let type_ref = type_ref @@ -315,7 +326,7 @@ pub(super) fn lower_generic_args( args: args.into_boxed_slice(), has_self_type: false, bindings: bindings.into_boxed_slice(), - desugared_from_fn: false, + parenthesized: GenericArgsParentheses::No, }) } @@ -353,5 +364,10 @@ fn lower_generic_args_from_fn_path( bounds: Box::default(), }]) }; - Some(GenericArgs { args, has_self_type: false, bindings, desugared_from_fn: true }) + Some(GenericArgs { + args, + has_self_type: false, + bindings, + parenthesized: GenericArgsParentheses::ParenSugar, + }) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 2ae7e746ba2..db305e98da4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -2303,77 +2303,82 @@ impl HirDisplayWithTypesMap for Path { if let Some(generic_args) = segment.args_and_bindings { // We should be in type context, so format as `Foo<Bar>` instead of `Foo::<Bar>`. // Do we actually format expressions? - if generic_args.desugared_from_fn { - // First argument will be a tuple, which already includes the parentheses. - // If the tuple only contains 1 item, write it manually to avoid the trailing `,`. - let tuple = match generic_args.args[0] { - hir_def::path::GenericArg::Type(ty) => match &types_map[ty] { - TypeRef::Tuple(it) => Some(it), + match generic_args.parenthesized { + hir_def::path::GenericArgsParentheses::ReturnTypeNotation => { + write!(f, "(..)")?; + } + hir_def::path::GenericArgsParentheses::ParenSugar => { + // First argument will be a tuple, which already includes the parentheses. + // If the tuple only contains 1 item, write it manually to avoid the trailing `,`. + let tuple = match generic_args.args[0] { + hir_def::path::GenericArg::Type(ty) => match &types_map[ty] { + TypeRef::Tuple(it) => Some(it), + _ => None, + }, _ => None, - }, - _ => None, - }; - if let Some(v) = tuple { - if v.len() == 1 { - write!(f, "(")?; - v[0].hir_fmt(f, types_map)?; - write!(f, ")")?; - } else { - generic_args.args[0].hir_fmt(f, types_map)?; + }; + if let Some(v) = tuple { + if v.len() == 1 { + write!(f, "(")?; + v[0].hir_fmt(f, types_map)?; + write!(f, ")")?; + } else { + generic_args.args[0].hir_fmt(f, types_map)?; + } } - } - if let Some(ret) = generic_args.bindings[0].type_ref { - if !matches!(&types_map[ret], TypeRef::Tuple(v) if v.is_empty()) { - write!(f, " -> ")?; - ret.hir_fmt(f, types_map)?; + if let Some(ret) = generic_args.bindings[0].type_ref { + if !matches!(&types_map[ret], TypeRef::Tuple(v) if v.is_empty()) { + write!(f, " -> ")?; + ret.hir_fmt(f, types_map)?; + } } } - return Ok(()); - } - - let mut first = true; - // Skip the `Self` bound if exists. It's handled outside the loop. - for arg in &generic_args.args[generic_args.has_self_type as usize..] { - if first { - first = false; - write!(f, "<")?; - } else { - write!(f, ", ")?; - } - arg.hir_fmt(f, types_map)?; - } - for binding in generic_args.bindings.iter() { - if first { - first = false; - write!(f, "<")?; - } else { - write!(f, ", ")?; - } - write!(f, "{}", binding.name.display(f.db.upcast(), f.edition()))?; - match &binding.type_ref { - Some(ty) => { - write!(f, " = ")?; - ty.hir_fmt(f, types_map)? + hir_def::path::GenericArgsParentheses::No => { + let mut first = true; + // Skip the `Self` bound if exists. It's handled outside the loop. + for arg in &generic_args.args[generic_args.has_self_type as usize..] { + if first { + first = false; + write!(f, "<")?; + } else { + write!(f, ", ")?; + } + arg.hir_fmt(f, types_map)?; } - None => { - write!(f, ": ")?; - f.write_joined( - binding.bounds.iter().map(TypesMapAdapter::wrap(types_map)), - " + ", - )?; + for binding in generic_args.bindings.iter() { + if first { + first = false; + write!(f, "<")?; + } else { + write!(f, ", ")?; + } + write!(f, "{}", binding.name.display(f.db.upcast(), f.edition()))?; + match &binding.type_ref { + Some(ty) => { + write!(f, " = ")?; + ty.hir_fmt(f, types_map)? + } + None => { + write!(f, ": ")?; + f.write_joined( + binding.bounds.iter().map(TypesMapAdapter::wrap(types_map)), + " + ", + )?; + } + } } - } - } - // There may be no generic arguments to print, in case of a trait having only a - // single `Self` bound which is converted to `<Ty as Trait>::Assoc`. - if !first { - write!(f, ">")?; - } + // There may be no generic arguments to print, in case of a trait having only a + // single `Self` bound which is converted to `<Ty as Trait>::Assoc`. + if !first { + write!(f, ">")?; + } - // Current position: `<Ty as Trait<Args>|` - if generic_args.has_self_type { - write!(f, ">")?; + // Current position: `<Ty as Trait<Args>|` + if generic_args.has_self_type { + write!(f, ">")?; + } + } } } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs index a165932ddcc..58b143e84e0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs @@ -8,7 +8,7 @@ use hir_def::{ data::TraitFlags, expr_store::HygieneId, generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget}, - path::{GenericArg, GenericArgs, Path, PathSegment, PathSegments}, + path::{GenericArg, GenericArgs, GenericArgsParentheses, Path, PathSegment, PathSegments}, resolver::{ResolveValueResult, TypeNs, ValueNs}, type_ref::{TypeBound, TypeRef, TypesMap}, GenericDefId, GenericParamId, ItemContainerId, Lookup, TraitId, @@ -138,12 +138,15 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { fn prohibit_parenthesized_generic_args(&mut self) -> bool { if let Some(generic_args) = self.current_or_prev_segment.args_and_bindings { - if generic_args.desugared_from_fn { - let segment = self.current_segment_u32(); - self.on_diagnostic( - PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment }, - ); - return true; + match generic_args.parenthesized { + GenericArgsParentheses::No => {} + GenericArgsParentheses::ReturnTypeNotation | GenericArgsParentheses::ParenSugar => { + let segment = self.current_segment_u32(); + self.on_diagnostic( + PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment }, + ); + return true; + } } } false |
