From 604af3f6c0be6ea428a55cfcb303fa1cd1c7958d Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 11 Aug 2014 09:32:26 -0700 Subject: [PATCH] librustc: Implement simple `where` clauses. These `where` clauses are accepted everywhere generics are currently accepted and desugar during type collection to the type parameter bounds we have today. A new keyword, `where`, has been added. Therefore, this is a breaking change. Change uses of `where` to other identifiers. [breaking-change] --- src/librustc/middle/resolve.rs | 31 ++++ src/librustc/middle/trans/debuginfo.rs | 4 +- src/librustc/middle/typeck/collect.rs | 173 +++++++++++------- .../middle/typeck/infer/error_reporting.rs | 13 +- src/librustdoc/clean/mod.rs | 24 +-- src/librustdoc/doctree.rs | 18 +- src/librustdoc/visit_ast.rs | 18 +- src/libsyntax/ast.rs | 17 +- src/libsyntax/ast_map/mod.rs | 21 ++- src/libsyntax/ast_util.rs | 10 +- src/libsyntax/ext/deriving/generic/mod.rs | 8 +- src/libsyntax/ext/deriving/generic/ty.rs | 9 +- src/libsyntax/fold.rs | 43 ++++- src/libsyntax/parse/lexer/mod.rs | 24 +-- src/libsyntax/parse/mod.rs | 4 + src/libsyntax/parse/parser.rs | 92 ++++++++-- src/libsyntax/parse/token.rs | 21 ++- src/libsyntax/print/pprust.rs | 139 +++++++++----- src/libsyntax/visit.rs | 14 +- src/test/auxiliary/where_clauses_xc.rs | 30 +++ .../where-clauses-no-bounds-or-predicates.rs | 23 +++ .../where-clauses-not-parameter.rs | 17 ++ .../compile-fail/where-clauses-unsatisfied.rs | 20 ++ .../run-pass/where-clauses-cross-crate.rs | 23 +++ src/test/run-pass/where-clauses.rs | 37 ++++ 25 files changed, 626 insertions(+), 207 deletions(-) create mode 100644 src/test/auxiliary/where_clauses_xc.rs create mode 100644 src/test/compile-fail/where-clauses-no-bounds-or-predicates.rs create mode 100644 src/test/compile-fail/where-clauses-not-parameter.rs create mode 100644 src/test/compile-fail/where-clauses-unsatisfied.rs create mode 100644 src/test/run-pass/where-clauses-cross-crate.rs create mode 100644 src/test/run-pass/where-clauses.rs diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 9edf9fcbdba..3ce6f726100 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -3671,6 +3671,7 @@ fn resolve_item(&mut self, item: &Item) { ItemRibKind), |this| { this.resolve_type_parameters(&generics.ty_params); + this.resolve_where_clause(&generics.where_clause); visit::walk_item(this, item, ()); }); } @@ -3713,6 +3714,7 @@ fn resolve_item(&mut self, item: &Item) { NormalRibKind), |this| { this.resolve_type_parameters(&generics.ty_params); + this.resolve_where_clause(&generics.where_clause); // Resolve derived traits. for trt in traits.iter() { @@ -3744,6 +3746,8 @@ fn resolve_item(&mut self, item: &Item) { // parameters. this.resolve_type_parameters( &ty_m.generics.ty_params); + this.resolve_where_clause(&ty_m.generics + .where_clause); for argument in ty_m.decl.inputs.iter() { this.resolve_type(&*argument.ty); @@ -3907,6 +3911,7 @@ fn resolve_function(&mut self, } HasTypeParameters(ref generics, _, _, _) => { this.resolve_type_parameters(&generics.ty_params); + this.resolve_where_clause(&generics.where_clause); } } @@ -4022,6 +4027,30 @@ fn resolve_trait_reference(&mut self, } } + fn resolve_where_clause(&mut self, where_clause: &ast::WhereClause) { + for predicate in where_clause.predicates.iter() { + match self.resolve_identifier(predicate.ident, + TypeNS, + true, + predicate.span) { + Some((def @ DefTyParam(_, _, _), last_private)) => { + self.record_def(predicate.id, (def, last_private)); + } + _ => { + self.resolve_error( + predicate.span, + format!("undeclared type parameter `{}`", + token::get_ident( + predicate.ident)).as_slice()); + } + } + + for bound in predicate.bounds.iter() { + self.resolve_type_parameter_bound(predicate.id, bound); + } + } + } + fn resolve_struct(&mut self, id: NodeId, generics: &Generics, @@ -4035,6 +4064,7 @@ fn resolve_struct(&mut self, |this| { // Resolve the type parameters. this.resolve_type_parameters(&generics.ty_params); + this.resolve_where_clause(&generics.where_clause); // Resolve the super struct. match super_struct { @@ -4146,6 +4176,7 @@ fn resolve_implementation(&mut self, |this| { // Resolve the type parameters. this.resolve_type_parameters(&generics.ty_params); + this.resolve_where_clause(&generics.where_clause); // Resolve the trait reference, if necessary. this.with_optional_trait_ref(id, opt_trait_reference, |this| { diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 9b78cedd4ac..de5e718206d 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -208,7 +208,6 @@ struct List { use syntax::codemap::{Span, Pos}; use syntax::{abi, ast, codemap, ast_util, ast_map}; use syntax::ast_util::PostExpansionMethod; -use syntax::owned_slice::OwnedSlice; use syntax::parse::token; use syntax::parse::token::special_idents; @@ -1123,8 +1122,7 @@ pub fn create_function_debug_context(cx: &CrateContext, return FunctionDebugContext { repr: FunctionWithoutDebugInfo }; } - let empty_generics = ast::Generics { lifetimes: Vec::new(), - ty_params: OwnedSlice::empty() }; + let empty_generics = ast_util::empty_generics(); let fnitem = cx.tcx.map.get(fn_ast_id); diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 284330c51c8..0c5d58ae930 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -987,20 +987,26 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt, fn ty_generics_for_type(ccx: &CrateCtxt, generics: &ast::Generics) - -> ty::Generics -{ - ty_generics(ccx, subst::TypeSpace, &generics.lifetimes, - &generics.ty_params, ty::Generics::empty()) + -> ty::Generics { + ty_generics(ccx, + subst::TypeSpace, + &generics.lifetimes, + &generics.ty_params, + ty::Generics::empty(), + &generics.where_clause) } fn ty_generics_for_trait(ccx: &CrateCtxt, trait_id: ast::NodeId, substs: &subst::Substs, generics: &ast::Generics) - -> ty::Generics -{ - let mut generics = ty_generics(ccx, subst::TypeSpace, &generics.lifetimes, - &generics.ty_params, ty::Generics::empty()); + -> ty::Generics { + let mut generics = ty_generics(ccx, + subst::TypeSpace, + &generics.lifetimes, + &generics.ty_params, + ty::Generics::empty(), + &generics.where_clause); // Something of a hack: use the node id for the trait, also as // the node id for the Self type parameter. @@ -1032,11 +1038,14 @@ fn ty_generics_for_trait(ccx: &CrateCtxt, fn ty_generics_for_fn_or_method(ccx: &CrateCtxt, generics: &ast::Generics, base_generics: ty::Generics) - -> ty::Generics -{ + -> ty::Generics { let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics); - ty_generics(ccx, subst::FnSpace, &early_lifetimes, - &generics.ty_params, base_generics) + ty_generics(ccx, + subst::FnSpace, + &early_lifetimes, + &generics.ty_params, + base_generics, + &generics.where_clause) } // Add the Sized bound, unless the type parameter is marked as `Sized?`. @@ -1080,9 +1089,9 @@ fn ty_generics(ccx: &CrateCtxt, space: subst::ParamSpace, lifetimes: &Vec, types: &OwnedSlice, - base_generics: ty::Generics) - -> ty::Generics -{ + base_generics: ty::Generics, + where_clause: &ast::WhereClause) + -> ty::Generics { let mut result = base_generics; for (i, l) in lifetimes.iter().enumerate() { @@ -1095,7 +1104,11 @@ fn ty_generics(ccx: &CrateCtxt, } for (i, param) in types.iter().enumerate() { - let def = get_or_create_type_parameter_def(ccx, space, param, i); + let def = get_or_create_type_parameter_def(ccx, + space, + param, + i, + where_clause); debug!("ty_generics: def for type param: {}", def.repr(ccx.tcx)); result.types.push(space, def); } @@ -1105,9 +1118,9 @@ fn ty_generics(ccx: &CrateCtxt, fn get_or_create_type_parameter_def(ccx: &CrateCtxt, space: subst::ParamSpace, param: &ast::TyParam, - index: uint) - -> ty::TypeParameterDef - { + index: uint, + where_clause: &ast::WhereClause) + -> ty::TypeParameterDef { match ccx.tcx.ty_param_defs.borrow().find(¶m.id) { Some(d) => { return (*d).clone(); } None => { } @@ -1121,7 +1134,8 @@ fn get_or_create_type_parameter_def(ccx: &CrateCtxt, ¶m.bounds, ¶m.unbound, param.ident, - param.span)); + param.span, + where_clause)); let default = param.default.map(|path| { let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &*path); let cur_idx = param_ty.idx; @@ -1154,14 +1168,14 @@ fn get_or_create_type_parameter_def(ccx: &CrateCtxt, def } - fn compute_bounds( - ccx: &CrateCtxt, - param_ty: ty::ParamTy, - ast_bounds: &OwnedSlice, - unbound: &Option, - ident: ast::Ident, - span: Span) -> ty::ParamBounds - { + fn compute_bounds(ccx: &CrateCtxt, + param_ty: ty::ParamTy, + ast_bounds: &OwnedSlice, + unbound: &Option, + ident: ast::Ident, + span: Span, + where_clause: &ast::WhereClause) + -> ty::ParamBounds { /*! * Translate the AST's notion of ty param bounds (which are an * enum consisting of a newtyped Ty or a region) to ty's @@ -1174,44 +1188,23 @@ fn compute_bounds( trait_bounds: Vec::new() }; for ast_bound in ast_bounds.iter() { - match *ast_bound { - TraitTyParamBound(ref b) => { - let ty = ty::mk_param(ccx.tcx, param_ty.space, - param_ty.idx, param_ty.def_id); - let trait_ref = instantiate_trait_ref(ccx, b, ty); - if !ty::try_add_builtin_trait( - ccx.tcx, trait_ref.def_id, - &mut param_bounds.builtin_bounds) { - // Must be a user-defined trait - param_bounds.trait_bounds.push(trait_ref); - } - } - - StaticRegionTyParamBound => { - param_bounds.builtin_bounds.add(ty::BoundStatic); - } - - UnboxedFnTyParamBound(ref unboxed_function) => { - let rscope = ExplicitRscope; - let self_ty = ty::mk_param(ccx.tcx, - param_ty.space, - param_ty.idx, - param_ty.def_id); - let trait_ref = - astconv::trait_ref_for_unboxed_function(ccx, - &rscope, - unboxed_function, - Some(self_ty)); - param_bounds.trait_bounds.push(Rc::new(trait_ref)); - } - - OtherRegionTyParamBound(span) => { - if !ccx.tcx.sess.features.issue_5723_bootstrap.get() { - ccx.tcx.sess.span_err( - span, - "only the 'static lifetime is accepted here."); - } - } + compute_bound(ccx, &mut param_bounds, param_ty, ast_bound); + } + for predicate in where_clause.predicates.iter() { + let predicate_param_id = ccx.tcx + .def_map + .borrow() + .find(&predicate.id) + .expect("compute_bounds(): resolve \ + didn't resolve the type \ + parameter identifier in a \ + `where` clause") + .def_id(); + if param_ty.def_id != predicate_param_id { + continue + } + for bound in predicate.bounds.iter() { + compute_bound(ccx, &mut param_bounds, param_ty, bound); } } @@ -1228,6 +1221,54 @@ fn compute_bounds( param_bounds } + /// Translates the AST's notion of a type parameter bound to + /// typechecking's notion of the same, and pushes the resulting bound onto + /// the appropriate section of `param_bounds`. + fn compute_bound(ccx: &CrateCtxt, + param_bounds: &mut ty::ParamBounds, + param_ty: ty::ParamTy, + ast_bound: &ast::TyParamBound) { + match *ast_bound { + TraitTyParamBound(ref b) => { + let ty = ty::mk_param(ccx.tcx, param_ty.space, + param_ty.idx, param_ty.def_id); + let trait_ref = instantiate_trait_ref(ccx, b, ty); + if !ty::try_add_builtin_trait( + ccx.tcx, trait_ref.def_id, + &mut param_bounds.builtin_bounds) { + // Must be a user-defined trait + param_bounds.trait_bounds.push(trait_ref); + } + } + + StaticRegionTyParamBound => { + param_bounds.builtin_bounds.add(ty::BoundStatic); + } + + UnboxedFnTyParamBound(ref unboxed_function) => { + let rscope = ExplicitRscope; + let self_ty = ty::mk_param(ccx.tcx, + param_ty.space, + param_ty.idx, + param_ty.def_id); + let trait_ref = + astconv::trait_ref_for_unboxed_function(ccx, + &rscope, + unboxed_function, + Some(self_ty)); + param_bounds.trait_bounds.push(Rc::new(trait_ref)); + } + + OtherRegionTyParamBound(span) => { + if !ccx.tcx.sess.features.issue_5723_bootstrap.get() { + ccx.tcx.sess.span_err( + span, + "only the 'static lifetime is accepted here."); + } + } + } + } + fn check_bounds_compatible(tcx: &ty::ctxt, param_bounds: &ty::ParamBounds, ident: ast::Ident, diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index a4e7f28b450..beaf81409a3 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -781,6 +781,7 @@ fn rebuild(&self) let mut inputs = self.fn_decl.inputs.clone(); let mut output = self.fn_decl.output; let mut ty_params = self.generics.ty_params.clone(); + let where_clause = self.generics.where_clause.clone(); let mut kept_lifetimes = HashSet::new(); for sr in self.same_regions.iter() { self.cur_anon.set(0); @@ -807,7 +808,8 @@ fn rebuild(&self) &fresh_lifetimes, &kept_lifetimes, &all_region_names, - ty_params); + ty_params, + where_clause); let new_fn_decl = ast::FnDecl { inputs: inputs, output: output, @@ -981,7 +983,8 @@ fn rebuild_generics(&self, add: &Vec, keep: &HashSet, remove: &HashSet, - ty_params: OwnedSlice) + ty_params: OwnedSlice, + where_clause: ast::WhereClause) -> ast::Generics { let mut lifetimes = Vec::new(); for lt in add.iter() { @@ -990,14 +993,14 @@ fn rebuild_generics(&self, } for lt in generics.lifetimes.iter() { if keep.contains(<.lifetime.name) || - !remove.contains(<.lifetime.name) - { + !remove.contains(<.lifetime.name) { lifetimes.push((*lt).clone()); } } ast::Generics { lifetimes: lifetimes, - ty_params: ty_params + ty_params: ty_params, + where_clause: where_clause, } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c5d3c73c9bc..68e1529fb17 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -363,7 +363,7 @@ fn clean(&self) -> Item { // determine if we should display the inner contents or // the outer `mod` item for the source code. - let where = { + let whence = { let ctxt = super::ctxtkey.get().unwrap(); let cm = ctxt.sess().codemap(); let outer = cm.lookup_char_pos(self.where_outer.lo); @@ -380,7 +380,7 @@ fn clean(&self) -> Item { Item { name: Some(name), attrs: self.attrs.clean(), - source: where.clean(), + source: whence.clean(), visibility: self.vis.clean(), stability: self.stab.clean(), def_id: ast_util::local_def(self.id), @@ -781,7 +781,7 @@ fn clean(&self) -> Item { Item { name: Some(self.name.clean()), attrs: self.attrs.clean(), - source: self.where.clean(), + source: self.whence.clean(), visibility: self.vis.clean(), stability: self.stab.clean(), def_id: ast_util::local_def(self.id), @@ -917,7 +917,7 @@ fn clean(&self) -> Item { Item { name: Some(self.name.clean()), attrs: self.attrs.clean(), - source: self.where.clean(), + source: self.whence.clean(), def_id: ast_util::local_def(self.id), visibility: self.vis.clean(), stability: self.stab.clean(), @@ -1397,7 +1397,7 @@ fn clean(&self) -> Item { Item { name: Some(self.name.clean()), attrs: self.attrs.clean(), - source: self.where.clean(), + source: self.whence.clean(), def_id: ast_util::local_def(self.id), visibility: self.vis.clean(), stability: self.stab.clean(), @@ -1443,7 +1443,7 @@ fn clean(&self) -> Item { Item { name: Some(self.name.clean()), attrs: self.attrs.clean(), - source: self.where.clean(), + source: self.whence.clean(), def_id: ast_util::local_def(self.id), visibility: self.vis.clean(), stability: self.stab.clean(), @@ -1466,7 +1466,7 @@ fn clean(&self) -> Item { Item { name: Some(self.name.clean()), attrs: self.attrs.clean(), - source: self.where.clean(), + source: self.whence.clean(), visibility: self.vis.clean(), stability: self.stab.clean(), def_id: ast_util::local_def(self.id), @@ -1652,7 +1652,7 @@ fn clean(&self) -> Item { Item { name: Some(self.name.clean()), attrs: self.attrs.clean(), - source: self.where.clean(), + source: self.whence.clean(), def_id: ast_util::local_def(self.id.clone()), visibility: self.vis.clean(), stability: self.stab.clean(), @@ -1702,7 +1702,7 @@ fn clean(&self) -> Item { Item { name: Some(self.name.clean()), attrs: self.attrs.clean(), - source: self.where.clean(), + source: self.whence.clean(), def_id: ast_util::local_def(self.id), visibility: self.vis.clean(), stability: self.stab.clean(), @@ -1748,7 +1748,7 @@ fn clean(&self) -> Item { Item { name: None, attrs: self.attrs.clean(), - source: self.where.clean(), + source: self.whence.clean(), def_id: ast_util::local_def(self.id), visibility: self.vis.clean(), stability: self.stab.clean(), @@ -2115,12 +2115,12 @@ fn clean(&self) -> Item { Item { name: Some(format!("{}!", self.name.clean())), attrs: self.attrs.clean(), - source: self.where.clean(), + source: self.whence.clean(), visibility: ast::Public.clean(), stability: self.stab.clean(), def_id: ast_util::local_def(self.id), inner: MacroItem(Macro { - source: self.where.to_src(), + source: self.whence.to_src(), }), } } diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index a5ead46384a..da45321e7fd 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -93,7 +93,7 @@ pub struct Struct { pub generics: ast::Generics, pub attrs: Vec, pub fields: Vec, - pub where: Span, + pub whence: Span, } pub struct Enum { @@ -103,7 +103,7 @@ pub struct Enum { pub generics: ast::Generics, pub attrs: Vec, pub id: NodeId, - pub where: Span, + pub whence: Span, pub name: Ident, } @@ -114,7 +114,7 @@ pub struct Variant { pub id: ast::NodeId, pub vis: ast::Visibility, pub stab: Option, - pub where: Span, + pub whence: Span, } pub struct Function { @@ -125,7 +125,7 @@ pub struct Function { pub vis: ast::Visibility, pub stab: Option, pub fn_style: ast::FnStyle, - pub where: Span, + pub whence: Span, pub generics: ast::Generics, } @@ -135,7 +135,7 @@ pub struct Typedef { pub name: Ident, pub id: ast::NodeId, pub attrs: Vec, - pub where: Span, + pub whence: Span, pub vis: ast::Visibility, pub stab: Option, } @@ -149,7 +149,7 @@ pub struct Static { pub vis: ast::Visibility, pub stab: Option, pub id: ast::NodeId, - pub where: Span, + pub whence: Span, } pub struct Trait { @@ -159,7 +159,7 @@ pub struct Trait { pub parents: Vec, pub attrs: Vec, pub id: ast::NodeId, - pub where: Span, + pub whence: Span, pub vis: ast::Visibility, pub stab: Option, } @@ -170,7 +170,7 @@ pub struct Impl { pub for_: ast::P, pub items: Vec, pub attrs: Vec, - pub where: Span, + pub whence: Span, pub vis: ast::Visibility, pub stab: Option, pub id: ast::NodeId, @@ -180,7 +180,7 @@ pub struct Macro { pub name: Ident, pub id: ast::NodeId, pub attrs: Vec, - pub where: Span, + pub whence: Span, pub stab: Option, } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index f7ccad79fda..b67b3c394d6 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -91,7 +91,7 @@ pub fn visit_struct_def(&mut self, item: &ast::Item, sd: Gc, attrs: item.attrs.iter().map(|x| *x).collect(), generics: generics.clone(), fields: sd.fields.iter().map(|x| (*x).clone()).collect(), - where: item.span + whence: item.span } } @@ -107,7 +107,7 @@ pub fn visit_enum_def(&mut self, it: &ast::Item, def: &ast::EnumDef, stab: self.stability(x.node.id), id: x.node.id, kind: x.node.kind.clone(), - where: x.span, + whence: x.span, }); } Enum { @@ -118,7 +118,7 @@ pub fn visit_enum_def(&mut self, it: &ast::Item, def: &ast::EnumDef, generics: params.clone(), attrs: it.attrs.iter().map(|x| *x).collect(), id: it.id, - where: it.span, + whence: it.span, } } @@ -133,7 +133,7 @@ pub fn visit_fn(&mut self, item: &ast::Item, fd: &ast::FnDecl, attrs: item.attrs.iter().map(|x| *x).collect(), decl: fd.clone(), name: item.ident, - where: item.span, + whence: item.span, generics: gen.clone(), fn_style: *fn_style, } @@ -297,7 +297,7 @@ pub fn visit_item(&mut self, item: &ast::Item, om: &mut Module) { name: item.ident, id: item.id, attrs: item.attrs.iter().map(|x| *x).collect(), - where: item.span, + whence: item.span, vis: item.vis, stab: self.stability(item.id), }; @@ -311,7 +311,7 @@ pub fn visit_item(&mut self, item: &ast::Item, om: &mut Module) { id: item.id, name: item.ident, attrs: item.attrs.iter().map(|x| *x).collect(), - where: item.span, + whence: item.span, vis: item.vis, stab: self.stability(item.id), }; @@ -325,7 +325,7 @@ pub fn visit_item(&mut self, item: &ast::Item, om: &mut Module) { parents: tr.iter().map(|x| (*x).clone()).collect(), id: item.id, attrs: item.attrs.iter().map(|x| *x).collect(), - where: item.span, + whence: item.span, vis: item.vis, stab: self.stability(item.id), }; @@ -339,7 +339,7 @@ pub fn visit_item(&mut self, item: &ast::Item, om: &mut Module) { items: items.iter().map(|x| *x).collect(), attrs: item.attrs.iter().map(|x| *x).collect(), id: item.id, - where: item.span, + whence: item.span, vis: item.vis, stab: self.stability(item.id), }; @@ -360,7 +360,7 @@ fn visit_macro(&self, item: &ast::Item) -> Macro { id: item.id, attrs: item.attrs.iter().map(|x| *x).collect(), name: item.ident, - where: item.span, + whence: item.span, stab: self.stability(item.id), } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 1ff8ca10fff..c658a5c3192 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -245,6 +245,7 @@ pub struct TyParam { pub struct Generics { pub lifetimes: Vec, pub ty_params: OwnedSlice, + pub where_clause: WhereClause, } impl Generics { @@ -259,9 +260,23 @@ pub fn is_type_parameterized(&self) -> bool { } } +#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +pub struct WhereClause { + pub id: NodeId, + pub predicates: Vec, +} + +#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +pub struct WherePredicate { + pub id: NodeId, + pub span: Span, + pub ident: Ident, + pub bounds: OwnedSlice, +} + /// The set of MetaItems that define the compilation environment of the crate, /// used to drive conditional compilation -pub type CrateConfig = Vec> ; +pub type CrateConfig = Vec>; #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub struct Crate { diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index 78afa8441c5..5fccf6cc3f0 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -431,11 +431,14 @@ pub fn with_attrs(&self, id: NodeId, f: |Option<&[Attribute]>| -> T) -> T { /// the iterator will produce node id's for items with paths /// such as `foo::bar::quux`, `bar::quux`, `other::bar::quux`, and /// any other such items it can find in the map. - pub fn nodes_matching_suffix<'a, S:Str>(&'a self, parts: &'a [S]) -> NodesMatchingSuffix<'a,S> { - NodesMatchingSuffix { map: self, - item_name: parts.last().unwrap(), - where: parts.slice_to(parts.len() - 1), - idx: 0 } + pub fn nodes_matching_suffix<'a, S:Str>(&'a self, parts: &'a [S]) + -> NodesMatchingSuffix<'a,S> { + NodesMatchingSuffix { + map: self, + item_name: parts.last().unwrap(), + in_which: parts.slice_to(parts.len() - 1), + idx: 0, + } } pub fn opt_span(&self, id: NodeId) -> Option { @@ -478,20 +481,20 @@ pub fn node_to_string(&self, id: NodeId) -> String { pub struct NodesMatchingSuffix<'a, S> { map: &'a Map, item_name: &'a S, - where: &'a [S], + in_which: &'a [S], idx: NodeId, } impl<'a,S:Str> NodesMatchingSuffix<'a,S> { /// Returns true only if some suffix of the module path for parent - /// matches `self.where`. + /// matches `self.in_which`. /// - /// In other words: let `[x_0,x_1,...,x_k]` be `self.where`; + /// In other words: let `[x_0,x_1,...,x_k]` be `self.in_which`; /// returns true if parent's path ends with the suffix /// `x_0::x_1::...::x_k`. fn suffix_matches(&self, parent: NodeId) -> bool { let mut cursor = parent; - for part in self.where.iter().rev() { + for part in self.in_which.iter().rev() { let (mod_id, mod_name) = match find_first_mod_parent(self.map, cursor) { None => return false, Some((node_id, name)) => (node_id, name), diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 7689646d373..5674c6675f9 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -320,8 +320,14 @@ pub fn operator_prec(op: ast::BinOp) -> uint { pub static as_prec: uint = 12u; pub fn empty_generics() -> Generics { - Generics {lifetimes: Vec::new(), - ty_params: OwnedSlice::empty()} + Generics { + lifetimes: Vec::new(), + ty_params: OwnedSlice::empty(), + where_clause: WhereClause { + id: DUMMY_NODE_ID, + predicates: Vec::new(), + } + } } // ______________________________________________________________________ diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 7a8ee6d1416..f9f2a86d182 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -390,7 +390,7 @@ fn create_derived_impl(&self, methods: Vec> ) -> Gc { let trait_path = self.path.to_path(cx, self.span, type_ident, generics); - let Generics { mut lifetimes, ty_params } = + let Generics { mut lifetimes, ty_params, where_clause: _ } = self.generics.to_generics(cx, self.span, type_ident, generics); let mut ty_params = ty_params.into_vec(); @@ -418,7 +418,11 @@ fn create_derived_impl(&self, })); let trait_generics = Generics { lifetimes: lifetimes, - ty_params: OwnedSlice::from_vec(ty_params) + ty_params: OwnedSlice::from_vec(ty_params), + where_clause: ast::WhereClause { + id: ast::DUMMY_NODE_ID, + predicates: Vec::new(), + }, }; // Create the reference to the trait. diff --git a/src/libsyntax/ext/deriving/generic/ty.rs b/src/libsyntax/ext/deriving/generic/ty.rs index 2130b6f4e9d..f4a9b85f75d 100644 --- a/src/libsyntax/ext/deriving/generic/ty.rs +++ b/src/libsyntax/ext/deriving/generic/ty.rs @@ -202,10 +202,15 @@ fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str, cx.typaram(span, cx.ident_of(name), bounds, unbound, None) } -fn mk_generics(lifetimes: Vec, ty_params: Vec ) -> Generics { +fn mk_generics(lifetimes: Vec, ty_params: Vec) + -> Generics { Generics { lifetimes: lifetimes, - ty_params: OwnedSlice::from_vec(ty_params) + ty_params: OwnedSlice::from_vec(ty_params), + where_clause: ast::WhereClause { + id: ast::DUMMY_NODE_ID, + predicates: Vec::new(), + }, } } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 4ed2a3ed4c2..9ad28f02e80 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -244,6 +244,16 @@ fn fold_field(&mut self, field: Field) -> Field { noop_fold_field(field, self) } + fn fold_where_clause(&mut self, where_clause: &WhereClause) + -> WhereClause { + noop_fold_where_clause(where_clause, self) + } + + fn fold_where_predicate(&mut self, where_predicate: &WherePredicate) + -> WherePredicate { + noop_fold_where_predicate(where_predicate, self) + } + // Helper methods: fn map_exprs(&self, f: |Gc| -> Gc, @@ -698,8 +708,37 @@ pub fn noop_fold_opt_lifetime(o_lt: &Option, fld: &mut T) } pub fn noop_fold_generics(generics: &Generics, fld: &mut T) -> Generics { - Generics {ty_params: fld.fold_ty_params(generics.ty_params.as_slice()), - lifetimes: fld.fold_lifetime_defs(generics.lifetimes.as_slice())} + Generics { + ty_params: fld.fold_ty_params(generics.ty_params.as_slice()), + lifetimes: fld.fold_lifetime_defs(generics.lifetimes.as_slice()), + where_clause: fld.fold_where_clause(&generics.where_clause), + } +} + +pub fn noop_fold_where_clause( + where_clause: &WhereClause, + fld: &mut T) + -> WhereClause { + WhereClause { + id: fld.new_id(where_clause.id), + predicates: where_clause.predicates.iter().map(|predicate| { + fld.fold_where_predicate(predicate) + }).collect(), + } +} + +pub fn noop_fold_where_predicate( + predicate: &WherePredicate, + fld: &mut T) + -> WherePredicate { + WherePredicate { + id: fld.new_id(predicate.id), + span: fld.new_span(predicate.span), + ident: fld.fold_ident(predicate.ident), + bounds: predicate.bounds.map(|x| { + fld.fold_ty_param_bound(x) + }), + } } pub fn noop_fold_struct_def(struct_def: Gc, diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index e5275af5cca..17249628989 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -543,7 +543,7 @@ fn scan_block_comment(&mut self) -> Option { // favors rustc debugging effectiveness over runtime efficiency. /// Scan through input of form \x00name_NNNNNN,ctxt_CCCCCCC\x00 - /// where: `NNNNNN` is a string of characters forming an integer + /// whence: `NNNNNN` is a string of characters forming an integer /// (the name) and `CCCCCCC` is a string of characters forming an /// integer (the ctxt), separate by a comma and delimited by a /// `\x00` marker. @@ -552,22 +552,22 @@ fn scan_embedded_hygienic_ident(&mut self) -> ast::Ident { fn bump_expecting_char<'a,D:fmt::Show>(r: &mut StringReader<'a>, c: char, described_c: D, - where: &str) { + whence: &str) { match r.curr { Some(r_c) if r_c == c => r.bump(), - Some(r_c) => fail!("expected {}, hit {}, {}", described_c, r_c, where), - None => fail!("expected {}, hit EOF, {}", described_c, where), + Some(r_c) => fail!("expected {}, hit {}, {}", described_c, r_c, whence), + None => fail!("expected {}, hit EOF, {}", described_c, whence), } } - let where = "while scanning embedded hygienic ident"; + let whence = "while scanning embedded hygienic ident"; // skip over the leading `\x00` - bump_expecting_char(self, '\x00', "nul-byte", where); + bump_expecting_char(self, '\x00', "nul-byte", whence); // skip over the "name_" for c in "name_".chars() { - bump_expecting_char(self, c, c, where); + bump_expecting_char(self, c, c, whence); } let start_bpos = self.last_pos; @@ -578,16 +578,16 @@ fn bump_expecting_char<'a,D:fmt::Show>(r: &mut StringReader<'a>, let encoded_name : u32 = self.with_str_from(start_bpos, |s| { num::from_str_radix(s, 10).unwrap_or_else(|| { fail!("expected digits representing a name, got `{}`, {}, range [{},{}]", - s, where, start_bpos, self.last_pos); + s, whence, start_bpos, self.last_pos); }) }); // skip over the `,` - bump_expecting_char(self, ',', "comma", where); + bump_expecting_char(self, ',', "comma", whence); // skip over the "ctxt_" for c in "ctxt_".chars() { - bump_expecting_char(self, c, c, where); + bump_expecting_char(self, c, c, whence); } // find the integer representing the ctxt @@ -595,12 +595,12 @@ fn bump_expecting_char<'a,D:fmt::Show>(r: &mut StringReader<'a>, self.scan_digits(base); let encoded_ctxt : ast::SyntaxContext = self.with_str_from(start_bpos, |s| { num::from_str_radix(s, 10).unwrap_or_else(|| { - fail!("expected digits representing a ctxt, got `{}`, {}", s, where); + fail!("expected digits representing a ctxt, got `{}`, {}", s, whence); }) }); // skip over the `\x00` - bump_expecting_char(self, '\x00', "nul-byte", where); + bump_expecting_char(self, '\x00', "nul-byte", whence); ast::Ident { name: ast::Name(encoded_name), ctxt: encoded_ctxt, } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index af1f296a6ca..271cefeaf03 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -1053,6 +1053,10 @@ fn parser_done(p: Parser){ ast::Generics{ // no idea on either of these: lifetimes: Vec::new(), ty_params: OwnedSlice::empty(), + where_clause: ast::WhereClause { + id: ast::DUMMY_NODE_ID, + predicates: Vec::new(), + } }, ast::P(ast::Block { view_items: Vec::new(), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f272f7e1887..577959ea36a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -60,7 +60,7 @@ use ast::{UnnamedField, UnsafeBlock}; use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse}; use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; -use ast::Visibility; +use ast::{Visibility, WhereClause, WherePredicate}; use ast; use ast_util::{as_prec, ident_to_path, lit_is_str, operator_prec}; use ast_util; @@ -1264,7 +1264,7 @@ pub fn parse_trait_methods(&mut self) -> Vec { let style = p.parse_fn_style(); let ident = p.parse_ident(); - let generics = p.parse_generics(); + let mut generics = p.parse_generics(); let (explicit_self, d) = p.parse_fn_decl_with_self(|p| { // This is somewhat dubious; We don't want to allow argument @@ -1272,6 +1272,8 @@ pub fn parse_trait_methods(&mut self) -> Vec { p.parse_arg_general(false) }); + p.parse_where_clause(&mut generics); + let hi = p.last_span.hi; match p.token { token::SEMI => { @@ -3742,7 +3744,10 @@ fn parse_ty_param(&mut self) -> TyParam { } } - /// Parse a set of optional generic type parameter declarations + /// Parse a set of optional generic type parameter declarations. Where + /// clauses are not parsed here, and must be added later via + /// `parse_where_clause()`. + /// /// matches generics = ( ) | ( < > ) | ( < typaramseq ( , )? > ) | ( < lifetimes ( , )? > ) /// | ( < lifetimes , typaramseq ( , )? > ) /// where typaramseq = ( typaram ) | ( typaram , typaramseq ) @@ -3762,7 +3767,14 @@ pub fn parse_generics(&mut self) -> ast::Generics { } ty_param }); - ast::Generics { lifetimes: lifetime_defs, ty_params: ty_params } + ast::Generics { + lifetimes: lifetime_defs, + ty_params: ty_params, + where_clause: WhereClause { + id: ast::DUMMY_NODE_ID, + predicates: Vec::new(), + } + } } else { ast_util::empty_generics() } @@ -3788,6 +3800,52 @@ fn forbid_lifetime(&mut self) { } } + /// Parses an optional `where` clause and places it in `generics`. + fn parse_where_clause(&mut self, generics: &mut ast::Generics) { + if !self.eat_keyword(keywords::Where) { + return + } + + let mut parsed_something = false; + loop { + let lo = self.span.lo; + let ident = match self.token { + token::IDENT(..) => self.parse_ident(), + _ => break, + }; + self.expect(&token::COLON); + + let (_, bounds) = self.parse_ty_param_bounds(false); + let hi = self.span.hi; + let span = mk_sp(lo, hi); + + if bounds.len() == 0 { + self.span_err(span, + "each predicate in a `where` clause must have \ + at least one bound in it"); + } + + generics.where_clause.predicates.push(ast::WherePredicate { + id: ast::DUMMY_NODE_ID, + span: span, + ident: ident, + bounds: bounds, + }); + parsed_something = true; + + if !self.eat(&token::COMMA) { + break + } + } + + if !parsed_something { + let last_span = self.last_span; + self.span_err(last_span, + "a `where` clause must have at least one predicate \ + in it"); + } + } + fn parse_fn_args(&mut self, named_args: bool, allow_variadic: bool) -> (Vec , bool) { let sp = self.span; @@ -4143,8 +4201,9 @@ fn mk_item(&mut self, lo: BytePos, hi: BytePos, ident: Ident, /// Parse an item-position function declaration. fn parse_item_fn(&mut self, fn_style: FnStyle, abi: abi::Abi) -> ItemInfo { - let (ident, generics) = self.parse_fn_header(); + let (ident, mut generics) = self.parse_fn_header(); let decl = self.parse_fn_decl(false); + self.parse_where_clause(&mut generics); let (inner_attrs, body) = self.parse_inner_attrs_and_block(); (ident, ItemFn(decl, fn_style, abi, generics, body), Some(inner_attrs)) } @@ -4200,10 +4259,11 @@ pub fn parse_method(&mut self, }; let fn_style = self.parse_fn_style(); let ident = self.parse_ident(); - let generics = self.parse_generics(); + let mut generics = self.parse_generics(); let (explicit_self, decl) = self.parse_fn_decl_with_self(|p| { p.parse_arg() }); + self.parse_where_clause(&mut generics); let (inner_attrs, body) = self.parse_inner_attrs_and_block(); let new_attrs = attrs.append(inner_attrs.as_slice()); (ast::MethDecl(ident, @@ -4228,7 +4288,7 @@ pub fn parse_method(&mut self, /// Parse trait Foo { ... } fn parse_item_trait(&mut self) -> ItemInfo { let ident = self.parse_ident(); - let tps = self.parse_generics(); + let mut tps = self.parse_generics(); let sized = self.parse_for_sized(); // Parse traits, if necessary. @@ -4240,6 +4300,8 @@ fn parse_item_trait(&mut self) -> ItemInfo { traits = Vec::new(); } + self.parse_where_clause(&mut tps); + let meths = self.parse_trait_methods(); (ident, ItemTrait(tps, sized, traits, meths), None) } @@ -4261,7 +4323,7 @@ fn parse_impl_items(&mut self) -> (Vec, Vec) { /// impl ToString for ~[T] { ... } fn parse_item_impl(&mut self) -> ItemInfo { // First, parse type parameters if necessary. - let generics = self.parse_generics(); + let mut generics = self.parse_generics(); // Special case: if the next identifier that follows is '(', don't // allow this to be parsed as a trait. @@ -4297,6 +4359,7 @@ fn parse_item_impl(&mut self) -> ItemInfo { None }; + self.parse_where_clause(&mut generics); let (impl_items, attrs) = self.parse_impl_items(); let ident = ast_util::impl_pretty_name(&opt_trait, &*ty); @@ -4326,7 +4389,7 @@ fn parse_trait_ref_list(&mut self, ket: &token::Token) -> Vec { /// Parse struct Foo { ... } fn parse_item_struct(&mut self, is_virtual: bool) -> ItemInfo { let class_name = self.parse_ident(); - let generics = self.parse_generics(); + let mut generics = self.parse_generics(); let super_struct = if self.eat(&token::COLON) { let ty = self.parse_ty(true); @@ -4343,6 +4406,8 @@ fn parse_item_struct(&mut self, is_virtual: bool) -> ItemInfo { None }; + self.parse_where_clause(&mut generics); + let mut fields: Vec; let is_tuple_like; @@ -4683,8 +4748,9 @@ fn parse_item_foreign_fn(&mut self, vis: ast::Visibility, let lo = self.span.lo; self.expect_keyword(keywords::Fn); - let (ident, generics) = self.parse_fn_header(); + let (ident, mut generics) = self.parse_fn_header(); let decl = self.parse_fn_decl(true); + self.parse_where_clause(&mut generics); let hi = self.span.hi; self.expect(&token::SEMI); box(GC) ast::ForeignItem { ident: ident, @@ -4834,7 +4900,8 @@ fn parse_item_foreign_mod(&mut self, /// Parse type Foo = Bar; fn parse_item_type(&mut self) -> ItemInfo { let ident = self.parse_ident(); - let tps = self.parse_generics(); + let mut tps = self.parse_generics(); + self.parse_where_clause(&mut tps); self.expect(&token::EQ); let ty = self.parse_ty(true); self.expect(&token::SEMI); @@ -4925,7 +4992,8 @@ fn parse_enum_def(&mut self, _generics: &ast::Generics) -> EnumDef { /// Parse an "enum" declaration fn parse_item_enum(&mut self) -> ItemInfo { let id = self.parse_ident(); - let generics = self.parse_generics(); + let mut generics = self.parse_generics(); + self.parse_where_clause(&mut generics); self.expect(&token::LBRACE); let enum_definition = self.parse_enum_def(&generics); diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index f1ef7980151..4c959932f41 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -499,18 +499,19 @@ pub mod keywords { (41, Proc, "proc"); (42, Box, "box"); (43, Const, "const"); + (44, Where, "where"); 'reserved: - (44, Alignof, "alignof"); - (45, Be, "be"); - (46, Offsetof, "offsetof"); - (47, Priv, "priv"); - (48, Pure, "pure"); - (49, Sizeof, "sizeof"); - (50, Typeof, "typeof"); - (51, Unsized, "unsized"); - (52, Yield, "yield"); - (53, Do, "do"); + (45, Alignof, "alignof"); + (46, Be, "be"); + (47, Offsetof, "offsetof"); + (48, Priv, "priv"); + (49, Pure, "pure"); + (50, Sizeof, "sizeof"); + (51, Typeof, "typeof"); + (52, Unsized, "unsized"); + (53, Yield, "yield"); + (54, Do, "do"); } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index c573cc0c0ad..998049b83cc 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -584,7 +584,11 @@ pub fn print_type(&mut self, ty: &ast::Ty) -> IoResult<()> { ast::TyBareFn(f) => { let generics = ast::Generics { lifetimes: f.lifetimes.clone(), - ty_params: OwnedSlice::empty() + ty_params: OwnedSlice::empty(), + where_clause: ast::WhereClause { + id: ast::DUMMY_NODE_ID, + predicates: Vec::new(), + }, }; try!(self.print_ty_fn(Some(f.abi), None, @@ -601,7 +605,11 @@ pub fn print_type(&mut self, ty: &ast::Ty) -> IoResult<()> { ast::TyClosure(f, ref region) => { let generics = ast::Generics { lifetimes: f.lifetimes.clone(), - ty_params: OwnedSlice::empty() + ty_params: OwnedSlice::empty(), + where_clause: ast::WhereClause { + id: ast::DUMMY_NODE_ID, + predicates: Vec::new(), + }, }; try!(self.print_ty_fn(None, Some('&'), @@ -618,7 +626,11 @@ pub fn print_type(&mut self, ty: &ast::Ty) -> IoResult<()> { ast::TyProc(ref f) => { let generics = ast::Generics { lifetimes: f.lifetimes.clone(), - ty_params: OwnedSlice::empty() + ty_params: OwnedSlice::empty(), + where_clause: ast::WhereClause { + id: ast::DUMMY_NODE_ID, + predicates: Vec::new(), + }, }; try!(self.print_ty_fn(None, Some('~'), @@ -765,6 +777,7 @@ pub fn print_item(&mut self, item: &ast::Item) -> IoResult<()> { try!(space(&mut self.s)); try!(self.word_space("=")); try!(self.print_type(&**ty)); + try!(self.print_where_clause(params)); try!(word(&mut self.s, ";")); try!(self.end()); // end the outer ibox } @@ -808,6 +821,7 @@ pub fn print_item(&mut self, item: &ast::Item) -> IoResult<()> { } try!(self.print_type(&**ty)); + try!(self.print_where_clause(generics)); try!(space(&mut self.s)); try!(self.bopen()); @@ -845,6 +859,7 @@ pub fn print_item(&mut self, item: &ast::Item) -> IoResult<()> { try!(self.print_path(&trait_.path, false)); } } + try!(self.print_where_clause(generics)); try!(word(&mut self.s, " ")); try!(self.bopen()); for meth in methods.iter() { @@ -880,6 +895,7 @@ pub fn print_enum_def(&mut self, enum_definition: &ast::EnumDef, try!(self.head(visibility_qualified(visibility, "enum").as_slice())); try!(self.print_ident(ident)); try!(self.print_generics(generics)); + try!(self.print_where_clause(generics)); try!(space(&mut self.s)); self.print_variants(enum_definition.variants.as_slice(), span) } @@ -2010,7 +2026,8 @@ pub fn print_fn(&mut self, try!(self.nbsp()); try!(self.print_ident(name)); try!(self.print_generics(generics)); - self.print_fn_args_and_ret(decl, opt_explicit_self) + try!(self.print_fn_args_and_ret(decl, opt_explicit_self)) + self.print_where_clause(generics) } pub fn print_fn_args(&mut self, decl: &ast::FnDecl, @@ -2201,54 +2218,83 @@ pub fn print_lifetime_def(&mut self, Ok(()) } - pub fn print_generics(&mut self, - generics: &ast::Generics) -> IoResult<()> { - let total = generics.lifetimes.len() + generics.ty_params.len(); - if total > 0 { - try!(word(&mut self.s, "<")); + fn print_type_parameters(&mut self, + lifetimes: &[ast::LifetimeDef], + ty_params: &[ast::TyParam]) + -> IoResult<()> { + let total = lifetimes.len() + ty_params.len(); + let mut ints = Vec::new(); + for i in range(0u, total) { + ints.push(i); + } - let mut ints = Vec::new(); - for i in range(0u, total) { - ints.push(i); - } - - try!(self.commasep( - Inconsistent, ints.as_slice(), - |s, &idx| { - if idx < generics.lifetimes.len() { - let lifetime = generics.lifetimes.get(idx); - s.print_lifetime_def(lifetime) - } else { - let idx = idx - generics.lifetimes.len(); - let param = generics.ty_params.get(idx); - match param.unbound { - Some(TraitTyParamBound(ref tref)) => { - try!(s.print_trait_ref(tref)); - try!(s.word_space("?")); - } - _ => {} - } - try!(s.print_ident(param.ident)); - try!(s.print_bounds(&None, - ¶m.bounds, - false, - false)); - match param.default { - Some(ref default) => { - try!(space(&mut s.s)); - try!(s.word_space("=")); - s.print_type(&**default) - } - _ => Ok(()) - } + self.commasep(Inconsistent, ints.as_slice(), |s, &idx| { + if idx < lifetimes.len() { + let lifetime = &lifetimes[idx]; + s.print_lifetime_def(lifetime) + } else { + let idx = idx - lifetimes.len(); + let param = &ty_params[idx]; + match param.unbound { + Some(TraitTyParamBound(ref tref)) => { + try!(s.print_trait_ref(tref)); + try!(s.word_space("?")); } - })); + _ => {} + } + try!(s.print_ident(param.ident)); + try!(s.print_bounds(&None, + ¶m.bounds, + false, + false)); + match param.default { + Some(ref default) => { + try!(space(&mut s.s)); + try!(s.word_space("=")); + s.print_type(&**default) + } + _ => Ok(()) + } + } + }) + } + + pub fn print_generics(&mut self, generics: &ast::Generics) + -> IoResult<()> { + if generics.lifetimes.len() + generics.ty_params.len() > 0 { + try!(word(&mut self.s, "<")); + try!(self.print_type_parameters(generics.lifetimes.as_slice(), + generics.ty_params.as_slice())); word(&mut self.s, ">") } else { Ok(()) } } + pub fn print_where_clause(&mut self, generics: &ast::Generics) + -> IoResult<()> { + if generics.where_clause.predicates.len() == 0 { + return Ok(()) + } + + try!(space(&mut self.s)); + try!(self.word_space("where")); + + for (i, predicate) in generics.where_clause + .predicates + .iter() + .enumerate() { + if i != 0 { + try!(self.word_space(",")); + } + + try!(self.print_ident(predicate.ident)); + try!(self.print_bounds(&None, &predicate.bounds, false, false)); + } + + Ok(()) + } + pub fn print_meta_item(&mut self, item: &ast::MetaItem) -> IoResult<()> { try!(self.ibox(indent_unit)); match item.node { @@ -2472,6 +2518,11 @@ pub fn print_ty_fn(&mut self, } } + match generics { + Some(generics) => try!(self.print_where_clause(generics)), + None => {} + } + self.end() } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 18cbf797d03..ac1dbdc439c 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -27,6 +27,7 @@ use abi::Abi; use ast::*; use ast; +use ast_util; use codemap::Span; use parse; use owned_slice::OwnedSlice; @@ -58,12 +59,7 @@ pub fn generics_of_fn(fk: &FnKind) -> Generics { FkMethod(_, generics, _) => { (*generics).clone() } - FkFnBlock(..) => { - Generics { - lifetimes: Vec::new(), - ty_params: OwnedSlice::empty(), - } - } + FkFnBlock(..) => ast_util::empty_generics(), } } @@ -559,7 +555,11 @@ pub fn walk_generics>(visitor: &mut V, None => {} } } - walk_lifetime_decls(visitor, &generics.lifetimes, env); + walk_lifetime_decls(visitor, &generics.lifetimes, env.clone()); + for predicate in generics.where_clause.predicates.iter() { + visitor.visit_ident(predicate.span, predicate.ident, env.clone()); + walk_ty_param_bounds(visitor, &predicate.bounds, env.clone()); + } } pub fn walk_fn_decl>(visitor: &mut V, diff --git a/src/test/auxiliary/where_clauses_xc.rs b/src/test/auxiliary/where_clauses_xc.rs new file mode 100644 index 00000000000..002b31f099f --- /dev/null +++ b/src/test/auxiliary/where_clauses_xc.rs @@ -0,0 +1,30 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub trait Equal { + fn equal(&self, other: &Self) -> bool; + fn equals(&self, this: &T, that: &T, x: &U, y: &U) -> bool + where T: Eq, U: Eq; +} + +impl Equal for T where T: Eq { + fn equal(&self, other: &T) -> bool { + self == other + } + fn equals(&self, this: &U, other: &U, x: &X, y: &X) -> bool + where U: Eq, X: Eq { + this == other && x == y + } +} + +pub fn equal(x: &T, y: &T) -> bool where T: Eq { + x == y +} + diff --git a/src/test/compile-fail/where-clauses-no-bounds-or-predicates.rs b/src/test/compile-fail/where-clauses-no-bounds-or-predicates.rs new file mode 100644 index 00000000000..b96c7c2de6b --- /dev/null +++ b/src/test/compile-fail/where-clauses-no-bounds-or-predicates.rs @@ -0,0 +1,23 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn equal1(_: &T, _: &T) -> bool where { +//~^ ERROR a `where` clause must have at least one predicate in it + true +} + +fn equal2(_: &T, _: &T) -> bool where T: { +//~^ ERROR each predicate in a `where` clause must have at least one bound + true +} + +fn main() { +} + diff --git a/src/test/compile-fail/where-clauses-not-parameter.rs b/src/test/compile-fail/where-clauses-not-parameter.rs new file mode 100644 index 00000000000..2817aa16e8e --- /dev/null +++ b/src/test/compile-fail/where-clauses-not-parameter.rs @@ -0,0 +1,17 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn equal(_: &T, _: &T) -> bool where int : Eq { + //~^ ERROR undeclared type parameter +} + +fn main() { +} + diff --git a/src/test/compile-fail/where-clauses-unsatisfied.rs b/src/test/compile-fail/where-clauses-unsatisfied.rs new file mode 100644 index 00000000000..1d21313975f --- /dev/null +++ b/src/test/compile-fail/where-clauses-unsatisfied.rs @@ -0,0 +1,20 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn equal(_: &T, _: &T) -> bool where T : Eq { +} + +struct Struct; + +fn main() { + equal(&Struct, &Struct) + //~^ ERROR failed to find an implementation of trait +} + diff --git a/src/test/run-pass/where-clauses-cross-crate.rs b/src/test/run-pass/where-clauses-cross-crate.rs new file mode 100644 index 00000000000..648f646b637 --- /dev/null +++ b/src/test/run-pass/where-clauses-cross-crate.rs @@ -0,0 +1,23 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:where_clauses_xc.rs + +extern crate where_clauses_xc; + +use where_clauses_xc::{Equal, equal}; + +fn main() { + println!("{}", equal(&1i, &2i)); + println!("{}", equal(&1i, &1i)); + println!("{}", "hello".equal(&"hello")); + println!("{}", "hello".equals::(&1i, &1i, &"foo", &"bar")); +} + diff --git a/src/test/run-pass/where-clauses.rs b/src/test/run-pass/where-clauses.rs new file mode 100644 index 00000000000..807d95691f4 --- /dev/null +++ b/src/test/run-pass/where-clauses.rs @@ -0,0 +1,37 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Equal { + fn equal(&self, other: &Self) -> bool; + fn equals(&self, this: &T, that: &T, x: &U, y: &U) -> bool + where T: Eq, U: Eq; +} + +impl Equal for T where T: Eq { + fn equal(&self, other: &T) -> bool { + self == other + } + fn equals(&self, this: &U, other: &U, x: &X, y: &X) -> bool + where U: Eq, X: Eq { + this == other && x == y + } +} + +fn equal(x: &T, y: &T) -> bool where T: Eq { + x == y +} + +fn main() { + println!("{}", equal(&1i, &2i)); + println!("{}", equal(&1i, &1i)); + println!("{}", "hello".equal(&"hello")); + println!("{}", "hello".equals::(&1i, &1i, &"foo", &"bar")); +} + -- GitLab