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
>,
}
+/// 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
>,
}
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(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(
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(
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(
&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, " = ;");
}
- 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, " = ;");
}
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 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", " { }");
}
- 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", " = ;");
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 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 ",
};
}
+
+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()?;
+ 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,
- );
-
- 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`.
diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs b/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs
index 1d2be3657ff..c5c13451488 100644
--- a/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs
+++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs
@@ -24,7 +24,7 @@ trait Bar {
}
impl Bar for Foo {
- type Assoc where Self: Sized = Foo;
+ type Assoc = Foo where Self: Sized;
//~^ ERROR where clauses on associated types are unstable
}
diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr
index 6c2c3ed9c36..12a40ff0a12 100644
--- a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr
+++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr
@@ -55,7 +55,7 @@ LL | type Assoc where Self: Sized;
error[E0658]: where clauses on associated types are unstable
--> $DIR/feature-gate-generic_associated_types.rs:27:5
|
-LL | type Assoc where Self: Sized = Foo;
+LL | type Assoc = Foo where Self: Sized;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #44265 for more information
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87735.rs b/src/test/ui/generic-associated-types/bugs/issue-87735.rs
index 6d6063f8085..53e3ad7fe69 100644
--- a/src/test/ui/generic-associated-types/bugs/issue-87735.rs
+++ b/src/test/ui/generic-associated-types/bugs/issue-87735.rs
@@ -12,7 +12,7 @@ pub trait AsRef2 {
}
impl AsRef2 for Vec {
- type Output<'a> where Self: 'a = &'a [T];
+ type Output<'a> = &'a [T] where Self: 'a;
fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
&self[..]
@@ -33,7 +33,7 @@ where
T: AsRef2