Rollup merge of #121326 - fmease:detect-empty-leading-where-clauses-on-ty-aliases, r=compiler-errors

Detect empty leading where clauses on type aliases

1. commit: refactor the AST of type alias where clauses
   * I could no longer bear the look of `.0.1` and `.1.0`
   * Arguably moving `split` out of `TyAlias` into a substruct might not make that much sense from a semantic standpoint since it reprs an index into `TyAlias.predicates` but it's alright and it cleans up the usage sites of `TyAlias`
2. commit: fix an oversight: An empty leading where clause is still a leading where clause
   * semantically reject empty leading where clauses on lazy type aliases
     * e.g., on `#![feature(lazy_type_alias)] type X where = ();`
   * make empty leading where clauses on assoc types trigger lint `deprecated_where_clause_location`
     * e.g., `impl Trait for () { type X where = (); }`
This commit is contained in:
Matthias Krüger 2024-02-29 20:50:02 +01:00 committed by GitHub
commit dd4ecd1cf4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 248 additions and 150 deletions

View File

@ -403,9 +403,10 @@ fn default() -> Generics {
/// A where-clause in a definition. /// A where-clause in a definition.
#[derive(Clone, Encodable, Decodable, Debug)] #[derive(Clone, Encodable, Decodable, Debug)]
pub struct WhereClause { pub struct WhereClause {
/// `true` if we ate a `where` token: this can happen /// `true` if we ate a `where` token.
/// if we parsed no predicates (e.g. `struct Foo where {}`). ///
/// This allows us to pretty-print accurately. /// This can happen if we parsed no predicates, e.g., `struct Foo where {}`.
/// This allows us to pretty-print accurately and provide correct suggestion diagnostics.
pub has_where_token: bool, pub has_where_token: bool,
pub predicates: ThinVec<WherePredicate>, pub predicates: ThinVec<WherePredicate>,
pub span: Span, pub span: Span,
@ -3007,18 +3008,29 @@ pub struct Trait {
/// ///
/// If there is no where clause, then this is `false` with `DUMMY_SP`. /// If there is no where clause, then this is `false` with `DUMMY_SP`.
#[derive(Copy, Clone, Encodable, Decodable, Debug, Default)] #[derive(Copy, Clone, Encodable, Decodable, Debug, Default)]
pub struct TyAliasWhereClause(pub bool, pub Span); pub struct TyAliasWhereClause {
pub has_where_token: bool,
pub span: Span,
}
/// The span information for the two where clauses on a `TyAlias`.
#[derive(Copy, Clone, Encodable, Decodable, Debug, Default)]
pub struct TyAliasWhereClauses {
/// Before the equals sign.
pub before: TyAliasWhereClause,
/// After the equals sign.
pub after: TyAliasWhereClause,
/// The index in `TyAlias.generics.where_clause.predicates` that would split
/// into predicates from the where clause before the equals sign and the ones
/// from the where clause after the equals sign.
pub split: usize,
}
#[derive(Clone, Encodable, Decodable, Debug)] #[derive(Clone, Encodable, Decodable, Debug)]
pub struct TyAlias { pub struct TyAlias {
pub defaultness: Defaultness, pub defaultness: Defaultness,
pub generics: Generics, pub generics: Generics,
/// The span information for the two where clauses (before equals, after equals) pub where_clauses: TyAliasWhereClauses,
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 bounds: GenericBounds,
pub ty: Option<P<Ty>>, pub ty: Option<P<Ty>>,
} }

View File

@ -1079,8 +1079,8 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
}) => { }) => {
visit_defaultness(defaultness, vis); visit_defaultness(defaultness, vis);
vis.visit_generics(generics); vis.visit_generics(generics);
vis.visit_span(&mut where_clauses.0.1); vis.visit_span(&mut where_clauses.before.span);
vis.visit_span(&mut where_clauses.1.1); vis.visit_span(&mut where_clauses.after.span);
visit_bounds(bounds, vis); visit_bounds(bounds, vis);
visit_opt(ty, |ty| vis.visit_ty(ty)); visit_opt(ty, |ty| vis.visit_ty(ty));
} }
@ -1163,8 +1163,8 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
}) => { }) => {
visit_defaultness(defaultness, visitor); visit_defaultness(defaultness, visitor);
visitor.visit_generics(generics); visitor.visit_generics(generics);
visitor.visit_span(&mut where_clauses.0.1); visitor.visit_span(&mut where_clauses.before.span);
visitor.visit_span(&mut where_clauses.1.1); visitor.visit_span(&mut where_clauses.after.span);
visit_bounds(bounds, visitor); visit_bounds(bounds, visitor);
visit_opt(ty, |ty| visitor.visit_ty(ty)); visit_opt(ty, |ty| visitor.visit_ty(ty));
} }
@ -1257,8 +1257,8 @@ pub fn noop_flat_map_foreign_item<T: MutVisitor>(
}) => { }) => {
visit_defaultness(defaultness, visitor); visit_defaultness(defaultness, visitor);
visitor.visit_generics(generics); visitor.visit_generics(generics);
visitor.visit_span(&mut where_clauses.0.1); visitor.visit_span(&mut where_clauses.before.span);
visitor.visit_span(&mut where_clauses.1.1); visitor.visit_span(&mut where_clauses.after.span);
visit_bounds(bounds, visitor); visit_bounds(bounds, visitor);
visit_opt(ty, |ty| visitor.visit_ty(ty)); visit_opt(ty, |ty| visitor.visit_ty(ty));
} }

View File

@ -33,19 +33,20 @@ pub(super) struct ItemLowerer<'a, 'hir> {
/// clause if it exists. /// clause if it exists.
fn add_ty_alias_where_clause( fn add_ty_alias_where_clause(
generics: &mut ast::Generics, generics: &mut ast::Generics,
mut where_clauses: (TyAliasWhereClause, TyAliasWhereClause), mut where_clauses: TyAliasWhereClauses,
prefer_first: bool, prefer_first: bool,
) { ) {
if !prefer_first { if !prefer_first {
where_clauses = (where_clauses.1, where_clauses.0); (where_clauses.before, where_clauses.after) = (where_clauses.after, where_clauses.before);
}
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;
} }
let where_clause =
if where_clauses.before.has_where_token || !where_clauses.after.has_where_token {
where_clauses.before
} else {
where_clauses.after
};
generics.where_clause.has_where_token = where_clause.has_where_token;
generics.where_clause.span = where_clause.span;
} }
impl<'a, 'hir> ItemLowerer<'a, 'hir> { impl<'a, 'hir> ItemLowerer<'a, 'hir> {

View File

@ -280,4 +280,5 @@ ast_passes_where_clause_after_type_alias = where clauses are not allowed after t
ast_passes_where_clause_before_type_alias = where clauses are not allowed before the type for type aliases ast_passes_where_clause_before_type_alias = where clauses are not allowed before the type for type aliases
.note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information .note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
.suggestion = move it to the end of the type declaration .remove_suggestion = remove this `where`
.move_suggestion = move it to the end of the type declaration

View File

@ -138,38 +138,42 @@ fn check_type_alias_where_clause_location(
&mut self, &mut self,
ty_alias: &TyAlias, ty_alias: &TyAlias,
) -> Result<(), errors::WhereClauseBeforeTypeAlias> { ) -> Result<(), errors::WhereClauseBeforeTypeAlias> {
let before_predicates = if ty_alias.ty.is_none() || !ty_alias.where_clauses.before.has_where_token {
ty_alias.generics.where_clause.predicates.split_at(ty_alias.where_predicates_split).0;
if ty_alias.ty.is_none() || before_predicates.is_empty() {
return Ok(()); return Ok(());
} }
let mut state = State::new(); let (before_predicates, after_predicates) =
if !ty_alias.where_clauses.1.0 { ty_alias.generics.where_clause.predicates.split_at(ty_alias.where_clauses.split);
state.space(); let span = ty_alias.where_clauses.before.span;
state.word_space("where");
} else {
state.word_space(",");
}
let mut first = true;
for p in before_predicates {
if !first {
state.word_space(",");
}
first = false;
state.print_where_predicate(p);
}
let span = ty_alias.where_clauses.0.1; let sugg = if !before_predicates.is_empty() || !ty_alias.where_clauses.after.has_where_token
Err(errors::WhereClauseBeforeTypeAlias { {
span, let mut state = State::new();
sugg: errors::WhereClauseBeforeTypeAliasSugg {
if !ty_alias.where_clauses.after.has_where_token {
state.space();
state.word_space("where");
}
let mut first = after_predicates.is_empty();
for p in before_predicates {
if !first {
state.word_space(",");
}
first = false;
state.print_where_predicate(p);
}
errors::WhereClauseBeforeTypeAliasSugg::Move {
left: span, left: span,
snippet: state.s.eof(), snippet: state.s.eof(),
right: ty_alias.where_clauses.1.1.shrink_to_hi(), right: ty_alias.where_clauses.after.span.shrink_to_hi(),
}, }
}) } else {
errors::WhereClauseBeforeTypeAliasSugg::Remove { span }
};
Err(errors::WhereClauseBeforeTypeAlias { span, sugg })
} }
fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) { fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
@ -457,8 +461,7 @@ fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
fn check_foreign_ty_genericless( fn check_foreign_ty_genericless(
&self, &self,
generics: &Generics, generics: &Generics,
before_where_clause: &TyAliasWhereClause, where_clauses: &TyAliasWhereClauses,
after_where_clause: &TyAliasWhereClause,
) { ) {
let cannot_have = |span, descr, remove_descr| { let cannot_have = |span, descr, remove_descr| {
self.dcx().emit_err(errors::ExternTypesCannotHave { self.dcx().emit_err(errors::ExternTypesCannotHave {
@ -473,14 +476,14 @@ fn check_foreign_ty_genericless(
cannot_have(generics.span, "generic parameters", "generic parameters"); cannot_have(generics.span, "generic parameters", "generic parameters");
} }
let check_where_clause = |where_clause: &TyAliasWhereClause| { let check_where_clause = |where_clause: TyAliasWhereClause| {
if let TyAliasWhereClause(true, where_clause_span) = where_clause { if where_clause.has_where_token {
cannot_have(*where_clause_span, "`where` clauses", "`where` clause"); cannot_have(where_clause.span, "`where` clauses", "`where` clause");
} }
}; };
check_where_clause(before_where_clause); check_where_clause(where_clauses.before);
check_where_clause(after_where_clause); check_where_clause(where_clauses.after);
} }
fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) { fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
@ -1122,9 +1125,9 @@ fn visit_item(&mut self, item: &'a Item) {
if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) { if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) {
self.dcx().emit_err(err); self.dcx().emit_err(err);
} }
} else if where_clauses.1.0 { } else if where_clauses.after.has_where_token {
self.dcx().emit_err(errors::WhereClauseAfterTypeAlias { self.dcx().emit_err(errors::WhereClauseAfterTypeAlias {
span: where_clauses.1.1, span: where_clauses.after.span,
help: self.session.is_nightly_build().then_some(()), help: self.session.is_nightly_build().then_some(()),
}); });
} }
@ -1154,7 +1157,7 @@ fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
self.check_defaultness(fi.span, *defaultness); self.check_defaultness(fi.span, *defaultness);
self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span)); 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_type_no_bounds(bounds, "`extern` blocks");
self.check_foreign_ty_genericless(generics, &where_clauses.0, &where_clauses.1); self.check_foreign_ty_genericless(generics, where_clauses);
self.check_foreign_item_ascii_only(fi.ident); self.check_foreign_item_ascii_only(fi.ident);
} }
ForeignItemKind::Static(_, _, body) => { ForeignItemKind::Static(_, _, body) => {
@ -1477,15 +1480,18 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
if let AssocItemKind::Type(ty_alias) = &item.kind if let AssocItemKind::Type(ty_alias) = &item.kind
&& let Err(err) = self.check_type_alias_where_clause_location(ty_alias) && let Err(err) = self.check_type_alias_where_clause_location(ty_alias)
{ {
let sugg = match err.sugg {
errors::WhereClauseBeforeTypeAliasSugg::Remove { .. } => None,
errors::WhereClauseBeforeTypeAliasSugg::Move { snippet, right, .. } => {
Some((right, snippet))
}
};
self.lint_buffer.buffer_lint_with_diagnostic( self.lint_buffer.buffer_lint_with_diagnostic(
DEPRECATED_WHERE_CLAUSE_LOCATION, DEPRECATED_WHERE_CLAUSE_LOCATION,
item.id, item.id,
err.span, err.span,
fluent::ast_passes_deprecated_where_clause_location, fluent::ast_passes_deprecated_where_clause_location,
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation( BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(sugg),
err.sugg.right,
err.sugg.snippet,
),
); );
} }

View File

@ -515,17 +515,25 @@ pub struct WhereClauseBeforeTypeAlias {
} }
#[derive(Subdiagnostic)] #[derive(Subdiagnostic)]
#[multipart_suggestion(
ast_passes_suggestion, pub enum WhereClauseBeforeTypeAliasSugg {
applicability = "machine-applicable", #[suggestion(ast_passes_remove_suggestion, applicability = "machine-applicable", code = "")]
style = "verbose" Remove {
)] #[primary_span]
pub struct WhereClauseBeforeTypeAliasSugg { span: Span,
#[suggestion_part(code = "")] },
pub left: Span, #[multipart_suggestion(
pub snippet: String, ast_passes_move_suggestion,
#[suggestion_part(code = "{snippet}")] applicability = "machine-applicable",
pub right: Span, style = "verbose"
)]
Move {
#[suggestion_part(code = "")]
left: Span,
snippet: String,
#[suggestion_part(code = "{snippet}")]
right: Span,
},
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]

View File

@ -43,7 +43,6 @@ fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
defaultness, defaultness,
generics, generics,
where_clauses, where_clauses,
where_predicates_split,
bounds, bounds,
ty, ty,
}) => { }) => {
@ -51,7 +50,6 @@ fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
ident, ident,
generics, generics,
*where_clauses, *where_clauses,
*where_predicates_split,
bounds, bounds,
ty.as_deref(), ty.as_deref(),
vis, vis,
@ -108,15 +106,14 @@ fn print_associated_type(
&mut self, &mut self,
ident: Ident, ident: Ident,
generics: &ast::Generics, generics: &ast::Generics,
where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause), where_clauses: ast::TyAliasWhereClauses,
where_predicates_split: usize,
bounds: &ast::GenericBounds, bounds: &ast::GenericBounds,
ty: Option<&ast::Ty>, ty: Option<&ast::Ty>,
vis: &ast::Visibility, vis: &ast::Visibility,
defaultness: ast::Defaultness, defaultness: ast::Defaultness,
) { ) {
let (before_predicates, after_predicates) = let (before_predicates, after_predicates) =
generics.where_clause.predicates.split_at(where_predicates_split); generics.where_clause.predicates.split_at(where_clauses.split);
self.head(""); self.head("");
self.print_visibility(vis); self.print_visibility(vis);
self.print_defaultness(defaultness); self.print_defaultness(defaultness);
@ -127,13 +124,13 @@ fn print_associated_type(
self.word_nbsp(":"); self.word_nbsp(":");
self.print_type_bounds(bounds); self.print_type_bounds(bounds);
} }
self.print_where_clause_parts(where_clauses.0.0, before_predicates); self.print_where_clause_parts(where_clauses.before.has_where_token, before_predicates);
if let Some(ty) = ty { if let Some(ty) = ty {
self.space(); self.space();
self.word_space("="); self.word_space("=");
self.print_type(ty); self.print_type(ty);
} }
self.print_where_clause_parts(where_clauses.1.0, after_predicates); self.print_where_clause_parts(where_clauses.after.has_where_token, after_predicates);
self.word(";"); self.word(";");
self.end(); // end inner head-block self.end(); // end inner head-block
self.end(); // end outer head-block self.end(); // end outer head-block
@ -249,7 +246,6 @@ pub(crate) fn print_item(&mut self, item: &ast::Item) {
defaultness, defaultness,
generics, generics,
where_clauses, where_clauses,
where_predicates_split,
bounds, bounds,
ty, ty,
}) => { }) => {
@ -257,7 +253,6 @@ pub(crate) fn print_item(&mut self, item: &ast::Item) {
item.ident, item.ident,
generics, generics,
*where_clauses, *where_clauses,
*where_predicates_split,
bounds, bounds,
ty.as_deref(), ty.as_deref(),
&item.vis, &item.vis,
@ -536,7 +531,6 @@ fn print_assoc_item(&mut self, item: &ast::AssocItem) {
defaultness, defaultness,
generics, generics,
where_clauses, where_clauses,
where_predicates_split,
bounds, bounds,
ty, ty,
}) => { }) => {
@ -544,7 +538,6 @@ fn print_assoc_item(&mut self, item: &ast::AssocItem) {
ident, ident,
generics, generics,
*where_clauses, *where_clauses,
*where_predicates_split,
bounds, bounds,
ty.as_deref(), ty.as_deref(),
vis, vis,

View File

@ -601,11 +601,7 @@ fn create_derived_impl(
kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias { kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias {
defaultness: ast::Defaultness::Final, defaultness: ast::Defaultness::Final,
generics: Generics::default(), generics: Generics::default(),
where_clauses: ( where_clauses: ast::TyAliasWhereClauses::default(),
ast::TyAliasWhereClause::default(),
ast::TyAliasWhereClause::default(),
),
where_predicates_split: 0,
bounds: Vec::new(), bounds: Vec::new(),
ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)), ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)),
})), })),

View File

@ -428,15 +428,22 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiagnostics, diag:
diag.note("see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration"); diag.note("see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration");
} }
} }
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(new_span, suggestion) => { BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(sugg) => {
diag.multipart_suggestion( let left_sp = diag.span.primary_span().unwrap();
"move it to the end of the type declaration", match sugg {
vec![(diag.span.primary_span().unwrap(), "".to_string()), (new_span, suggestion)], Some((right_sp, sugg)) => diag.multipart_suggestion(
Applicability::MachineApplicable, "move it to the end of the type declaration",
); vec![(left_sp, String::new()), (right_sp, sugg)],
diag.note( Applicability::MachineApplicable,
"see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information", ),
); None => diag.span_suggestion(
left_sp,
"remove this `where`",
"",
Applicability::MachineApplicable,
),
};
diag.note("see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information");
} }
BuiltinLintDiagnostics::SingleUseLifetime { BuiltinLintDiagnostics::SingleUseLifetime {
param_span, param_span,

View File

@ -597,7 +597,7 @@ pub enum BuiltinLintDiagnostics {
UnicodeTextFlow(Span, String), UnicodeTextFlow(Span, String),
UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
DeprecatedWhereclauseLocation(Span, String), DeprecatedWhereclauseLocation(Option<(Span, String)>),
SingleUseLifetime { SingleUseLifetime {
/// Span of the parameter which declares this lifetime. /// Span of the parameter which declares this lifetime.
param_span: Span, param_span: Span,

View File

@ -971,11 +971,17 @@ fn parse_type_alias(&mut self, defaultness: Defaultness) -> PResult<'a, ItemInfo
let after_where_clause = self.parse_where_clause()?; let after_where_clause = self.parse_where_clause()?;
let where_clauses = ( let where_clauses = TyAliasWhereClauses {
TyAliasWhereClause(before_where_clause.has_where_token, before_where_clause.span), before: TyAliasWhereClause {
TyAliasWhereClause(after_where_clause.has_where_token, after_where_clause.span), has_where_token: before_where_clause.has_where_token,
); span: before_where_clause.span,
let where_predicates_split = before_where_clause.predicates.len(); },
after: TyAliasWhereClause {
has_where_token: after_where_clause.has_where_token,
span: after_where_clause.span,
},
split: before_where_clause.predicates.len(),
};
let mut predicates = before_where_clause.predicates; let mut predicates = before_where_clause.predicates;
predicates.extend(after_where_clause.predicates); predicates.extend(after_where_clause.predicates);
let where_clause = WhereClause { let where_clause = WhereClause {
@ -994,7 +1000,6 @@ fn parse_type_alias(&mut self, defaultness: Defaultness) -> PResult<'a, ItemInfo
defaultness, defaultness,
generics, generics,
where_clauses, where_clauses,
where_predicates_split,
bounds, bounds,
ty, ty,
})), })),

View File

@ -1651,8 +1651,7 @@ struct TyAliasRewriteInfo<'c, 'g>(
&'c RewriteContext<'c>, &'c RewriteContext<'c>,
Indent, Indent,
&'g ast::Generics, &'g ast::Generics,
(ast::TyAliasWhereClause, ast::TyAliasWhereClause), ast::TyAliasWhereClauses,
usize,
symbol::Ident, symbol::Ident,
Span, Span,
); );
@ -1672,7 +1671,6 @@ pub(crate) fn rewrite_type_alias<'a, 'b>(
ref bounds, ref bounds,
ref ty, ref ty,
where_clauses, where_clauses,
where_predicates_split,
} = *ty_alias_kind; } = *ty_alias_kind;
let ty_opt = ty.as_ref(); let ty_opt = ty.as_ref();
let (ident, vis) = match visitor_kind { let (ident, vis) = match visitor_kind {
@ -1680,15 +1678,7 @@ pub(crate) fn rewrite_type_alias<'a, 'b>(
AssocTraitItem(i) | AssocImplItem(i) => (i.ident, &i.vis), AssocTraitItem(i) | AssocImplItem(i) => (i.ident, &i.vis),
ForeignItem(i) => (i.ident, &i.vis), ForeignItem(i) => (i.ident, &i.vis),
}; };
let rw_info = &TyAliasRewriteInfo( let rw_info = &TyAliasRewriteInfo(context, indent, generics, where_clauses, ident, span);
context,
indent,
generics,
where_clauses,
where_predicates_split,
ident,
span,
);
let op_ty = opaque_ty(ty); let op_ty = opaque_ty(ty);
// Type Aliases are formatted slightly differently depending on the context // Type Aliases are formatted slightly differently depending on the context
// in which they appear, whether they are opaque, and whether they are associated. // in which they appear, whether they are opaque, and whether they are associated.
@ -1724,19 +1714,11 @@ fn rewrite_ty<R: Rewrite>(
vis: &ast::Visibility, vis: &ast::Visibility,
) -> Option<String> { ) -> Option<String> {
let mut result = String::with_capacity(128); let mut result = String::with_capacity(128);
let TyAliasRewriteInfo( let TyAliasRewriteInfo(context, indent, generics, where_clauses, ident, span) = *rw_info;
context,
indent,
generics,
where_clauses,
where_predicates_split,
ident,
span,
) = *rw_info;
let (before_where_predicates, after_where_predicates) = generics let (before_where_predicates, after_where_predicates) = generics
.where_clause .where_clause
.predicates .predicates
.split_at(where_predicates_split); .split_at(where_clauses.split);
if !after_where_predicates.is_empty() { if !after_where_predicates.is_empty() {
return None; return None;
} }
@ -1771,7 +1753,7 @@ fn rewrite_ty<R: Rewrite>(
let where_clause_str = rewrite_where_clause( let where_clause_str = rewrite_where_clause(
context, context,
before_where_predicates, before_where_predicates,
where_clauses.0.1, where_clauses.before.span,
context.config.brace_style(), context.config.brace_style(),
Shape::legacy(where_budget, indent), Shape::legacy(where_budget, indent),
false, false,
@ -1795,7 +1777,7 @@ fn rewrite_ty<R: Rewrite>(
let comment_span = context let comment_span = context
.snippet_provider .snippet_provider
.opt_span_before(span, "=") .opt_span_before(span, "=")
.map(|op_lo| mk_sp(where_clauses.0.1.hi(), op_lo)); .map(|op_lo| mk_sp(where_clauses.before.span.hi(), op_lo));
let lhs = match comment_span { let lhs = match comment_span {
Some(comment_span) Some(comment_span)

View File

@ -2,14 +2,22 @@
#![feature(lazy_type_alias)] #![feature(lazy_type_alias)]
#![allow(incomplete_features)] #![allow(incomplete_features)]
#![crate_type = "lib"]
// Check that we *reject* leading where-clauses on lazy type aliases. // Check that we *reject* leading where-clauses on lazy type aliases.
type Alias<T> pub type Leading0<T>
= T where String: From<T>; = T where String: From<T>;
//~^^^ ERROR where clauses are not allowed before the type for type aliases
fn main() { pub type Leading1<T, U>
let _: Alias<&str>;
} = (T, U)
where
U: Copy, String: From<T>;
pub type EmptyLeading0 = () where;
//~^ ERROR where clauses are not allowed before the type for type aliases
pub type EmptyLeading1<T> = T where T: Copy;
//~^ ERROR where clauses are not allowed before the type for type aliases

View File

@ -2,15 +2,24 @@
#![feature(lazy_type_alias)] #![feature(lazy_type_alias)]
#![allow(incomplete_features)] #![allow(incomplete_features)]
#![crate_type = "lib"]
// Check that we *reject* leading where-clauses on lazy type aliases. // Check that we *reject* leading where-clauses on lazy type aliases.
type Alias<T> pub type Leading0<T>
where where //~ ERROR where clauses are not allowed before the type for type aliases
String: From<T>, String: From<T>,
= T; = T;
//~^^^ ERROR where clauses are not allowed before the type for type aliases
fn main() { pub type Leading1<T, U>
let _: Alias<&str>; where //~ ERROR where clauses are not allowed before the type for type aliases
} String: From<T>,
= (T, U)
where
U: Copy;
pub type EmptyLeading0 where = ();
//~^ ERROR where clauses are not allowed before the type for type aliases
pub type EmptyLeading1<T> where = T where T: Copy;
//~^ ERROR where clauses are not allowed before the type for type aliases

View File

@ -1,5 +1,5 @@
error: where clauses are not allowed before the type for type aliases error: where clauses are not allowed before the type for type aliases
--> $DIR/leading-where-clause.rs:9:1 --> $DIR/leading-where-clause.rs:10:1
| |
LL | / where LL | / where
LL | | String: From<T>, LL | | String: From<T>,
@ -12,5 +12,42 @@ LL +
LL ~ = T where String: From<T>; LL ~ = T where String: From<T>;
| |
error: aborting due to 1 previous error error: where clauses are not allowed before the type for type aliases
--> $DIR/leading-where-clause.rs:15:1
|
LL | / where
LL | | String: From<T>,
| |____________________^
|
= note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
help: move it to the end of the type declaration
|
LL +
LL | = (T, U)
LL | where
LL ~ U: Copy, String: From<T>;
|
error: where clauses are not allowed before the type for type aliases
--> $DIR/leading-where-clause.rs:21:24
|
LL | pub type EmptyLeading0 where = ();
| ^^^^^
|
= note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
help: move it to the end of the type declaration
|
LL - pub type EmptyLeading0 where = ();
LL + pub type EmptyLeading0 = () where;
|
error: where clauses are not allowed before the type for type aliases
--> $DIR/leading-where-clause.rs:24:27
|
LL | pub type EmptyLeading1<T> where = T where T: Copy;
| ^^^^^ help: remove this `where`
|
= note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
error: aborting due to 4 previous errors

View File

@ -8,6 +8,8 @@ trait Trait {
type Assoc where u32: Copy; type Assoc where u32: Copy;
// Fine. // Fine.
type Assoc2 where u32: Copy, i32: Copy; type Assoc2 where u32: Copy, i32: Copy;
//
type Assoc3;
} }
impl Trait for u32 { impl Trait for u32 {
@ -17,6 +19,8 @@ impl Trait for u32 {
// Not fine, suggests moving `u32: Copy` // Not fine, suggests moving `u32: Copy`
type Assoc2 = () where i32: Copy, u32: Copy; type Assoc2 = () where i32: Copy, u32: Copy;
//~^ WARNING where clause not allowed here //~^ WARNING where clause not allowed here
type Assoc3 = () where;
//~^ WARNING where clause not allowed here
} }
impl Trait for i32 { impl Trait for i32 {
@ -25,6 +29,8 @@ impl Trait for i32 {
// Not fine, suggests moving both. // Not fine, suggests moving both.
type Assoc2 = () where u32: Copy, i32: Copy; type Assoc2 = () where u32: Copy, i32: Copy;
//~^ WARNING where clause not allowed here //~^ WARNING where clause not allowed here
type Assoc3 = () where;
//~^ WARNING where clause not allowed here
} }
fn main() {} fn main() {}

View File

@ -8,6 +8,8 @@ trait Trait {
type Assoc where u32: Copy; type Assoc where u32: Copy;
// Fine. // Fine.
type Assoc2 where u32: Copy, i32: Copy; type Assoc2 where u32: Copy, i32: Copy;
//
type Assoc3;
} }
impl Trait for u32 { impl Trait for u32 {
@ -17,6 +19,8 @@ impl Trait for u32 {
// Not fine, suggests moving `u32: Copy` // Not fine, suggests moving `u32: Copy`
type Assoc2 where u32: Copy = () where i32: Copy; type Assoc2 where u32: Copy = () where i32: Copy;
//~^ WARNING where clause not allowed here //~^ WARNING where clause not allowed here
type Assoc3 where = ();
//~^ WARNING where clause not allowed here
} }
impl Trait for i32 { impl Trait for i32 {
@ -25,6 +29,8 @@ impl Trait for i32 {
// Not fine, suggests moving both. // Not fine, suggests moving both.
type Assoc2 where u32: Copy, i32: Copy = (); type Assoc2 where u32: Copy, i32: Copy = ();
//~^ WARNING where clause not allowed here //~^ WARNING where clause not allowed here
type Assoc3 where = () where;
//~^ WARNING where clause not allowed here
} }
fn main() {} fn main() {}

View File

@ -1,5 +1,5 @@
warning: where clause not allowed here warning: where clause not allowed here
--> $DIR/where-clause-placement-assoc-type-in-impl.rs:15:16 --> $DIR/where-clause-placement-assoc-type-in-impl.rs:17:16
| |
LL | type Assoc where u32: Copy = (); LL | type Assoc where u32: Copy = ();
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
@ -13,7 +13,7 @@ LL + type Assoc = () where u32: Copy;
| |
warning: where clause not allowed here warning: where clause not allowed here
--> $DIR/where-clause-placement-assoc-type-in-impl.rs:18:17 --> $DIR/where-clause-placement-assoc-type-in-impl.rs:20:17
| |
LL | type Assoc2 where u32: Copy = () where i32: Copy; LL | type Assoc2 where u32: Copy = () where i32: Copy;
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
@ -26,7 +26,20 @@ LL + type Assoc2 = () where i32: Copy, u32: Copy;
| |
warning: where clause not allowed here warning: where clause not allowed here
--> $DIR/where-clause-placement-assoc-type-in-impl.rs:26:17 --> $DIR/where-clause-placement-assoc-type-in-impl.rs:22:17
|
LL | type Assoc3 where = ();
| ^^^^^
|
= note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
help: move it to the end of the type declaration
|
LL - type Assoc3 where = ();
LL + type Assoc3 = () where;
|
warning: where clause not allowed here
--> $DIR/where-clause-placement-assoc-type-in-impl.rs:30:17
| |
LL | type Assoc2 where u32: Copy, i32: Copy = (); LL | type Assoc2 where u32: Copy, i32: Copy = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -38,5 +51,13 @@ LL - type Assoc2 where u32: Copy, i32: Copy = ();
LL + type Assoc2 = () where u32: Copy, i32: Copy; LL + type Assoc2 = () where u32: Copy, i32: Copy;
| |
warning: 3 warnings emitted warning: where clause not allowed here
--> $DIR/where-clause-placement-assoc-type-in-impl.rs:32:17
|
LL | type Assoc3 where = () where;
| ^^^^^ help: remove this `where`
|
= note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
warning: 5 warnings emitted