From 8b592db27afdc9edac084520bca98508da53c996 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 16 Mar 2023 22:00:08 +0000 Subject: [PATCH] Add `(..)` syntax for RTN --- compiler/rustc_ast/src/ast.rs | 20 ++-- compiler/rustc_ast/src/mut_visit.rs | 1 + compiler/rustc_ast/src/visit.rs | 1 + compiler/rustc_ast_lowering/messages.ftl | 4 + compiler/rustc_ast_lowering/src/errors.rs | 8 +- compiler/rustc_ast_lowering/src/lib.rs | 85 +++++++++------ compiler/rustc_ast_lowering/src/path.rs | 30 +++++- .../rustc_ast_passes/src/ast_validation.rs | 14 ++- compiler/rustc_ast_passes/src/feature_gate.rs | 20 ++-- compiler/rustc_ast_pretty/src/pprust/state.rs | 4 + compiler/rustc_expand/src/build.rs | 2 +- compiler/rustc_hir/src/hir.rs | 22 +++- .../rustc_hir_analysis/src/astconv/errors.rs | 22 ++-- .../rustc_hir_analysis/src/astconv/mod.rs | 2 +- .../src/collect/resolve_bound_vars.rs | 4 +- .../wrong_number_of_generic_args.rs | 8 +- compiler/rustc_hir_pretty/src/lib.rs | 100 +++++++++--------- compiler/rustc_parse/messages.ftl | 4 + compiler/rustc_parse/src/errors.rs | 8 ++ .../rustc_parse/src/parser/diagnostics.rs | 3 +- compiler/rustc_parse/src/parser/path.rs | 29 ++++- compiler/rustc_parse/src/parser/ty.rs | 7 +- compiler/rustc_passes/src/hir_stats.rs | 2 +- compiler/rustc_resolve/src/late.rs | 1 + compiler/rustc_resolve/src/lib.rs | 1 + src/librustdoc/clean/mod.rs | 3 +- .../clippy/clippy_lints/src/ref_option_ref.rs | 4 +- .../clippy_lints/src/types/borrowed_box.rs | 2 +- .../clippy/clippy_lints/src/types/utils.rs | 4 +- src/tools/clippy/clippy_lints/src/use_self.rs | 5 +- .../clippy/clippy_utils/src/hir_utils.rs | 7 +- .../bad-inputs-and-output.rs | 5 +- .../bad-inputs-and-output.stderr | 18 ++-- .../return-type-notation/basic.rs | 2 +- .../return-type-notation/equality.rs | 2 +- .../return-type-notation/equality.stderr | 4 +- .../return-type-notation/missing.rs | 2 +- .../return-type-notation/missing.stderr | 4 +- .../return-type-notation/non-rpitit.rs | 2 +- .../return-type-notation/non-rpitit.stderr | 4 +- ...ature-gate-return_type_notation.cfg.stderr | 21 ++++ ...eature-gate-return_type_notation.no.stderr | 21 ++++ .../feature-gate-return_type_notation.rs | 8 +- .../feature-gate-return_type_notation.stderr | 36 ------- 44 files changed, 355 insertions(+), 201 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr create mode 100644 tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr delete mode 100644 tests/ui/feature-gates/feature-gate-return_type_notation.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 710c7ad3b2e..f8f639d982f 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -167,6 +167,9 @@ pub enum GenericArgs { AngleBracketed(AngleBracketedArgs), /// The `(A, B)` and `C` in `Foo(A, B) -> C`. Parenthesized(ParenthesizedArgs), + /// Associated return type bounds, like `T: Trait` + /// which applies the `Send` bound to the return-type of `method`. + ReturnTypeNotation(Span), } impl GenericArgs { @@ -174,14 +177,11 @@ pub fn is_angle_bracketed(&self) -> bool { matches!(self, AngleBracketed(..)) } - pub fn is_parenthesized(&self) -> bool { - matches!(self, Parenthesized(..)) - } - pub fn span(&self) -> Span { match self { AngleBracketed(data) => data.span, Parenthesized(data) => data.span, + ReturnTypeNotation(span) => *span, } } } @@ -235,15 +235,15 @@ pub fn span(&self) -> Span { } } -impl Into>> for AngleBracketedArgs { - fn into(self) -> Option> { - Some(P(GenericArgs::AngleBracketed(self))) +impl Into> for AngleBracketedArgs { + fn into(self) -> P { + P(GenericArgs::AngleBracketed(self)) } } -impl Into>> for ParenthesizedArgs { - fn into(self) -> Option> { - Some(P(GenericArgs::Parenthesized(self))) +impl Into> for ParenthesizedArgs { + fn into(self) -> P { + P(GenericArgs::Parenthesized(self)) } } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 46e46ab575e..514978f5569 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -561,6 +561,7 @@ pub fn noop_visit_generic_args(generic_args: &mut GenericArgs, vi match generic_args { GenericArgs::AngleBracketed(data) => vis.visit_angle_bracketed_parameter_data(data), GenericArgs::Parenthesized(data) => vis.visit_parenthesized_parameter_data(data), + GenericArgs::ReturnTypeNotation(_span) => {} } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 608f87ab6eb..e5a0ad1f1e4 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -481,6 +481,7 @@ pub fn walk_generic_args<'a, V>(visitor: &mut V, generic_args: &'a GenericArgs) walk_list!(visitor, visit_ty, &data.inputs); walk_fn_ret_ty(visitor, &data.output); } + GenericArgs::ReturnTypeNotation(_span) => {} } } diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index dac61ec975e..21b2a3c22fa 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -144,6 +144,10 @@ 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 diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 4eefd951b24..f4e55619ebb 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -353,7 +353,13 @@ pub enum BadReturnTypeNotation { #[diag(ast_lowering_bad_return_type_notation_inputs)] Inputs { #[primary_span] - #[suggestion(code = "()", applicability = "maybe-incorrect")] + #[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)] diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index aa4ff2882b2..c5d39634c44 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -66,7 +66,7 @@ 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}; @@ -987,33 +987,56 @@ fn lower_assoc_ty_constraint( GenericArgs::AngleBracketed(data) => { self.lower_angle_bracketed_parameter_data(data, ParamMode::Explicit, itctx).0 } - GenericArgs::Parenthesized(data) if self.tcx.features().return_type_notation => { - if !data.inputs.is_empty() { - self.tcx.sess.emit_err(errors::BadReturnTypeNotation::Inputs { - span: data.inputs_span, - }); - } else if let FnRetTy::Ty(ty) = &data.output { - self.tcx.sess.emit_err(errors::BadReturnTypeNotation::Output { - span: data.inputs_span.shrink_to_hi().to(ty.span), - }); - } - GenericArgsCtor { - args: Default::default(), - bindings: &[], - parenthesized: true, - span: data.span, - } - } + &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); - // 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 + 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) @@ -2094,7 +2117,7 @@ fn lower_async_fn_output_type_to_future_bound( 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, }); @@ -2614,13 +2637,15 @@ fn elided_dyn_bound(&mut self, span: Span) -> &'hir hir::Lifetime { 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> { diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 6ab23206f54..1c47a969696 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -13,6 +13,7 @@ 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))] @@ -218,13 +219,25 @@ pub(crate) fn lower_path_segment( ) } }, + &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 @@ pub(crate) fn lower_path_segment( 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 @@ pub(crate) fn lower_angle_bracketed_parameter_data( 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 @@ fn lower_parenthesized_parameter_data( GenericArgsCtor { args, bindings: arena_vec![self; binding], - parenthesized: true, + parenthesized: hir::GenericArgsParentheses::ParenSugar, span: data.inputs_span, }, false, @@ -396,7 +416,7 @@ pub(crate) fn output_ty_binding( let gen_args = self.arena.alloc(hir::GenericArgs { args, bindings, - parenthesized: false, + parenthesized: hir::GenericArgsParentheses::No, span_ext: DUMMY_SP, }); hir::TypeBinding { diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 93c854cc809..44b6c77fc41 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1075,6 +1075,7 @@ fn visit_generic_args(&mut self, generic_args: &'a GenericArgs) { self.with_impl_trait(None, |this| this.visit_ty(ty)); } } + GenericArgs::ReturnTypeNotation(_span) => {} } } @@ -1387,16 +1388,19 @@ fn deny_equality_constraints( match &mut assoc_path.segments[len].args { Some(args) => match args.deref_mut() { GenericArgs::Parenthesized(_) => continue, + GenericArgs::ReturnTypeNotation(_span) => continue, GenericArgs::AngleBracketed(args) => { args.args.push(arg); } }, empty_args => { - *empty_args = AngleBracketedArgs { - span: ident.span, - args: thin_vec![arg], - } - .into(); + *empty_args = Some( + AngleBracketedArgs { + span: ident.span, + args: thin_vec![arg], + } + .into(), + ); } } err.assoc = Some(errors::AssociatedSuggestion { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 1413db64a48..de94c1bc477 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -482,13 +482,20 @@ fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) { if let AssocConstraintKind::Bound { .. } = constraint.kind { - if constraint.gen_args.as_ref().map_or(false, |args| args.is_parenthesized()) { - gate_feature_post!( - &self, - return_type_notation, - constraint.span, - "return type notation is unstable" + if let Some(args) = constraint.gen_args.as_ref() + && matches!( + args, + ast::GenericArgs::ReturnTypeNotation(..) | ast::GenericArgs::Parenthesized(..) ) + { + // RTN is gated elsewhere, and parenthesized args will turn into + // another error. + if matches!(args, ast::GenericArgs::Parenthesized(..)) { + self.sess.delay_span_bug( + constraint.span, + "should have emitted a parenthesized generics error", + ); + } } else { gate_feature_post!( &self, @@ -586,6 +593,7 @@ macro_rules! gate_all { gate_all!(yeet_expr, "`do yeet` expression is experimental"); gate_all!(dyn_star, "`dyn*` trait objects are experimental"); gate_all!(const_closures, "const closures are experimental"); + gate_all!(return_type_notation, "return type notation is experimental"); // All uses of `gate_all!` below this point were added in #65742, // and subsequently disabled (with the non-early gating readded). diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 694d688bf1f..80c451d6753 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -936,6 +936,10 @@ fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: self.word(")"); self.print_fn_ret_ty(&data.output); } + + ast::GenericArgs::ReturnTypeNotation(_span) => { + self.word("(..)"); + } } } } diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 8a78c3296f9..8a16143311b 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -36,7 +36,7 @@ pub fn path_all( ); let args = if !args.is_empty() { let args = args.into_iter().map(ast::AngleBracketedArg::Arg).collect(); - ast::AngleBracketedArgs { args, span }.into() + Some(ast::AngleBracketedArgs { args, span }.into()) } else { None }; diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f4b46b9a131..35a72f868fb 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -328,7 +328,7 @@ pub struct GenericArgs<'hir> { /// Were arguments written in parenthesized form `Fn(T) -> U`? /// This is required mostly for pretty-printing and diagnostics, /// but also for changing lifetime elision rules to be "function-like". - pub parenthesized: bool, + pub parenthesized: GenericArgsParentheses, /// The span encompassing arguments and the surrounding brackets `<>` or `()` /// Foo Fn(T, U, V) -> W /// ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ @@ -340,11 +340,16 @@ pub struct GenericArgs<'hir> { impl<'hir> GenericArgs<'hir> { pub const fn none() -> Self { - Self { args: &[], bindings: &[], parenthesized: false, span_ext: DUMMY_SP } + Self { + args: &[], + bindings: &[], + parenthesized: GenericArgsParentheses::No, + span_ext: DUMMY_SP, + } } pub fn inputs(&self) -> &[Ty<'hir>] { - if self.parenthesized { + if self.parenthesized == GenericArgsParentheses::ParenSugar { for arg in self.args { match arg { GenericArg::Lifetime(_) => {} @@ -417,6 +422,17 @@ pub fn is_empty(&self) -> bool { } } +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Hash, Debug)] +#[derive(HashStable_Generic)] +pub enum GenericArgsParentheses { + No, + /// Bounds for `feature(return_type_notation)`, like `T: Trait`, + /// where the args are explicitly elided with `..` + ReturnTypeNotation, + /// parenthesized function-family traits, like `T: Fn(u32) -> i32` + ParenSugar, +} + /// A modifier on a bound, currently this is only used for `?Sized`, where the /// modifier is `Maybe`. Negative bounds should also be handled here. #[derive(Copy, Clone, PartialEq, Eq, Encodable, Hash, Debug)] diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index 156334fe785..672e7176fde 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -55,7 +55,7 @@ pub(crate) fn complain_about_internal_fn_trait( let trait_def = self.tcx().trait_def(trait_def_id); if !trait_def.paren_sugar { - if trait_segment.args().parenthesized { + if trait_segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar { // For now, require that parenthetical notation be used only with `Fn()` etc. let mut err = feature_err( &self.tcx().sess.parse_sess, @@ -71,7 +71,7 @@ pub(crate) fn complain_about_internal_fn_trait( let sess = self.tcx().sess; - if !trait_segment.args().parenthesized { + if trait_segment.args().parenthesized != hir::GenericArgsParentheses::ParenSugar { // For now, require that parenthetical notation be used only with `Fn()` etc. let mut err = feature_err( &sess.parse_sess, @@ -607,11 +607,19 @@ pub fn prohibit_assoc_ty_binding( span: Span, segment: Option<(&hir::PathSegment<'_>, Span)>, ) { - tcx.sess.emit_err(AssocTypeBindingNotAllowed { span, fn_trait_expansion: if let Some((segment, span)) = segment && segment.args().parenthesized { - Some(ParenthesizedFnTraitExpansion { span, expanded_type: fn_trait_to_string(tcx, segment, false) }) - } else { - None - }}); + tcx.sess.emit_err(AssocTypeBindingNotAllowed { + span, + fn_trait_expansion: if let Some((segment, span)) = segment + && segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar + { + Some(ParenthesizedFnTraitExpansion { + span, + expanded_type: fn_trait_to_string(tcx, segment, false), + }) + } else { + None + }, + }); } pub(crate) fn fn_trait_to_string( diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 1e590d93c8c..e25b07d9392 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1087,7 +1087,7 @@ fn add_predicates_for_ast_type_binding( let tcx = self.tcx(); let return_type_notation = - binding.gen_args.parenthesized && tcx.features().return_type_notation; + binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation; let candidate = if return_type_notation { if self.trait_defines_associated_item_named( diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 1a4a1636071..5e4f377a1e7 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1461,7 +1461,7 @@ fn visit_segment_args( depth: usize, generic_args: &'tcx hir::GenericArgs<'tcx>, ) { - if generic_args.parenthesized { + if generic_args.parenthesized == hir::GenericArgsParentheses::ParenSugar { self.visit_fn_like_elision( generic_args.inputs(), Some(generic_args.bindings[0].ty()), @@ -1653,7 +1653,7 @@ fn visit_segment_args( // `for<'a> T::Trait<'a, x(): for<'b> Other<'b>>` // this is going to expand to something like: // `for<'a> for<'r, T> >::x::<'r, T>::{opaque#0}: for<'b> Other<'b>`. - if binding.gen_args.parenthesized { + if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation { let bound_vars = if let Some(type_def_id) = type_def_id && self.tcx.def_kind(type_def_id) == DefKind::Trait // FIXME(return_type_notation): We could bound supertrait methods. diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs index cae884ae8fb..8f4d81ec3a9 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs @@ -565,7 +565,7 @@ fn suggest(&self, err: &mut Diagnostic) { /// type Map = HashMap; /// ``` fn suggest_adding_args(&self, err: &mut Diagnostic) { - if self.gen_args.parenthesized { + if self.gen_args.parenthesized != hir::GenericArgsParentheses::No { return; } @@ -962,7 +962,11 @@ fn suggest_removing_args_or_generics(&self, err: &mut Diagnostic) { let msg = format!( "remove these {}generics", - if self.gen_args.parenthesized { "parenthetical " } else { "" }, + if self.gen_args.parenthesized == hir::GenericArgsParentheses::ParenSugar { + "parenthetical " + } else { + "" + }, ); err.span_suggestion(span, &msg, "", Applicability::MaybeIncorrect); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 63ea6c90477..4f27c01fad2 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1652,61 +1652,65 @@ fn print_generic_args( generic_args: &hir::GenericArgs<'_>, colons_before_params: bool, ) { - if generic_args.parenthesized { - self.word("("); - self.commasep(Inconsistent, generic_args.inputs(), |s, ty| s.print_type(ty)); - self.word(")"); + match generic_args.parenthesized { + hir::GenericArgsParentheses::No => { + let start = if colons_before_params { "::<" } else { "<" }; + let empty = Cell::new(true); + let start_or_comma = |this: &mut Self| { + if empty.get() { + empty.set(false); + this.word(start) + } else { + this.word_space(",") + } + }; - self.space_if_not_bol(); - self.word_space("->"); - self.print_type(generic_args.bindings[0].ty()); - } else { - let start = if colons_before_params { "::<" } else { "<" }; - let empty = Cell::new(true); - let start_or_comma = |this: &mut Self| { - if empty.get() { - empty.set(false); - this.word(start) - } else { - this.word_space(",") - } - }; + let mut nonelided_generic_args: bool = false; + let elide_lifetimes = generic_args.args.iter().all(|arg| match arg { + GenericArg::Lifetime(lt) if lt.is_elided() => true, + GenericArg::Lifetime(_) => { + nonelided_generic_args = true; + false + } + _ => { + nonelided_generic_args = true; + true + } + }); - let mut nonelided_generic_args: bool = false; - let elide_lifetimes = generic_args.args.iter().all(|arg| match arg { - GenericArg::Lifetime(lt) if lt.is_elided() => true, - GenericArg::Lifetime(_) => { - nonelided_generic_args = true; - false + if nonelided_generic_args { + start_or_comma(self); + self.commasep(Inconsistent, generic_args.args, |s, generic_arg| { + match generic_arg { + GenericArg::Lifetime(lt) if !elide_lifetimes => s.print_lifetime(lt), + GenericArg::Lifetime(_) => {} + GenericArg::Type(ty) => s.print_type(ty), + GenericArg::Const(ct) => s.print_anon_const(&ct.value), + GenericArg::Infer(_inf) => s.word("_"), + } + }); } - _ => { - nonelided_generic_args = true; - true - } - }); - if nonelided_generic_args { - start_or_comma(self); - self.commasep( - Inconsistent, - generic_args.args, - |s, generic_arg| match generic_arg { - GenericArg::Lifetime(lt) if !elide_lifetimes => s.print_lifetime(lt), - GenericArg::Lifetime(_) => {} - GenericArg::Type(ty) => s.print_type(ty), - GenericArg::Const(ct) => s.print_anon_const(&ct.value), - GenericArg::Infer(_inf) => s.word("_"), - }, - ); + for binding in generic_args.bindings { + start_or_comma(self); + self.print_type_binding(binding); + } + + if !empty.get() { + self.word(">") + } } + hir::GenericArgsParentheses::ParenSugar => { + self.word("("); + self.commasep(Inconsistent, generic_args.inputs(), |s, ty| s.print_type(ty)); + self.word(")"); - for binding in generic_args.bindings { - start_or_comma(self); - self.print_type_binding(binding); + self.space_if_not_bol(); + self.word_space("->"); + self.print_type(generic_args.bindings[0].ty()); } - - if !empty.get() { - self.word(">") + hir::GenericArgsParentheses::ReturnTypeNotation => { + self.word("(..)"); } } } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 96765c296e7..e21bbd0217b 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -734,3 +734,7 @@ parse_unknown_start_of_token = unknown start of token: {$escaped} parse_box_syntax_removed = `box_syntax` has been removed .suggestion = use `Box::new()` instead + +parse_bad_return_type_notation_output = + return type not allowed with return type notation + .suggestion = remove the return type diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index a9d116012ae..aead216b61c 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2316,3 +2316,11 @@ pub struct BoxSyntaxRemoved<'a> { pub span: Span, pub code: &'a str, } + +#[derive(Diagnostic)] +#[diag(parse_bad_return_type_notation_output)] +pub(crate) struct BadReturnTypeNotationOutput { + #[primary_span] + #[suggestion(code = "", applicability = "maybe-incorrect")] + pub span: Span, +} diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 9544afd3d6d..5210b8fe69d 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -989,8 +989,7 @@ pub(super) fn check_turbofish_missing_angle_brackets(&mut self, segment: &mut Pa } if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) { // Recover from bad turbofish: `foo.collect::Vec<_>()`. - let args = AngleBracketedArgs { args, span }.into(); - segment.args = args; + segment.args = Some(AngleBracketedArgs { args, span }.into()); self.sess.emit_err(GenericParamsWithoutAngleBrackets { span, diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 72f230e628d..f1c9f0109f8 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -1,6 +1,6 @@ use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{Parser, Restrictions, TokenType}; -use crate::maybe_whole; +use crate::{errors, maybe_whole}; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::{ @@ -290,6 +290,25 @@ pub(super) fn parse_path_segment( })?; let span = lo.to(self.prev_token.span); AngleBracketedArgs { args, span }.into() + } else if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) + // FIXME(return_type_notation): Could also recover `...` here. + && self.look_ahead(1, |tok| tok.kind == token::DotDot) + { + let lo = self.token.span; + self.bump(); + self.bump(); + self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; + let span = lo.to(self.prev_token.span); + self.sess.gated_spans.gate(sym::return_type_notation, span); + + if self.eat_noexpect(&token::RArrow) { + let lo = self.prev_token.span; + let ty = self.parse_ty()?; + self.sess + .emit_err(errors::BadReturnTypeNotationOutput { span: lo.to(ty.span) }); + } + + P(GenericArgs::ReturnTypeNotation(span)) } else { // `(T, U) -> R` let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?; @@ -300,7 +319,7 @@ pub(super) fn parse_path_segment( ParenthesizedArgs { span, inputs, inputs_span, output }.into() }; - PathSegment { ident, args, id: ast::DUMMY_NODE_ID } + PathSegment { ident, args: Some(args), id: ast::DUMMY_NODE_ID } } else { // Generic arguments are not found. PathSegment::from_ident(ident) @@ -550,8 +569,10 @@ fn parse_angle_arg( // Gate associated type bounds, e.g., `Iterator`. if let AssocConstraintKind::Bound { .. } = kind { - if gen_args.as_ref().map_or(false, |args| args.is_parenthesized()) { - self.sess.gated_spans.gate(sym::return_type_notation, span); + if gen_args.as_ref().map_or(false, |args| { + matches!(args, GenericArgs::ReturnTypeNotation(..)) + }) { + // This is already gated in `parse_path_segment` } else { self.sess.gated_spans.gate(sym::associated_type_bounds, span); } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 3d9d2cc62e3..400c8dbe9bc 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -1059,8 +1059,11 @@ fn recover_fn_trait_with_lifetime_params( output, } .into(); - *fn_path_segment = - ast::PathSegment { ident: fn_path_segment.ident, args, id: ast::DUMMY_NODE_ID }; + *fn_path_segment = ast::PathSegment { + ident: fn_path_segment.ident, + args: Some(args), + id: ast::DUMMY_NODE_ID, + }; // Convert parsed `<'a>` in `Fn<'a>` into `for<'a>`. let mut generic_params = lifetimes diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 47e032758f2..ce44f709f3b 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -666,7 +666,7 @@ fn visit_path_segment(&mut self, path_segment: &'v ast::PathSegment) { fn visit_generic_args(&mut self, g: &'v ast::GenericArgs) { record_variants!( (self, g, g, Id::None, ast, GenericArgs, GenericArgs), - [AngleBracketed, Parenthesized] + [AngleBracketed, Parenthesized, ReturnTypeNotation] ); ast_visit::walk_generic_args(self, g) } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 4ca54bab31a..f66bad1d429 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1110,6 +1110,7 @@ fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) { } } } + GenericArgs::ReturnTypeNotation(_span) => {} } } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 0e84432a5b4..99fad22d4a1 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -312,6 +312,7 @@ fn from(seg: &'a ast::PathSegment) -> Segment { (args.span, found_lifetimes) } GenericArgs::Parenthesized(args) => (args.span, true), + GenericArgs::ReturnTypeNotation(span) => (*span, false), } } else { (DUMMY_SP, false) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 5f5521caf68..a25210d265a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2013,7 +2013,8 @@ fn clean_generic_args<'tcx>( generic_args: &hir::GenericArgs<'tcx>, cx: &mut DocContext<'tcx>, ) -> GenericArgs { - if generic_args.parenthesized { + // FIXME(return_type_notation): Fix RTN parens rendering + if generic_args.parenthesized == hir::GenericArgsParentheses::ParenSugar { let output = clean_ty(generic_args.bindings[0].ty(), cx); let output = if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None }; let inputs = diff --git a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs index 448a32b77c0..c984a8286eb 100644 --- a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs +++ b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{GenericArg, Mutability, Ty, TyKind}; +use rustc_hir::{GenericArg, GenericArgsParentheses, Mutability, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; @@ -47,7 +47,7 @@ fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) { if cx.tcx.is_diagnostic_item(sym::Option, def_id); if let Some(params) = last_path_segment(qpath).args ; - if !params.parenthesized; + if params.parenthesized == GenericArgsParentheses::No; if let Some(inner_ty) = params.args.iter().find_map(|arg| match arg { GenericArg::Type(inner_ty) => Some(inner_ty), _ => None, diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs index 65dfe7637ea..acdf5471069 100644 --- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs +++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs @@ -20,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m if let QPath::Resolved(None, path) = *qpath; if let [ref bx] = *path.segments; if let Some(params) = bx.args; - if !params.parenthesized; + if params.parenthesized == hir::GenericArgsParentheses::No; if let Some(inner) = params.args.iter().find_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), _ => None, diff --git a/src/tools/clippy/clippy_lints/src/types/utils.rs b/src/tools/clippy/clippy_lints/src/types/utils.rs index 7f43b7841ff..a30748db88f 100644 --- a/src/tools/clippy/clippy_lints/src/types/utils.rs +++ b/src/tools/clippy/clippy_lints/src/types/utils.rs @@ -1,6 +1,6 @@ use clippy_utils::last_path_segment; use if_chain::if_chain; -use rustc_hir::{GenericArg, QPath, TyKind}; +use rustc_hir::{GenericArg, GenericArgsParentheses, QPath, TyKind}; use rustc_lint::LateContext; use rustc_span::source_map::Span; @@ -8,7 +8,7 @@ pub(super) fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) let last = last_path_segment(qpath); if_chain! { if let Some(params) = last.args; - if !params.parenthesized; + if params.parenthesized == GenericArgsParentheses::No; if let Some(ty) = params.args.iter().find_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), _ => None, diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index 8ea5475fb25..7dfb0956077 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -10,7 +10,7 @@ def::{CtorOf, DefKind, Res}, def_id::LocalDefId, intravisit::{walk_inf, walk_ty, Visitor}, - Expr, ExprKind, FnRetTy, FnSig, GenericArg, GenericParam, GenericParamKind, HirId, Impl, ImplItemKind, Item, + Expr, ExprKind, FnRetTy, FnSig, GenericArg, GenericArgsParentheses, GenericParam, GenericParamKind, HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind, }; use rustc_hir_analysis::hir_ty_to_ty; @@ -100,7 +100,8 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) { if let TyKind::Path(QPath::Resolved(_, item_path)) = self_ty.kind; let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args; if parameters.as_ref().map_or(true, |params| { - !params.parenthesized && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))) + params.parenthesized == GenericArgsParentheses::No + && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))) }); if !item.span.from_expansion(); if !is_from_proc_macro(cx, item); // expensive, should be last check diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 3a6d23ca5c1..3ee7147828b 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -401,14 +401,9 @@ pub fn eq_path(&mut self, left: &Path<'_>, right: &Path<'_>) -> bool { } fn eq_path_parameters(&mut self, left: &GenericArgs<'_>, right: &GenericArgs<'_>) -> bool { - if !(left.parenthesized || right.parenthesized) { + if left.parenthesized == right.parenthesized { over(left.args, right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work && over(left.bindings, right.bindings, |l, r| self.eq_type_binding(l, r)) - } else if left.parenthesized && right.parenthesized { - over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r)) - && both(&Some(&left.bindings[0].ty()), &Some(&right.bindings[0].ty()), |l, r| { - self.eq_ty(l, r) - }) } else { false } diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs index 68e991de51f..75aa25906aa 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs @@ -11,7 +11,10 @@ async fn method() {} fn foo>() {} //~^ ERROR argument types not allowed with return type notation -fn bar (): Send>>() {} +fn bar (): Send>>() {} //~^ ERROR return type not allowed with return type notation +fn baz>() {} +//~^ ERROR return type notation arguments must be elided with `..` + fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr index 03d97743271..5b075a0fa29 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr @@ -1,3 +1,9 @@ +error: return type not allowed with return type notation + --> $DIR/bad-inputs-and-output.rs:14:28 + | +LL | fn bar (): Send>>() {} + | ^^^^^ help: remove the return type + warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/bad-inputs-and-output.rs:3:12 | @@ -19,13 +25,13 @@ error: argument types not allowed with return type notation --> $DIR/bad-inputs-and-output.rs:11:23 | LL | fn foo>() {} - | ^^^^^ help: remove the input types: `()` + | ^^^^^ help: remove the input types: `(..)` -error: return type not allowed with return type notation - --> $DIR/bad-inputs-and-output.rs:14:25 +error: return type notation arguments must be elided with `..` + --> $DIR/bad-inputs-and-output.rs:17:23 | -LL | fn bar (): Send>>() {} - | ^^^^^^ help: remove the return type +LL | fn baz>() {} + | ^^ help: add `..`: `(..)` -error: aborting due to 2 previous errors; 2 warnings emitted +error: aborting due to 3 previous errors; 2 warnings emitted diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.rs b/tests/ui/associated-type-bounds/return-type-notation/basic.rs index 0b7530b65d7..75d1dc745d1 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.rs @@ -18,7 +18,7 @@ async fn foo() -> Result<(), ()> { fn is_send(_: impl Send) {} fn test< - #[cfg(with)] T: Foo, + #[cfg(with)] T: Foo, #[cfg(without)] T: Foo, >() { is_send(foo::()); diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.rs b/tests/ui/associated-type-bounds/return-type-notation/equality.rs index 75f757e9025..c8fc980974e 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/equality.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.rs @@ -10,7 +10,7 @@ trait Trait { async fn method() {} } -fn test>>>() {} +fn test>>>() {} //~^ ERROR return type notation is not allowed to use type equality fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.stderr b/tests/ui/associated-type-bounds/return-type-notation/equality.stderr index c5b2e5710d4..cd50ff38694 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/equality.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.stderr @@ -18,8 +18,8 @@ LL | #![feature(return_type_notation, async_fn_in_trait)] error: return type notation is not allowed to use type equality --> $DIR/equality.rs:13:18 | -LL | fn test>>>() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn test>>>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error; 2 warnings emitted diff --git a/tests/ui/associated-type-bounds/return-type-notation/missing.rs b/tests/ui/associated-type-bounds/return-type-notation/missing.rs index 7b98a5cdafd..1263cae4477 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/missing.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/missing.rs @@ -8,7 +8,7 @@ trait Trait { async fn method() {} } -fn bar>() {} +fn bar>() {} //~^ ERROR cannot find associated function `methid` in trait `Trait` fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/missing.stderr b/tests/ui/associated-type-bounds/return-type-notation/missing.stderr index 34f5bda884d..93111b5c36b 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/missing.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/missing.stderr @@ -18,8 +18,8 @@ LL | #![feature(return_type_notation, async_fn_in_trait)] error: cannot find associated function `methid` in trait `Trait` --> $DIR/missing.rs:11:17 | -LL | fn bar>() {} - | ^^^^^^^^^^^^^^ +LL | fn bar>() {} + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error; 2 warnings emitted diff --git a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs index db5f6fe389e..d283c6eab37 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs @@ -5,7 +5,7 @@ trait Trait { fn method() {} } -fn test>() {} +fn test>() {} //~^ ERROR return type notation used on function that is not `async` and does not return `impl Trait` fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr index 31b793995f8..38c498bc2fb 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr @@ -13,8 +13,8 @@ error: return type notation used on function that is not `async` and does not re LL | fn method() {} | ----------- this function must be `async` or return `impl Trait` ... -LL | fn test>() {} - | ^^^^^^^^^^^^^^ +LL | fn test>() {} + | ^^^^^^^^^^^^^^^^ | = note: function returns `()`, which is not compatible with associated type return bounds diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr new file mode 100644 index 00000000000..85728f8e1ad --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr @@ -0,0 +1,21 @@ +error[E0658]: return type notation is experimental + --> $DIR/feature-gate-return_type_notation.rs:12:18 + | +LL | fn foo>() {} + | ^^^^ + | + = note: see issue #109417 for more information + = help: add `#![feature(return_type_notation)]` to the crate attributes to enable + +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/feature-gate-return_type_notation.rs:4:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr new file mode 100644 index 00000000000..85728f8e1ad --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr @@ -0,0 +1,21 @@ +error[E0658]: return type notation is experimental + --> $DIR/feature-gate-return_type_notation.rs:12:18 + | +LL | fn foo>() {} + | ^^^^ + | + = note: see issue #109417 for more information + = help: add `#![feature(return_type_notation)]` to the crate attributes to enable + +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/feature-gate-return_type_notation.rs:4:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.rs b/tests/ui/feature-gates/feature-gate-return_type_notation.rs index fea953dcdd0..b75feb130a6 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.rs +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.rs @@ -1,4 +1,5 @@ // edition: 2021 +// revisions: cfg no #![feature(async_fn_in_trait)] //~^ WARN the feature `async_fn_in_trait` is incomplete @@ -7,9 +8,8 @@ trait Trait { async fn m(); } -fn foo>() {} -//~^ ERROR parenthesized generic arguments cannot be used in associated type constraints -//~| ERROR associated type `m` not found for `Trait` -//~| ERROR return type notation is unstable +#[cfg(cfg)] +fn foo>() {} +//~^ ERROR return type notation is experimental fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.stderr deleted file mode 100644 index a9373482e5a..00000000000 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.stderr +++ /dev/null @@ -1,36 +0,0 @@ -error[E0658]: return type notation is unstable - --> $DIR/feature-gate-return_type_notation.rs:10:17 - | -LL | fn foo>() {} - | ^^^^^^^^^ - | - = note: see issue #109417 for more information - = help: add `#![feature(return_type_notation)]` to the crate attributes to enable - -warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/feature-gate-return_type_notation.rs:3:12 - | -LL | #![feature(async_fn_in_trait)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #91611 for more information - = note: `#[warn(incomplete_features)]` on by default - -error: parenthesized generic arguments cannot be used in associated type constraints - --> $DIR/feature-gate-return_type_notation.rs:10:17 - | -LL | fn foo>() {} - | ^-- - | | - | help: remove these parentheses - -error[E0220]: associated type `m` not found for `Trait` - --> $DIR/feature-gate-return_type_notation.rs:10:17 - | -LL | fn foo>() {} - | ^ associated type `m` not found - -error: aborting due to 3 previous errors; 1 warning emitted - -Some errors have detailed explanations: E0220, E0658. -For more information about an error, try `rustc --explain E0220`.