Auto merge of #109010 - compiler-errors:rtn, r=eholk
Initial support for return type notation (RTN) See: https://smallcultfollowing.com/babysteps/blog/2023/02/13/return-type-notation-send-bounds-part-2/ 1. Only supports `T: Trait<method(): Send>` style bounds, not `<T as Trait>::method(): Send`. Checking validity and injecting an implicit binder for all of the late-bound method generics is harder to do for the latter. * I'd add this in a follow-up. 3. ~Doesn't support RTN in general type position, i.e. no `let x: <T as Trait>::method() = ...`~ * I don't think we actually want this. 5. Doesn't add syntax for "eliding" the function args -- i.e. for now, we write `method(): Send` instead of `method(..): Send`. * May be a hazard if we try to add it in the future. I'll probably add it in a follow-up later, with a structured suggestion to change `method()` to `method(..)` once we add it. 7. ~I'm not in love with the feature gate name 😺~ * I renamed it to `return_type_notation` ✔️ Follow-up PRs will probably add support for `where T::method(): Send` bounds. I'm not sure if we ever want to support return-type-notation in arbitrary type positions. I may also make the bounds require `..` in the args list later. r? `@ghost`
This commit is contained in:
commit
7402519c63
49 changed files with 880 additions and 174 deletions
|
@ -139,3 +139,15 @@ ast_lowering_trait_fn_async =
|
|||
.label = `async` because of this
|
||||
.note = `async` trait functions are not currently supported
|
||||
.note2 = consider using the `async-trait` crate: https://crates.io/crates/async-trait
|
||||
|
||||
ast_lowering_bad_return_type_notation_inputs =
|
||||
argument types not allowed with return type notation
|
||||
.suggestion = remove the input types
|
||||
|
||||
ast_lowering_bad_return_type_notation_needs_dots =
|
||||
return type notation arguments must be elided with `..`
|
||||
.suggestion = add `..`
|
||||
|
||||
ast_lowering_bad_return_type_notation_output =
|
||||
return type not allowed with return type notation
|
||||
.suggestion = remove the return type
|
||||
|
|
|
@ -347,3 +347,25 @@ pub struct TraitFnAsync {
|
|||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
pub enum BadReturnTypeNotation {
|
||||
#[diag(ast_lowering_bad_return_type_notation_inputs)]
|
||||
Inputs {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "(..)", applicability = "maybe-incorrect")]
|
||||
span: Span,
|
||||
},
|
||||
#[diag(ast_lowering_bad_return_type_notation_needs_dots)]
|
||||
NeedsDots {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "(..)", applicability = "maybe-incorrect")]
|
||||
span: Span,
|
||||
},
|
||||
#[diag(ast_lowering_bad_return_type_notation_output)]
|
||||
Output {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "", applicability = "maybe-incorrect")]
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ use rustc_middle::{
|
|||
span_bug,
|
||||
ty::{ResolverAstLowering, TyCtxt},
|
||||
};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::parse::{add_feature_diagnostics, feature_err};
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
use rustc_span::source_map::DesugaringKind;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
|
@ -482,7 +482,7 @@ enum ParamMode {
|
|||
}
|
||||
|
||||
enum ParenthesizedGenericArgs {
|
||||
Ok,
|
||||
ParenSugar,
|
||||
Err,
|
||||
}
|
||||
|
||||
|
@ -987,14 +987,56 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
GenericArgs::AngleBracketed(data) => {
|
||||
self.lower_angle_bracketed_parameter_data(data, ParamMode::Explicit, itctx).0
|
||||
}
|
||||
&GenericArgs::ReturnTypeNotation(span) => GenericArgsCtor {
|
||||
args: Default::default(),
|
||||
bindings: &[],
|
||||
parenthesized: hir::GenericArgsParentheses::ReturnTypeNotation,
|
||||
span,
|
||||
},
|
||||
GenericArgs::Parenthesized(data) => {
|
||||
self.emit_bad_parenthesized_trait_in_assoc_ty(data);
|
||||
self.lower_angle_bracketed_parameter_data(
|
||||
&data.as_angle_bracketed_args(),
|
||||
ParamMode::Explicit,
|
||||
itctx,
|
||||
)
|
||||
.0
|
||||
if let Some(start_char) = constraint.ident.as_str().chars().next()
|
||||
&& start_char.is_ascii_lowercase()
|
||||
{
|
||||
let mut err = if !data.inputs.is_empty() {
|
||||
self.tcx.sess.create_err(errors::BadReturnTypeNotation::Inputs {
|
||||
span: data.inputs_span,
|
||||
})
|
||||
} else if let FnRetTy::Ty(ty) = &data.output {
|
||||
self.tcx.sess.create_err(errors::BadReturnTypeNotation::Output {
|
||||
span: data.inputs_span.shrink_to_hi().to(ty.span),
|
||||
})
|
||||
} else {
|
||||
self.tcx.sess.create_err(errors::BadReturnTypeNotation::NeedsDots {
|
||||
span: data.inputs_span,
|
||||
})
|
||||
};
|
||||
if !self.tcx.features().return_type_notation
|
||||
&& self.tcx.sess.is_nightly_build()
|
||||
{
|
||||
add_feature_diagnostics(
|
||||
&mut err,
|
||||
&self.tcx.sess.parse_sess,
|
||||
sym::return_type_notation,
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
GenericArgsCtor {
|
||||
args: Default::default(),
|
||||
bindings: &[],
|
||||
parenthesized: hir::GenericArgsParentheses::ReturnTypeNotation,
|
||||
span: data.span,
|
||||
}
|
||||
} else {
|
||||
self.emit_bad_parenthesized_trait_in_assoc_ty(data);
|
||||
// FIXME(return_type_notation): we could issue a feature error
|
||||
// if the parens are empty and there's no return type.
|
||||
self.lower_angle_bracketed_parameter_data(
|
||||
&data.as_angle_bracketed_args(),
|
||||
ParamMode::Explicit,
|
||||
itctx,
|
||||
)
|
||||
.0
|
||||
}
|
||||
}
|
||||
};
|
||||
gen_args_ctor.into_generic_args(self)
|
||||
|
@ -2075,7 +2117,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let future_args = self.arena.alloc(hir::GenericArgs {
|
||||
args: &[],
|
||||
bindings: arena_vec![self; self.output_ty_binding(span, output_ty)],
|
||||
parenthesized: false,
|
||||
parenthesized: hir::GenericArgsParentheses::No,
|
||||
span_ext: DUMMY_SP,
|
||||
});
|
||||
|
||||
|
@ -2595,13 +2637,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
struct GenericArgsCtor<'hir> {
|
||||
args: SmallVec<[hir::GenericArg<'hir>; 4]>,
|
||||
bindings: &'hir [hir::TypeBinding<'hir>],
|
||||
parenthesized: bool,
|
||||
parenthesized: hir::GenericArgsParentheses,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl<'hir> GenericArgsCtor<'hir> {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.args.is_empty() && self.bindings.is_empty() && !self.parenthesized
|
||||
self.args.is_empty()
|
||||
&& self.bindings.is_empty()
|
||||
&& self.parenthesized == hir::GenericArgsParentheses::No
|
||||
}
|
||||
|
||||
fn into_generic_args(self, this: &LoweringContext<'_, 'hir>) -> &'hir hir::GenericArgs<'hir> {
|
||||
|
|
|
@ -13,6 +13,7 @@ use rustc_span::symbol::{kw, sym, Ident};
|
|||
use rustc_span::{BytePos, Span, DUMMY_SP};
|
||||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
|
@ -51,7 +52,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let parenthesized_generic_args = match base_res {
|
||||
// `a::b::Trait(Args)`
|
||||
Res::Def(DefKind::Trait, _) if i + 1 == proj_start => {
|
||||
ParenthesizedGenericArgs::Ok
|
||||
ParenthesizedGenericArgs::ParenSugar
|
||||
}
|
||||
// `a::b::Trait(Args)::TraitItem`
|
||||
Res::Def(DefKind::AssocFn, _)
|
||||
|
@ -59,10 +60,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
| Res::Def(DefKind::AssocTy, _)
|
||||
if i + 2 == proj_start =>
|
||||
{
|
||||
ParenthesizedGenericArgs::Ok
|
||||
ParenthesizedGenericArgs::ParenSugar
|
||||
}
|
||||
// Avoid duplicated errors.
|
||||
Res::Err => ParenthesizedGenericArgs::Ok,
|
||||
Res::Err => ParenthesizedGenericArgs::ParenSugar,
|
||||
// An error
|
||||
_ => ParenthesizedGenericArgs::Err,
|
||||
};
|
||||
|
@ -180,7 +181,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
|
||||
}
|
||||
GenericArgs::Parenthesized(data) => match parenthesized_generic_args {
|
||||
ParenthesizedGenericArgs::Ok => {
|
||||
ParenthesizedGenericArgs::ParenSugar => {
|
||||
self.lower_parenthesized_parameter_data(data, itctx)
|
||||
}
|
||||
ParenthesizedGenericArgs::Err => {
|
||||
|
@ -218,13 +219,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
)
|
||||
}
|
||||
},
|
||||
&GenericArgs::ReturnTypeNotation(span) => {
|
||||
self.tcx.sess.emit_err(GenericTypeWithParentheses { span, sub: None });
|
||||
(
|
||||
self.lower_angle_bracketed_parameter_data(
|
||||
&AngleBracketedArgs { span, args: ThinVec::default() },
|
||||
param_mode,
|
||||
itctx,
|
||||
)
|
||||
.0,
|
||||
false,
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(
|
||||
GenericArgsCtor {
|
||||
args: Default::default(),
|
||||
bindings: &[],
|
||||
parenthesized: false,
|
||||
parenthesized: hir::GenericArgsParentheses::No,
|
||||
span: path_span.shrink_to_hi(),
|
||||
},
|
||||
param_mode == ParamMode::Optional,
|
||||
|
@ -233,7 +246,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
let has_lifetimes =
|
||||
generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)));
|
||||
if !generic_args.parenthesized && !has_lifetimes {
|
||||
|
||||
// FIXME(return_type_notation): Is this correct? I think so.
|
||||
if generic_args.parenthesized != hir::GenericArgsParentheses::ParenSugar && !has_lifetimes {
|
||||
self.maybe_insert_elided_lifetimes_in_path(
|
||||
path_span,
|
||||
segment.id,
|
||||
|
@ -328,7 +343,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
AngleBracketedArg::Constraint(c) => Some(self.lower_assoc_ty_constraint(c, itctx)),
|
||||
AngleBracketedArg::Arg(_) => None,
|
||||
}));
|
||||
let ctor = GenericArgsCtor { args, bindings, parenthesized: false, span: data.span };
|
||||
let ctor = GenericArgsCtor {
|
||||
args,
|
||||
bindings,
|
||||
parenthesized: hir::GenericArgsParentheses::No,
|
||||
span: data.span,
|
||||
};
|
||||
(ctor, !has_non_lt_args && param_mode == ParamMode::Optional)
|
||||
}
|
||||
|
||||
|
@ -376,7 +396,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
GenericArgsCtor {
|
||||
args,
|
||||
bindings: arena_vec![self; binding],
|
||||
parenthesized: true,
|
||||
parenthesized: hir::GenericArgsParentheses::ParenSugar,
|
||||
span: data.inputs_span,
|
||||
},
|
||||
false,
|
||||
|
@ -396,7 +416,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let gen_args = self.arena.alloc(hir::GenericArgs {
|
||||
args,
|
||||
bindings,
|
||||
parenthesized: false,
|
||||
parenthesized: hir::GenericArgsParentheses::No,
|
||||
span_ext: DUMMY_SP,
|
||||
});
|
||||
hir::TypeBinding {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue