diff options
| author | bors <bors@rust-lang.org> | 2022-03-06 07:22:09 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-03-06 07:22:09 +0000 |
| commit | ad0d1d71d3bc6f85f53d8ab2bf47daa7c8bc2c51 (patch) | |
| tree | 1770b05f82d090b965fbad680818a99c26482ef4 /compiler | |
| parent | 5d9d1e88910f2c7f58e8258b87d30b1340b647fa (diff) | |
| parent | d16ec7b9d1bc6550af3a68e250582a628f5be800 (diff) | |
| download | rust-ad0d1d71d3bc6f85f53d8ab2bf47daa7c8bc2c51.tar.gz rust-ad0d1d71d3bc6f85f53d8ab2bf47daa7c8bc2c51.zip | |
Auto merge of #90076 - jackh726:wherethewhere, r=nikomatsakis
Change location of where clause on GATs Closes #89122 ~Blocked on lang FCP~ r? `@nikomatsakis`
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_ast/src/ast.rs | 27 | ||||
| -rw-r--r-- | compiler/rustc_ast/src/mut_visit.rs | 28 | ||||
| -rw-r--r-- | compiler/rustc_ast/src/visit.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_ast_lowering/src/item.rs | 59 | ||||
| -rw-r--r-- | compiler/rustc_ast_passes/src/ast_validation.rs | 91 | ||||
| -rw-r--r-- | compiler/rustc_ast_pretty/src/pprust/state/item.rs | 38 | ||||
| -rw-r--r-- | compiler/rustc_builtin_macros/src/deriving/generic/mod.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/context.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_lint_defs/src/builtin.rs | 34 | ||||
| -rw-r--r-- | compiler/rustc_lint_defs/src/lib.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 82 |
11 files changed, 301 insertions, 80 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 725499e5c78..ed5a282ec06 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2662,10 +2662,37 @@ pub struct Trait { pub items: Vec<P<AssocItem>>, } +/// The location of a where clause on a `TyAlias` (`Span`) and whether there was +/// a `where` keyword (`bool`). This is split out from `WhereClause`, since there +/// are two locations for where clause on type aliases, but their predicates +/// are concatenated together. +/// +/// Take this example: +/// ```ignore (only-for-syntax-highlight) +/// trait Foo { +/// type Assoc<'a, 'b> where Self: 'a, Self: 'b; +/// } +/// impl Foo for () { +/// type Assoc<'a, 'b> where Self: 'a = () where Self: 'b; +/// // ^^^^^^^^^^^^^^ first where clause +/// // ^^^^^^^^^^^^^^ second where clause +/// } +/// ``` +/// +/// If there is no where clause, then this is `false` with `DUMMY_SP`. +#[derive(Copy, Clone, Encodable, Decodable, Debug, Default)] +pub struct TyAliasWhereClause(pub bool, pub Span); + #[derive(Clone, Encodable, Decodable, Debug)] pub struct TyAlias { pub defaultness: Defaultness, pub generics: Generics, + /// The span information for the two where clauses (before equals, after equals) + pub where_clauses: (TyAliasWhereClause, TyAliasWhereClause), + /// The index in `generics.where_clause.predicates` that would split into + /// predicates from the where clause before the equals and the predicates + /// from the where clause after the equals + pub where_predicates_split: usize, pub bounds: GenericBounds, pub ty: Option<P<Ty>>, } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index a81a2276295..c60c77e6987 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1018,9 +1018,13 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) { } ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm), ItemKind::GlobalAsm(asm) => noop_visit_inline_asm(asm, vis), - ItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => { + ItemKind::TyAlias(box TyAlias { + defaultness, generics, where_clauses, bounds, ty, .. + }) => { visit_defaultness(defaultness, vis); vis.visit_generics(generics); + vis.visit_span(&mut where_clauses.0.1); + vis.visit_span(&mut where_clauses.1.1); visit_bounds(bounds, vis); visit_opt(ty, |ty| vis.visit_ty(ty)); } @@ -1087,9 +1091,18 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>( visit_fn_sig(sig, visitor); visit_opt(body, |body| visitor.visit_block(body)); } - AssocItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => { + AssocItemKind::TyAlias(box TyAlias { + defaultness, + generics, + where_clauses, + bounds, + ty, + .. + }) => { visit_defaultness(defaultness, visitor); visitor.visit_generics(generics); + visitor.visit_span(&mut where_clauses.0.1); + visitor.visit_span(&mut where_clauses.1.1); visit_bounds(bounds, visitor); visit_opt(ty, |ty| visitor.visit_ty(ty)); } @@ -1152,9 +1165,18 @@ pub fn noop_flat_map_foreign_item<T: MutVisitor>( visit_fn_sig(sig, visitor); visit_opt(body, |body| visitor.visit_block(body)); } - ForeignItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => { + ForeignItemKind::TyAlias(box TyAlias { + defaultness, + generics, + where_clauses, + bounds, + ty, + .. + }) => { visit_defaultness(defaultness, visitor); visitor.visit_generics(generics); + visitor.visit_span(&mut where_clauses.0.1); + visitor.visit_span(&mut where_clauses.1.1); visit_bounds(bounds, visitor); visit_opt(ty, |ty| visitor.visit_ty(ty)); } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 73e9297549c..ed16c25d921 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -303,7 +303,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { walk_list!(visitor, visit_foreign_item, &foreign_module.items); } ItemKind::GlobalAsm(ref asm) => walk_inline_asm(visitor, asm), - ItemKind::TyAlias(box TyAlias { defaultness: _, ref generics, ref bounds, ref ty }) => { + ItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => { visitor.visit_generics(generics); walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_ty, ty); @@ -559,7 +559,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, body.as_deref()); visitor.visit_fn(kind, span, id); } - ForeignItemKind::TyAlias(box TyAlias { defaultness: _, generics, bounds, ty }) => { + ForeignItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => { visitor.visit_generics(generics); walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_ty, ty); @@ -665,7 +665,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem, let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, body.as_deref()); visitor.visit_fn(kind, span, id); } - AssocItemKind::TyAlias(box TyAlias { defaultness: _, generics, bounds, ty }) => { + AssocItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => { visitor.visit_generics(generics); walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_ty, ty); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index e8fca6f04ba..b452290dff4 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -25,6 +25,26 @@ pub(super) struct ItemLowerer<'a, 'lowering, 'hir> { pub(super) lctx: &'a mut LoweringContext<'lowering, 'hir>, } +/// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span +/// to the where clause that is prefered, if it exists. Otherwise, it sets the span to the other where +/// clause if it exists. +fn add_ty_alias_where_clause( + generics: &mut ast::Generics, + mut where_clauses: (TyAliasWhereClause, TyAliasWhereClause), + prefer_first: bool, +) { + if !prefer_first { + where_clauses = (where_clauses.1, where_clauses.0); + } + if where_clauses.0.0 || !where_clauses.1.0 { + generics.where_clause.has_where_token = where_clauses.0.0; + generics.where_clause.span = where_clauses.0.1; + } else { + generics.where_clause.has_where_token = where_clauses.1.0; + generics.where_clause.span = where_clauses.1.1; + } +} + impl ItemLowerer<'_, '_, '_> { fn with_trait_impl_ref<T>( &mut self, @@ -277,7 +297,12 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::GlobalAsm(ref asm) => { hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm)) } - ItemKind::TyAlias(box TyAlias { ref generics, ty: Some(ref ty), .. }) => { + ItemKind::TyAlias(box TyAlias { + ref generics, + where_clauses, + ty: Some(ref ty), + .. + }) => { // We lower // // type Foo = impl Trait @@ -292,16 +317,22 @@ impl<'hir> LoweringContext<'_, 'hir> { capturable_lifetimes: &mut FxHashSet::default(), }, ); + let mut generics = generics.clone(); + add_ty_alias_where_clause(&mut generics, where_clauses, true); let generics = self.lower_generics( - generics, + &generics, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), ); hir::ItemKind::TyAlias(ty, generics) } - ItemKind::TyAlias(box TyAlias { ref generics, ty: None, .. }) => { + ItemKind::TyAlias(box TyAlias { + ref generics, ref where_clauses, ty: None, .. + }) => { let ty = self.arena.alloc(self.ty(span, hir::TyKind::Err)); + let mut generics = generics.clone(); + add_ty_alias_where_clause(&mut generics, *where_clauses, true); let generics = self.lower_generics( - generics, + &generics, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), ); hir::ItemKind::TyAlias(ty, generics) @@ -832,18 +863,26 @@ impl<'hir> LoweringContext<'_, 'hir> { ); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id))) } - AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => { + AssocItemKind::TyAlias(box TyAlias { + ref generics, + where_clauses, + ref bounds, + ref ty, + .. + }) => { let ty = ty.as_ref().map(|x| { self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type)) }); + let mut generics = generics.clone(); + add_ty_alias_where_clause(&mut generics, where_clauses, false); let generics = self.lower_generics( - generics, + &generics, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), ); let kind = hir::TraitItemKind::Type( self.lower_param_bounds( bounds, - ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), ), ty, ); @@ -917,9 +956,11 @@ impl<'hir> LoweringContext<'_, 'hir> { (generics, hir::ImplItemKind::Fn(sig, body_id)) } - AssocItemKind::TyAlias(box TyAlias { generics, ty, .. }) => { + AssocItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => { + let mut generics = generics.clone(); + add_ty_alias_where_clause(&mut generics, *where_clauses, false); let generics = self.lower_generics( - generics, + &generics, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), ); let kind = match ty { diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 20caed1b230..0cf73178d67 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -11,11 +11,13 @@ use rustc_ast::ptr::P; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::walk_list; use rustc_ast::*; -use rustc_ast_pretty::pprust; +use rustc_ast_pretty::pprust::{self, State}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{error_code, pluralize, struct_span_err, Applicability}; use rustc_parse::validate_attr; -use rustc_session::lint::builtin::{MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY}; +use rustc_session::lint::builtin::{ + DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY, +}; use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; use rustc_session::Session; use rustc_span::source_map::Spanned; @@ -122,6 +124,42 @@ impl<'a> AstValidator<'a> { } } + fn check_gat_where( + &mut self, + id: NodeId, + before_predicates: &[WherePredicate], + where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause), + ) { + if !before_predicates.is_empty() { + let mut state = State::new(); + if !where_clauses.1.0 { + state.space(); + state.word_space("where"); + } else { + state.word_space(","); + } + let mut first = true; + for p in before_predicates.iter() { + if !first { + state.word_space(","); + } + first = false; + state.print_where_predicate(p); + } + let suggestion = state.s.eof(); + self.lint_buffer.buffer_lint_with_diagnostic( + DEPRECATED_WHERE_CLAUSE_LOCATION, + id, + where_clauses.0.1, + "where clause not allowed here", + BuiltinLintDiagnostics::DeprecatedWhereclauseLocation( + where_clauses.1.1.shrink_to_hi(), + suggestion, + ), + ); + } + } + fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) { let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true); f(self); @@ -454,7 +492,7 @@ impl<'a> AstValidator<'a> { .emit(); } - fn check_foreign_ty_genericless(&self, generics: &Generics) { + fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) { let cannot_have = |span, descr, remove_descr| { self.err_handler() .struct_span_err( @@ -477,7 +515,7 @@ impl<'a> AstValidator<'a> { } if !generics.where_clause.predicates.is_empty() { - cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause"); + cannot_have(where_span, "`where` clauses", "`where` clause"); } } @@ -1223,13 +1261,29 @@ impl<'a> Visitor<'a> for AstValidator<'a> { let msg = "free static item without body"; self.error_item_without_body(item.span, "static", msg, " = <expr>;"); } - ItemKind::TyAlias(box TyAlias { defaultness, ref bounds, ref ty, .. }) => { + ItemKind::TyAlias(box TyAlias { + defaultness, + where_clauses, + ref bounds, + ref ty, + .. + }) => { self.check_defaultness(item.span, defaultness); if ty.is_none() { let msg = "free type alias without body"; self.error_item_without_body(item.span, "type", msg, " = <type>;"); } self.check_type_no_bounds(bounds, "this context"); + if where_clauses.1.0 { + let mut err = self.err_handler().struct_span_err( + where_clauses.1.1, + "where clauses are not allowed after the type for type aliases", + ); + err.note( + "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information", + ); + err.emit(); + } } _ => {} } @@ -1245,11 +1299,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header); self.check_foreign_item_ascii_only(fi.ident); } - ForeignItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty, .. }) => { + ForeignItemKind::TyAlias(box TyAlias { + defaultness, + generics, + where_clauses, + bounds, + ty, + .. + }) => { self.check_defaultness(fi.span, *defaultness); self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span)); self.check_type_no_bounds(bounds, "`extern` blocks"); - self.check_foreign_ty_genericless(generics); + self.check_foreign_ty_genericless(generics, where_clauses.0.1); self.check_foreign_item_ascii_only(fi.ident); } ForeignItemKind::Static(_, _, body) => { @@ -1503,9 +1564,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> { AssocItemKind::Fn(box Fn { body, .. }) => { self.check_impl_item_provided(item.span, body, "function", " { <body> }"); } - AssocItemKind::TyAlias(box TyAlias { bounds, ty, .. }) => { + AssocItemKind::TyAlias(box TyAlias { + generics, + where_clauses, + where_predicates_split, + bounds, + ty, + .. + }) => { self.check_impl_item_provided(item.span, ty, "type", " = <type>;"); self.check_type_no_bounds(bounds, "`impl`s"); + if ty.is_some() { + self.check_gat_where( + item.id, + generics.where_clause.predicates.split_at(*where_predicates_split).0, + *where_clauses, + ); + } } _ => {} } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index d7e9ef0e50d..2a35dd1006e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -36,12 +36,16 @@ impl<'a> State<'a> { ast::ForeignItemKind::TyAlias(box ast::TyAlias { defaultness, generics, + where_clauses, + where_predicates_split, bounds, ty, }) => { self.print_associated_type( ident, generics, + *where_clauses, + *where_predicates_split, bounds, ty.as_deref(), vis, @@ -95,11 +99,15 @@ impl<'a> State<'a> { &mut self, ident: Ident, generics: &ast::Generics, + where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause), + where_predicates_split: usize, bounds: &ast::GenericBounds, ty: Option<&ast::Ty>, vis: &ast::Visibility, defaultness: ast::Defaultness, ) { + let (before_predicates, after_predicates) = + generics.where_clause.predicates.split_at(where_predicates_split); self.head(""); self.print_visibility(vis); self.print_defaultness(defaultness); @@ -107,12 +115,13 @@ impl<'a> State<'a> { self.print_ident(ident); self.print_generic_params(&generics.params); self.print_type_bounds(":", bounds); - self.print_where_clause(&generics.where_clause); + self.print_where_clause_parts(where_clauses.0.0, before_predicates); if let Some(ty) = ty { self.space(); self.word_space("="); self.print_type(ty); } + self.print_where_clause_parts(where_clauses.1.0, after_predicates); self.word(";"); self.end(); // end inner head-block self.end(); // end outer head-block @@ -211,6 +220,8 @@ impl<'a> State<'a> { ast::ItemKind::TyAlias(box ast::TyAlias { defaultness, ref generics, + where_clauses, + where_predicates_split, ref bounds, ref ty, }) => { @@ -218,6 +229,8 @@ impl<'a> State<'a> { self.print_associated_type( item.ident, generics, + where_clauses, + where_predicates_split, bounds, ty, &item.vis, @@ -496,10 +509,19 @@ impl<'a> State<'a> { ast::AssocItemKind::Const(def, ty, body) => { self.print_item_const(ident, None, ty, body.as_deref(), vis, *def); } - ast::AssocItemKind::TyAlias(box ast::TyAlias { defaultness, generics, bounds, ty }) => { + ast::AssocItemKind::TyAlias(box ast::TyAlias { + defaultness, + generics, + where_clauses, + where_predicates_split, + bounds, + ty, + }) => { self.print_associated_type( ident, generics, + *where_clauses, + *where_predicates_split, bounds, ty.as_deref(), vis, @@ -566,14 +588,22 @@ impl<'a> State<'a> { } fn print_where_clause(&mut self, where_clause: &ast::WhereClause) { - if where_clause.predicates.is_empty() && !where_clause.has_where_token { + self.print_where_clause_parts(where_clause.has_where_token, &where_clause.predicates); + } + + crate fn print_where_clause_parts( + &mut self, + has_where_token: bool, + predicates: &[ast::WherePredicate], + ) { + if predicates.is_empty() && !has_where_token { return; } self.space(); self.word_space("where"); - for (i, predicate) in where_clause.predicates.iter().enumerate() { + for (i, predicate) in predicates.iter().enumerate() { if i != 0 { self.word_space(","); } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 985c45e2253..f87f4726d1c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -560,6 +560,11 @@ impl<'a> TraitDef<'a> { kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAlias { defaultness: ast::Defaultness::Final, generics: Generics::default(), + where_clauses: ( + ast::TyAliasWhereClause::default(), + ast::TyAliasWhereClause::default(), + ), + where_predicates_split: 0, bounds: Vec::new(), ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)), })), diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index c6bbf769b23..b892e520d3b 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -818,6 +818,16 @@ pub trait LintContext: Sized { } } }, + BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(new_span, suggestion) => { + db.multipart_suggestion( + "move it to the end of the type declaration", + vec![(db.span.primary_span().unwrap(), "".to_string()), (new_span, suggestion)], + Applicability::MachineApplicable, + ); + db.note( + "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information", + ); + }, } // Rewrap `db`, and pass control to the user. decorate(LintDiagnosticBuilder::new(db)); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 272913f3f0e..04a339f3c95 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3127,6 +3127,7 @@ declare_lint_pass! { DUPLICATE_MACRO_ATTRIBUTES, SUSPICIOUS_AUTO_TRAIT_IMPLS, UNEXPECTED_CFGS, + DEPRECATED_WHERE_CLAUSE_LOCATION, ] } @@ -3737,3 +3738,36 @@ declare_lint! { reference: "issue #93367 <https://github.com/rust-lang/rust/issues/93367>", }; } + +declare_lint! { + /// The `deprecated_where_clause_location` lint detects when a where clause in front of the equals + /// in an associated type. + /// + /// ### Example + /// + /// ```rust + /// #![feature(generic_associated_types)] + /// + /// trait Trait { + /// type Assoc<'a> where Self: 'a; + /// } + /// + /// impl Trait for () { + /// type Assoc<'a> where Self: 'a = (); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The preferred location for where clauses on associated types in impls + /// is after the type. However, for most of generic associated types development, + /// it was only accepted before the equals. To provide a transition period and + /// further evaluate this change, both are currently accepted. At some point in + /// the future, this may be disallowed at an edition boundary; but, that is + /// undecided currently. + pub DEPRECATED_WHERE_CLAUSE_LOCATION, + Warn, + "deprecated where clause location" +} diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index e7f6dfa67b9..cd328b08735 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -427,6 +427,7 @@ pub enum BuiltinLintDiagnostics { NamedAsmLabel(String), UnicodeTextFlow(Span, String), UnexpectedCfg((Symbol, Span), Option<(Symbol, Span)>), + DeprecatedWhereclauseLocation(Span, String), } /// Lints that are buffered up early on in the `Session` before the diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 4f91f1fecba..5db1e4e0523 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -13,11 +13,12 @@ use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, Vari use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind}; use rustc_ast::{MacArgs, MacCall, MacDelimiter}; use rustc_ast_pretty::pprust; -use rustc_errors::{struct_span_err, Applicability, ErrorGuaranteed, PResult, StashKey}; +use rustc_errors::{struct_span_err, Applicability, PResult, StashKey}; use rustc_span::edition::{Edition, LATEST_STABLE_EDITION}; use rustc_span::lev_distance::lev_distance; use rustc_span::source_map::{self, Span}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::DUMMY_SP; use std::convert::TryFrom; use std::mem; @@ -801,44 +802,6 @@ impl<'a> Parser<'a> { )) } - /// Emits an error that the where clause at the end of a type alias is not - /// allowed and suggests moving it. - fn error_ty_alias_where( - &self, - before_where_clause_present: bool, - before_where_clause_span: Span, - after_predicates: &[WherePredicate], - after_where_clause_span: Span, - ) -> ErrorGuaranteed { - let mut err = - self.struct_span_err(after_where_clause_span, "where clause not allowed here"); - if !after_predicates.is_empty() { - let mut state = crate::pprust::State::new(); - if !before_where_clause_present { - state.space(); - state.word_space("where"); - } else { - state.word_space(","); - } - let mut first = true; - for p in after_predicates.iter() { - if !first { - state.word_space(","); - } - first = false; - state.print_where_predicate(p); - } - let suggestion = state.s.eof(); - err.span_suggestion( - before_where_clause_span.shrink_to_hi(), - "move it here", - suggestion, - Applicability::MachineApplicable, - ); - } - err.emit() - } - /// Parses a `type` alias with the following grammar: /// ``` /// TypeAlias = "type" Ident Generics {":" GenericBounds}? {"=" Ty}? ";" ; @@ -851,27 +814,40 @@ impl<'a> Parser<'a> { // Parse optional colon and param bounds. let bounds = if self.eat(&token::Colon) { self.parse_generic_bounds(None)? } else { Vec::new() }; - - generics.where_clause = self.parse_where_clause()?; + let before_where_clause = self.parse_where_clause()?; let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None }; - if self.token.is_keyword(kw::Where) { - let after_where_clause = self.parse_where_clause()?; - - self.error_ty_alias_where( - generics.where_clause.has_where_token, - generics.where_clause.span, - &after_where_clause.predicates, - after_where_clause.span, - ); + let after_where_clause = self.parse_where_clause()?; - generics.where_clause.predicates.extend(after_where_clause.predicates.into_iter()); - } + let where_clauses = ( + TyAliasWhereClause(before_where_clause.has_where_token, before_where_clause.span), + TyAliasWhereClause(after_where_clause.has_where_token, after_where_clause.span), + ); + let where_predicates_split = before_where_clause.predicates.len(); + let mut predicates = before_where_clause.predicates; + predicates.extend(after_where_clause.predicates.into_iter()); + let where_clause = WhereClause { + has_where_token: before_where_clause.has_where_token + || after_where_clause.has_where_token, + predicates, + span: DUMMY_SP, + }; + generics.where_clause = where_clause; self.expect_semi()?; - Ok((ident, ItemKind::TyAlias(Box::new(TyAlias { defaultness, generics, bounds, ty })))) + Ok(( + ident, + ItemKind::TyAlias(Box::new(TyAlias { + defaultness, + generics, + where_clauses, + where_predicates_split, + bounds, + ty, + })), + )) } /// Parses a `UseTree`. |
