Skip to content

Commit

Permalink
Auto merge of #90076 - jackh726:wherethewhere, r=nikomatsakis
Browse files Browse the repository at this point in the history
Change location of where clause on GATs

Closes #89122

~Blocked on lang FCP~

r? `@nikomatsakis`
  • Loading branch information
bors committed Mar 6, 2022
2 parents 5d9d1e8 + d16ec7b commit ad0d1d7
Show file tree
Hide file tree
Showing 52 changed files with 552 additions and 283 deletions.
27 changes: 27 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>>,
}
Expand Down
28 changes: 25 additions & 3 deletions compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down Expand Up @@ -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));
}
Expand Down Expand Up @@ -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));
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
59 changes: 50 additions & 9 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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,
);
Expand Down Expand Up @@ -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 {
Expand Down
91 changes: 83 additions & 8 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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(
Expand All @@ -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");
}
}

Expand Down Expand Up @@ -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();
}
}
_ => {}
}
Expand All @@ -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) => {
Expand Down Expand Up @@ -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,
);
}
}
_ => {}
}
Expand Down
Loading

0 comments on commit ad0d1d7

Please sign in to comment.