From 35585c499f1466037b3788598756e1eb0009f51f Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Thu, 28 Feb 2019 22:43:53 +0000 Subject: Aggregation of drive-by cosmetic changes. --- src/libsyntax/parse/parser.rs | 58 +++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 39fcd29e1b0..abfce660c80 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -191,24 +191,24 @@ enum PrevTokenKind { Other, } -/* ident is handled by common.rs */ +// NOTE: `Ident`s are handled by `common.rs`. #[derive(Clone)] pub struct Parser<'a> { pub sess: &'a ParseSess, - /// the current token: + /// The current token. pub token: token::Token, - /// the span of the current token: + /// The span of the current token. pub span: Span, - /// the span of the previous token: meta_var_span: Option, + /// The span of the previous token. pub prev_span: Span, - /// the previous token kind + /// The kind of the previous troken. prev_token_kind: PrevTokenKind, restrictions: Restrictions, - /// Used to determine the path to externally loaded source files + /// Used to determine the path to externally loaded source files. crate directory: Directory<'a>, - /// Whether to parse sub-modules in other files. + /// `true` to parse sub-modules in other files. pub recurse_into_file_modules: bool, /// Name of the root module this parser originated from. If `None`, then the /// name is not known. This does not change while the parser is descending @@ -217,7 +217,7 @@ pub struct Parser<'a> { crate expected_tokens: Vec, crate token_cursor: TokenCursor, desugar_doc_comments: bool, - /// Whether we should configure out of line modules as we parse. + /// `true` we should configure out of line modules as we parse. pub cfg_mods: bool, /// This field is used to keep track of how many left angle brackets we have seen. This is /// required in order to detect extra leading left angle brackets (`<` characters) and error @@ -2680,8 +2680,7 @@ impl<'a> Parser<'a> { } } - // parse a stream of tokens into a list of TokenTree's, - // up to EOF. + /// Parses a stream of tokens into a list of `TokenTree`s, up to EOF. pub fn parse_all_token_trees(&mut self) -> PResult<'a, Vec> { let mut tts = Vec::new(); while self.token != token::Eof { @@ -5344,9 +5343,10 @@ impl<'a> Parser<'a> { // Parse optional `for<'a, 'b>`. // This `for` is parsed greedily and applies to the whole predicate, // the bounded type can have its own `for` applying only to it. - // Example 1: for<'a> Trait1<'a>: Trait2<'a /*ok*/> - // Example 2: (for<'a> Trait1<'a>): Trait2<'a /*not ok*/> - // Example 3: for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /*ok*/, 'b /*not ok*/> + // Examples: + // * `for<'a> Trait1<'a>: Trait2<'a /* ok */>` + // * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>` + // * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>` let lifetime_defs = self.parse_late_bound_lifetime_defs()?; // Parse type with mandatory colon and (possibly empty) bounds, @@ -5478,17 +5478,17 @@ impl<'a> Parser<'a> { this.look_ahead(n + 1, |t| t != &token::ModSep) }; - // Parse optional self parameter of a method. - // Only a limited set of initial token sequences is considered self parameters, anything + // Parse optional `self` parameter of a method. + // Only a limited set of initial token sequences is considered `self` parameters; anything // else is parsed as a normal function parameter list, so some lookahead is required. let eself_lo = self.span; let (eself, eself_ident, eself_hi) = match self.token { token::BinOp(token::And) => { - // &self - // &mut self - // &'lt self - // &'lt mut self - // ¬_self + // `&self` + // `&mut self` + // `&'lt self` + // `&'lt mut self` + // `¬_self` (if isolated_self(self, 1) { self.bump(); SelfKind::Region(None, Mutability::Immutable) @@ -5514,10 +5514,10 @@ impl<'a> Parser<'a> { }, expect_ident(self), self.prev_span) } token::BinOp(token::Star) => { - // *self - // *const self - // *mut self - // *not_self + // `*self` + // `*const self` + // `*mut self` + // `*not_self` // Emit special error for `self` cases. let msg = "cannot pass `self` by raw pointer"; (if isolated_self(self, 1) { @@ -5540,8 +5540,8 @@ impl<'a> Parser<'a> { } token::Ident(..) => { if isolated_self(self, 0) { - // self - // self: TYPE + // `self` + // `self: TYPE` let eself_ident = expect_ident(self); let eself_hi = self.prev_span; (if self.eat(&token::Colon) { @@ -5552,8 +5552,8 @@ impl<'a> Parser<'a> { }, eself_ident, eself_hi) } else if self.token.is_keyword(kw::Mut) && isolated_self(self, 1) { - // mut self - // mut self: TYPE + // `mut self` + // `mut self: TYPE` self.bump(); let eself_ident = expect_ident(self); let eself_hi = self.prev_span; @@ -5580,7 +5580,7 @@ impl<'a> Parser<'a> { { self.expect(&token::OpenDelim(token::Paren))?; - // Parse optional self argument + // Parse optional self argument. let self_arg = self.parse_self_arg()?; // Parse the rest of the function parameter list. -- cgit 1.4.1-3-g733a5 From 3816958f18ea6c8990d64d03da839e5a180b0b9b Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Thu, 28 Feb 2019 22:43:53 +0000 Subject: Implemented for function bounds, type bounds, and named existential types. --- src/librustc/hir/lowering.rs | 68 +++++++++++++------ src/librustc/hir/map/definitions.rs | 5 ++ src/librustc/hir/map/mod.rs | 83 +++++++++++++++++------ src/librustc/infer/opaque_types/mod.rs | 41 +++++++----- src/librustc/traits/select.rs | 3 +- src/librustc_interface/util.rs | 16 ++++- src/librustc_passes/ast_validation.rs | 18 ++--- src/librustc_passes/hir_stats.rs | 6 +- src/librustc_typeck/check/wfcheck.rs | 118 ++++++++++++++++++--------------- src/librustc_typeck/collect.rs | 46 +++++++++---- src/libsyntax/ast.rs | 28 ++++++-- src/libsyntax/ext/build.rs | 16 ++--- src/libsyntax/mut_visit.rs | 23 +++++-- src/libsyntax/parse/parser.rs | 52 +++++++++------ src/libsyntax/print/pprust.rs | 15 +++-- src/libsyntax/util/node_count.rs | 4 +- src/libsyntax/visit.rs | 21 ++++-- 17 files changed, 367 insertions(+), 196 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index af8c9c38de5..5a0e9d53b08 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -69,7 +69,7 @@ use syntax::symbol::{kw, sym, Symbol}; use syntax::tokenstream::{TokenStream, TokenTree}; use syntax::parse::token::Token; use syntax::visit::{self, Visitor}; -use syntax_pos::{edition, Span}; +use syntax_pos::{DUMMY_SP, edition, Span}; const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF; @@ -191,9 +191,9 @@ enum ImplTraitContext<'a> { /// equivalent to a fresh existential parameter like `existential type T; fn foo() -> T`. /// /// We optionally store a `DefId` for the parent item here so we can look up necessary - /// information later. It is `None` when no information about the context should be stored, - /// e.g., for consts and statics. - Existential(Option), + /// information later. It is `None` when no information about the context should be stored + /// (e.g., for consts and statics). + Existential(Option /* fn def-ID */), /// `impl Trait` is not accepted in this position. Disallowed(ImplTraitPosition), @@ -216,7 +216,7 @@ impl<'a> ImplTraitContext<'a> { use self::ImplTraitContext::*; match self { Universal(params) => Universal(params), - Existential(did) => Existential(*did), + Existential(fn_def_id) => Existential(*fn_def_id), Disallowed(pos) => Disallowed(*pos), } } @@ -1342,13 +1342,36 @@ impl<'a> LoweringContext<'a> { } } - fn lower_ty_binding(&mut self, b: &TypeBinding, - itctx: ImplTraitContext<'_>) -> hir::TypeBinding { + fn lower_assoc_ty_constraint(&mut self, + c: &AssocTyConstraint, + itctx: ImplTraitContext<'_>) + -> hir::TypeBinding { + let ty = match c.kind { + AssocTyConstraintKind::Equality { ref ty } => self.lower_ty(ty, itctx), + AssocTyConstraintKind::Bound { ref bounds } => { + // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. + let impl_ty_node_id = self.sess.next_node_id(); + let parent_def_index = self.current_hir_id_owner.last().unwrap().0; + self.resolver.definitions().create_def_with_parent( + parent_def_index, + impl_ty_node_id, + DefPathData::Misc, + DefIndexAddressSpace::High, + Mark::root(), + DUMMY_SP); + self.lower_ty(&Ty { + id: self.sess.next_node_id(), + node: TyKind::ImplTrait(impl_ty_node_id, bounds.clone()), + span: DUMMY_SP, + }, itctx) + } + }; + hir::TypeBinding { - hir_id: self.lower_node_id(b.id), - ident: b.ident, - ty: self.lower_ty(&b.ty, itctx), - span: b.span, + hir_id: self.lower_node_id(c.id), + ident: c.ident, + ty + span: c.span, } } @@ -1604,7 +1627,7 @@ impl<'a> LoweringContext<'a> { origin: hir::ExistTyOrigin::ReturnImplTrait, }; - trace!("exist ty from impl trait def index: {:#?}", exist_ty_def_index); + trace!("exist ty from impl trait def-index: {:#?}", exist_ty_def_index); let exist_ty_id = lctx.generate_existential_type( exist_ty_node_id, exist_ty_item, @@ -1617,7 +1640,7 @@ impl<'a> LoweringContext<'a> { }) } - /// Registers a new existential type with the proper NodeIds and + /// Registers a new existential type with the proper `NodeId`ss and /// returns the lowered node ID for the existential type. fn generate_existential_type( &mut self, @@ -2195,7 +2218,7 @@ impl<'a> LoweringContext<'a> { param_mode: ParamMode, mut itctx: ImplTraitContext<'_>, ) -> (hir::GenericArgs, bool) { - let &AngleBracketedArgs { ref args, ref bindings, .. } = data; + let &AngleBracketedArgs { ref args, ref constraints, .. } = data; let has_types = args.iter().any(|arg| match arg { ast::GenericArg::Type(_) => true, _ => false, @@ -2203,7 +2226,8 @@ impl<'a> LoweringContext<'a> { ( hir::GenericArgs { args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(), - bindings: bindings.iter().map(|b| self.lower_ty_binding(b, itctx.reborrow())).collect(), + bindings: constraints.iter().map( + |b| self.lower_assoc_ty_constraint(b, itctx.reborrow())).collect(), parenthesized: false, }, !has_types && param_mode == ParamMode::Optional @@ -3236,12 +3260,14 @@ impl<'a> LoweringContext<'a> { self.lower_ty(t, ImplTraitContext::disallowed()), self.lower_generics(generics, ImplTraitContext::disallowed()), ), - ItemKind::Existential(ref b, ref generics) => hir::ItemKind::Existential(hir::ExistTy { - generics: self.lower_generics(generics, ImplTraitContext::disallowed()), - bounds: self.lower_param_bounds(b, ImplTraitContext::disallowed()), - impl_trait_fn: None, - origin: hir::ExistTyOrigin::ExistentialType, - }), + ItemKind::Existential(ref b, ref generics) => hir::ItemKind::Existential( + hir::ExistTy { + generics: self.lower_generics(generics, ImplTraitContext::disallowed()), + bounds: self.lower_param_bounds(b, ImplTraitContext::Existential(None)), + impl_trait_fn: None, + origin: hir::ExistTyOrigin::ExistentialType, + }, + ), ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum( hir::EnumDef { variants: enum_definition diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index b85f6f6ce84..b01eed8f660 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -397,6 +397,11 @@ impl Definitions { self.node_to_hir_id[node_id] } + #[inline] + pub fn def_index_to_node_id(&self, def_index: DefIndex) -> ast::NodeId { + self.as_local_node_id(DefId::local(def_index)).unwrap() + } + /// Retrieves the span of the given `DefId` if `DefId` is in the local crate, the span exists /// and it's not `DUMMY_SP`. #[inline] diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 18c596f164d..cdbeb8a4a54 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -288,7 +288,7 @@ impl<'hir> Map<'hir> { #[inline] pub fn def_index_to_node_id(&self, def_index: DefIndex) -> NodeId { - self.definitions.as_local_node_id(DefId::local(def_index)).unwrap() + self.definitions.def_index_to_node_id(def_index) } #[inline] @@ -649,16 +649,16 @@ impl<'hir> Map<'hir> { result } - /// Similar to `get_parent`; returns the parent node-id, or own `id` if there is - /// no parent. Note that the parent may be `CRATE_NODE_ID`, which is not itself - /// present in the map -- so passing the return value of get_parent_node to - /// get may actually panic. - /// This function returns the immediate parent in the AST, whereas get_parent + /// Similar to `get_parent`; returns the parent node-ID, or just `hir_id` if there + /// is no parent. Note that the parent may be `CRATE_NODE_ID`, which is not itself + /// present in the map, so passing the return value of `get_parent_node` to + /// `get` may in fact panic. + /// This function returns the immediate parent in the AST, whereas `get_parent` /// returns the enclosing item. Note that this might not be the actual parent - /// node in the AST - some kinds of nodes are not in the map and these will - /// never appear as the parent_node. So you can always walk the `parent_nodes` - /// from a node to the root of the ast (unless you get the same ID back here - /// that can happen if the ID is not in the map itself or is just weird). + /// node in the AST -- some kinds of nodes are not in the map and these will + /// never appear as the parent node. Thus, you can always walk the parent nodes + /// from a node to the root of the AST (unless you get back the same ID here, + /// which can happen if the ID is not in the map itself or is just weird). pub fn get_parent_node(&self, id: NodeId) -> NodeId { let hir_id = self.node_to_hir_id(id); let parent_hir_id = self.get_parent_node_by_hir_id(hir_id); @@ -841,21 +841,66 @@ impl<'hir> Map<'hir> { } } - /// Returns the nearest enclosing scope. A scope is an item or block. - /// FIXME: it is not clear to me that all items qualify as scopes -- statics - /// and associated types probably shouldn't, for example. Behavior in this - /// regard should be expected to be highly unstable. - pub fn get_enclosing_scope(&self, hir_id: HirId) -> Option { + /// Returns the nearest enclosing scope. A scope is roughly an item or block. + pub fn get_enclosing_scope(&self, id: HirId) -> Option { self.walk_parent_nodes(hir_id, |node| match *node { - Node::Item(_) | - Node::ForeignItem(_) | - Node::TraitItem(_) | - Node::ImplItem(_) | + Node::Item(i) => { + match i.node { + ItemKind::Fn(..) + | ItemKind::Mod(..) + | ItemKind::Enum(..) + | ItemKind::Struct(..) + | ItemKind::Union(..) + | ItemKind::Trait(..) + | ItemKind::Impl(..) => true, + _ => false, + } + }, + Node::ForeignItem(fi) => { + match fi.node { + ForeignItemKind::Fn(..) => true, + _ => false, + } + }, + Node::TraitItem(ti) => { + match ti.node { + TraitItemKind::Method(..) => true, + _ => false, + } + }, + Node::ImplItem(ii) => { + match ii.node { + ImplItemKind::Method(..) => true, + _ => false, + } + }, Node::Block(_) => true, _ => false, }, |_| false).ok() } + /// Returns the defining scope for an existential type definition. + pub fn get_defining_scope(&self, id: NodeId) -> Option { + let mut scope = id; + loop { + scope = self.get_enclosing_scope(scope)?; + if scope == CRATE_NODE_ID { + return Some(CRATE_NODE_ID); + } + match self.get(scope) { + Node::Item(i) => { + match i.node { + ItemKind::Existential(ExistTy { impl_trait_fn: None, .. }) => {} + _ => break, + } + } + Node::Block(_) => {} + _ => break, + } + } + Some(scope) + } + pub fn get_parent_did(&self, id: NodeId) -> DefId { let hir_id = self.node_to_hir_id(id); self.get_parent_did_by_hir_id(hir_id) diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 1423b855745..ef216110c9e 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -786,13 +786,13 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { match tcx.hir().find_by_hir_id(opaque_hir_id) { Some(Node::Item(item)) => match item.node { - // impl trait + // Anonymous `impl Trait` hir::ItemKind::Existential(hir::ExistTy { impl_trait_fn: Some(parent), origin, .. }) => (parent == self.parent_def_id, origin), - // named existential types + // Named `existential type` hir::ItemKind::Existential(hir::ExistTy { impl_trait_fn: None, origin, @@ -868,7 +868,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { let predicates_of = tcx.predicates_of(def_id); debug!( - "instantiate_opaque_types: predicates: {:#?}", + "instantiate_opaque_types: predicates={:#?}", predicates_of, ); let bounds = predicates_of.instantiate(tcx, substs); @@ -884,11 +884,11 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { // (e.g., `existential type Foo: Bar;` needs to be // defined by a function like `fn foo() -> Foo`). debug!( - "instantiate_opaque_types: param_env: {:#?}", + "instantiate_opaque_types: param_env={:#?}", self.param_env, ); debug!( - "instantiate_opaque_types: generics: {:#?}", + "instantiate_opaque_types: generics={:#?}", tcx.generics_of(def_id), ); @@ -922,8 +922,9 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { } } -/// Returns `true` if `opaque_node_id` is a sibling or a child of a sibling of `def_id`. +/// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `def_id`. /// +/// Example: /// ```rust /// pub mod foo { /// pub mod bar { @@ -936,24 +937,28 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { /// } /// ``` /// -/// Here, `def_id` is the `DefId` of the existential type `Baz` and `opaque_node_id` is the -/// `NodeId` of the reference to `Baz` (i.e., the return type of both `f1` and `f2`). -/// We return `true` if the reference is within the same module as the existential type -/// (i.e., `true` for `f1`, `false` for `f2`). +/// Here, `def_id` is the `DefId` of the defining use of the existential type (e.g., `f1` or `f2`), +/// and `opaque_hir_id` is the `HirId` of the definition of the existential type `Baz`. +/// For the above example, this function returns `true` for `f1` and `false` for `f2`. pub fn may_define_existential_type( tcx: TyCtxt<'_, '_, '_>, def_id: DefId, opaque_hir_id: hir::HirId, ) -> bool { let mut hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - // Named existential types can be defined by any siblings or - // children of siblings. - let mod_id = tcx.hir().get_parent_item(opaque_hir_id); - // We walk up the node tree until we hit the root or the parent - // of the opaque type. - while hir_id != mod_id && node_id != ast::CRATE_HIR_ID { + trace!( + "may_define_existential_type(def={:?}, opaque_node={:?})", + tcx.hir().get(hir_id), + tcx.hir().get(opaque_hir_id) + ); + + // Named existential types can be defined by any siblings or children of siblings. + let scope_id = tcx.hir().get_defining_scope(opaque_hir_id) + .expect("could not get defining scope"); + // We walk up the node tree until we hit the root or the scope of the opaque type. + while hir_id != scope_id && hir_id != ast::CRATE_hir_ID { hir_id = tcx.hir().get_parent_item(hir_id); } - // Syntactically we are allowed to define the concrete type. - hir_id == mod_id + // Syntactically, we are allowed to define the concrete type if: + hir_id == scope_id } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index fc9756d52f5..7810d65e88c 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1848,8 +1848,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { .iter() .filter_map(|o| o.to_opt_poly_trait_ref()); - // micro-optimization: filter out predicates relating to different - // traits. + // Micro-optimization: filter out predicates relating to different traits. let matching_bounds = all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id()); diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 4ff996d1f57..f49f2110f23 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -716,8 +716,22 @@ impl<'a> ReplaceBodyWithLoop<'a> { ast::GenericArg::Type(ty) => Some(ty), _ => None, }); + let any_assoc_ty_bounds = data.constraints.iter().any(|c| { + if let ast::AssocTyConstraintKind::Bound { .. } = c.kind { + true + } else { + false + } + }); + any_assoc_ty_bounds || any_involves_impl_trait(types.into_iter()) || - any_involves_impl_trait(data.bindings.iter().map(|b| &b.ty)) + any_involves_impl_trait(data.constraints.iter().filter_map(|c| { + if let ast::AssocTyConstraintKind::Equality { ref ty } = c.kind { + Some(ty) + } else { + None + } + })) }, Some(&ast::GenericArgs::Parenthesized(ref data)) => { any_involves_impl_trait(data.inputs.iter()) || diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 6a17a84517e..2d602a7f1b4 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -93,14 +93,16 @@ impl<'a> AstValidator<'a> { self.outer_impl_trait = old; } - fn visit_assoc_type_binding_from_generic_args(&mut self, type_binding: &'a TypeBinding) { - // rust-lang/rust#57979: bug in old `visit_generic_args` called - // `walk_ty` rather than `visit_ty`, skipping outer `impl Trait` - // if it happened to occur at `type_binding.ty`. - if let TyKind::ImplTrait(..) = type_binding.ty.node { - self.warning_period_57979_didnt_record_next_impl_trait = true; + fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) { + if let AssocTyConstraintKind::Equality { ref ty } = constraint.kind { + // rust-lang/rust#57979: bug in old `visit_generic_args` called + // `walk_ty` rather than `visit_ty`, skipping outer `impl Trait` + // if it happened to occur at `ty`. + if let TyKind::ImplTrait(..) = ty.node { + self.warning_period_57979_didnt_record_next_impl_trait = true; + } } - self.visit_assoc_type_binding(type_binding); + self.visit_assoc_ty_constraint(constraint); } fn visit_ty_from_generic_args(&mut self, ty: &'a Ty) { @@ -724,7 +726,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // Type bindings such as `Item = impl Debug` in `Iterator` // are allowed to contain nested `impl Trait`. self.with_impl_trait(None, |this| { - walk_list!(this, visit_assoc_type_binding_from_generic_args, &data.bindings); + walk_list!(this, visit_assoc_ty_constraint_from_generic_args, &data.constraints); }); } GenericArgs::Parenthesized(ref data) => { diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index 0088c97679c..6936aedb9de 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -353,9 +353,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { ast_visit::walk_path_segment(self, path_span, path_segment) } - fn visit_assoc_type_binding(&mut self, type_binding: &'v ast::TypeBinding) { - self.record("TypeBinding", Id::None, type_binding); - ast_visit::walk_assoc_type_binding(self, type_binding) + fn visit_assoc_ty_constraint(&mut self, constraint: &'v ast::AssocTyConstraint) { + self.record("AssocTyConstraint", Id::None, constraint); + ast_visit::walk_assoc_ty_constraint(self, constraint) } fn visit_attribute(&mut self, attr: &'v ast::Attribute) { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index e11172ae36d..2b627a69250 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -20,8 +20,11 @@ use rustc::hir::itemlikevisit::ParItemLikeVisitor; use rustc::hir; /// Helper type of a temporary returned by `.for_item(...)`. -/// Necessary because we can't write the following bound: -/// `F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(FnCtxt<'b, 'gcx, 'tcx>)`. +/// This is necessary because we can't write the following bound: +/// +/// ```rust +/// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(FnCtxt<'b, 'gcx, 'tcx>) +/// ``` struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { inherited: super::InheritedBuilder<'a, 'gcx, 'tcx>, id: hir::HirId, @@ -42,7 +45,7 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { if !inh.tcx.features().trivial_bounds { // As predicates are cached rather than obligations, this // needsto be called first so that they are checked with an - // empty param_env. + // empty `param_env`. check_false_global_bounds(&fcx, span, id); } let wf_tys = f(&fcx, fcx.tcx.global_tcx()); @@ -56,7 +59,9 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { /// well-formed, meaning that they do not require any constraints not declared in the struct /// definition itself. For example, this definition would be illegal: /// -/// struct Ref<'a, T> { x: &'a T } +/// ```rust +/// struct Ref<'a, T> { x: &'a T } +/// ``` /// /// because the type did not declare that `T:'a`. /// @@ -75,7 +80,7 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def // Right now we check that every default trait implementation // has an implementation of itself. Basically, a case like: // - // `impl Trait for T {}` + // impl Trait for T {} // // has a requirement of `T: Trait` which was required for default // method implementations. Although this could be improved now that @@ -85,7 +90,7 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def // Since there's such a requirement, we need to check *just* positive // implementations, otherwise things like: // - // impl !Send for T {} + // impl !Send for T {} // // won't be allowed unless there's an *explicit* implementation of `Send` // for `T` @@ -98,7 +103,7 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def if polarity == hir::ImplPolarity::Positive { check_impl(tcx, item, self_ty, trait_ref); } else { - // FIXME(#27579) what amount of WF checking do we need for neg impls? + // FIXME(#27579): what amount of WF checking do we need for neg impls? if trait_ref.is_some() && !is_auto { span_err!(tcx.sess, item.span, E0192, "negative impls are only allowed for \ @@ -302,7 +307,8 @@ fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, check_where_clauses(tcx, fcx, item.span, def_id, None); - vec![] // no implied bounds in a struct def'n + // No implied bounds in a struct definition. + vec![] }); } @@ -369,7 +375,8 @@ fn check_item_type<'a, 'tcx>( ); } - vec![] // no implied bounds in a const etc + // No implied bounds in a const, etc. + vec![] }); } @@ -421,6 +428,8 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( def_id: DefId, return_ty: Option>, ) { + debug!("check_where_clauses(def_id={:?}, return_ty={:?})", def_id, return_ty); + let predicates = fcx.tcx.predicates_of(def_id); let generics = tcx.generics_of(def_id); @@ -434,15 +443,17 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( }; // Check that concrete defaults are well-formed. See test `type-check-defaults.rs`. - // For example this forbids the declaration: - // struct Foo> { .. } - // Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold. + // For example, this forbids the declaration: + // + // struct Foo> { .. } + // + // Here, the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold. for param in &generics.params { if let GenericParamDefKind::Type { .. } = param.kind { if is_our_default(¶m) { let ty = fcx.tcx.type_of(param.def_id); - // ignore dependent defaults -- that is, where the default of one type - // parameter includes another (e.g., ). In those cases, we can't + // Ignore dependent defaults -- that is, where the default of one type + // parameter includes another (e.g., ``). In those cases, we can't // be sure if it will error or not as user might always specify the other. if !ty.needs_subst() { fcx.register_wf_obligation(ty, fcx.tcx.def_span(param.def_id), @@ -468,16 +479,16 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( } GenericParamDefKind::Type { .. } => { - // If the param has a default, + // If the param has a default, ... if is_our_default(param) { let default_ty = fcx.tcx.type_of(param.def_id); - // and it's not a dependent default + // ... and it's not a dependent default, ... if !default_ty.needs_subst() { - // then substitute with the default. + // ... then substitute it with the default. return default_ty.into(); } } - // Mark unwanted params as err. + // Mark unwanted params as error. fcx.tcx.types.err.into() } @@ -525,7 +536,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( Some(substituted_pred) } }).map(|pred| { - // convert each of those into an obligation. So if you have + // Convert each of those into an obligation. So if you have // something like `struct Foo`, we would // take that predicate `T: Copy`, substitute to `String: Copy` // (actually that happens in the previous `flat_map` call), @@ -595,14 +606,13 @@ fn check_fn_or_method<'a, 'fcx, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, /// ```rust /// existential type Foo; /// -/// // ok -- `Foo` is applied to two distinct, generic types. +/// // Okay -- `Foo` is applied to two distinct, generic types. /// fn a() -> Foo { .. } /// -/// // not ok -- `Foo` is applied to `T` twice. +/// // Not okay -- `Foo` is applied to `T` twice. /// fn b() -> Foo { .. } /// -/// -/// // not ok -- `Foo` is applied to a non-generic type. +/// // Not okay -- `Foo` is applied to a non-generic type. /// fn b() -> Foo { .. } /// ``` /// @@ -613,7 +623,7 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( span: Span, ty: Ty<'tcx>, ) -> Vec> { - trace!("check_existential_types: {:?}", ty); + trace!("check_existential_types(ty={:?})", ty); let mut substituted_predicates = Vec::new(); ty.fold_with(&mut ty::fold::BottomUpFolder { tcx: fcx.tcx, @@ -621,17 +631,17 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( if let ty::Opaque(def_id, substs) = ty.sty { trace!("check_existential_types: opaque_ty, {:?}, {:?}", def_id, substs); let generics = tcx.generics_of(def_id); - // only check named existential types defined in this crate + // Only check named existential types defined in this crate. if generics.parent.is_none() && def_id.is_local() { let opaque_hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); if may_define_existential_type(tcx, fn_def_id, opaque_hir_id) { - trace!("check_existential_types may define. Generics: {:#?}", generics); + trace!("check_existential_types: may define, generics={:#?}", generics); let mut seen: FxHashMap<_, Vec<_>> = FxHashMap::default(); for (subst, param) in substs.iter().zip(&generics.params) { match subst.unpack() { ty::subst::UnpackedKind::Type(ty) => match ty.sty { ty::Param(..) => {} - // prevent `fn foo() -> Foo` from being defining + // Prevent `fn foo() -> Foo` from being defining. _ => { tcx.sess .struct_span_err( @@ -713,20 +723,19 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( } } // if may_define_existential_type - // now register the bounds on the parameters of the existential type - // so the parameters given by the function need to fulfill them - // ```rust - // existential type Foo: 'static; - // fn foo() -> Foo { .. *} - // ``` + // Now register the bounds on the parameters of the existential type + // so the parameters given by the function need to fulfill them. + // + // existential type Foo: 'static; + // fn foo() -> Foo { .. *} + // // becomes - // ```rust - // existential type Foo: 'static; - // fn foo() -> Foo { .. *} - // ``` + // + // existential type Foo: 'static; + // fn foo() -> Foo { .. *} let predicates = tcx.predicates_of(def_id); trace!( - "check_existential_types may define. adding predicates: {:#?}", + "check_existential_types: may define, predicates={:#?}", predicates, ); for &(pred, _) in predicates.predicates.iter() { @@ -751,7 +760,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, method: &ty::AssocItem, self_ty: Ty<'tcx>) { - // check that the method has a valid receiver type, given the type `Self` + // Check that the method has a valid receiver type, given the type `Self`. debug!("check_method_receiver({:?}, self_ty={:?})", method, self_ty); @@ -783,7 +792,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, if fcx.tcx.features().arbitrary_self_types { if !receiver_is_valid(fcx, span, receiver_ty, self_ty, true) { - // report error, arbitrary_self_types was enabled + // Report error; `arbitrary_self_types` was enabled. fcx.tcx.sess.diagnostic().mut_span_err( span, &format!("invalid method receiver type: {:?}", receiver_ty) ).note("type of `self` must be `Self` or a type that dereferences to it") @@ -794,7 +803,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, } else { if !receiver_is_valid(fcx, span, receiver_ty, self_ty, false) { if receiver_is_valid(fcx, span, receiver_ty, self_ty, true) { - // report error, would have worked with arbitrary_self_types + // Report error; would have worked with `arbitrary_self_types`. feature_gate::feature_err( &fcx.tcx.sess.parse_sess, sym::arbitrary_self_types, @@ -808,7 +817,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, ).help("consider changing to `self`, `&self`, `&mut self`, or `self: Box`") .emit(); } else { - // report error, would not have worked with arbitrary_self_types + // Report error; would not have worked with `arbitrary_self_types`. fcx.tcx.sess.diagnostic().mut_span_err( span, &format!("invalid method receiver type: {:?}", receiver_ty) ).note("type must be `Self` or a type that dereferences to it") @@ -820,10 +829,11 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, } } -/// returns true if `receiver_ty` would be considered a valid receiver type for `self_ty`. If +/// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If /// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly /// through a `*const/mut T` raw pointer. If the feature is not enabled, the requirements are more -/// strict: `receiver_ty` must implement `Receiver` and directly implement `Deref`. +/// strict: `receiver_ty` must implement `Receiver` and directly implement +/// `Deref`. /// /// N.B., there are cases this function returns `true` but causes an error to be emitted, /// particularly when `receiver_ty` derefs to a type that is the same as `self_ty` but has the @@ -839,7 +849,7 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>( let can_eq_self = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok(); - // `self: Self` is always valid + // `self: Self` is always valid. if can_eq_self(receiver_ty) { if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, receiver_ty) { err.emit(); @@ -849,15 +859,15 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>( let mut autoderef = fcx.autoderef(span, receiver_ty); - // the `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self` + // The `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`. if arbitrary_self_types_enabled { autoderef = autoderef.include_raw_pointers(); } - // the first type is `receiver_ty`, which we know its not equal to `self_ty`. skip it. + // The first type is `receiver_ty`, which we know its not equal to `self_ty`; skip it. autoderef.next(); - // keep dereferencing `receiver_ty` until we get to `self_ty` + // Keep dereferencing `receiver_ty` until we get to `self_ty`. loop { if let Some((potential_self_ty, _)) = autoderef.next() { debug!("receiver_is_valid: potential self type `{:?}` to match `{:?}`", @@ -882,14 +892,14 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>( return receiver_ty.references_error(); } - // without the `arbitrary_self_types` feature, `receiver_ty` must directly deref to - // `self_ty`. Enforce this by only doing one iteration of the loop + // Without the `arbitrary_self_types` feature, `receiver_ty` must directly deref to + // `self_ty`. Enforce this by only doing one iteration of the loop. if !arbitrary_self_types_enabled { return false } } - // without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver` + // Without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver`. if !arbitrary_self_types_enabled { let trait_def_id = match fcx.tcx.lang_items().receiver_trait() { Some(did) => did, @@ -968,7 +978,7 @@ fn report_bivariance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut err = error_392(tcx, span, param_name); let suggested_marker_id = tcx.lang_items().phantom_data(); - // help is available only in presence of lang items + // Help is available only in presence of lang items. if let Some(def_id) = suggested_marker_id { err.help(&format!("consider removing `{}` or using a marker such as `{}`", param_name, @@ -988,12 +998,12 @@ fn reject_shadowing_parameters(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) { }).collect(); for method_param in &generics.params { - // Shadowing is checked in resolve_lifetime. + // Shadowing is checked in `resolve_lifetime`. if let GenericParamDefKind::Lifetime = method_param.kind { continue } if impl_params.contains_key(&method_param.name) { - // Tighten up the span to focus on only the shadowing type + // Tighten up the span to focus on only the shadowing type. let type_span = tcx.def_span(method_param.def_id); // The expectation here is that the original trait declaration is diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index f362263c16e..ee7961197d3 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1488,10 +1488,13 @@ fn find_existential_constraints<'a, 'tcx>( impl<'a, 'tcx> ConstraintLocator<'a, 'tcx> { fn check(&mut self, def_id: DefId) { - trace!("checking {:?}", def_id); - // don't try to check items that cannot possibly constrain the type + // Don't try to check items that cannot possibly constrain the type. if !self.tcx.has_typeck_tables(def_id) { - trace!("no typeck tables for {:?}", def_id); + debug!( + "find_existential_constraints: no constraint for `{:?}` at `{:?}`: no tables", + self.def_id, + def_id, + ); return; } let ty = self @@ -1500,7 +1503,14 @@ fn find_existential_constraints<'a, 'tcx>( .concrete_existential_types .get(&self.def_id); if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty { - // FIXME(oli-obk): trace the actual span from inference to improve errors + debug!( + "find_existential_constraints: found constraint for `{:?}` at `{:?}`: {:?}", + self.def_id, + def_id, + ty, + ); + + // FIXME(oli-obk): trace the actual span from inference to improve errors. let span = self.tcx.def_span(def_id); // used to quickly look up the position of a generic parameter let mut index_map: FxHashMap = FxHashMap::default(); @@ -1555,14 +1565,15 @@ fn find_existential_constraints<'a, 'tcx>( let mut ty = concrete_type.walk().fuse(); let mut p_ty = prev_ty.walk().fuse(); let iter_eq = (&mut ty).zip(&mut p_ty).all(|(t, p)| match (&t.sty, &p.sty) { - // type parameters are equal to any other type parameter for the purpose of + // Type parameters are equal to any other type parameter for the purpose of // concrete type equality, as it is possible to obtain the same type just // by passing matching parameters to a function. (ty::Param(_), ty::Param(_)) => true, _ => t == p, }); if !iter_eq || ty.next().is_some() || p_ty.next().is_some() { - // found different concrete types for the existential type + debug!("find_existential_constraints: span={:?}", span); + // Found different concrete types for the existential type. let mut err = self.tcx.sess.struct_span_err( span, "concrete type differs from previous defining existential type use", @@ -1574,7 +1585,7 @@ fn find_existential_constraints<'a, 'tcx>( err.span_note(prev_span, "previous use here"); err.emit(); } else if indices != *prev_indices { - // found "same" concrete types, but the generic parameter order differs + // Found "same" concrete types, but the generic parameter order differs. let mut err = self.tcx.sess.struct_span_err( span, "concrete type's generic parameters differ from previous defining use", @@ -1602,6 +1613,12 @@ fn find_existential_constraints<'a, 'tcx>( } else { self.found = Some((span, concrete_type, indices)); } + } else { + debug!( + "find_existential_constraints: no constraint for `{:?}` at `{:?}`", + self.def_id, + def_id, + ); } } } @@ -1633,26 +1650,27 @@ fn find_existential_constraints<'a, 'tcx>( } } + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let scope_id = tcx.hir().get_defining_scope(hir_id) + .expect("could not get defining scope"); let mut locator = ConstraintLocator { def_id, tcx, found: None, }; - let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - let parent = tcx.hir().get_parent_item(hir_id); - trace!("parent_id: {:?}", parent); + debug!("find_existential_constraints: scope_id={:?}", scope_id); - if parent == hir::CRATE_HIR_ID { + if scope_id == ast::CRATE_HIR_ID { intravisit::walk_crate(&mut locator, tcx.hir().krate()); } else { - trace!("parent: {:?}", tcx.hir().get_by_hir_id(parent)); - match tcx.hir().get_by_hir_id(parent) { + debug!("find_existential_constraints: scope={:?}", tcx.hir().get_by_hir_id(scope_id)); + match tcx.hir().get_by_hir_id(scope_id) { Node::Item(ref it) => intravisit::walk_item(&mut locator, it), Node::ImplItem(ref it) => intravisit::walk_impl_item(&mut locator, it), Node::TraitItem(ref it) => intravisit::walk_trait_item(&mut locator, it), other => bug!( - "{:?} is not a valid parent of an existential type item", + "{:?} is not a valid scope for an existential type item", other ), } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 31e89804800..598232f9f8f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -190,9 +190,9 @@ pub struct AngleBracketedArgs { pub span: Span, /// The arguments for this path segment. pub args: Vec, - /// Bindings (equality constraints) on associated types, if present. - /// E.g., `Foo`. - pub bindings: Vec, + /// Constraints on associated types, if any. + /// E.g., `Foo`. + pub constraints: Vec, } impl Into>> for AngleBracketedArgs { @@ -225,7 +225,7 @@ impl ParenthesizedArgs { AngleBracketedArgs { span: self.span, args: self.inputs.iter().cloned().map(|input| GenericArg::Type(input)).collect(), - bindings: vec![], + constraints: vec![], } } } @@ -1611,15 +1611,29 @@ impl fmt::Display for UintTy { } } -// Bind a type to an associated type: `A = Foo`. +/// A constraint on an associated type (e.g., `A = Bar` in `Foo` or +/// `A: TraitA + TraitB` in `Foo`). #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub struct TypeBinding { +pub struct AssocTyConstraint { pub id: NodeId, pub ident: Ident, - pub ty: P, + pub kind: AssocTyConstraintKind, pub span: Span, } +/// The kinds of an `AssocTyConstraint`. +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub enum AssocTyConstraintKind { + /// E.g., `A = Bar` in `Foo`. + Equality { + ty: P, + }, + /// E.g. `A: TraitA + TraitB` in `Foo`. + Bound { + bounds: GenericBounds, + }, +} + #[derive(Clone, RustcEncodable, RustcDecodable)] pub struct Ty { pub id: NodeId, diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 435a3d7b6a2..2a03e49996b 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -18,7 +18,7 @@ pub trait AstBuilder { global: bool, idents: Vec, args: Vec, - bindings: Vec) + constraints: Vec) -> ast::Path; fn qpath(&self, self_type: P, @@ -29,7 +29,7 @@ pub trait AstBuilder { trait_path: ast::Path, ident: ast::Ident, args: Vec, - bindings: Vec) + constraints: Vec) -> (ast::QSelf, ast::Path); // types and consts @@ -302,7 +302,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { global: bool, mut idents: Vec , args: Vec, - bindings: Vec ) + constraints: Vec ) -> ast::Path { assert!(!idents.is_empty()); let add_root = global && !idents[0].is_path_segment_keyword(); @@ -314,8 +314,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> { segments.extend(idents.into_iter().map(|ident| { ast::PathSegment::from_ident(ident.with_span_pos(span)) })); - let args = if !args.is_empty() || !bindings.is_empty() { - ast::AngleBracketedArgs { args, bindings, span }.into() + let args = if !args.is_empty() || !constraints.is_empty() { + ast::AngleBracketedArgs { args, constraints, span }.into() } else { None }; @@ -346,11 +346,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> { trait_path: ast::Path, ident: ast::Ident, args: Vec, - bindings: Vec) + constraints: Vec) -> (ast::QSelf, ast::Path) { let mut path = trait_path; - let args = if !args.is_empty() || !bindings.is_empty() { - ast::AngleBracketedArgs { args, bindings, span: ident.span }.into() + let args = if !args.is_empty() || !constraints.is_empty() { + ast::AngleBracketedArgs { args, constraints, span: ident.span }.into() } else { None }; diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 75751309899..fb1a7a680ba 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -163,8 +163,8 @@ pub trait MutVisitor: Sized { noop_visit_lifetime(l, self); } - fn visit_ty_binding(&mut self, t: &mut TypeBinding) { - noop_visit_ty_binding(t, self); + fn visit_ty_constraint(&mut self, t: &mut AssocTyConstraint) { + noop_visit_ty_constraint(t, self); } fn visit_mod(&mut self, m: &mut Mod) { @@ -400,11 +400,20 @@ pub fn noop_visit_guard(g: &mut Guard, vis: &mut T) { } } -pub fn noop_visit_ty_binding(TypeBinding { id, ident, ty, span }: &mut TypeBinding, - vis: &mut T) { +pub fn noop_visit_ty_constraint( + AssocTyConstraint { id, ident, kind, span }: &mut AssocTyConstraint, + vis: &mut T +) { vis.visit_id(id); vis.visit_ident(ident); - vis.visit_ty(ty); + match kind { + AssocTyConstraintKind::Equality { ref mut ty } => { + vis.visit_ty(ty); + } + AssocTyConstraintKind::Bound { ref mut bounds } => { + visit_bounds(bounds, vis); + } + } vis.visit_span(span); } @@ -499,9 +508,9 @@ pub fn noop_visit_generic_arg(arg: &mut GenericArg, vis: &mut T) pub fn noop_visit_angle_bracketed_parameter_data(data: &mut AngleBracketedArgs, vis: &mut T) { - let AngleBracketedArgs { args, bindings, span } = data; + let AngleBracketedArgs { args, constraints, span } = data; visit_vec(args, |arg| vis.visit_generic_arg(arg)); - visit_vec(bindings, |binding| vis.visit_ty_binding(binding)); + visit_vec(constraints, |constraint| vis.visit_ty_constraint(constraint)); vis.visit_span(span); } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index abfce660c80..790013f6eb1 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -27,7 +27,7 @@ use crate::ast::{VariantData, StructField}; use crate::ast::StrStyle; use crate::ast::SelfKind; use crate::ast::{TraitItem, TraitRef, TraitObjectSyntax}; -use crate::ast::{Ty, TyKind, TypeBinding, GenericBounds}; +use crate::ast::{Ty, TyKind, AssocTyConstraint, AssocTyConstraintKind, GenericBounds}; use crate::ast::{Visibility, VisibilityKind, WhereClause, CrateSugar}; use crate::ast::{UseTree, UseTreeKind}; use crate::ast::{BinOpKind, UnOp}; @@ -1791,11 +1791,11 @@ impl<'a> Parser<'a> { let lo = self.span; let args = if self.eat_lt() { // `<'a, T, A = U>` - let (args, bindings) = + let (args, constraints) = self.parse_generic_args_with_leaning_angle_bracket_recovery(style, lo)?; self.expect_gt()?; let span = lo.to(self.prev_span); - AngleBracketedArgs { args, bindings, span }.into() + AngleBracketedArgs { args, constraints, span }.into() } else { // `(T, U) -> R` self.bump(); // `(` @@ -5076,7 +5076,7 @@ impl<'a> Parser<'a> { &mut self, style: PathStyle, lo: Span, - ) -> PResult<'a, (Vec, Vec)> { + ) -> PResult<'a, (Vec, Vec)> { // We need to detect whether there are extra leading left angle brackets and produce an // appropriate error and suggestion. This cannot be implemented by looking ahead at // upcoming tokens for a matching `>` character - if there are unmatched `<` tokens @@ -5211,11 +5211,11 @@ impl<'a> Parser<'a> { /// Parses (possibly empty) list of lifetime and type arguments and associated type bindings, /// possibly including trailing comma. - fn parse_generic_args(&mut self) -> PResult<'a, (Vec, Vec)> { + fn parse_generic_args(&mut self) -> PResult<'a, (Vec, Vec)> { let mut args = Vec::new(); - let mut bindings = Vec::new(); - let mut misplaced_assoc_ty_bindings: Vec = Vec::new(); - let mut assoc_ty_bindings: Vec = Vec::new(); + let mut constraints = Vec::new(); + let mut misplaced_assoc_ty_constraints: Vec = Vec::new(); + let mut assoc_ty_constraints: Vec = Vec::new(); let args_lo = self.span; @@ -5223,21 +5223,31 @@ impl<'a> Parser<'a> { if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { // Parse lifetime argument. args.push(GenericArg::Lifetime(self.expect_lifetime())); - misplaced_assoc_ty_bindings.append(&mut assoc_ty_bindings); - } else if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) { - // Parse associated type binding. + misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints); + } else if self.check_ident() && self.look_ahead(1, + |t| t == &token::Eq || t == &token::Colon) { + // Parse associated type constraint. let lo = self.span; let ident = self.parse_ident()?; - self.bump(); - let ty = self.parse_ty()?; + let kind = if self.eat(&token::Eq) { + AssocTyConstraintKind::Equality { + ty: self.parse_ty()?, + } + } else if self.eat(&token::Colon) { + AssocTyConstraintKind::Bound { + bounds: self.parse_generic_bounds(Some(self.prev_span))?, + } + } else { + unreachable!(); + }; let span = lo.to(self.prev_span); - bindings.push(TypeBinding { + constraints.push(AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, - ty, + kind, span, }); - assoc_ty_bindings.push(span); + assoc_ty_constraints.push(span); } else if self.check_const_arg() { // Parse const argument. let expr = if let token::OpenDelim(token::Brace) = self.token { @@ -5261,11 +5271,11 @@ impl<'a> Parser<'a> { value: expr, }; args.push(GenericArg::Const(value)); - misplaced_assoc_ty_bindings.append(&mut assoc_ty_bindings); + misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints); } else if self.check_type() { // Parse type argument. args.push(GenericArg::Type(self.parse_ty()?)); - misplaced_assoc_ty_bindings.append(&mut assoc_ty_bindings); + misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints); } else { break } @@ -5278,12 +5288,12 @@ impl<'a> Parser<'a> { // FIXME: we would like to report this in ast_validation instead, but we currently do not // preserve ordering of generic parameters with respect to associated type binding, so we // lose that information after parsing. - if misplaced_assoc_ty_bindings.len() > 0 { + if misplaced_assoc_ty_constraints.len() > 0 { let mut err = self.struct_span_err( args_lo.to(self.prev_span), "associated type bindings must be declared after generic parameters", ); - for span in misplaced_assoc_ty_bindings { + for span in misplaced_assoc_ty_constraints { err.span_label( span, "this associated type binding should be moved after the generic parameters", @@ -5292,7 +5302,7 @@ impl<'a> Parser<'a> { err.emit(); } - Ok((args, bindings)) + Ok((args, constraints)) } /// Parses an optional where-clause and places it in `generics`. diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 44e1f5398d3..57c01e9e3ef 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2450,14 +2450,21 @@ impl<'a> State<'a> { let mut comma = data.args.len() != 0; - for binding in data.bindings.iter() { + for constraint in data.constraints.iter() { if comma { self.word_space(",")? } - self.print_ident(binding.ident)?; + self.print_ident(constraint.ident)?; self.s.space()?; - self.word_space("=")?; - self.print_type(&binding.ty)?; + match constraint.kind { + ast::AssocTyConstraintKind::Equality { ref ty } => { + self.word_space("=")?; + self.print_type(ty)?; + } + ast::AssocTyConstraintKind::Bound { ref bounds } => { + self.print_type_bounds(":", &*bounds)?; + } + } comma = true; } diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs index 521edac8f5f..f17eb3b3943 100644 --- a/src/libsyntax/util/node_count.rs +++ b/src/libsyntax/util/node_count.rs @@ -131,9 +131,9 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_generic_args(self, path_span, generic_args) } - fn visit_assoc_type_binding(&mut self, type_binding: &TypeBinding) { + fn visit_assoc_ty_constraint(&mut self, constraint: &AssocTyConstraint) { self.count += 1; - walk_assoc_type_binding(self, type_binding) + walk_assoc_ty_constraint(self, constraint) } fn visit_attribute(&mut self, _attr: &Attribute) { self.count += 1; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index ba57055b8e0..334709b1521 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -139,8 +139,8 @@ pub trait Visitor<'ast>: Sized { GenericArg::Const(ct) => self.visit_anon_const(ct), } } - fn visit_assoc_type_binding(&mut self, type_binding: &'ast TypeBinding) { - walk_assoc_type_binding(self, type_binding) + fn visit_assoc_ty_constraint(&mut self, constraint: &'ast AssocTyConstraint) { + walk_assoc_ty_constraint(self, constraint) } fn visit_attribute(&mut self, attr: &'ast Attribute) { walk_attribute(self, attr) @@ -404,7 +404,7 @@ pub fn walk_generic_args<'a, V>(visitor: &mut V, match *generic_args { GenericArgs::AngleBracketed(ref data) => { walk_list!(visitor, visit_generic_arg, &data.args); - walk_list!(visitor, visit_assoc_type_binding, &data.bindings); + walk_list!(visitor, visit_assoc_ty_constraint, &data.constraints); } GenericArgs::Parenthesized(ref data) => { walk_list!(visitor, visit_ty, &data.inputs); @@ -413,10 +413,17 @@ pub fn walk_generic_args<'a, V>(visitor: &mut V, } } -pub fn walk_assoc_type_binding<'a, V: Visitor<'a>>(visitor: &mut V, - type_binding: &'a TypeBinding) { - visitor.visit_ident(type_binding.ident); - visitor.visit_ty(&type_binding.ty); +pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(visitor: &mut V, + constraint: &'a AssocTyConstraint) { + visitor.visit_ident(constraint.ident); + match constraint.kind { + AssocTyConstraintKind::Equality { ref ty } => { + visitor.visit_ty(ty); + } + AssocTyConstraintKind::Bound { ref bounds } => { + walk_list!(visitor, visit_param_bound, bounds); + } + } } pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { -- cgit 1.4.1-3-g733a5