Skip to content

Commit eaa0a39

Browse files
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.
1 parent 3fc655b commit eaa0a39

File tree

5 files changed

+125
-80
lines changed

5 files changed

+125
-80
lines changed

crates/hir-def/src/generics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -872,7 +872,7 @@ fn copy_generic_args(
872872
args,
873873
has_self_type: generic_args.has_self_type,
874874
bindings,
875-
desugared_from_fn: generic_args.desugared_from_fn,
875+
parenthesized: generic_args.parenthesized,
876876
}
877877
})
878878
}

crates/hir-def/src/path.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,19 @@ thin_vec_with_header_struct! {
7979
}
8080
}
8181

82+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
83+
pub enum GenericArgsParentheses {
84+
No,
85+
/// Bounds of the form `Type::method(..): Send` or `impl Trait<method(..): Send>`,
86+
/// aka. Return Type Notation or RTN.
87+
ReturnTypeNotation,
88+
/// `Fn`-family parenthesized traits, e.g. `impl Fn(u32) -> String`.
89+
///
90+
/// This is desugared into one generic argument containing a tuple of all arguments,
91+
/// and an associated type binding for `Output` for the return type.
92+
ParenSugar,
93+
}
94+
8295
/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
8396
/// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
8497
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -92,9 +105,8 @@ pub struct GenericArgs {
92105
pub has_self_type: bool,
93106
/// Associated type bindings like in `Iterator<Item = T>`.
94107
pub bindings: Box<[AssociatedTypeBinding]>,
95-
/// Whether these generic args were desugared from `Trait(Arg) -> Output`
96-
/// parenthesis notation typically used for the `Fn` traits.
97-
pub desugared_from_fn: bool,
108+
/// Whether these generic args were written with parentheses and how.
109+
pub parenthesized: GenericArgsParentheses,
98110
}
99111

100112
/// An associated type binding like in `Iterator<Item = T>`.
@@ -326,7 +338,16 @@ impl GenericArgs {
326338
args: Box::default(),
327339
has_self_type: false,
328340
bindings: Box::default(),
329-
desugared_from_fn: false,
341+
parenthesized: GenericArgsParentheses::No,
342+
}
343+
}
344+
345+
pub(crate) fn return_type_notation() -> GenericArgs {
346+
GenericArgs {
347+
args: Box::default(),
348+
has_self_type: false,
349+
bindings: Box::default(),
350+
parenthesized: GenericArgsParentheses::ReturnTypeNotation,
330351
}
331352
}
332353
}

crates/hir-def/src/path/lower.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ use stdx::thin_vec::EmptyOptimizedThinVec;
1313
use syntax::ast::{self, AstNode, HasGenericArgs, HasTypeBounds};
1414

1515
use crate::{
16-
path::{AssociatedTypeBinding, GenericArg, GenericArgs, ModPath, Path, PathKind},
16+
path::{
17+
AssociatedTypeBinding, GenericArg, GenericArgs, GenericArgsParentheses, ModPath, Path,
18+
PathKind,
19+
},
1720
type_ref::{LifetimeRef, TypeBound, TypeRef},
1821
};
1922

@@ -73,6 +76,9 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
7376
segment.parenthesized_arg_list(),
7477
segment.ret_type(),
7578
)
79+
})
80+
.or_else(|| {
81+
segment.return_type_syntax().map(|_| GenericArgs::return_type_notation())
7682
});
7783
if args.is_some() {
7884
generic_args.resize(segments.len(), None);
@@ -126,7 +132,7 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<
126132

127133
has_self_type: true,
128134
bindings: it.bindings.clone(),
129-
desugared_from_fn: it.desugared_from_fn,
135+
parenthesized: it.parenthesized,
130136
},
131137
None => GenericArgs {
132138
args: Box::new([self_type]),
@@ -281,7 +287,12 @@ pub(super) fn lower_generic_args(
281287
let name = name_ref.as_name();
282288
let args = assoc_type_arg
283289
.generic_arg_list()
284-
.and_then(|args| lower_generic_args(lower_ctx, args));
290+
.and_then(|args| lower_generic_args(lower_ctx, args))
291+
.or_else(|| {
292+
assoc_type_arg
293+
.return_type_syntax()
294+
.map(|_| GenericArgs::return_type_notation())
295+
});
285296
let type_ref =
286297
assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
287298
let type_ref = type_ref
@@ -315,7 +326,7 @@ pub(super) fn lower_generic_args(
315326
args: args.into_boxed_slice(),
316327
has_self_type: false,
317328
bindings: bindings.into_boxed_slice(),
318-
desugared_from_fn: false,
329+
parenthesized: GenericArgsParentheses::No,
319330
})
320331
}
321332

@@ -353,5 +364,10 @@ fn lower_generic_args_from_fn_path(
353364
bounds: Box::default(),
354365
}])
355366
};
356-
Some(GenericArgs { args, has_self_type: false, bindings, desugared_from_fn: true })
367+
Some(GenericArgs {
368+
args,
369+
has_self_type: false,
370+
bindings,
371+
parenthesized: GenericArgsParentheses::ParenSugar,
372+
})
357373
}

crates/hir-ty/src/display.rs

Lines changed: 68 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2303,77 +2303,82 @@ impl HirDisplayWithTypesMap for Path {
23032303
if let Some(generic_args) = segment.args_and_bindings {
23042304
// We should be in type context, so format as `Foo<Bar>` instead of `Foo::<Bar>`.
23052305
// Do we actually format expressions?
2306-
if generic_args.desugared_from_fn {
2307-
// First argument will be a tuple, which already includes the parentheses.
2308-
// If the tuple only contains 1 item, write it manually to avoid the trailing `,`.
2309-
let tuple = match generic_args.args[0] {
2310-
hir_def::path::GenericArg::Type(ty) => match &types_map[ty] {
2311-
TypeRef::Tuple(it) => Some(it),
2306+
match generic_args.parenthesized {
2307+
hir_def::path::GenericArgsParentheses::ReturnTypeNotation => {
2308+
write!(f, "(..)")?;
2309+
}
2310+
hir_def::path::GenericArgsParentheses::ParenSugar => {
2311+
// First argument will be a tuple, which already includes the parentheses.
2312+
// If the tuple only contains 1 item, write it manually to avoid the trailing `,`.
2313+
let tuple = match generic_args.args[0] {
2314+
hir_def::path::GenericArg::Type(ty) => match &types_map[ty] {
2315+
TypeRef::Tuple(it) => Some(it),
2316+
_ => None,
2317+
},
23122318
_ => None,
2313-
},
2314-
_ => None,
2315-
};
2316-
if let Some(v) = tuple {
2317-
if v.len() == 1 {
2318-
write!(f, "(")?;
2319-
v[0].hir_fmt(f, types_map)?;
2320-
write!(f, ")")?;
2321-
} else {
2322-
generic_args.args[0].hir_fmt(f, types_map)?;
2319+
};
2320+
if let Some(v) = tuple {
2321+
if v.len() == 1 {
2322+
write!(f, "(")?;
2323+
v[0].hir_fmt(f, types_map)?;
2324+
write!(f, ")")?;
2325+
} else {
2326+
generic_args.args[0].hir_fmt(f, types_map)?;
2327+
}
23232328
}
2324-
}
2325-
if let Some(ret) = generic_args.bindings[0].type_ref {
2326-
if !matches!(&types_map[ret], TypeRef::Tuple(v) if v.is_empty()) {
2327-
write!(f, " -> ")?;
2328-
ret.hir_fmt(f, types_map)?;
2329+
if let Some(ret) = generic_args.bindings[0].type_ref {
2330+
if !matches!(&types_map[ret], TypeRef::Tuple(v) if v.is_empty()) {
2331+
write!(f, " -> ")?;
2332+
ret.hir_fmt(f, types_map)?;
2333+
}
23292334
}
23302335
}
2331-
return Ok(());
2332-
}
2333-
2334-
let mut first = true;
2335-
// Skip the `Self` bound if exists. It's handled outside the loop.
2336-
for arg in &generic_args.args[generic_args.has_self_type as usize..] {
2337-
if first {
2338-
first = false;
2339-
write!(f, "<")?;
2340-
} else {
2341-
write!(f, ", ")?;
2342-
}
2343-
arg.hir_fmt(f, types_map)?;
2344-
}
2345-
for binding in generic_args.bindings.iter() {
2346-
if first {
2347-
first = false;
2348-
write!(f, "<")?;
2349-
} else {
2350-
write!(f, ", ")?;
2351-
}
2352-
write!(f, "{}", binding.name.display(f.db.upcast(), f.edition()))?;
2353-
match &binding.type_ref {
2354-
Some(ty) => {
2355-
write!(f, " = ")?;
2356-
ty.hir_fmt(f, types_map)?
2336+
hir_def::path::GenericArgsParentheses::No => {
2337+
let mut first = true;
2338+
// Skip the `Self` bound if exists. It's handled outside the loop.
2339+
for arg in &generic_args.args[generic_args.has_self_type as usize..] {
2340+
if first {
2341+
first = false;
2342+
write!(f, "<")?;
2343+
} else {
2344+
write!(f, ", ")?;
2345+
}
2346+
arg.hir_fmt(f, types_map)?;
23572347
}
2358-
None => {
2359-
write!(f, ": ")?;
2360-
f.write_joined(
2361-
binding.bounds.iter().map(TypesMapAdapter::wrap(types_map)),
2362-
" + ",
2363-
)?;
2348+
for binding in generic_args.bindings.iter() {
2349+
if first {
2350+
first = false;
2351+
write!(f, "<")?;
2352+
} else {
2353+
write!(f, ", ")?;
2354+
}
2355+
write!(f, "{}", binding.name.display(f.db.upcast(), f.edition()))?;
2356+
match &binding.type_ref {
2357+
Some(ty) => {
2358+
write!(f, " = ")?;
2359+
ty.hir_fmt(f, types_map)?
2360+
}
2361+
None => {
2362+
write!(f, ": ")?;
2363+
f.write_joined(
2364+
binding.bounds.iter().map(TypesMapAdapter::wrap(types_map)),
2365+
" + ",
2366+
)?;
2367+
}
2368+
}
23642369
}
2365-
}
2366-
}
23672370

2368-
// There may be no generic arguments to print, in case of a trait having only a
2369-
// single `Self` bound which is converted to `<Ty as Trait>::Assoc`.
2370-
if !first {
2371-
write!(f, ">")?;
2372-
}
2371+
// There may be no generic arguments to print, in case of a trait having only a
2372+
// single `Self` bound which is converted to `<Ty as Trait>::Assoc`.
2373+
if !first {
2374+
write!(f, ">")?;
2375+
}
23732376

2374-
// Current position: `<Ty as Trait<Args>|`
2375-
if generic_args.has_self_type {
2376-
write!(f, ">")?;
2377+
// Current position: `<Ty as Trait<Args>|`
2378+
if generic_args.has_self_type {
2379+
write!(f, ">")?;
2380+
}
2381+
}
23772382
}
23782383
}
23792384
}

crates/hir-ty/src/lower/path.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use hir_def::{
88
data::TraitFlags,
99
expr_store::HygieneId,
1010
generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
11-
path::{GenericArg, GenericArgs, Path, PathSegment, PathSegments},
11+
path::{GenericArg, GenericArgs, GenericArgsParentheses, Path, PathSegment, PathSegments},
1212
resolver::{ResolveValueResult, TypeNs, ValueNs},
1313
type_ref::{TypeBound, TypeRef, TypesMap},
1414
GenericDefId, GenericParamId, ItemContainerId, Lookup, TraitId,
@@ -138,12 +138,15 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
138138

139139
fn prohibit_parenthesized_generic_args(&mut self) -> bool {
140140
if let Some(generic_args) = self.current_or_prev_segment.args_and_bindings {
141-
if generic_args.desugared_from_fn {
142-
let segment = self.current_segment_u32();
143-
self.on_diagnostic(
144-
PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment },
145-
);
146-
return true;
141+
match generic_args.parenthesized {
142+
GenericArgsParentheses::No => {}
143+
GenericArgsParentheses::ReturnTypeNotation | GenericArgsParentheses::ParenSugar => {
144+
let segment = self.current_segment_u32();
145+
self.on_diagnostic(
146+
PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment },
147+
);
148+
return true;
149+
}
147150
}
148151
}
149152
false

0 commit comments

Comments
 (0)