ast: normalize ForeignItemKind::Ty & AssocItemKind::TyAlias.

This commit is contained in:
Mazdak Farrokhzad 2020-02-14 12:55:42 +01:00
parent e2ae717265
commit 95dc9b9a73
18 changed files with 192 additions and 37 deletions

View File

@ -682,7 +682,7 @@ fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem<'hir> {
let ty = self.lower_ty(t, ImplTraitContext::disallowed()); let ty = self.lower_ty(t, ImplTraitContext::disallowed());
hir::ForeignItemKind::Static(ty, m) hir::ForeignItemKind::Static(ty, m)
} }
ForeignItemKind::Ty => hir::ForeignItemKind::Type, ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
ForeignItemKind::Macro(_) => panic!("macro shouldn't exist here"), ForeignItemKind::Macro(_) => panic!("macro shouldn't exist here"),
}, },
vis: self.lower_visibility(&i.vis, None), vis: self.lower_visibility(&i.vis, None),

View File

@ -22,6 +22,9 @@
use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use syntax::walk_list; use syntax::walk_list;
const MORE_EXTERN: &str =
"for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
/// Is `self` allowed semantically as the first parameter in an `FnDecl`? /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
enum SelfSemantic { enum SelfSemantic {
Yes, Yes,
@ -423,14 +426,59 @@ fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sug
} }
} }
fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) { fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
let span = match bounds { let span = match bounds {
[] => return, [] => return,
[b0] => b0.span(), [b0] => b0.span(),
[b0, .., bl] => b0.span().to(bl.span()), [b0, .., bl] => b0.span().to(bl.span()),
}; };
self.err_handler() self.err_handler()
.struct_span_err(span, "bounds on associated `type`s in `impl`s have no effect") .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
.emit();
}
fn check_foreign_ty_genericless(&self, generics: &Generics) {
let cannot_have = |span, descr, remove_descr| {
self.err_handler()
.struct_span_err(
span,
&format!("`type`s inside `extern` blocks cannot have {}", descr),
)
.span_suggestion(
span,
&format!("remove the {}", remove_descr),
String::new(),
Applicability::MaybeIncorrect,
)
.span_label(self.current_extern_span(), "`extern` block begins here")
.note(MORE_EXTERN)
.emit();
};
if !generics.params.is_empty() {
cannot_have(generics.span, "generic parameters", "generic parameters");
}
if !generics.where_clause.predicates.is_empty() {
cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause");
}
}
fn check_foreign_ty_bodyless(&self, ident: Ident, body: Option<&Ty>) {
let body = match body {
None => return,
Some(body) => body,
};
self.err_handler()
.struct_span_err(ident.span, "incorrect `type` inside `extern` block")
.span_label(ident.span, "cannot have a body")
.span_label(body.span, "the invalid body")
.span_label(
self.current_extern_span(),
"`extern` blocks define existing foreign types and types \
inside of them cannot have a body",
)
.note(MORE_EXTERN)
.emit(); .emit();
} }
@ -458,7 +506,7 @@ fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
"`extern` blocks define existing foreign functions and functions \ "`extern` blocks define existing foreign functions and functions \
inside of them cannot have a body", inside of them cannot have a body",
) )
.note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html") .note(MORE_EXTERN)
.emit(); .emit();
} }
@ -912,7 +960,12 @@ fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
self.check_foreign_fn_bodyless(fi.ident, body.as_deref()); self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header); self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
} }
ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {} ForeignItemKind::TyAlias(generics, bounds, body) => {
self.check_foreign_ty_bodyless(fi.ident, body.as_deref());
self.check_type_no_bounds(bounds, "`extern` blocks");
self.check_foreign_ty_genericless(generics);
}
ForeignItemKind::Static(..) | ForeignItemKind::Macro(..) => {}
} }
visit::walk_foreign_item(self, fi) visit::walk_foreign_item(self, fi)
@ -1159,7 +1212,7 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
} }
AssocItemKind::TyAlias(_, bounds, body) => { AssocItemKind::TyAlias(_, bounds, body) => {
self.check_impl_item_provided(item.span, body, "type", " = <type>;"); self.check_impl_item_provided(item.span, body, "type", " = <type>;");
self.check_impl_assoc_type_no_bounds(bounds); self.check_type_no_bounds(bounds, "`impl`s");
} }
_ => {} _ => {}
} }

View File

@ -397,7 +397,7 @@ fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
); );
} }
} }
ast::ForeignItemKind::Ty => { ast::ForeignItemKind::TyAlias(..) => {
gate_feature_post!(&self, extern_types, i.span, "extern types are experimental"); gate_feature_post!(&self, extern_types, i.span, "extern types are experimental");
} }
ast::ForeignItemKind::Macro(..) => {} ast::ForeignItemKind::Macro(..) => {}

View File

@ -1019,13 +1019,13 @@ pub fn print_type(&mut self, ty: &ast::Ty) {
self.hardbreak_if_not_bol(); self.hardbreak_if_not_bol();
self.maybe_print_comment(item.span.lo()); self.maybe_print_comment(item.span.lo());
self.print_outer_attributes(&item.attrs); self.print_outer_attributes(&item.attrs);
match item.kind { match &item.kind {
ast::ForeignItemKind::Fn(ref sig, ref gen, ref body) => { ast::ForeignItemKind::Fn(sig, gen, body) => {
self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs); self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs);
} }
ast::ForeignItemKind::Static(ref t, m) => { ast::ForeignItemKind::Static(t, m) => {
self.head(visibility_qualified(&item.vis, "static")); self.head(visibility_qualified(&item.vis, "static"));
if m == ast::Mutability::Mut { if *m == ast::Mutability::Mut {
self.word_space("mut"); self.word_space("mut");
} }
self.print_ident(item.ident); self.print_ident(item.ident);
@ -1035,14 +1035,10 @@ pub fn print_type(&mut self, ty: &ast::Ty) {
self.end(); // end the head-ibox self.end(); // end the head-ibox
self.end(); // end the outer cbox self.end(); // end the outer cbox
} }
ast::ForeignItemKind::Ty => { ast::ForeignItemKind::TyAlias(generics, bounds, ty) => {
self.head(visibility_qualified(&item.vis, "type")); self.print_associated_type(item.ident, generics, bounds, ty.as_deref());
self.print_ident(item.ident);
self.s.word(";");
self.end(); // end the head-ibox
self.end(); // end the outer cbox
} }
ast::ForeignItemKind::Macro(ref m) => { ast::ForeignItemKind::Macro(m) => {
self.print_mac(m); self.print_mac(m);
if m.args.need_semicolon() { if m.args.need_semicolon() {
self.s.word(";"); self.s.word(";");

View File

@ -876,7 +876,7 @@ pub fn parse_foreign_item(&mut self, at_end: &mut bool) -> PResult<'a, P<Foreign
let lo = self.token.span; let lo = self.token.span;
let vis = self.parse_visibility(FollowedByType::No)?; let vis = self.parse_visibility(FollowedByType::No)?;
let (ident, kind) = if self.check_keyword(kw::Type) { let (ident, kind) = if self.eat_keyword(kw::Type) {
// FOREIGN TYPE ITEM // FOREIGN TYPE ITEM
self.parse_item_foreign_type()? self.parse_item_foreign_type()?
} else if self.check_fn_front_matter() { } else if self.check_fn_front_matter() {
@ -925,10 +925,12 @@ fn parse_item_foreign_static(&mut self) -> PResult<'a, (Ident, ForeignItemKind)>
/// Parses a type from a foreign module. /// Parses a type from a foreign module.
fn parse_item_foreign_type(&mut self) -> PResult<'a, (Ident, ForeignItemKind)> { fn parse_item_foreign_type(&mut self) -> PResult<'a, (Ident, ForeignItemKind)> {
self.expect_keyword(kw::Type)?; let (ident, kind) = self.parse_assoc_ty()?;
let ident = self.parse_ident()?; let kind = match kind {
self.expect_semi()?; AssocItemKind::TyAlias(g, b, d) => ForeignItemKind::TyAlias(g, b, d),
Ok((ident, ForeignItemKind::Ty)) _ => unreachable!(),
};
Ok((ident, kind))
} }
fn is_static_global(&mut self) -> bool { fn is_static_global(&mut self) -> bool {

View File

@ -829,7 +829,7 @@ fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem) {
ForeignItemKind::Static(..) => { ForeignItemKind::Static(..) => {
(Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id)), ValueNS) (Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id)), ValueNS)
} }
ForeignItemKind::Ty => { ForeignItemKind::TyAlias(..) => {
(Res::Def(DefKind::ForeignTy, self.r.definitions.local_def_id(item.id)), TypeNS) (Res::Def(DefKind::ForeignTy, self.r.definitions.local_def_id(item.id)), TypeNS)
} }
ForeignItemKind::Macro(_) => unreachable!(), ForeignItemKind::Macro(_) => unreachable!(),

View File

@ -437,7 +437,8 @@ fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, m: &'ast TraitBound
} }
fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) { fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
match foreign_item.kind { match foreign_item.kind {
ForeignItemKind::Fn(_, ref generics, _) => { ForeignItemKind::Fn(_, ref generics, _)
| ForeignItemKind::TyAlias(ref generics, ..) => {
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
visit::walk_foreign_item(this, foreign_item); visit::walk_foreign_item(this, foreign_item);
}); });
@ -447,7 +448,7 @@ fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
visit::walk_foreign_item(this, foreign_item); visit::walk_foreign_item(this, foreign_item);
}); });
} }
ForeignItemKind::Ty | ForeignItemKind::Macro(..) => { ForeignItemKind::Macro(..) => {
visit::walk_foreign_item(self, foreign_item); visit::walk_foreign_item(self, foreign_item);
} }
} }

View File

@ -1540,7 +1540,7 @@ fn visit_foreign_item(&mut self, item: &'l ast::ForeignItem) {
self.visit_ty(ty); self.visit_ty(ty);
} }
ast::ForeignItemKind::Ty => { ast::ForeignItemKind::TyAlias(..) => {
if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) { if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
down_cast_data!(var_data, DefData, item.span); down_cast_data!(var_data, DefData, item.span);
self.dumper.dump_def(&access, var_data); self.dumper.dump_def(&access, var_data);

View File

@ -173,7 +173,7 @@ pub fn get_extern_item_data(&self, item: &ast::ForeignItem) -> Option<Data> {
})) }))
} }
// FIXME(plietar): needs a new DefKind in rls-data // FIXME(plietar): needs a new DefKind in rls-data
ast::ForeignItemKind::Ty => None, ast::ForeignItemKind::TyAlias(..) => None,
ast::ForeignItemKind::Macro(..) => None, ast::ForeignItemKind::Macro(..) => None,
} }
} }

View File

@ -773,7 +773,7 @@ fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_,
Ok(extend_sig(ty_sig, text, defs, vec![])) Ok(extend_sig(ty_sig, text, defs, vec![]))
} }
ast::ForeignItemKind::Ty => { ast::ForeignItemKind::TyAlias(..) => {
let mut text = "type ".to_owned(); let mut text = "type ".to_owned();
let name = self.ident.to_string(); let name = self.ident.to_string();
let defs = vec![SigElement { let defs = vec![SigElement {

View File

@ -2610,7 +2610,7 @@ pub enum ForeignItemKind {
/// A function. /// A function.
Fn(FnSig, Generics, Option<P<Block>>), Fn(FnSig, Generics, Option<P<Block>>),
/// A type. /// A type.
Ty, TyAlias(Generics, GenericBounds, Option<P<Ty>>),
/// A macro expanding to an item. /// A macro expanding to an item.
Macro(Mac), Macro(Mac),
} }
@ -2620,7 +2620,7 @@ pub fn descriptive_variant(&self) -> &str {
match *self { match *self {
ForeignItemKind::Fn(..) => "foreign function", ForeignItemKind::Fn(..) => "foreign function",
ForeignItemKind::Static(..) => "foreign static item", ForeignItemKind::Static(..) => "foreign static item",
ForeignItemKind::Ty => "foreign type", ForeignItemKind::TyAlias(..) => "foreign type",
ForeignItemKind::Macro(..) => "macro in foreign module", ForeignItemKind::Macro(..) => "macro in foreign module",
} }
} }

View File

@ -1051,7 +1051,11 @@ pub fn noop_flat_map_foreign_item<T: MutVisitor>(
visit_opt(body, |body| visitor.visit_block(body)); visit_opt(body, |body| visitor.visit_block(body));
} }
ForeignItemKind::Static(t, _m) => visitor.visit_ty(t), ForeignItemKind::Static(t, _m) => visitor.visit_ty(t),
ForeignItemKind::Ty => {} ForeignItemKind::TyAlias(generics, bounds, ty) => {
visitor.visit_generics(generics);
visit_bounds(bounds, visitor);
visit_opt(ty, |ty| visitor.visit_ty(ty));
}
ForeignItemKind::Macro(mac) => visitor.visit_mac(mac), ForeignItemKind::Macro(mac) => visitor.visit_mac(mac),
} }
visitor.visit_id(id); visitor.visit_id(id);

View File

@ -535,7 +535,11 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI
visitor.visit_fn(kind, item.span, item.id); visitor.visit_fn(kind, item.span, item.id);
} }
ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ), ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ),
ForeignItemKind::Ty => (), ForeignItemKind::TyAlias(ref generics, ref bounds, ref ty) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_ty, ty);
}
ForeignItemKind::Macro(ref mac) => visitor.visit_mac(mac), ForeignItemKind::Macro(ref mac) => visitor.visit_mac(mac),
} }

View File

@ -0,0 +1,18 @@
#![feature(extern_types)]
fn main() {}
extern "C" {
type A: Ord;
//~^ ERROR bounds on `type`s in `extern` blocks have no effect
type B<'a> where 'a: 'static;
//~^ ERROR `type`s inside `extern` blocks cannot have generic parameters
//~| ERROR `type`s inside `extern` blocks cannot have `where` clauses
type C<T: Ord> where T: 'static;
//~^ ERROR `type`s inside `extern` blocks cannot have generic parameters
//~| ERROR `type`s inside `extern` blocks cannot have `where` clauses
type D = u8;
//~^ ERROR incorrect `type` inside `extern` block
type E: where;
}

View File

@ -0,0 +1,65 @@
error: bounds on `type`s in `extern` blocks have no effect
--> $DIR/foreign-ty-semantic-fail.rs:6:13
|
LL | type A: Ord;
| ^^^
error: `type`s inside `extern` blocks cannot have generic parameters
--> $DIR/foreign-ty-semantic-fail.rs:8:11
|
LL | extern "C" {
| ---------- `extern` block begins here
...
LL | type B<'a> where 'a: 'static;
| ^^^^ help: remove the generic parameters
|
= note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
error: `type`s inside `extern` blocks cannot have `where` clauses
--> $DIR/foreign-ty-semantic-fail.rs:8:16
|
LL | extern "C" {
| ---------- `extern` block begins here
...
LL | type B<'a> where 'a: 'static;
| ^^^^^^^^^^^^^^^^^ help: remove the `where` clause
|
= note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
error: `type`s inside `extern` blocks cannot have generic parameters
--> $DIR/foreign-ty-semantic-fail.rs:11:11
|
LL | extern "C" {
| ---------- `extern` block begins here
...
LL | type C<T: Ord> where T: 'static;
| ^^^^^^^^ help: remove the generic parameters
|
= note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
error: `type`s inside `extern` blocks cannot have `where` clauses
--> $DIR/foreign-ty-semantic-fail.rs:11:20
|
LL | extern "C" {
| ---------- `extern` block begins here
...
LL | type C<T: Ord> where T: 'static;
| ^^^^^^^^^^^^^^^^ help: remove the `where` clause
|
= note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
error: incorrect `type` inside `extern` block
--> $DIR/foreign-ty-semantic-fail.rs:14:10
|
LL | extern "C" {
| ---------- `extern` blocks define existing foreign types and types inside of them cannot have a body
...
LL | type D = u8;
| ^ -- the invalid body
| |
| cannot have a body
|
= note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
error: aborting due to 6 previous errors

View File

@ -0,0 +1,12 @@
// check-pass
fn main() {}
#[cfg(FALSE)]
extern "C" {
type A: Ord;
type A<'a> where 'a: 'static;
type A<T: Ord> where T: 'static;
type A = u8;
type A<'a: 'static, T: Ord + 'static>: Eq + PartialEq where T: 'static + Copy = Vec<u8>;
}

View File

@ -11,11 +11,11 @@ impl X {
//~| ERROR associated types are not yet supported in inherent impls //~| ERROR associated types are not yet supported in inherent impls
type Z: Ord; type Z: Ord;
//~^ ERROR associated type in `impl` without body //~^ ERROR associated type in `impl` without body
//~| ERROR bounds on associated `type`s in `impl`s have no effect //~| ERROR bounds on `type`s in `impl`s have no effect
//~| ERROR associated types are not yet supported in inherent impls //~| ERROR associated types are not yet supported in inherent impls
type W: Ord where Self: Eq; type W: Ord where Self: Eq;
//~^ ERROR associated type in `impl` without body //~^ ERROR associated type in `impl` without body
//~| ERROR bounds on associated `type`s in `impl`s have no effect //~| ERROR bounds on `type`s in `impl`s have no effect
//~| ERROR associated types are not yet supported in inherent impls //~| ERROR associated types are not yet supported in inherent impls
type W where Self: Eq; type W where Self: Eq;
//~^ ERROR associated type in `impl` without body //~^ ERROR associated type in `impl` without body

View File

@ -14,7 +14,7 @@ LL | type Z: Ord;
| | | |
| help: provide a definition for the type: `= <type>;` | help: provide a definition for the type: `= <type>;`
error: bounds on associated `type`s in `impl`s have no effect error: bounds on `type`s in `impl`s have no effect
--> $DIR/impl-item-type-no-body-semantic-fail.rs:12:13 --> $DIR/impl-item-type-no-body-semantic-fail.rs:12:13
| |
LL | type Z: Ord; LL | type Z: Ord;
@ -28,7 +28,7 @@ LL | type W: Ord where Self: Eq;
| | | |
| help: provide a definition for the type: `= <type>;` | help: provide a definition for the type: `= <type>;`
error: bounds on associated `type`s in `impl`s have no effect error: bounds on `type`s in `impl`s have no effect
--> $DIR/impl-item-type-no-body-semantic-fail.rs:16:13 --> $DIR/impl-item-type-no-body-semantic-fail.rs:16:13
| |
LL | type W: Ord where Self: Eq; LL | type W: Ord where Self: Eq;