about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/generics.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path.rs29
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs131
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs17
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