diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index d9272986a7e09..329fa723b1cb0 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1391,6 +1391,7 @@ impl Expr { path.clone(), TraitBoundModifiers::NONE, self.span, + Parens::No, ))), _ => None, } @@ -3360,6 +3361,13 @@ pub struct TraitRef { pub ref_id: NodeId, } +/// Whether enclosing parentheses are present or not. +#[derive(Clone, Encodable, Decodable, Debug)] +pub enum Parens { + Yes, + No, +} + #[derive(Clone, Encodable, Decodable, Debug)] pub struct PolyTraitRef { /// The `'a` in `for<'a> Foo<&'a T>`. @@ -3372,6 +3380,10 @@ pub struct PolyTraitRef { pub trait_ref: TraitRef, pub span: Span, + + /// When `Yes`, the first and last character of `span` are an opening + /// and a closing paren respectively. + pub parens: Parens, } impl PolyTraitRef { @@ -3380,12 +3392,14 @@ impl PolyTraitRef { path: Path, modifiers: TraitBoundModifiers, span: Span, + parens: Parens, ) -> Self { PolyTraitRef { bound_generic_params: generic_params, modifiers, trait_ref: TraitRef { path, ref_id: DUMMY_NODE_ID }, span, + parens, } } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index d0c2b2bf68b0d..867ab7d947898 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1142,7 +1142,7 @@ macro_rules! common_visitor_and_walkers { vis: &mut V, p: &$($lt)? $($mut)? PolyTraitRef, ) -> V::Result { - let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span } = p; + let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span, parens: _ } = p; try_visit!(visit_modifiers(vis, modifiers)); try_visit!(visit_generic_params(vis, bound_generic_params)); try_visit!(vis.visit_trait_ref(trait_ref)); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 26d7c0cd6d38f..d14e27982ef50 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1209,6 +1209,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { modifiers: TraitBoundModifiers::NONE, trait_ref: TraitRef { path: path.clone(), ref_id: t.id }, span: t.span, + parens: ast::Parens::No, }, itctx, ); diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 14b8cc90d97d6..a333f2c7cb787 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -195,6 +195,7 @@ impl<'a> ExtCtxt<'a> { }, trait_ref: self.trait_ref(path), span, + parens: ast::Parens::No, } } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index a868c887493c9..e958908440ed8 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -3,6 +3,7 @@ use std::iter; use rustc_ast::util::{classify, parser}; use rustc_ast::{self as ast, ExprKind, HasAttrs as _, StmtKind}; use rustc_attr_data_structures::{AttributeKind, find_attr}; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::{MultiSpan, pluralize}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -10,6 +11,7 @@ use rustc_hir::{self as hir, LangItem}; use rustc_infer::traits::util::elaborate; use rustc_middle::ty::{self, Ty, adjustment}; use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; +use rustc_span::edition::Edition::Edition2015; use rustc_span::{BytePos, Span, Symbol, kw, sym}; use tracing::instrument; @@ -1032,6 +1034,31 @@ pub(crate) struct UnusedParens { /// `1 as (i32) < 2` parses to ExprKind::Lt /// `1 as i32 < 2` parses to i32::<2[missing angle bracket] parens_in_cast_in_lt: Vec, + /// Ty nodes in this map are in TypeNoBounds position. Any bounds they + /// contain may be ambiguous w/r/t trailing `+` operators. + in_no_bounds_pos: FxHashMap, +} + +/// Whether parentheses may be omitted from a type without resulting in ambiguity. +/// +/// ``` +/// type Example = Box &'static (dyn Send) + Sync>; +/// ``` +/// +/// Here, `&'static (dyn Send) + Sync` is a `TypeNoBounds`. As such, it may not directly +/// contain `ImplTraitType` or `TraitObjectType` which is why `(dyn Send)` is parenthesized. +/// However, an exception is made for `ImplTraitTypeOneBound` and `TraitObjectTypeOneBound`. +/// The following is accepted because there is no `+`. +/// +/// ``` +/// type Example = Box &'static dyn Send>; +/// ``` +enum NoBoundsException { + /// The type must be parenthesized. + None, + /// The type is the last bound of the containing type expression. If it has exactly one bound, + /// parentheses around the type are unnecessary. + OneBound, } impl_lint_pass!(UnusedParens => [UNUSED_PARENS]); @@ -1275,23 +1302,100 @@ impl EarlyLintPass for UnusedParens { ); } ast::TyKind::Paren(r) => { - match &r.kind { - ast::TyKind::TraitObject(..) => {} - ast::TyKind::BareFn(b) - if self.with_self_ty_parens && b.generic_params.len() > 0 => {} - ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {} - _ => { - let spans = if !ty.span.from_expansion() { + let unused_parens = match &r.kind { + ast::TyKind::ImplTrait(_, bounds) | ast::TyKind::TraitObject(bounds, _) => { + match self.in_no_bounds_pos.get(&ty.id) { + Some(NoBoundsException::None) => false, + Some(NoBoundsException::OneBound) => bounds.len() <= 1, + None => true, + } + } + ast::TyKind::BareFn(b) => { + !self.with_self_ty_parens || b.generic_params.is_empty() + } + _ => true, + }; + + if unused_parens { + let spans = (!ty.span.from_expansion()) + .then(|| { r.span .find_ancestor_inside(ty.span) .map(|r| (ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi()))) + }) + .flatten(); + + self.emit_unused_delims(cx, ty.span, spans, "type", (false, false), false); + } + + self.with_self_ty_parens = false; + } + ast::TyKind::Ref(_, mut_ty) | ast::TyKind::Ptr(mut_ty) => { + self.in_no_bounds_pos.insert(mut_ty.ty.id, NoBoundsException::OneBound); + } + ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds) => { + for i in 0..bounds.len() { + let is_last = i == bounds.len() - 1; + + if let ast::GenericBound::Trait(poly_trait_ref) = &bounds[i] { + let fn_with_explicit_ret_ty = if let [.., segment] = + &*poly_trait_ref.trait_ref.path.segments + && let Some(args) = segment.args.as_ref() + && let ast::GenericArgs::Parenthesized(paren_args) = &**args + && let ast::FnRetTy::Ty(ret_ty) = &paren_args.output + { + self.in_no_bounds_pos.insert( + ret_ty.id, + if is_last { + NoBoundsException::OneBound + } else { + NoBoundsException::None + }, + ); + + true } else { - None + false }; - self.emit_unused_delims(cx, ty.span, spans, "type", (false, false), false); + + // In edition 2015, dyn is a contextual keyword and `dyn::foo::Bar` is + // parsed as a path, so parens are necessary to disambiguate. See + // - tests/ui/lint/unused/unused-parens-trait-obj-e2015.rs and + // - https://doc.rust-lang.org/reference/types/trait-object.html#r-type.trait-object.syntax-edition2018 + let dyn2015_exception = cx.sess().psess.edition == Edition2015 + && matches!(ty.kind, ast::TyKind::TraitObject(..)) + && i == 0 + && poly_trait_ref + .trait_ref + .path + .segments + .first() + .map(|s| s.ident.name == kw::PathRoot) + .unwrap_or(false); + + if let ast::Parens::Yes = poly_trait_ref.parens + && (is_last || !fn_with_explicit_ret_ty) + && !dyn2015_exception + { + let s = poly_trait_ref.span; + let spans = (!s.from_expansion()).then(|| { + ( + s.with_hi(s.lo() + rustc_span::BytePos(1)), + s.with_lo(s.hi() - rustc_span::BytePos(1)), + ) + }); + + self.emit_unused_delims( + cx, + poly_trait_ref.span, + spans, + "type", + (false, false), + false, + ); + } } } - self.with_self_ty_parens = false; } _ => {} } @@ -1301,6 +1405,10 @@ impl EarlyLintPass for UnusedParens { ::check_item(self, cx, item) } + fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Item) { + self.in_no_bounds_pos.clear(); + } + fn enter_where_predicate(&mut self, _: &EarlyContext<'_>, pred: &ast::WherePredicate) { use rustc_ast::{WhereBoundPredicate, WherePredicateKind}; if let WherePredicateKind::BoundPredicate(WhereBoundPredicate { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 620a34044d12e..e926be2909203 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -305,8 +305,13 @@ impl<'a> Parser<'a> { let removal_span = kw.span.with_hi(self.token.span.lo()); let path = self.parse_path(PathStyle::Type)?; let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); - let kind = - self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?; + let kind = self.parse_remaining_bounds_path( + lifetime_defs, + path, + lo, + parse_plus, + ast::Parens::No, + )?; let err = self.dcx().create_err(errors::TransposeDynOrImpl { span: kw.span, kw: kw.name.as_str(), @@ -333,7 +338,13 @@ impl<'a> Parser<'a> { } else { let path = self.parse_path(PathStyle::Type)?; let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); - self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)? + self.parse_remaining_bounds_path( + lifetime_defs, + path, + lo, + parse_plus, + ast::Parens::No, + )? } } } else if self.eat_keyword(exp!(Impl)) { @@ -413,9 +424,13 @@ impl<'a> Parser<'a> { let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus(); match ty.kind { // `(TY_BOUND_NOPAREN) + BOUND + ...`. - TyKind::Path(None, path) if maybe_bounds => { - self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true) - } + TyKind::Path(None, path) if maybe_bounds => self.parse_remaining_bounds_path( + ThinVec::new(), + path, + lo, + true, + ast::Parens::Yes, + ), // For `('a) + …`, we know that `'a` in type position already lead to an error being // emitted. To reduce output, let's indirectly suppress E0178 (bad `+` in type) and // other irrelevant consequential errors. @@ -495,12 +510,14 @@ impl<'a> Parser<'a> { path: ast::Path, lo: Span, parse_plus: bool, + parens: ast::Parens, ) -> PResult<'a, TyKind> { let poly_trait_ref = PolyTraitRef::new( generic_params, path, TraitBoundModifiers::NONE, lo.to(self.prev_token.span), + parens, ); let bounds = vec![GenericBound::Trait(poly_trait_ref)]; self.parse_remaining_bounds(bounds, parse_plus) @@ -832,7 +849,7 @@ impl<'a> Parser<'a> { Ok(TyKind::MacCall(P(MacCall { path, args: self.parse_delim_args()? }))) } else if allow_plus == AllowPlus::Yes && self.check_plus() { // `Trait1 + Trait2 + 'a` - self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true) + self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true, ast::Parens::No) } else { // Just a type path. Ok(TyKind::Path(None, path)) @@ -897,10 +914,10 @@ impl<'a> Parser<'a> { fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> { let lo = self.token.span; let leading_token = self.prev_token; - let has_parens = self.eat(exp!(OpenParen)); + let parens = if self.eat(exp!(OpenParen)) { ast::Parens::Yes } else { ast::Parens::No }; let bound = if self.token.is_lifetime() { - self.parse_generic_lt_bound(lo, has_parens)? + self.parse_generic_lt_bound(lo, parens)? } else if self.eat_keyword(exp!(Use)) { // parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of // lifetimes and ident params (including SelfUpper). These are validated later @@ -909,7 +926,7 @@ impl<'a> Parser<'a> { let (args, args_span) = self.parse_precise_capturing_args()?; GenericBound::Use(args, use_span.to(args_span)) } else { - self.parse_generic_ty_bound(lo, has_parens, &leading_token)? + self.parse_generic_ty_bound(lo, parens, &leading_token)? }; Ok(bound) @@ -919,10 +936,14 @@ impl<'a> Parser<'a> { /// ```ebnf /// LT_BOUND = LIFETIME /// ``` - fn parse_generic_lt_bound(&mut self, lo: Span, has_parens: bool) -> PResult<'a, GenericBound> { + fn parse_generic_lt_bound( + &mut self, + lo: Span, + parens: ast::Parens, + ) -> PResult<'a, GenericBound> { let lt = self.expect_lifetime(); let bound = GenericBound::Outlives(lt); - if has_parens { + if let ast::Parens::Yes = parens { // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead, // possibly introducing `GenericBound::Paren(P)`? self.recover_paren_lifetime(lo)?; @@ -1078,7 +1099,7 @@ impl<'a> Parser<'a> { fn parse_generic_ty_bound( &mut self, lo: Span, - has_parens: bool, + parens: ast::Parens, leading_token: &Token, ) -> PResult<'a, GenericBound> { let (mut lifetime_defs, binder_span) = self.parse_late_bound_lifetime_defs()?; @@ -1104,7 +1125,7 @@ impl<'a> Parser<'a> { // e.g. `T: for<'a> 'a` or `T: ~const 'a`. if self.token.is_lifetime() { let _: ErrorGuaranteed = self.error_lt_bound_with_modifiers(modifiers, binder_span); - return self.parse_generic_lt_bound(lo, has_parens); + return self.parse_generic_lt_bound(lo, parens); } if let (more_lifetime_defs, Some(binder_span)) = self.parse_late_bound_lifetime_defs()? { @@ -1171,7 +1192,7 @@ impl<'a> Parser<'a> { self.recover_fn_trait_with_lifetime_params(&mut path, &mut lifetime_defs)?; } - if has_parens { + if let ast::Parens::Yes = parens { // Someone has written something like `&dyn (Trait + Other)`. The correct code // would be `&(dyn Trait + Other)` if self.token.is_like_plus() && leading_token.is_keyword(kw::Dyn) { @@ -1191,7 +1212,7 @@ impl<'a> Parser<'a> { } let poly_trait = - PolyTraitRef::new(lifetime_defs, path, modifiers, lo.to(self.prev_token.span)); + PolyTraitRef::new(lifetime_defs, path, modifiers, lo.to(self.prev_token.span), parens); Ok(GenericBound::Trait(poly_trait)) } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index e7b8c988cd4af..6230b8cfbec7d 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -3832,6 +3832,7 @@ fn mk_where_bound_predicate( ref_id: DUMMY_NODE_ID, }, span: DUMMY_SP, + parens: ast::Parens::No, })], }; diff --git a/library/core/src/error.rs b/library/core/src/error.rs index bfa392003b91b..7f5c6ac42bc1c 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -347,7 +347,7 @@ impl dyn Error { /// let b = B(Some(Box::new(A))); /// /// // let err : Box = b.into(); // or - /// let err = &b as &(dyn Error); + /// let err = &b as &dyn Error; /// /// let mut iter = err.sources(); /// diff --git a/tests/ui/lint/lint-unnecessary-parens.fixed b/tests/ui/lint/lint-unnecessary-parens.fixed index a8c8dd1d512fb..be322a31363de 100644 --- a/tests/ui/lint/lint-unnecessary-parens.fixed +++ b/tests/ui/lint/lint-unnecessary-parens.fixed @@ -1,5 +1,6 @@ //@ run-rustfix +#![feature(impl_trait_in_fn_trait_return)] #![deny(unused_parens)] #![allow(while_true)] // for rustfix @@ -16,11 +17,11 @@ fn bar(y: bool) -> X { return X { y }; //~ ERROR unnecessary parentheses around `return` value } -pub fn unused_parens_around_return_type() -> u32 { //~ ERROR unnecessary parentheses around type +pub fn around_return_type() -> u32 { //~ ERROR unnecessary parentheses around type panic!() } -pub fn unused_parens_around_block_return() -> u32 { +pub fn around_block_return() -> u32 { let _foo = { 5 //~ ERROR unnecessary parentheses around block return value }; @@ -31,10 +32,90 @@ pub trait Trait { fn test(&self); } -pub fn passes_unused_parens_lint() -> &'static (dyn Trait) { +pub fn around_multi_bound_ref() -> &'static (dyn Trait + Send) { panic!() } +//~v ERROR unnecessary parentheses around type +pub fn around_single_bound_ref() -> &'static dyn Trait { + panic!() +} + +pub fn around_multi_bound_ptr() -> *const (dyn Trait + Send) { + panic!() +} + +//~v ERROR unnecessary parentheses around type +pub fn around_single_bound_ptr() -> *const dyn Trait { + panic!() +} + +pub fn around_multi_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send + Sync) { + &|| () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> impl Send { + &|| () +} + +pub fn around_dyn_fn_output_given_more_bounds() -> &'static (dyn FnOnce() -> (impl Send) + Sync) { + &|| () +} + +pub fn around_multi_bound_impl_fn_output() -> impl FnOnce() -> (impl Send + Sync) { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> impl Send { + || () +} + +pub fn around_impl_fn_output_given_more_bounds() -> impl FnOnce() -> (impl Send) + Sync { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_dyn_bound() -> &'static dyn FnOnce() { + &|| () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_impl_trait_bound() -> impl FnOnce() { + || () +} + +// these parens aren't strictly required but they help disambiguate => no lint +pub fn around_fn_bound_with_explicit_ret_ty() -> impl (Fn() -> ()) + Send { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_fn_bound_with_implicit_ret_ty() -> impl Fn() + Send { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + Fn() -> () { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_regular_bound1() -> &'static (dyn Send + Sync) { + &|| () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_regular_bound2() -> &'static (dyn Send + Sync) { + &|| () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_regular_bound3() -> &'static (dyn Send + ::std::marker::Sync) { + &|| () +} + pub fn parens_with_keyword(e: &[()]) -> i32 { if true {} //~ ERROR unnecessary parentheses around `if` while true {} //~ ERROR unnecessary parentheses around `while` diff --git a/tests/ui/lint/lint-unnecessary-parens.rs b/tests/ui/lint/lint-unnecessary-parens.rs index 02aa78283c78f..dccad07311bca 100644 --- a/tests/ui/lint/lint-unnecessary-parens.rs +++ b/tests/ui/lint/lint-unnecessary-parens.rs @@ -1,5 +1,6 @@ //@ run-rustfix +#![feature(impl_trait_in_fn_trait_return)] #![deny(unused_parens)] #![allow(while_true)] // for rustfix @@ -16,11 +17,11 @@ fn bar(y: bool) -> X { return (X { y }); //~ ERROR unnecessary parentheses around `return` value } -pub fn unused_parens_around_return_type() -> (u32) { //~ ERROR unnecessary parentheses around type +pub fn around_return_type() -> (u32) { //~ ERROR unnecessary parentheses around type panic!() } -pub fn unused_parens_around_block_return() -> u32 { +pub fn around_block_return() -> u32 { let _foo = { (5) //~ ERROR unnecessary parentheses around block return value }; @@ -31,10 +32,90 @@ pub trait Trait { fn test(&self); } -pub fn passes_unused_parens_lint() -> &'static (dyn Trait) { +pub fn around_multi_bound_ref() -> &'static (dyn Trait + Send) { panic!() } +//~v ERROR unnecessary parentheses around type +pub fn around_single_bound_ref() -> &'static (dyn Trait) { + panic!() +} + +pub fn around_multi_bound_ptr() -> *const (dyn Trait + Send) { + panic!() +} + +//~v ERROR unnecessary parentheses around type +pub fn around_single_bound_ptr() -> *const (dyn Trait) { + panic!() +} + +pub fn around_multi_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send + Sync) { + &|| () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send) { + &|| () +} + +pub fn around_dyn_fn_output_given_more_bounds() -> &'static (dyn FnOnce() -> (impl Send) + Sync) { + &|| () +} + +pub fn around_multi_bound_impl_fn_output() -> impl FnOnce() -> (impl Send + Sync) { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> (impl Send) { + || () +} + +pub fn around_impl_fn_output_given_more_bounds() -> impl FnOnce() -> (impl Send) + Sync { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_dyn_bound() -> &'static dyn (FnOnce()) { + &|| () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_impl_trait_bound() -> impl (FnOnce()) { + || () +} + +// these parens aren't strictly required but they help disambiguate => no lint +pub fn around_fn_bound_with_explicit_ret_ty() -> impl (Fn() -> ()) + Send { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_fn_bound_with_implicit_ret_ty() -> impl (Fn()) + Send { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + (Fn() -> ()) { + || () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_regular_bound1() -> &'static (dyn (Send) + Sync) { + &|| () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_regular_bound2() -> &'static (dyn Send + (Sync)) { + &|| () +} + +//~v ERROR unnecessary parentheses around type +pub fn around_regular_bound3() -> &'static (dyn Send + (::std::marker::Sync)) { + &|| () +} + pub fn parens_with_keyword(e: &[()]) -> i32 { if(true) {} //~ ERROR unnecessary parentheses around `if` while(true) {} //~ ERROR unnecessary parentheses around `while` diff --git a/tests/ui/lint/lint-unnecessary-parens.stderr b/tests/ui/lint/lint-unnecessary-parens.stderr index f2e5debd6e08f..a7fc1e89c6ccb 100644 --- a/tests/ui/lint/lint-unnecessary-parens.stderr +++ b/tests/ui/lint/lint-unnecessary-parens.stderr @@ -1,11 +1,11 @@ error: unnecessary parentheses around `return` value - --> $DIR/lint-unnecessary-parens.rs:13:12 + --> $DIR/lint-unnecessary-parens.rs:14:12 | LL | return (1); | ^ ^ | note: the lint level is defined here - --> $DIR/lint-unnecessary-parens.rs:3:9 + --> $DIR/lint-unnecessary-parens.rs:4:9 | LL | #![deny(unused_parens)] | ^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL + return 1; | error: unnecessary parentheses around `return` value - --> $DIR/lint-unnecessary-parens.rs:16:12 + --> $DIR/lint-unnecessary-parens.rs:17:12 | LL | return (X { y }); | ^ ^ @@ -28,19 +28,19 @@ LL + return X { y }; | error: unnecessary parentheses around type - --> $DIR/lint-unnecessary-parens.rs:19:46 + --> $DIR/lint-unnecessary-parens.rs:20:32 | -LL | pub fn unused_parens_around_return_type() -> (u32) { - | ^ ^ +LL | pub fn around_return_type() -> (u32) { + | ^ ^ | help: remove these parentheses | -LL - pub fn unused_parens_around_return_type() -> (u32) { -LL + pub fn unused_parens_around_return_type() -> u32 { +LL - pub fn around_return_type() -> (u32) { +LL + pub fn around_return_type() -> u32 { | error: unnecessary parentheses around block return value - --> $DIR/lint-unnecessary-parens.rs:25:9 + --> $DIR/lint-unnecessary-parens.rs:26:9 | LL | (5) | ^ ^ @@ -52,7 +52,7 @@ LL + 5 | error: unnecessary parentheses around block return value - --> $DIR/lint-unnecessary-parens.rs:27:5 + --> $DIR/lint-unnecessary-parens.rs:28:5 | LL | (5) | ^ ^ @@ -63,8 +63,140 @@ LL - (5) LL + 5 | +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:40:46 + | +LL | pub fn around_single_bound_ref() -> &'static (dyn Trait) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_single_bound_ref() -> &'static (dyn Trait) { +LL + pub fn around_single_bound_ref() -> &'static dyn Trait { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:49:44 + | +LL | pub fn around_single_bound_ptr() -> *const (dyn Trait) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_single_bound_ptr() -> *const (dyn Trait) { +LL + pub fn around_single_bound_ptr() -> *const dyn Trait { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:58:72 + | +LL | pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> (impl Send) { +LL + pub fn around_single_bound_dyn_fn_output() -> &'static dyn FnOnce() -> impl Send { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:71:65 + | +LL | pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> (impl Send) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> (impl Send) { +LL + pub fn around_single_bound_impl_fn_output() -> impl FnOnce() -> impl Send { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:80:43 + | +LL | pub fn around_dyn_bound() -> &'static dyn (FnOnce()) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_dyn_bound() -> &'static dyn (FnOnce()) { +LL + pub fn around_dyn_bound() -> &'static dyn FnOnce() { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:85:42 + | +LL | pub fn around_impl_trait_bound() -> impl (FnOnce()) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_impl_trait_bound() -> impl (FnOnce()) { +LL + pub fn around_impl_trait_bound() -> impl FnOnce() { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:95:55 + | +LL | pub fn around_fn_bound_with_implicit_ret_ty() -> impl (Fn()) + Send { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_fn_bound_with_implicit_ret_ty() -> impl (Fn()) + Send { +LL + pub fn around_fn_bound_with_implicit_ret_ty() -> impl Fn() + Send { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:100:67 + | +LL | pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + (Fn() -> ()) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + (Fn() -> ()) { +LL + pub fn around_last_fn_bound_with_explicit_ret_ty() -> impl Send + Fn() -> () { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:105:49 + | +LL | pub fn around_regular_bound1() -> &'static (dyn (Send) + Sync) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_regular_bound1() -> &'static (dyn (Send) + Sync) { +LL + pub fn around_regular_bound1() -> &'static (dyn Send + Sync) { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:110:56 + | +LL | pub fn around_regular_bound2() -> &'static (dyn Send + (Sync)) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_regular_bound2() -> &'static (dyn Send + (Sync)) { +LL + pub fn around_regular_bound2() -> &'static (dyn Send + Sync) { + | + +error: unnecessary parentheses around type + --> $DIR/lint-unnecessary-parens.rs:115:56 + | +LL | pub fn around_regular_bound3() -> &'static (dyn Send + (::std::marker::Sync)) { + | ^ ^ + | +help: remove these parentheses + | +LL - pub fn around_regular_bound3() -> &'static (dyn Send + (::std::marker::Sync)) { +LL + pub fn around_regular_bound3() -> &'static (dyn Send + ::std::marker::Sync) { + | + error: unnecessary parentheses around `if` condition - --> $DIR/lint-unnecessary-parens.rs:39:7 + --> $DIR/lint-unnecessary-parens.rs:120:7 | LL | if(true) {} | ^ ^ @@ -76,7 +208,7 @@ LL + if true {} | error: unnecessary parentheses around `while` condition - --> $DIR/lint-unnecessary-parens.rs:40:10 + --> $DIR/lint-unnecessary-parens.rs:121:10 | LL | while(true) {} | ^ ^ @@ -88,7 +220,7 @@ LL + while true {} | error: unnecessary parentheses around `for` iterator expression - --> $DIR/lint-unnecessary-parens.rs:41:13 + --> $DIR/lint-unnecessary-parens.rs:122:13 | LL | for _ in(e) {} | ^ ^ @@ -100,7 +232,7 @@ LL + for _ in e {} | error: unnecessary parentheses around `match` scrutinee expression - --> $DIR/lint-unnecessary-parens.rs:42:10 + --> $DIR/lint-unnecessary-parens.rs:123:10 | LL | match(1) { _ => ()} | ^ ^ @@ -112,7 +244,7 @@ LL + match 1 { _ => ()} | error: unnecessary parentheses around `return` value - --> $DIR/lint-unnecessary-parens.rs:43:11 + --> $DIR/lint-unnecessary-parens.rs:124:11 | LL | return(1); | ^ ^ @@ -124,7 +256,7 @@ LL + return 1; | error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:74:31 + --> $DIR/lint-unnecessary-parens.rs:155:31 | LL | pub const CONST_ITEM: usize = (10); | ^ ^ @@ -136,7 +268,7 @@ LL + pub const CONST_ITEM: usize = 10; | error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:75:33 + --> $DIR/lint-unnecessary-parens.rs:156:33 | LL | pub static STATIC_ITEM: usize = (10); | ^ ^ @@ -148,7 +280,7 @@ LL + pub static STATIC_ITEM: usize = 10; | error: unnecessary parentheses around function argument - --> $DIR/lint-unnecessary-parens.rs:79:9 + --> $DIR/lint-unnecessary-parens.rs:160:9 | LL | bar((true)); | ^ ^ @@ -160,7 +292,7 @@ LL + bar(true); | error: unnecessary parentheses around `if` condition - --> $DIR/lint-unnecessary-parens.rs:81:8 + --> $DIR/lint-unnecessary-parens.rs:162:8 | LL | if (true) {} | ^ ^ @@ -172,7 +304,7 @@ LL + if true {} | error: unnecessary parentheses around `while` condition - --> $DIR/lint-unnecessary-parens.rs:82:11 + --> $DIR/lint-unnecessary-parens.rs:163:11 | LL | while (true) {} | ^ ^ @@ -184,7 +316,7 @@ LL + while true {} | error: unnecessary parentheses around `match` scrutinee expression - --> $DIR/lint-unnecessary-parens.rs:83:11 + --> $DIR/lint-unnecessary-parens.rs:164:11 | LL | match (true) { | ^ ^ @@ -196,7 +328,7 @@ LL + match true { | error: unnecessary parentheses around `let` scrutinee expression - --> $DIR/lint-unnecessary-parens.rs:86:16 + --> $DIR/lint-unnecessary-parens.rs:167:16 | LL | if let 1 = (1) {} | ^ ^ @@ -208,7 +340,7 @@ LL + if let 1 = 1 {} | error: unnecessary parentheses around `let` scrutinee expression - --> $DIR/lint-unnecessary-parens.rs:87:19 + --> $DIR/lint-unnecessary-parens.rs:168:19 | LL | while let 1 = (2) {} | ^ ^ @@ -220,7 +352,7 @@ LL + while let 1 = 2 {} | error: unnecessary parentheses around method argument - --> $DIR/lint-unnecessary-parens.rs:103:24 + --> $DIR/lint-unnecessary-parens.rs:184:24 | LL | X { y: false }.foo((true)); | ^ ^ @@ -232,7 +364,7 @@ LL + X { y: false }.foo(true); | error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:105:18 + --> $DIR/lint-unnecessary-parens.rs:186:18 | LL | let mut _a = (0); | ^ ^ @@ -244,7 +376,7 @@ LL + let mut _a = 0; | error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:106:10 + --> $DIR/lint-unnecessary-parens.rs:187:10 | LL | _a = (0); | ^ ^ @@ -256,7 +388,7 @@ LL + _a = 0; | error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:107:11 + --> $DIR/lint-unnecessary-parens.rs:188:11 | LL | _a += (1); | ^ ^ @@ -268,7 +400,7 @@ LL + _a += 1; | error: unnecessary parentheses around pattern - --> $DIR/lint-unnecessary-parens.rs:109:8 + --> $DIR/lint-unnecessary-parens.rs:190:8 | LL | let(mut _a) = 3; | ^ ^ @@ -280,7 +412,7 @@ LL + let mut _a = 3; | error: unnecessary parentheses around pattern - --> $DIR/lint-unnecessary-parens.rs:110:9 + --> $DIR/lint-unnecessary-parens.rs:191:9 | LL | let (mut _a) = 3; | ^ ^ @@ -292,7 +424,7 @@ LL + let mut _a = 3; | error: unnecessary parentheses around pattern - --> $DIR/lint-unnecessary-parens.rs:111:8 + --> $DIR/lint-unnecessary-parens.rs:192:8 | LL | let( mut _a) = 3; | ^^ ^ @@ -304,7 +436,7 @@ LL + let mut _a = 3; | error: unnecessary parentheses around pattern - --> $DIR/lint-unnecessary-parens.rs:113:8 + --> $DIR/lint-unnecessary-parens.rs:194:8 | LL | let(_a) = 3; | ^ ^ @@ -316,7 +448,7 @@ LL + let _a = 3; | error: unnecessary parentheses around pattern - --> $DIR/lint-unnecessary-parens.rs:114:9 + --> $DIR/lint-unnecessary-parens.rs:195:9 | LL | let (_a) = 3; | ^ ^ @@ -328,7 +460,7 @@ LL + let _a = 3; | error: unnecessary parentheses around pattern - --> $DIR/lint-unnecessary-parens.rs:115:8 + --> $DIR/lint-unnecessary-parens.rs:196:8 | LL | let( _a) = 3; | ^^ ^ @@ -340,7 +472,7 @@ LL + let _a = 3; | error: unnecessary parentheses around block return value - --> $DIR/lint-unnecessary-parens.rs:121:9 + --> $DIR/lint-unnecessary-parens.rs:202:9 | LL | (unit!() - One) | ^ ^ @@ -352,7 +484,7 @@ LL + unit!() - One | error: unnecessary parentheses around block return value - --> $DIR/lint-unnecessary-parens.rs:123:9 + --> $DIR/lint-unnecessary-parens.rs:204:9 | LL | (unit![] - One) | ^ ^ @@ -364,7 +496,7 @@ LL + unit![] - One | error: unnecessary parentheses around block return value - --> $DIR/lint-unnecessary-parens.rs:126:9 + --> $DIR/lint-unnecessary-parens.rs:207:9 | LL | (unit! {} - One) | ^ ^ @@ -376,7 +508,7 @@ LL + unit! {} - One | error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:131:14 + --> $DIR/lint-unnecessary-parens.rs:212:14 | LL | let _r = (&x); | ^ ^ @@ -388,7 +520,7 @@ LL + let _r = &x; | error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:132:14 + --> $DIR/lint-unnecessary-parens.rs:213:14 | LL | let _r = (&mut x); | ^ ^ @@ -399,5 +531,5 @@ LL - let _r = (&mut x); LL + let _r = &mut x; | -error: aborting due to 33 previous errors +error: aborting due to 44 previous errors diff --git a/tests/ui/lint/unused/issue-105061-should-lint.rs b/tests/ui/lint/unused/issue-105061-should-lint.rs index 433c288208910..74a0ff83739a8 100644 --- a/tests/ui/lint/unused/issue-105061-should-lint.rs +++ b/tests/ui/lint/unused/issue-105061-should-lint.rs @@ -14,7 +14,7 @@ where trait Hello {} fn with_dyn_bound() where - (dyn Hello<(for<'b> fn(&'b ()))>): Hello //~ ERROR unnecessary parentheses around type + dyn Hello<(for<'b> fn(&'b ()))>: Hello //~ ERROR unnecessary parentheses around type {} fn main() { diff --git a/tests/ui/lint/unused/issue-105061-should-lint.stderr b/tests/ui/lint/unused/issue-105061-should-lint.stderr index e591f1ffb6b89..ae69f018eae97 100644 --- a/tests/ui/lint/unused/issue-105061-should-lint.stderr +++ b/tests/ui/lint/unused/issue-105061-should-lint.stderr @@ -17,15 +17,15 @@ LL + for<'b> for<'a> fn(Inv<'a>): Trait<'b>, | error: unnecessary parentheses around type - --> $DIR/issue-105061-should-lint.rs:17:16 + --> $DIR/issue-105061-should-lint.rs:17:15 | -LL | (dyn Hello<(for<'b> fn(&'b ()))>): Hello - | ^ ^ +LL | dyn Hello<(for<'b> fn(&'b ()))>: Hello + | ^ ^ | help: remove these parentheses | -LL - (dyn Hello<(for<'b> fn(&'b ()))>): Hello -LL + (dyn Hello fn(&'b ())>): Hello +LL - dyn Hello<(for<'b> fn(&'b ()))>: Hello +LL + dyn Hello fn(&'b ())>: Hello | error: aborting due to 2 previous errors diff --git a/tests/ui/lint/unused/unused-parens-trait-obj.edition2018.fixed b/tests/ui/lint/unused/unused-parens-trait-obj.edition2018.fixed new file mode 100644 index 0000000000000..f95418868e15f --- /dev/null +++ b/tests/ui/lint/unused/unused-parens-trait-obj.edition2018.fixed @@ -0,0 +1,27 @@ +//@ revisions: edition2015 edition2018 +//@[edition2015] check-pass +//@[edition2015] edition: 2015 +//@[edition2018] run-rustfix +//@[edition2018] edition: 2018 + +#![deny(unused_parens)] + +#[allow(unused)] +macro_rules! edition2015_only { + () => { + mod dyn { + pub type IsAContextualKeywordIn2015 = (); + } + + pub type DynIsAContextualKeywordIn2015A = dyn::IsAContextualKeywordIn2015; + } +} + +#[cfg(edition2015)] +edition2015_only!(); + +// there's a lint for 2018 and later only because of how dyn is parsed in edition 2015 +//[edition2018]~v ERROR unnecessary parentheses around type +pub type DynIsAContextualKeywordIn2015B = Box; + +fn main() {} diff --git a/tests/ui/lint/unused/unused-parens-trait-obj.edition2018.stderr b/tests/ui/lint/unused/unused-parens-trait-obj.edition2018.stderr new file mode 100644 index 0000000000000..aed8cec68e8da --- /dev/null +++ b/tests/ui/lint/unused/unused-parens-trait-obj.edition2018.stderr @@ -0,0 +1,19 @@ +error: unnecessary parentheses around type + --> $DIR/unused-parens-trait-obj.rs:25:51 + | +LL | pub type DynIsAContextualKeywordIn2015B = Box; + | ^ ^ + | +note: the lint level is defined here + --> $DIR/unused-parens-trait-obj.rs:7:9 + | +LL | #![deny(unused_parens)] + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - pub type DynIsAContextualKeywordIn2015B = Box; +LL + pub type DynIsAContextualKeywordIn2015B = Box; + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/unused/unused-parens-trait-obj.rs b/tests/ui/lint/unused/unused-parens-trait-obj.rs new file mode 100644 index 0000000000000..2192baa2e0205 --- /dev/null +++ b/tests/ui/lint/unused/unused-parens-trait-obj.rs @@ -0,0 +1,27 @@ +//@ revisions: edition2015 edition2018 +//@[edition2015] check-pass +//@[edition2015] edition: 2015 +//@[edition2018] run-rustfix +//@[edition2018] edition: 2018 + +#![deny(unused_parens)] + +#[allow(unused)] +macro_rules! edition2015_only { + () => { + mod dyn { + pub type IsAContextualKeywordIn2015 = (); + } + + pub type DynIsAContextualKeywordIn2015A = dyn::IsAContextualKeywordIn2015; + } +} + +#[cfg(edition2015)] +edition2015_only!(); + +// there's a lint for 2018 and later only because of how dyn is parsed in edition 2015 +//[edition2018]~v ERROR unnecessary parentheses around type +pub type DynIsAContextualKeywordIn2015B = Box; + +fn main() {} diff --git a/tests/ui/sanitizer/cfi/closures.rs b/tests/ui/sanitizer/cfi/closures.rs index 9f9002da674f5..424e70560dbb4 100644 --- a/tests/ui/sanitizer/cfi/closures.rs +++ b/tests/ui/sanitizer/cfi/closures.rs @@ -31,7 +31,7 @@ fn dyn_fn_with_params() { #[test] fn call_fn_trait() { - let f: &(dyn Fn()) = &(|| {}) as _; + let f: &dyn Fn() = &(|| {}) as _; f.call(()); } @@ -47,7 +47,7 @@ fn use_fnmut(mut f: F) { #[test] fn fn_to_fnmut() { - let f: &(dyn Fn()) = &(|| {}) as _; + let f: &dyn Fn() = &(|| {}) as _; use_fnmut(f); } diff --git a/tests/ui/traits/dyn-trait.rs b/tests/ui/traits/dyn-trait.rs index 4fb7aea5cbabe..a378ce5a696fd 100644 --- a/tests/ui/traits/dyn-trait.rs +++ b/tests/ui/traits/dyn-trait.rs @@ -7,7 +7,7 @@ static BYTE: u8 = 33; fn main() { let x: &(dyn 'static + Display) = &BYTE; let y: Box = Box::new(BYTE); - let _: &dyn (Display) = &BYTE; + let _: &dyn Display = &BYTE; let _: &dyn (::std::fmt::Display) = &BYTE; let xstr = format!("{}", x); let ystr = format!("{}", y); diff --git a/tests/ui/traits/impl-2.rs b/tests/ui/traits/impl-2.rs index 41fa1cd334f40..eafbaeaa167b9 100644 --- a/tests/ui/traits/impl-2.rs +++ b/tests/ui/traits/impl-2.rs @@ -10,7 +10,7 @@ pub mod Foo { } mod Bar { - impl<'a> dyn (crate::Foo::Trait) + 'a { + impl<'a> dyn crate::Foo::Trait + 'a { fn bar(&self) { self.foo() } } }