Skip to content

Commit 9187403

Browse files
authored
Merge pull request #19354 from ChayimFriedman2/rtn-prep
Preparation to Return Type Notation (RTN)
2 parents 5c39c02 + 5076ef7 commit 9187403

File tree

8 files changed

+205
-82
lines changed

8 files changed

+205
-82
lines changed

crates/hir-def/src/generics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,7 @@ fn copy_generic_args(
868868
args,
869869
has_self_type: generic_args.has_self_type,
870870
bindings,
871-
desugared_from_fn: generic_args.desugared_from_fn,
871+
parenthesized: generic_args.parenthesized,
872872
}
873873
})
874874
}

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

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

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

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

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use hir_def::{
99
data::TraitFlags,
1010
expr_store::HygieneId,
1111
generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
12-
path::{GenericArg, GenericArgs, Path, PathSegment, PathSegments},
12+
path::{GenericArg, GenericArgs, GenericArgsParentheses, Path, PathSegment, PathSegments},
1313
resolver::{ResolveValueResult, TypeNs, ValueNs},
1414
type_ref::{TypeBound, TypeRef, TypesMap},
1515
};
@@ -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
@@ -604,8 +607,14 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
604607
) -> Substitution {
605608
let prohibit_parens = match def {
606609
GenericDefId::TraitId(trait_) => {
607-
let trait_data = self.ctx.db.trait_data(trait_);
608-
!trait_data.flags.contains(TraitFlags::RUSTC_PAREN_SUGAR)
610+
// RTN is prohibited anyways if we got here.
611+
let is_rtn =
612+
self.current_or_prev_segment.args_and_bindings.is_some_and(|generics| {
613+
generics.parenthesized == GenericArgsParentheses::ReturnTypeNotation
614+
});
615+
let is_fn_trait =
616+
!self.ctx.db.trait_data(trait_).flags.contains(TraitFlags::RUSTC_PAREN_SUGAR);
617+
is_rtn || is_fn_trait
609618
}
610619
_ => true,
611620
};

crates/hir/src/diagnostics.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ diagnostics![
114114
UnusedVariable,
115115
GenericArgsProhibited,
116116
ParenthesizedGenericArgsWithoutFnTrait,
117+
BadRtn,
117118
];
118119

119120
#[derive(Debug)]
@@ -421,6 +422,11 @@ pub struct ParenthesizedGenericArgsWithoutFnTrait {
421422
pub args: InFile<AstPtr<ast::ParenthesizedArgList>>,
422423
}
423424

425+
#[derive(Debug)]
426+
pub struct BadRtn {
427+
pub rtn: InFile<AstPtr<ast::ReturnTypeSyntax>>,
428+
}
429+
424430
impl AnyDiagnostic {
425431
pub(crate) fn body_validation_diagnostic(
426432
db: &dyn HirDatabase,
@@ -713,6 +719,12 @@ impl AnyDiagnostic {
713719
Some(match *diag {
714720
PathLoweringDiagnostic::GenericArgsProhibited { segment, reason } => {
715721
let segment = hir_segment_to_ast_segment(&path.value, segment)?;
722+
723+
if let Some(rtn) = segment.return_type_syntax() {
724+
// RTN errors are emitted as `GenericArgsProhibited` or `ParenthesizedGenericArgsWithoutFnTrait`.
725+
return Some(BadRtn { rtn: path.with_value(AstPtr::new(&rtn)) }.into());
726+
}
727+
716728
let args = if let Some(generics) = segment.generic_arg_list() {
717729
AstPtr::new(&generics).wrap_left()
718730
} else {
@@ -723,6 +735,12 @@ impl AnyDiagnostic {
723735
}
724736
PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment } => {
725737
let segment = hir_segment_to_ast_segment(&path.value, segment)?;
738+
739+
if let Some(rtn) = segment.return_type_syntax() {
740+
// RTN errors are emitted as `GenericArgsProhibited` or `ParenthesizedGenericArgsWithoutFnTrait`.
741+
return Some(BadRtn { rtn: path.with_value(AstPtr::new(&rtn)) }.into());
742+
}
743+
726744
let args = AstPtr::new(&segment.parenthesized_arg_list()?);
727745
let args = path.with_value(args);
728746
ParenthesizedGenericArgsWithoutFnTrait { args }.into()

0 commit comments

Comments
 (0)