Skip to content

Commit b864d23

Browse files
authored
Rollup merge of rust-lang#69194 - Centril:assoc-extern-fuse, r=petrochenkov
parse: fuse associated and extern items up to defaultness Language changes: - The grammar of extern `type` aliases is unified with associated ones, and becomes: ```rust TypeItem = "type" ident generics {":" bounds}? where_clause {"=" type}? ";" ; ``` Semantic restrictions (`ast_validation`) are added to forbid any parameters in `generics`, any bounds in `bounds`, and any predicates in `where_clause`, as well as the presence of a type expression (`= u8`). (Work still remains to fuse this with free `type` aliases, but this can be done later.) - The grammar of constants and static items (free, associated, and extern) now permits the absence of an expression, and becomes: ```rust GlobalItem = {"const" {ident | "_"} | "static" "mut"? ident} {"=" expr}? ";" ; ``` - A semantic restriction is added to enforce the presence of the expression (the body). - A semantic restriction is added to reject `const _` in associated contexts. Together, these changes allow us to fuse the grammar of associated items and extern items up to `default`ness which is the main goal of the PR. ----------------------- We are now very close to fully fusing the entirely of item parsing and their ASTs. To progress further, we must make a decision: should we parse e.g. `default use foo::bar;` and whatnot? Accepting that is likely easiest from a parsing perspective, as it does not require using look-ahead, but it is perhaps not too onerous to only accept it for `fn`s (and all their various qualifiers), `const`s, `static`s, and `type`s. r? @petrochenkov
2 parents 981acd9 + 045b7d5 commit b864d23

File tree

77 files changed

+1314
-714
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+1314
-714
lines changed

src/librustc_ast_lowering/item.rs

+53-49
Original file line numberDiff line numberDiff line change
@@ -269,26 +269,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
269269
self.lower_use_tree(use_tree, &prefix, id, vis, ident, attrs)
270270
}
271271
ItemKind::Static(ref t, m, ref e) => {
272-
let ty = self.lower_ty(
273-
t,
274-
if self.sess.features_untracked().impl_trait_in_bindings {
275-
ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc)
276-
} else {
277-
ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
278-
},
279-
);
280-
hir::ItemKind::Static(ty, m, self.lower_const_body(span, Some(e)))
272+
let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
273+
hir::ItemKind::Static(ty, m, body_id)
281274
}
282275
ItemKind::Const(ref t, ref e) => {
283-
let ty = self.lower_ty(
284-
t,
285-
if self.sess.features_untracked().impl_trait_in_bindings {
286-
ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc)
287-
} else {
288-
ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
289-
},
290-
);
291-
hir::ItemKind::Const(ty, self.lower_const_body(span, Some(e)))
276+
let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
277+
hir::ItemKind::Const(ty, body_id)
292278
}
293279
ItemKind::Fn(FnSig { ref decl, header }, ref generics, ref body) => {
294280
let fn_def_id = self.resolver.definitions().local_def_id(id);
@@ -457,6 +443,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
457443
// not cause an assertion failure inside the `lower_defaultness` function.
458444
}
459445

446+
fn lower_const_item(
447+
&mut self,
448+
ty: &Ty,
449+
span: Span,
450+
body: Option<&Expr>,
451+
) -> (&'hir hir::Ty<'hir>, hir::BodyId) {
452+
let itctx = if self.sess.features_untracked().impl_trait_in_bindings {
453+
ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc)
454+
} else {
455+
ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
456+
};
457+
let ty = self.lower_ty(ty, itctx);
458+
(ty, self.lower_const_body(span, body))
459+
}
460+
460461
fn lower_use_tree(
461462
&mut self,
462463
tree: &UseTree,
@@ -678,11 +679,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
678679

679680
hir::ForeignItemKind::Fn(fn_dec, fn_args, generics)
680681
}
681-
ForeignItemKind::Static(ref t, m) => {
682+
ForeignItemKind::Static(ref t, m, _) => {
682683
let ty = self.lower_ty(t, ImplTraitContext::disallowed());
683684
hir::ForeignItemKind::Static(ty, m)
684685
}
685-
ForeignItemKind::Ty => hir::ForeignItemKind::Type,
686+
ForeignItemKind::Const(ref t, _) => {
687+
// For recovery purposes.
688+
let ty = self.lower_ty(t, ImplTraitContext::disallowed());
689+
hir::ForeignItemKind::Static(ty, Mutability::Not)
690+
}
691+
ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
686692
ForeignItemKind::Macro(_) => panic!("macro shouldn't exist here"),
687693
},
688694
vis: self.lower_visibility(&i.vis, None),
@@ -759,32 +765,27 @@ impl<'hir> LoweringContext<'_, 'hir> {
759765
let trait_item_def_id = self.resolver.definitions().local_def_id(i.id);
760766

761767
let (generics, kind) = match i.kind {
762-
AssocItemKind::Const(ref ty, ref default) => {
763-
let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed());
768+
AssocItemKind::Static(ref ty, _, ref default) // Let's pretend this is a `const`.
769+
| AssocItemKind::Const(ref ty, ref default) => {
764770
let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
765-
(
766-
generics,
767-
hir::TraitItemKind::Const(
768-
ty,
769-
default.as_ref().map(|x| self.lower_const_body(i.span, Some(x))),
770-
),
771-
)
771+
let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
772+
(hir::Generics::empty(), hir::TraitItemKind::Const(ty, body))
772773
}
773-
AssocItemKind::Fn(ref sig, None) => {
774+
AssocItemKind::Fn(ref sig, ref generics, None) => {
774775
let names = self.lower_fn_params_to_names(&sig.decl);
775776
let (generics, sig) =
776-
self.lower_method_sig(&i.generics, sig, trait_item_def_id, false, None);
777+
self.lower_method_sig(generics, sig, trait_item_def_id, false, None);
777778
(generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Required(names)))
778779
}
779-
AssocItemKind::Fn(ref sig, Some(ref body)) => {
780+
AssocItemKind::Fn(ref sig, ref generics, Some(ref body)) => {
780781
let body_id = self.lower_fn_body_block(i.span, &sig.decl, Some(body));
781782
let (generics, sig) =
782-
self.lower_method_sig(&i.generics, sig, trait_item_def_id, false, None);
783+
self.lower_method_sig(generics, sig, trait_item_def_id, false, None);
783784
(generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id)))
784785
}
785-
AssocItemKind::TyAlias(ref bounds, ref default) => {
786+
AssocItemKind::TyAlias(ref generics, ref bounds, ref default) => {
786787
let ty = default.as_ref().map(|x| self.lower_ty(x, ImplTraitContext::disallowed()));
787-
let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed());
788+
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
788789
let kind = hir::TraitItemKind::Type(
789790
self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
790791
ty,
@@ -806,10 +807,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
806807
}
807808

808809
fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
809-
let (kind, has_default) = match i.kind {
810-
AssocItemKind::Const(_, ref default) => (hir::AssocItemKind::Const, default.is_some()),
811-
AssocItemKind::TyAlias(_, ref default) => (hir::AssocItemKind::Type, default.is_some()),
812-
AssocItemKind::Fn(ref sig, ref default) => {
810+
let (kind, has_default) = match &i.kind {
811+
AssocItemKind::Static(_, _, default) // Let's pretend this is a `const` for recovery.
812+
| AssocItemKind::Const(_, default) => {
813+
(hir::AssocItemKind::Const, default.is_some())
814+
}
815+
AssocItemKind::TyAlias(_, _, default) => (hir::AssocItemKind::Type, default.is_some()),
816+
AssocItemKind::Fn(sig, _, default) => {
813817
(hir::AssocItemKind::Method { has_self: sig.decl.has_self() }, default.is_some())
814818
}
815819
AssocItemKind::Macro(..) => unimplemented!(),
@@ -832,22 +836,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
832836
let impl_item_def_id = self.resolver.definitions().local_def_id(i.id);
833837

834838
let (generics, kind) = match i.kind {
835-
AssocItemKind::Const(ref ty, ref expr) => {
836-
let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed());
839+
AssocItemKind::Static(ref ty, _, ref expr) | AssocItemKind::Const(ref ty, ref expr) => {
837840
let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
838841
(
839-
generics,
842+
hir::Generics::empty(),
840843
hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
841844
)
842845
}
843-
AssocItemKind::Fn(ref sig, ref body) => {
846+
AssocItemKind::Fn(ref sig, ref generics, ref body) => {
844847
self.current_item = Some(i.span);
845848
let asyncness = sig.header.asyncness;
846849
let body_id =
847850
self.lower_maybe_async_body(i.span, &sig.decl, asyncness, body.as_deref());
848851
let impl_trait_return_allow = !self.is_in_trait_impl;
849852
let (generics, sig) = self.lower_method_sig(
850-
&i.generics,
853+
generics,
851854
sig,
852855
impl_item_def_id,
853856
impl_trait_return_allow,
@@ -856,8 +859,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
856859

857860
(generics, hir::ImplItemKind::Method(sig, body_id))
858861
}
859-
AssocItemKind::TyAlias(_, ref ty) => {
860-
let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed());
862+
AssocItemKind::TyAlias(ref generics, _, ref ty) => {
863+
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
861864
let kind = match ty {
862865
None => {
863866
let ty = self.arena.alloc(self.ty(i.span, hir::TyKind::Err));
@@ -901,14 +904,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
901904
vis: self.lower_visibility(&i.vis, Some(i.id)),
902905
defaultness: self.lower_defaultness(i.defaultness, true /* [1] */),
903906
kind: match &i.kind {
904-
AssocItemKind::Const(..) => hir::AssocItemKind::Const,
905-
AssocItemKind::TyAlias(_, ty) => {
907+
AssocItemKind::Static(..) // Let's pretend this is a `const` for recovery.
908+
| AssocItemKind::Const(..) => hir::AssocItemKind::Const,
909+
AssocItemKind::TyAlias(_, _, ty) => {
906910
match ty.as_deref().and_then(|ty| ty.kind.opaque_top_hack()) {
907911
None => hir::AssocItemKind::Type,
908912
Some(_) => hir::AssocItemKind::OpaqueTy,
909913
}
910914
}
911-
AssocItemKind::Fn(sig, _) => {
915+
AssocItemKind::Fn(sig, _, _) => {
912916
hir::AssocItemKind::Method { has_self: sig.decl.has_self() }
913917
}
914918
AssocItemKind::Macro(..) => unimplemented!(),

src/librustc_ast_lowering/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
490490
self.lctx.allocate_hir_id_counter(item.id);
491491
let owner = match (&item.kind, ctxt) {
492492
// Ignore patterns in trait methods without bodies.
493-
(AssocItemKind::Fn(_, None), AssocCtxt::Trait) => None,
493+
(AssocItemKind::Fn(_, _, None), AssocCtxt::Trait) => None,
494494
_ => Some(item.id),
495495
};
496496
self.with_hir_id_owner(owner, |this| visit::walk_assoc_item(this, item, ctxt));

src/librustc_ast_passes/ast_validation.rs

+89-8
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ use syntax::expand::is_proc_macro_attr;
2222
use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
2323
use syntax::walk_list;
2424

25+
const MORE_EXTERN: &str =
26+
"for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
27+
2528
/// Is `self` allowed semantically as the first parameter in an `FnDecl`?
2629
enum SelfSemantic {
2730
Yes,
@@ -423,14 +426,62 @@ impl<'a> AstValidator<'a> {
423426
}
424427
}
425428

426-
fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) {
429+
fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
427430
let span = match bounds {
428431
[] => return,
429432
[b0] => b0.span(),
430433
[b0, .., bl] => b0.span().to(bl.span()),
431434
};
432435
self.err_handler()
433-
.struct_span_err(span, "bounds on associated `type`s in `impl`s have no effect")
436+
.struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
437+
.emit();
438+
}
439+
440+
fn check_foreign_ty_genericless(&self, generics: &Generics) {
441+
let cannot_have = |span, descr, remove_descr| {
442+
self.err_handler()
443+
.struct_span_err(
444+
span,
445+
&format!("`type`s inside `extern` blocks cannot have {}", descr),
446+
)
447+
.span_suggestion(
448+
span,
449+
&format!("remove the {}", remove_descr),
450+
String::new(),
451+
Applicability::MaybeIncorrect,
452+
)
453+
.span_label(self.current_extern_span(), "`extern` block begins here")
454+
.note(MORE_EXTERN)
455+
.emit();
456+
};
457+
458+
if !generics.params.is_empty() {
459+
cannot_have(generics.span, "generic parameters", "generic parameters");
460+
}
461+
462+
if !generics.where_clause.predicates.is_empty() {
463+
cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause");
464+
}
465+
}
466+
467+
fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
468+
let body = match body {
469+
None => return,
470+
Some(body) => body,
471+
};
472+
self.err_handler()
473+
.struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
474+
.span_label(ident.span, "cannot have a body")
475+
.span_label(body, "the invalid body")
476+
.span_label(
477+
self.current_extern_span(),
478+
format!(
479+
"`extern` blocks define existing foreign {0}s and {0}s \
480+
inside of them cannot have a body",
481+
kind
482+
),
483+
)
484+
.note(MORE_EXTERN)
434485
.emit();
435486
}
436487

@@ -458,7 +509,7 @@ impl<'a> AstValidator<'a> {
458509
"`extern` blocks define existing foreign functions and functions \
459510
inside of them cannot have a body",
460511
)
461-
.note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html")
512+
.note(MORE_EXTERN)
462513
.emit();
463514
}
464515

@@ -531,6 +582,16 @@ impl<'a> AstValidator<'a> {
531582
}
532583
}
533584
}
585+
586+
fn check_item_named(&self, ident: Ident, kind: &str) {
587+
if ident.name != kw::Underscore {
588+
return;
589+
}
590+
self.err_handler()
591+
.struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
592+
.span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
593+
.emit();
594+
}
534595
}
535596

536597
enum GenericPosition {
@@ -900,6 +961,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
900961
self.err_handler().span_err(item.span, "unions cannot have zero fields");
901962
}
902963
}
964+
ItemKind::Const(.., None) => {
965+
let msg = "free constant item without body";
966+
self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
967+
}
968+
ItemKind::Static(.., None) => {
969+
let msg = "free static item without body";
970+
self.error_item_without_body(item.span, "static", msg, " = <expr>;");
971+
}
903972
_ => {}
904973
}
905974

@@ -912,7 +981,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
912981
self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
913982
self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
914983
}
915-
ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {}
984+
ForeignItemKind::TyAlias(generics, bounds, body) => {
985+
self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
986+
self.check_type_no_bounds(bounds, "`extern` blocks");
987+
self.check_foreign_ty_genericless(generics);
988+
}
989+
ForeignItemKind::Static(_, _, body) => {
990+
self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
991+
}
992+
ForeignItemKind::Const(..) | ForeignItemKind::Macro(..) => {}
916993
}
917994

918995
visit::walk_foreign_item(self, fi)
@@ -1154,25 +1231,29 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11541231
AssocItemKind::Const(_, body) => {
11551232
self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
11561233
}
1157-
AssocItemKind::Fn(_, body) => {
1234+
AssocItemKind::Fn(_, _, body) => {
11581235
self.check_impl_item_provided(item.span, body, "function", " { <body> }");
11591236
}
1160-
AssocItemKind::TyAlias(bounds, body) => {
1237+
AssocItemKind::TyAlias(_, bounds, body) => {
11611238
self.check_impl_item_provided(item.span, body, "type", " = <type>;");
1162-
self.check_impl_assoc_type_no_bounds(bounds);
1239+
self.check_type_no_bounds(bounds, "`impl`s");
11631240
}
11641241
_ => {}
11651242
}
11661243
}
11671244

11681245
if ctxt == AssocCtxt::Trait || self.in_trait_impl {
11691246
self.invalid_visibility(&item.vis, None);
1170-
if let AssocItemKind::Fn(sig, _) = &item.kind {
1247+
if let AssocItemKind::Fn(sig, _, _) = &item.kind {
11711248
self.check_trait_fn_not_const(sig.header.constness);
11721249
self.check_trait_fn_not_async(item.span, sig.header.asyncness);
11731250
}
11741251
}
11751252

1253+
if let AssocItemKind::Const(..) = item.kind {
1254+
self.check_item_named(item.ident, "const");
1255+
}
1256+
11761257
self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
11771258
}
11781259
}

0 commit comments

Comments
 (0)