mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00
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.
This commit is contained in:
parent
3fc655b239
commit
eaa0a39831
@ -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,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
@ -2303,78 +2303,83 @@ 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)?;
|
||||
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)?;
|
||||
}
|
||||
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)),
|
||||
" + ",
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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)?
|
||||
// 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, ">")?;
|
||||
}
|
||||
None => {
|
||||
write!(f, ": ")?;
|
||||
f.write_joined(
|
||||
binding.bounds.iter().map(TypesMapAdapter::wrap(types_map)),
|
||||
" + ",
|
||||
)?;
|
||||
|
||||
// Current position: `<Ty as Trait<Args>|`
|
||||
if generic_args.has_self_type {
|
||||
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, ">")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user