parse: allow `type Foo: Ord` syntactically.

This commit is contained in:
Mazdak Farrokhzad 2020-02-21 23:00:27 +01:00
parent 14442e0ebb
commit 9f3dfd29a2
18 changed files with 160 additions and 61 deletions

View File

@ -297,28 +297,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(m)), ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(m)),
ItemKind::ForeignMod(ref nm) => hir::ItemKind::ForeignMod(self.lower_foreign_mod(nm)), ItemKind::ForeignMod(ref nm) => hir::ItemKind::ForeignMod(self.lower_foreign_mod(nm)),
ItemKind::GlobalAsm(ref ga) => hir::ItemKind::GlobalAsm(self.lower_global_asm(ga)), ItemKind::GlobalAsm(ref ga) => hir::ItemKind::GlobalAsm(self.lower_global_asm(ga)),
ItemKind::TyAlias(ref ty, ref generics) => match ty.kind.opaque_top_hack() { ItemKind::TyAlias(ref generics, _, Some(ref ty)) => match ty.kind.opaque_top_hack() {
None => { None => {
let ty = self.lower_ty(ty, ImplTraitContext::disallowed()); let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
let generics = self.lower_generics(generics, ImplTraitContext::disallowed()); let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
hir::ItemKind::TyAlias(ty, generics) hir::ItemKind::TyAlias(ty, generics)
} }
Some(bounds) => { Some(bounds) => {
let ctx = || ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc);
let ty = hir::OpaqueTy { let ty = hir::OpaqueTy {
generics: self.lower_generics( generics: self.lower_generics(generics, ctx()),
generics, bounds: self.lower_param_bounds(bounds, ctx()),
ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc),
),
bounds: self.lower_param_bounds(
bounds,
ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc),
),
impl_trait_fn: None, impl_trait_fn: None,
origin: hir::OpaqueTyOrigin::TypeAlias, origin: hir::OpaqueTyOrigin::TypeAlias,
}; };
hir::ItemKind::OpaqueTy(ty) hir::ItemKind::OpaqueTy(ty)
} }
}, },
ItemKind::TyAlias(ref generics, _, None) => {
let ty = self.arena.alloc(self.ty(span, hir::TyKind::Err));
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
hir::ItemKind::TyAlias(ty, generics)
}
ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum( ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum(
hir::EnumDef { hir::EnumDef {
variants: self.arena.alloc_from_iter( variants: self.arena.alloc_from_iter(

View File

@ -462,7 +462,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ItemKind::Struct(_, ref generics) ItemKind::Struct(_, ref generics)
| ItemKind::Union(_, ref generics) | ItemKind::Union(_, ref generics)
| ItemKind::Enum(_, ref generics) | ItemKind::Enum(_, ref generics)
| ItemKind::TyAlias(_, ref generics) | ItemKind::TyAlias(ref generics, ..)
| ItemKind::Trait(_, _, ref generics, ..) => { | ItemKind::Trait(_, _, ref generics, ..) => {
let def_id = self.lctx.resolver.definitions().local_def_id(item.id); let def_id = self.lctx.resolver.definitions().local_def_id(item.id);
let count = generics let count = generics

View File

@ -969,6 +969,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
let msg = "free static item without body"; let msg = "free static item without body";
self.error_item_without_body(item.span, "static", msg, " = <expr>;"); self.error_item_without_body(item.span, "static", msg, " = <expr>;");
} }
ItemKind::TyAlias(_, ref bounds, ref body) => {
if body.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");
}
_ => {} _ => {}
} }

View File

@ -372,7 +372,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
gate_feature_post!(&self, decl_macro, i.span, msg); gate_feature_post!(&self, decl_macro, i.span, msg);
} }
ast::ItemKind::TyAlias(ref ty, ..) => self.check_impl_trait(&ty), ast::ItemKind::TyAlias(_, _, Some(ref ty)) => self.check_impl_trait(&ty),
_ => {} _ => {}
} }

View File

@ -1185,18 +1185,10 @@ impl<'a> State<'a> {
self.s.word(ga.asm.to_string()); self.s.word(ga.asm.to_string());
self.end(); self.end();
} }
ast::ItemKind::TyAlias(ref ty, ref generics) => { ast::ItemKind::TyAlias(ref generics, ref bounds, ref ty) => {
self.head(visibility_qualified(&item.vis, "type")); let def = ast::Defaultness::Final;
self.print_ident(item.ident); let ty = ty.as_deref();
self.print_generic_params(&generics.params); self.print_associated_type(item.ident, generics, bounds, ty, &item.vis, def);
self.end(); // end the inner ibox
self.print_where_clause(&generics.where_clause);
self.s.space();
self.word_space("=");
self.print_type(ty);
self.s.word(";");
self.end(); // end the outer ibox
} }
ast::ItemKind::Enum(ref enum_definition, ref params) => { ast::ItemKind::Enum(ref enum_definition, ref params) => {
self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis); self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis);

View File

@ -156,8 +156,7 @@ impl<'a> Parser<'a> {
self.parse_item_mod(attrs)? self.parse_item_mod(attrs)?
} else if self.eat_keyword(kw::Type) { } else if self.eat_keyword(kw::Type) {
// TYPE ITEM // TYPE ITEM
let (ident, ty, generics) = self.parse_type_alias()?; self.parse_type_alias()?
(ident, ItemKind::TyAlias(ty, generics))
} else if self.eat_keyword(kw::Enum) { } else if self.eat_keyword(kw::Enum) {
// ENUM ITEM // ENUM ITEM
self.parse_item_enum()? self.parse_item_enum()?
@ -676,7 +675,10 @@ impl<'a> Parser<'a> {
vis: &Visibility, vis: &Visibility,
) -> PResult<'a, (Ident, AssocItemKind)> { ) -> PResult<'a, (Ident, AssocItemKind)> {
if self.eat_keyword(kw::Type) { if self.eat_keyword(kw::Type) {
self.parse_assoc_ty() match self.parse_type_alias()? {
(ident, ItemKind::TyAlias(a, b, c)) => Ok((ident, AssocItemKind::TyAlias(a, b, c))),
_ => unreachable!(),
}
} else if self.check_fn_front_matter() { } else if self.check_fn_front_matter() {
let (ident, sig, generics, body) = self.parse_fn(at_end, attrs, req_name)?; let (ident, sig, generics, body) = self.parse_fn(at_end, attrs, req_name)?;
Ok((ident, AssocItemKind::Fn(sig, generics, body))) Ok((ident, AssocItemKind::Fn(sig, generics, body)))
@ -700,10 +702,12 @@ impl<'a> Parser<'a> {
} }
} }
/// Parses the following grammar: /// Parses a `type` alias with the following grammar:
/// /// ```
/// AssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty] /// TypeAlias = "type" Ident Generics {":" GenericBounds}? {"=" Ty}? ";" ;
fn parse_assoc_ty(&mut self) -> PResult<'a, (Ident, AssocItemKind)> { /// ```
/// The `"type"` has already been eaten.
fn parse_type_alias(&mut self) -> PResult<'a, (Ident, ItemKind)> {
let ident = self.parse_ident()?; let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?; let mut generics = self.parse_generics()?;
@ -715,7 +719,7 @@ impl<'a> Parser<'a> {
let default = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None }; let default = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
self.expect_semi()?; self.expect_semi()?;
Ok((ident, AssocItemKind::TyAlias(generics, bounds, default))) Ok((ident, ItemKind::TyAlias(generics, bounds, default)))
} }
/// Parses a `UseTree`. /// Parses a `UseTree`.
@ -989,18 +993,6 @@ impl<'a> Parser<'a> {
P(Ty { kind: TyKind::Infer, span: id.span, id: ast::DUMMY_NODE_ID }) P(Ty { kind: TyKind::Infer, span: id.span, id: ast::DUMMY_NODE_ID })
} }
/// Parses the grammar:
/// Ident ["<"...">"] ["where" ...] ("=" | ":") Ty ";"
fn parse_type_alias(&mut self) -> PResult<'a, (Ident, P<Ty>, Generics)> {
let ident = self.parse_ident()?;
let mut tps = self.parse_generics()?;
tps.where_clause = self.parse_where_clause()?;
self.expect(&token::Eq)?;
let ty = self.parse_ty()?;
self.expect_semi()?;
Ok((ident, ty, tps))
}
/// Parses an enum declaration. /// Parses an enum declaration.
fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> { fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> {
let id = self.parse_ident()?; let id = self.parse_ident()?;

View File

@ -718,8 +718,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
} }
// These items live in the type namespace. // These items live in the type namespace.
ItemKind::TyAlias(ref ty, _) => { ItemKind::TyAlias(_, _, ref ty) => {
let def_kind = match ty.kind.opaque_top_hack() { let def_kind = match ty.as_deref().and_then(|ty| ty.kind.opaque_top_hack()) {
None => DefKind::TyAlias, None => DefKind::TyAlias,
Some(_) => DefKind::OpaqueTy, Some(_) => DefKind::OpaqueTy,
}; };

View File

@ -797,7 +797,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
debug!("(resolving item) resolving {} ({:?})", name, item.kind); debug!("(resolving item) resolving {} ({:?})", name, item.kind);
match item.kind { match item.kind {
ItemKind::TyAlias(_, ref generics) | ItemKind::Fn(_, ref generics, _) => { ItemKind::TyAlias(ref generics, _, _) | ItemKind::Fn(_, ref generics, _) => {
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
visit::walk_item(this, item) visit::walk_item(this, item)
}); });

View File

@ -1311,12 +1311,15 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
self.process_mod(item); self.process_mod(item);
visit::walk_mod(self, m); visit::walk_mod(self, m);
} }
TyAlias(ref ty, ref ty_params) => { TyAlias(ref ty_params, _, ref ty) => {
let qualname = format!( let qualname = format!(
"::{}", "::{}",
self.tcx.def_path_str(self.tcx.hir().local_def_id_from_node_id(item.id)) self.tcx.def_path_str(self.tcx.hir().local_def_id_from_node_id(item.id))
); );
let value = ty_to_string(&ty); let value = match ty {
Some(ty) => ty_to_string(&ty),
None => "_".to_string(),
};
if !self.span.filter_generated(item.ident.span) { if !self.span.filter_generated(item.ident.span) {
let span = self.span_from_span(item.ident.span); let span = self.span_from_span(item.ident.span);
let id = id_from_node_id(item.id, &self.save_ctxt); let id = id_from_node_id(item.id, &self.save_ctxt);
@ -1341,7 +1344,7 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
); );
} }
self.visit_ty(&ty); walk_list!(self, visit_ty, ty);
self.process_generic_params(ty_params, &qualname, item.id); self.process_generic_params(ty_params, &qualname, item.id);
} }
Mac(_) => (), Mac(_) => (),

View File

@ -423,12 +423,15 @@ impl Sig for ast::Item {
Ok(Signature { text, defs, refs: vec![] }) Ok(Signature { text, defs, refs: vec![] })
} }
ast::ItemKind::TyAlias(ref ty, ref generics) => { ast::ItemKind::TyAlias(ref generics, _, ref ty) => {
let text = "type ".to_owned(); let text = "type ".to_owned();
let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?; let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
sig.text.push_str(" = "); sig.text.push_str(" = ");
let ty = ty.make(offset + sig.text.len(), id, scx)?; let ty = match ty {
Some(ty) => ty.make(offset + sig.text.len(), id, scx)?,
None => Err("Ty")?,
};
sig.text.push_str(&ty.text); sig.text.push_str(&ty.text);
sig.text.push(';'); sig.text.push(';');

View File

@ -2524,7 +2524,7 @@ pub enum ItemKind {
/// A type alias (`type`). /// A type alias (`type`).
/// ///
/// E.g., `type Foo = Bar<u8>;`. /// E.g., `type Foo = Bar<u8>;`.
TyAlias(P<Ty>, Generics), TyAlias(Generics, GenericBounds, Option<P<Ty>>),
/// An enum definition (`enum`). /// An enum definition (`enum`).
/// ///
/// E.g., `enum Foo<A, B> { C<A>, D<B> }`. /// E.g., `enum Foo<A, B> { C<A>, D<B> }`.
@ -2594,7 +2594,7 @@ impl ItemKind {
pub fn generics(&self) -> Option<&Generics> { pub fn generics(&self) -> Option<&Generics> {
match self { match self {
Self::Fn(_, generics, _) Self::Fn(_, generics, _)
| Self::TyAlias(_, generics) | Self::TyAlias(generics, ..)
| Self::Enum(_, generics) | Self::Enum(_, generics)
| Self::Struct(_, generics) | Self::Struct(_, generics)
| Self::Union(_, generics) | Self::Union(_, generics)

View File

@ -902,9 +902,10 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
ItemKind::Mod(m) => vis.visit_mod(m), ItemKind::Mod(m) => vis.visit_mod(m),
ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm), ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
ItemKind::GlobalAsm(_ga) => {} ItemKind::GlobalAsm(_ga) => {}
ItemKind::TyAlias(ty, generics) => { ItemKind::TyAlias(generics, bounds, ty) => {
vis.visit_ty(ty);
vis.visit_generics(generics); vis.visit_generics(generics);
visit_bounds(bounds, vis);
visit_opt(ty, |ty| vis.visit_ty(ty));
} }
ItemKind::Enum(EnumDef { variants }, generics) => { ItemKind::Enum(EnumDef { variants }, generics) => {
variants.flat_map_in_place(|variant| vis.flat_map_variant(variant)); variants.flat_map_in_place(|variant| vis.flat_map_variant(variant));

View File

@ -312,9 +312,10 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
walk_list!(visitor, visit_foreign_item, &foreign_module.items); walk_list!(visitor, visit_foreign_item, &foreign_module.items);
} }
ItemKind::GlobalAsm(ref ga) => visitor.visit_global_asm(ga), ItemKind::GlobalAsm(ref ga) => visitor.visit_global_asm(ga),
ItemKind::TyAlias(ref typ, ref generics) => { ItemKind::TyAlias(ref generics, ref bounds, ref ty) => {
visitor.visit_ty(typ); visitor.visit_generics(generics);
visitor.visit_generics(generics) walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_ty, ty);
} }
ItemKind::Enum(ref enum_definition, ref generics) => { ItemKind::Enum(ref enum_definition, ref generics) => {
visitor.visit_generics(generics); visitor.visit_generics(generics);

View File

@ -5,6 +5,6 @@ type A where 'a:, = u8; // OK
type A where 'a: 'b + 'c = u8; // OK type A where 'a: 'b + 'c = u8; // OK
type A where = u8; // OK type A where = u8; // OK
type A where 'a: 'b + = u8; // OK type A where 'a: 'b + = u8; // OK
type A where , = u8; //~ ERROR expected one of `=`, lifetime, or type, found `,` type A where , = u8; //~ ERROR expected one of `;`, `=`, lifetime, or type, found `,`
fn main() {} fn main() {}

View File

@ -1,8 +1,8 @@
error: expected one of `=`, lifetime, or type, found `,` error: expected one of `;`, `=`, lifetime, or type, found `,`
--> $DIR/bounds-lifetime-where.rs:8:14 --> $DIR/bounds-lifetime-where.rs:8:14
| |
LL | type A where , = u8; LL | type A where , = u8;
| ^ expected one of `=`, lifetime, or type | ^ expected one of `;`, `=`, lifetime, or type
error: aborting due to previous error error: aborting due to previous error

View File

@ -0,0 +1,20 @@
fn main() {}
fn semantics() {
type A: Ord;
//~^ ERROR bounds on `type`s in this context have no effect
//~| ERROR free type alias without body
type B: Ord = u8;
//~^ ERROR bounds on `type`s in this context have no effect
type C: Ord where 'static: 'static = u8;
//~^ ERROR bounds on `type`s in this context have no effect
type D<_T>: Ord;
//~^ ERROR bounds on `type`s in this context have no effect
//~| ERROR free type alias without body
type E<_T>: Ord = u8;
//~^ ERROR bounds on `type`s in this context have no effect
//~| ERROR type parameter `_T` is unused
type F<_T>: Ord where 'static: 'static = u8;
//~^ ERROR bounds on `type`s in this context have no effect
//~| ERROR type parameter `_T` is unused
}

View File

@ -0,0 +1,67 @@
error: free type alias without body
--> $DIR/item-free-type-bounds-semantic-fail.rs:4:5
|
LL | type A: Ord;
| ^^^^^^^^^^^-
| |
| help: provide a definition for the type: `= <type>;`
error: bounds on `type`s in this context have no effect
--> $DIR/item-free-type-bounds-semantic-fail.rs:4:13
|
LL | type A: Ord;
| ^^^
error: bounds on `type`s in this context have no effect
--> $DIR/item-free-type-bounds-semantic-fail.rs:7:13
|
LL | type B: Ord = u8;
| ^^^
error: bounds on `type`s in this context have no effect
--> $DIR/item-free-type-bounds-semantic-fail.rs:9:13
|
LL | type C: Ord where 'static: 'static = u8;
| ^^^
error: free type alias without body
--> $DIR/item-free-type-bounds-semantic-fail.rs:11:5
|
LL | type D<_T>: Ord;
| ^^^^^^^^^^^^^^^-
| |
| help: provide a definition for the type: `= <type>;`
error: bounds on `type`s in this context have no effect
--> $DIR/item-free-type-bounds-semantic-fail.rs:11:17
|
LL | type D<_T>: Ord;
| ^^^
error: bounds on `type`s in this context have no effect
--> $DIR/item-free-type-bounds-semantic-fail.rs:14:17
|
LL | type E<_T>: Ord = u8;
| ^^^
error: bounds on `type`s in this context have no effect
--> $DIR/item-free-type-bounds-semantic-fail.rs:17:17
|
LL | type F<_T>: Ord where 'static: 'static = u8;
| ^^^
error[E0091]: type parameter `_T` is unused
--> $DIR/item-free-type-bounds-semantic-fail.rs:14:12
|
LL | type E<_T>: Ord = u8;
| ^^ unused type parameter
error[E0091]: type parameter `_T` is unused
--> $DIR/item-free-type-bounds-semantic-fail.rs:17:12
|
LL | type F<_T>: Ord where 'static: 'static = u8;
| ^^ unused type parameter
error: aborting due to 10 previous errors
For more information about this error, try `rustc --explain E0091`.

View File

@ -0,0 +1,13 @@
// check-pass
fn main() {}
#[cfg(FALSE)]
fn syntax() {
type A: Ord;
type B: Ord = u8;
type C: Ord where 'static: 'static = u8;
type D<_T>: Ord;
type E<_T>: Ord = u8;
type F<_T>: Ord where 'static: 'static = u8;
}