auto merge of #16424 : pcwalton/rust/where-clauses, r=nikomatsakis
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] r? @nikomatsakis (or whoever)
This commit is contained in:
commit
36db3866c0
25 changed files with 626 additions and 207 deletions
|
@ -3671,6 +3671,7 @@ impl<'a> Resolver<'a> {
|
||||||
ItemRibKind),
|
ItemRibKind),
|
||||||
|this| {
|
|this| {
|
||||||
this.resolve_type_parameters(&generics.ty_params);
|
this.resolve_type_parameters(&generics.ty_params);
|
||||||
|
this.resolve_where_clause(&generics.where_clause);
|
||||||
visit::walk_item(this, item, ());
|
visit::walk_item(this, item, ());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -3713,6 +3714,7 @@ impl<'a> Resolver<'a> {
|
||||||
NormalRibKind),
|
NormalRibKind),
|
||||||
|this| {
|
|this| {
|
||||||
this.resolve_type_parameters(&generics.ty_params);
|
this.resolve_type_parameters(&generics.ty_params);
|
||||||
|
this.resolve_where_clause(&generics.where_clause);
|
||||||
|
|
||||||
// Resolve derived traits.
|
// Resolve derived traits.
|
||||||
for trt in traits.iter() {
|
for trt in traits.iter() {
|
||||||
|
@ -3744,6 +3746,8 @@ impl<'a> Resolver<'a> {
|
||||||
// parameters.
|
// parameters.
|
||||||
this.resolve_type_parameters(
|
this.resolve_type_parameters(
|
||||||
&ty_m.generics.ty_params);
|
&ty_m.generics.ty_params);
|
||||||
|
this.resolve_where_clause(&ty_m.generics
|
||||||
|
.where_clause);
|
||||||
|
|
||||||
for argument in ty_m.decl.inputs.iter() {
|
for argument in ty_m.decl.inputs.iter() {
|
||||||
this.resolve_type(&*argument.ty);
|
this.resolve_type(&*argument.ty);
|
||||||
|
@ -3907,6 +3911,7 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
HasTypeParameters(ref generics, _, _, _) => {
|
HasTypeParameters(ref generics, _, _, _) => {
|
||||||
this.resolve_type_parameters(&generics.ty_params);
|
this.resolve_type_parameters(&generics.ty_params);
|
||||||
|
this.resolve_where_clause(&generics.where_clause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4022,6 +4027,30 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
fn resolve_struct(&mut self,
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
generics: &Generics,
|
generics: &Generics,
|
||||||
|
@ -4035,6 +4064,7 @@ impl<'a> Resolver<'a> {
|
||||||
|this| {
|
|this| {
|
||||||
// Resolve the type parameters.
|
// Resolve the type parameters.
|
||||||
this.resolve_type_parameters(&generics.ty_params);
|
this.resolve_type_parameters(&generics.ty_params);
|
||||||
|
this.resolve_where_clause(&generics.where_clause);
|
||||||
|
|
||||||
// Resolve the super struct.
|
// Resolve the super struct.
|
||||||
match super_struct {
|
match super_struct {
|
||||||
|
@ -4146,6 +4176,7 @@ impl<'a> Resolver<'a> {
|
||||||
|this| {
|
|this| {
|
||||||
// Resolve the type parameters.
|
// Resolve the type parameters.
|
||||||
this.resolve_type_parameters(&generics.ty_params);
|
this.resolve_type_parameters(&generics.ty_params);
|
||||||
|
this.resolve_where_clause(&generics.where_clause);
|
||||||
|
|
||||||
// Resolve the trait reference, if necessary.
|
// Resolve the trait reference, if necessary.
|
||||||
this.with_optional_trait_ref(id, opt_trait_reference, |this| {
|
this.with_optional_trait_ref(id, opt_trait_reference, |this| {
|
||||||
|
|
|
@ -208,7 +208,6 @@ use syntax::util::interner::Interner;
|
||||||
use syntax::codemap::{Span, Pos};
|
use syntax::codemap::{Span, Pos};
|
||||||
use syntax::{abi, ast, codemap, ast_util, ast_map};
|
use syntax::{abi, ast, codemap, ast_util, ast_map};
|
||||||
use syntax::ast_util::PostExpansionMethod;
|
use syntax::ast_util::PostExpansionMethod;
|
||||||
use syntax::owned_slice::OwnedSlice;
|
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax::parse::token::special_idents;
|
use syntax::parse::token::special_idents;
|
||||||
|
|
||||||
|
@ -1123,8 +1122,7 @@ pub fn create_function_debug_context(cx: &CrateContext,
|
||||||
return FunctionDebugContext { repr: FunctionWithoutDebugInfo };
|
return FunctionDebugContext { repr: FunctionWithoutDebugInfo };
|
||||||
}
|
}
|
||||||
|
|
||||||
let empty_generics = ast::Generics { lifetimes: Vec::new(),
|
let empty_generics = ast_util::empty_generics();
|
||||||
ty_params: OwnedSlice::empty() };
|
|
||||||
|
|
||||||
let fnitem = cx.tcx.map.get(fn_ast_id);
|
let fnitem = cx.tcx.map.get(fn_ast_id);
|
||||||
|
|
||||||
|
|
|
@ -987,20 +987,26 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt,
|
||||||
|
|
||||||
fn ty_generics_for_type(ccx: &CrateCtxt,
|
fn ty_generics_for_type(ccx: &CrateCtxt,
|
||||||
generics: &ast::Generics)
|
generics: &ast::Generics)
|
||||||
-> ty::Generics
|
-> ty::Generics {
|
||||||
{
|
ty_generics(ccx,
|
||||||
ty_generics(ccx, subst::TypeSpace, &generics.lifetimes,
|
subst::TypeSpace,
|
||||||
&generics.ty_params, ty::Generics::empty())
|
&generics.lifetimes,
|
||||||
|
&generics.ty_params,
|
||||||
|
ty::Generics::empty(),
|
||||||
|
&generics.where_clause)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ty_generics_for_trait(ccx: &CrateCtxt,
|
fn ty_generics_for_trait(ccx: &CrateCtxt,
|
||||||
trait_id: ast::NodeId,
|
trait_id: ast::NodeId,
|
||||||
substs: &subst::Substs,
|
substs: &subst::Substs,
|
||||||
generics: &ast::Generics)
|
generics: &ast::Generics)
|
||||||
-> ty::Generics
|
-> ty::Generics {
|
||||||
{
|
let mut generics = ty_generics(ccx,
|
||||||
let mut generics = ty_generics(ccx, subst::TypeSpace, &generics.lifetimes,
|
subst::TypeSpace,
|
||||||
&generics.ty_params, ty::Generics::empty());
|
&generics.lifetimes,
|
||||||
|
&generics.ty_params,
|
||||||
|
ty::Generics::empty(),
|
||||||
|
&generics.where_clause);
|
||||||
|
|
||||||
// Something of a hack: use the node id for the trait, also as
|
// Something of a hack: use the node id for the trait, also as
|
||||||
// the node id for the Self type parameter.
|
// 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,
|
fn ty_generics_for_fn_or_method(ccx: &CrateCtxt,
|
||||||
generics: &ast::Generics,
|
generics: &ast::Generics,
|
||||||
base_generics: ty::Generics)
|
base_generics: ty::Generics)
|
||||||
-> ty::Generics
|
-> ty::Generics {
|
||||||
{
|
|
||||||
let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics);
|
let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics);
|
||||||
ty_generics(ccx, subst::FnSpace, &early_lifetimes,
|
ty_generics(ccx,
|
||||||
&generics.ty_params, base_generics)
|
subst::FnSpace,
|
||||||
|
&early_lifetimes,
|
||||||
|
&generics.ty_params,
|
||||||
|
base_generics,
|
||||||
|
&generics.where_clause)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the Sized bound, unless the type parameter is marked as `Sized?`.
|
// Add the Sized bound, unless the type parameter is marked as `Sized?`.
|
||||||
|
@ -1080,9 +1089,9 @@ fn ty_generics(ccx: &CrateCtxt,
|
||||||
space: subst::ParamSpace,
|
space: subst::ParamSpace,
|
||||||
lifetimes: &Vec<ast::LifetimeDef>,
|
lifetimes: &Vec<ast::LifetimeDef>,
|
||||||
types: &OwnedSlice<ast::TyParam>,
|
types: &OwnedSlice<ast::TyParam>,
|
||||||
base_generics: ty::Generics)
|
base_generics: ty::Generics,
|
||||||
-> ty::Generics
|
where_clause: &ast::WhereClause)
|
||||||
{
|
-> ty::Generics {
|
||||||
let mut result = base_generics;
|
let mut result = base_generics;
|
||||||
|
|
||||||
for (i, l) in lifetimes.iter().enumerate() {
|
for (i, l) in lifetimes.iter().enumerate() {
|
||||||
|
@ -1095,7 +1104,11 @@ fn ty_generics(ccx: &CrateCtxt,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i, param) in types.iter().enumerate() {
|
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));
|
debug!("ty_generics: def for type param: {}", def.repr(ccx.tcx));
|
||||||
result.types.push(space, def);
|
result.types.push(space, def);
|
||||||
}
|
}
|
||||||
|
@ -1105,9 +1118,9 @@ fn ty_generics(ccx: &CrateCtxt,
|
||||||
fn get_or_create_type_parameter_def(ccx: &CrateCtxt,
|
fn get_or_create_type_parameter_def(ccx: &CrateCtxt,
|
||||||
space: subst::ParamSpace,
|
space: subst::ParamSpace,
|
||||||
param: &ast::TyParam,
|
param: &ast::TyParam,
|
||||||
index: uint)
|
index: uint,
|
||||||
-> ty::TypeParameterDef
|
where_clause: &ast::WhereClause)
|
||||||
{
|
-> ty::TypeParameterDef {
|
||||||
match ccx.tcx.ty_param_defs.borrow().find(¶m.id) {
|
match ccx.tcx.ty_param_defs.borrow().find(¶m.id) {
|
||||||
Some(d) => { return (*d).clone(); }
|
Some(d) => { return (*d).clone(); }
|
||||||
None => { }
|
None => { }
|
||||||
|
@ -1121,7 +1134,8 @@ fn ty_generics(ccx: &CrateCtxt,
|
||||||
¶m.bounds,
|
¶m.bounds,
|
||||||
¶m.unbound,
|
¶m.unbound,
|
||||||
param.ident,
|
param.ident,
|
||||||
param.span));
|
param.span,
|
||||||
|
where_clause));
|
||||||
let default = param.default.map(|path| {
|
let default = param.default.map(|path| {
|
||||||
let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &*path);
|
let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &*path);
|
||||||
let cur_idx = param_ty.idx;
|
let cur_idx = param_ty.idx;
|
||||||
|
@ -1154,14 +1168,14 @@ fn ty_generics(ccx: &CrateCtxt,
|
||||||
def
|
def
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_bounds(
|
fn compute_bounds(ccx: &CrateCtxt,
|
||||||
ccx: &CrateCtxt,
|
param_ty: ty::ParamTy,
|
||||||
param_ty: ty::ParamTy,
|
ast_bounds: &OwnedSlice<ast::TyParamBound>,
|
||||||
ast_bounds: &OwnedSlice<ast::TyParamBound>,
|
unbound: &Option<ast::TyParamBound>,
|
||||||
unbound: &Option<ast::TyParamBound>,
|
ident: ast::Ident,
|
||||||
ident: ast::Ident,
|
span: Span,
|
||||||
span: Span) -> ty::ParamBounds
|
where_clause: &ast::WhereClause)
|
||||||
{
|
-> ty::ParamBounds {
|
||||||
/*!
|
/*!
|
||||||
* Translate the AST's notion of ty param bounds (which are an
|
* Translate the AST's notion of ty param bounds (which are an
|
||||||
* enum consisting of a newtyped Ty or a region) to ty's
|
* enum consisting of a newtyped Ty or a region) to ty's
|
||||||
|
@ -1174,44 +1188,23 @@ fn ty_generics(ccx: &CrateCtxt,
|
||||||
trait_bounds: Vec::new()
|
trait_bounds: Vec::new()
|
||||||
};
|
};
|
||||||
for ast_bound in ast_bounds.iter() {
|
for ast_bound in ast_bounds.iter() {
|
||||||
match *ast_bound {
|
compute_bound(ccx, &mut param_bounds, param_ty, ast_bound);
|
||||||
TraitTyParamBound(ref b) => {
|
}
|
||||||
let ty = ty::mk_param(ccx.tcx, param_ty.space,
|
for predicate in where_clause.predicates.iter() {
|
||||||
param_ty.idx, param_ty.def_id);
|
let predicate_param_id = ccx.tcx
|
||||||
let trait_ref = instantiate_trait_ref(ccx, b, ty);
|
.def_map
|
||||||
if !ty::try_add_builtin_trait(
|
.borrow()
|
||||||
ccx.tcx, trait_ref.def_id,
|
.find(&predicate.id)
|
||||||
&mut param_bounds.builtin_bounds) {
|
.expect("compute_bounds(): resolve \
|
||||||
// Must be a user-defined trait
|
didn't resolve the type \
|
||||||
param_bounds.trait_bounds.push(trait_ref);
|
parameter identifier in a \
|
||||||
}
|
`where` clause")
|
||||||
}
|
.def_id();
|
||||||
|
if param_ty.def_id != predicate_param_id {
|
||||||
StaticRegionTyParamBound => {
|
continue
|
||||||
param_bounds.builtin_bounds.add(ty::BoundStatic);
|
}
|
||||||
}
|
for bound in predicate.bounds.iter() {
|
||||||
|
compute_bound(ccx, &mut param_bounds, param_ty, bound);
|
||||||
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.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1228,6 +1221,54 @@ fn ty_generics(ccx: &CrateCtxt,
|
||||||
param_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,
|
fn check_bounds_compatible(tcx: &ty::ctxt,
|
||||||
param_bounds: &ty::ParamBounds,
|
param_bounds: &ty::ParamBounds,
|
||||||
ident: ast::Ident,
|
ident: ast::Ident,
|
||||||
|
|
|
@ -781,6 +781,7 @@ impl<'a> Rebuilder<'a> {
|
||||||
let mut inputs = self.fn_decl.inputs.clone();
|
let mut inputs = self.fn_decl.inputs.clone();
|
||||||
let mut output = self.fn_decl.output;
|
let mut output = self.fn_decl.output;
|
||||||
let mut ty_params = self.generics.ty_params.clone();
|
let mut ty_params = self.generics.ty_params.clone();
|
||||||
|
let where_clause = self.generics.where_clause.clone();
|
||||||
let mut kept_lifetimes = HashSet::new();
|
let mut kept_lifetimes = HashSet::new();
|
||||||
for sr in self.same_regions.iter() {
|
for sr in self.same_regions.iter() {
|
||||||
self.cur_anon.set(0);
|
self.cur_anon.set(0);
|
||||||
|
@ -807,7 +808,8 @@ impl<'a> Rebuilder<'a> {
|
||||||
&fresh_lifetimes,
|
&fresh_lifetimes,
|
||||||
&kept_lifetimes,
|
&kept_lifetimes,
|
||||||
&all_region_names,
|
&all_region_names,
|
||||||
ty_params);
|
ty_params,
|
||||||
|
where_clause);
|
||||||
let new_fn_decl = ast::FnDecl {
|
let new_fn_decl = ast::FnDecl {
|
||||||
inputs: inputs,
|
inputs: inputs,
|
||||||
output: output,
|
output: output,
|
||||||
|
@ -981,7 +983,8 @@ impl<'a> Rebuilder<'a> {
|
||||||
add: &Vec<ast::Lifetime>,
|
add: &Vec<ast::Lifetime>,
|
||||||
keep: &HashSet<ast::Name>,
|
keep: &HashSet<ast::Name>,
|
||||||
remove: &HashSet<ast::Name>,
|
remove: &HashSet<ast::Name>,
|
||||||
ty_params: OwnedSlice<ast::TyParam>)
|
ty_params: OwnedSlice<ast::TyParam>,
|
||||||
|
where_clause: ast::WhereClause)
|
||||||
-> ast::Generics {
|
-> ast::Generics {
|
||||||
let mut lifetimes = Vec::new();
|
let mut lifetimes = Vec::new();
|
||||||
for lt in add.iter() {
|
for lt in add.iter() {
|
||||||
|
@ -990,14 +993,14 @@ impl<'a> Rebuilder<'a> {
|
||||||
}
|
}
|
||||||
for lt in generics.lifetimes.iter() {
|
for lt in generics.lifetimes.iter() {
|
||||||
if keep.contains(<.lifetime.name) ||
|
if keep.contains(<.lifetime.name) ||
|
||||||
!remove.contains(<.lifetime.name)
|
!remove.contains(<.lifetime.name) {
|
||||||
{
|
|
||||||
lifetimes.push((*lt).clone());
|
lifetimes.push((*lt).clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::Generics {
|
ast::Generics {
|
||||||
lifetimes: lifetimes,
|
lifetimes: lifetimes,
|
||||||
ty_params: ty_params
|
ty_params: ty_params,
|
||||||
|
where_clause: where_clause,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -363,7 +363,7 @@ impl Clean<Item> for doctree::Module {
|
||||||
|
|
||||||
// determine if we should display the inner contents or
|
// determine if we should display the inner contents or
|
||||||
// the outer `mod` item for the source code.
|
// the outer `mod` item for the source code.
|
||||||
let where = {
|
let whence = {
|
||||||
let ctxt = super::ctxtkey.get().unwrap();
|
let ctxt = super::ctxtkey.get().unwrap();
|
||||||
let cm = ctxt.sess().codemap();
|
let cm = ctxt.sess().codemap();
|
||||||
let outer = cm.lookup_char_pos(self.where_outer.lo);
|
let outer = cm.lookup_char_pos(self.where_outer.lo);
|
||||||
|
@ -380,7 +380,7 @@ impl Clean<Item> for doctree::Module {
|
||||||
Item {
|
Item {
|
||||||
name: Some(name),
|
name: Some(name),
|
||||||
attrs: self.attrs.clean(),
|
attrs: self.attrs.clean(),
|
||||||
source: where.clean(),
|
source: whence.clean(),
|
||||||
visibility: self.vis.clean(),
|
visibility: self.vis.clean(),
|
||||||
stability: self.stab.clean(),
|
stability: self.stab.clean(),
|
||||||
def_id: ast_util::local_def(self.id),
|
def_id: ast_util::local_def(self.id),
|
||||||
|
@ -781,7 +781,7 @@ impl Clean<Item> for doctree::Function {
|
||||||
Item {
|
Item {
|
||||||
name: Some(self.name.clean()),
|
name: Some(self.name.clean()),
|
||||||
attrs: self.attrs.clean(),
|
attrs: self.attrs.clean(),
|
||||||
source: self.where.clean(),
|
source: self.whence.clean(),
|
||||||
visibility: self.vis.clean(),
|
visibility: self.vis.clean(),
|
||||||
stability: self.stab.clean(),
|
stability: self.stab.clean(),
|
||||||
def_id: ast_util::local_def(self.id),
|
def_id: ast_util::local_def(self.id),
|
||||||
|
@ -917,7 +917,7 @@ impl Clean<Item> for doctree::Trait {
|
||||||
Item {
|
Item {
|
||||||
name: Some(self.name.clean()),
|
name: Some(self.name.clean()),
|
||||||
attrs: self.attrs.clean(),
|
attrs: self.attrs.clean(),
|
||||||
source: self.where.clean(),
|
source: self.whence.clean(),
|
||||||
def_id: ast_util::local_def(self.id),
|
def_id: ast_util::local_def(self.id),
|
||||||
visibility: self.vis.clean(),
|
visibility: self.vis.clean(),
|
||||||
stability: self.stab.clean(),
|
stability: self.stab.clean(),
|
||||||
|
@ -1397,7 +1397,7 @@ impl Clean<Item> for doctree::Struct {
|
||||||
Item {
|
Item {
|
||||||
name: Some(self.name.clean()),
|
name: Some(self.name.clean()),
|
||||||
attrs: self.attrs.clean(),
|
attrs: self.attrs.clean(),
|
||||||
source: self.where.clean(),
|
source: self.whence.clean(),
|
||||||
def_id: ast_util::local_def(self.id),
|
def_id: ast_util::local_def(self.id),
|
||||||
visibility: self.vis.clean(),
|
visibility: self.vis.clean(),
|
||||||
stability: self.stab.clean(),
|
stability: self.stab.clean(),
|
||||||
|
@ -1443,7 +1443,7 @@ impl Clean<Item> for doctree::Enum {
|
||||||
Item {
|
Item {
|
||||||
name: Some(self.name.clean()),
|
name: Some(self.name.clean()),
|
||||||
attrs: self.attrs.clean(),
|
attrs: self.attrs.clean(),
|
||||||
source: self.where.clean(),
|
source: self.whence.clean(),
|
||||||
def_id: ast_util::local_def(self.id),
|
def_id: ast_util::local_def(self.id),
|
||||||
visibility: self.vis.clean(),
|
visibility: self.vis.clean(),
|
||||||
stability: self.stab.clean(),
|
stability: self.stab.clean(),
|
||||||
|
@ -1466,7 +1466,7 @@ impl Clean<Item> for doctree::Variant {
|
||||||
Item {
|
Item {
|
||||||
name: Some(self.name.clean()),
|
name: Some(self.name.clean()),
|
||||||
attrs: self.attrs.clean(),
|
attrs: self.attrs.clean(),
|
||||||
source: self.where.clean(),
|
source: self.whence.clean(),
|
||||||
visibility: self.vis.clean(),
|
visibility: self.vis.clean(),
|
||||||
stability: self.stab.clean(),
|
stability: self.stab.clean(),
|
||||||
def_id: ast_util::local_def(self.id),
|
def_id: ast_util::local_def(self.id),
|
||||||
|
@ -1652,7 +1652,7 @@ impl Clean<Item> for doctree::Typedef {
|
||||||
Item {
|
Item {
|
||||||
name: Some(self.name.clean()),
|
name: Some(self.name.clean()),
|
||||||
attrs: self.attrs.clean(),
|
attrs: self.attrs.clean(),
|
||||||
source: self.where.clean(),
|
source: self.whence.clean(),
|
||||||
def_id: ast_util::local_def(self.id.clone()),
|
def_id: ast_util::local_def(self.id.clone()),
|
||||||
visibility: self.vis.clean(),
|
visibility: self.vis.clean(),
|
||||||
stability: self.stab.clean(),
|
stability: self.stab.clean(),
|
||||||
|
@ -1702,7 +1702,7 @@ impl Clean<Item> for doctree::Static {
|
||||||
Item {
|
Item {
|
||||||
name: Some(self.name.clean()),
|
name: Some(self.name.clean()),
|
||||||
attrs: self.attrs.clean(),
|
attrs: self.attrs.clean(),
|
||||||
source: self.where.clean(),
|
source: self.whence.clean(),
|
||||||
def_id: ast_util::local_def(self.id),
|
def_id: ast_util::local_def(self.id),
|
||||||
visibility: self.vis.clean(),
|
visibility: self.vis.clean(),
|
||||||
stability: self.stab.clean(),
|
stability: self.stab.clean(),
|
||||||
|
@ -1748,7 +1748,7 @@ impl Clean<Item> for doctree::Impl {
|
||||||
Item {
|
Item {
|
||||||
name: None,
|
name: None,
|
||||||
attrs: self.attrs.clean(),
|
attrs: self.attrs.clean(),
|
||||||
source: self.where.clean(),
|
source: self.whence.clean(),
|
||||||
def_id: ast_util::local_def(self.id),
|
def_id: ast_util::local_def(self.id),
|
||||||
visibility: self.vis.clean(),
|
visibility: self.vis.clean(),
|
||||||
stability: self.stab.clean(),
|
stability: self.stab.clean(),
|
||||||
|
@ -2115,12 +2115,12 @@ impl Clean<Item> for doctree::Macro {
|
||||||
Item {
|
Item {
|
||||||
name: Some(format!("{}!", self.name.clean())),
|
name: Some(format!("{}!", self.name.clean())),
|
||||||
attrs: self.attrs.clean(),
|
attrs: self.attrs.clean(),
|
||||||
source: self.where.clean(),
|
source: self.whence.clean(),
|
||||||
visibility: ast::Public.clean(),
|
visibility: ast::Public.clean(),
|
||||||
stability: self.stab.clean(),
|
stability: self.stab.clean(),
|
||||||
def_id: ast_util::local_def(self.id),
|
def_id: ast_util::local_def(self.id),
|
||||||
inner: MacroItem(Macro {
|
inner: MacroItem(Macro {
|
||||||
source: self.where.to_src(),
|
source: self.whence.to_src(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,7 @@ pub struct Struct {
|
||||||
pub generics: ast::Generics,
|
pub generics: ast::Generics,
|
||||||
pub attrs: Vec<ast::Attribute>,
|
pub attrs: Vec<ast::Attribute>,
|
||||||
pub fields: Vec<ast::StructField>,
|
pub fields: Vec<ast::StructField>,
|
||||||
pub where: Span,
|
pub whence: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Enum {
|
pub struct Enum {
|
||||||
|
@ -103,7 +103,7 @@ pub struct Enum {
|
||||||
pub generics: ast::Generics,
|
pub generics: ast::Generics,
|
||||||
pub attrs: Vec<ast::Attribute>,
|
pub attrs: Vec<ast::Attribute>,
|
||||||
pub id: NodeId,
|
pub id: NodeId,
|
||||||
pub where: Span,
|
pub whence: Span,
|
||||||
pub name: Ident,
|
pub name: Ident,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ pub struct Variant {
|
||||||
pub id: ast::NodeId,
|
pub id: ast::NodeId,
|
||||||
pub vis: ast::Visibility,
|
pub vis: ast::Visibility,
|
||||||
pub stab: Option<attr::Stability>,
|
pub stab: Option<attr::Stability>,
|
||||||
pub where: Span,
|
pub whence: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
|
@ -125,7 +125,7 @@ pub struct Function {
|
||||||
pub vis: ast::Visibility,
|
pub vis: ast::Visibility,
|
||||||
pub stab: Option<attr::Stability>,
|
pub stab: Option<attr::Stability>,
|
||||||
pub fn_style: ast::FnStyle,
|
pub fn_style: ast::FnStyle,
|
||||||
pub where: Span,
|
pub whence: Span,
|
||||||
pub generics: ast::Generics,
|
pub generics: ast::Generics,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ pub struct Typedef {
|
||||||
pub name: Ident,
|
pub name: Ident,
|
||||||
pub id: ast::NodeId,
|
pub id: ast::NodeId,
|
||||||
pub attrs: Vec<ast::Attribute>,
|
pub attrs: Vec<ast::Attribute>,
|
||||||
pub where: Span,
|
pub whence: Span,
|
||||||
pub vis: ast::Visibility,
|
pub vis: ast::Visibility,
|
||||||
pub stab: Option<attr::Stability>,
|
pub stab: Option<attr::Stability>,
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,7 @@ pub struct Static {
|
||||||
pub vis: ast::Visibility,
|
pub vis: ast::Visibility,
|
||||||
pub stab: Option<attr::Stability>,
|
pub stab: Option<attr::Stability>,
|
||||||
pub id: ast::NodeId,
|
pub id: ast::NodeId,
|
||||||
pub where: Span,
|
pub whence: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Trait {
|
pub struct Trait {
|
||||||
|
@ -159,7 +159,7 @@ pub struct Trait {
|
||||||
pub parents: Vec<ast::TraitRef>,
|
pub parents: Vec<ast::TraitRef>,
|
||||||
pub attrs: Vec<ast::Attribute>,
|
pub attrs: Vec<ast::Attribute>,
|
||||||
pub id: ast::NodeId,
|
pub id: ast::NodeId,
|
||||||
pub where: Span,
|
pub whence: Span,
|
||||||
pub vis: ast::Visibility,
|
pub vis: ast::Visibility,
|
||||||
pub stab: Option<attr::Stability>,
|
pub stab: Option<attr::Stability>,
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ pub struct Impl {
|
||||||
pub for_: ast::P<ast::Ty>,
|
pub for_: ast::P<ast::Ty>,
|
||||||
pub items: Vec<ast::ImplItem>,
|
pub items: Vec<ast::ImplItem>,
|
||||||
pub attrs: Vec<ast::Attribute>,
|
pub attrs: Vec<ast::Attribute>,
|
||||||
pub where: Span,
|
pub whence: Span,
|
||||||
pub vis: ast::Visibility,
|
pub vis: ast::Visibility,
|
||||||
pub stab: Option<attr::Stability>,
|
pub stab: Option<attr::Stability>,
|
||||||
pub id: ast::NodeId,
|
pub id: ast::NodeId,
|
||||||
|
@ -180,7 +180,7 @@ pub struct Macro {
|
||||||
pub name: Ident,
|
pub name: Ident,
|
||||||
pub id: ast::NodeId,
|
pub id: ast::NodeId,
|
||||||
pub attrs: Vec<ast::Attribute>,
|
pub attrs: Vec<ast::Attribute>,
|
||||||
pub where: Span,
|
pub whence: Span,
|
||||||
pub stab: Option<attr::Stability>,
|
pub stab: Option<attr::Stability>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ impl<'a> RustdocVisitor<'a> {
|
||||||
attrs: item.attrs.iter().map(|x| *x).collect(),
|
attrs: item.attrs.iter().map(|x| *x).collect(),
|
||||||
generics: generics.clone(),
|
generics: generics.clone(),
|
||||||
fields: sd.fields.iter().map(|x| (*x).clone()).collect(),
|
fields: sd.fields.iter().map(|x| (*x).clone()).collect(),
|
||||||
where: item.span
|
whence: item.span
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ impl<'a> RustdocVisitor<'a> {
|
||||||
stab: self.stability(x.node.id),
|
stab: self.stability(x.node.id),
|
||||||
id: x.node.id,
|
id: x.node.id,
|
||||||
kind: x.node.kind.clone(),
|
kind: x.node.kind.clone(),
|
||||||
where: x.span,
|
whence: x.span,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Enum {
|
Enum {
|
||||||
|
@ -118,7 +118,7 @@ impl<'a> RustdocVisitor<'a> {
|
||||||
generics: params.clone(),
|
generics: params.clone(),
|
||||||
attrs: it.attrs.iter().map(|x| *x).collect(),
|
attrs: it.attrs.iter().map(|x| *x).collect(),
|
||||||
id: it.id,
|
id: it.id,
|
||||||
where: it.span,
|
whence: it.span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ impl<'a> RustdocVisitor<'a> {
|
||||||
attrs: item.attrs.iter().map(|x| *x).collect(),
|
attrs: item.attrs.iter().map(|x| *x).collect(),
|
||||||
decl: fd.clone(),
|
decl: fd.clone(),
|
||||||
name: item.ident,
|
name: item.ident,
|
||||||
where: item.span,
|
whence: item.span,
|
||||||
generics: gen.clone(),
|
generics: gen.clone(),
|
||||||
fn_style: *fn_style,
|
fn_style: *fn_style,
|
||||||
}
|
}
|
||||||
|
@ -297,7 +297,7 @@ impl<'a> RustdocVisitor<'a> {
|
||||||
name: item.ident,
|
name: item.ident,
|
||||||
id: item.id,
|
id: item.id,
|
||||||
attrs: item.attrs.iter().map(|x| *x).collect(),
|
attrs: item.attrs.iter().map(|x| *x).collect(),
|
||||||
where: item.span,
|
whence: item.span,
|
||||||
vis: item.vis,
|
vis: item.vis,
|
||||||
stab: self.stability(item.id),
|
stab: self.stability(item.id),
|
||||||
};
|
};
|
||||||
|
@ -311,7 +311,7 @@ impl<'a> RustdocVisitor<'a> {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
name: item.ident,
|
name: item.ident,
|
||||||
attrs: item.attrs.iter().map(|x| *x).collect(),
|
attrs: item.attrs.iter().map(|x| *x).collect(),
|
||||||
where: item.span,
|
whence: item.span,
|
||||||
vis: item.vis,
|
vis: item.vis,
|
||||||
stab: self.stability(item.id),
|
stab: self.stability(item.id),
|
||||||
};
|
};
|
||||||
|
@ -325,7 +325,7 @@ impl<'a> RustdocVisitor<'a> {
|
||||||
parents: tr.iter().map(|x| (*x).clone()).collect(),
|
parents: tr.iter().map(|x| (*x).clone()).collect(),
|
||||||
id: item.id,
|
id: item.id,
|
||||||
attrs: item.attrs.iter().map(|x| *x).collect(),
|
attrs: item.attrs.iter().map(|x| *x).collect(),
|
||||||
where: item.span,
|
whence: item.span,
|
||||||
vis: item.vis,
|
vis: item.vis,
|
||||||
stab: self.stability(item.id),
|
stab: self.stability(item.id),
|
||||||
};
|
};
|
||||||
|
@ -339,7 +339,7 @@ impl<'a> RustdocVisitor<'a> {
|
||||||
items: items.iter().map(|x| *x).collect(),
|
items: items.iter().map(|x| *x).collect(),
|
||||||
attrs: item.attrs.iter().map(|x| *x).collect(),
|
attrs: item.attrs.iter().map(|x| *x).collect(),
|
||||||
id: item.id,
|
id: item.id,
|
||||||
where: item.span,
|
whence: item.span,
|
||||||
vis: item.vis,
|
vis: item.vis,
|
||||||
stab: self.stability(item.id),
|
stab: self.stability(item.id),
|
||||||
};
|
};
|
||||||
|
@ -360,7 +360,7 @@ impl<'a> RustdocVisitor<'a> {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
attrs: item.attrs.iter().map(|x| *x).collect(),
|
attrs: item.attrs.iter().map(|x| *x).collect(),
|
||||||
name: item.ident,
|
name: item.ident,
|
||||||
where: item.span,
|
whence: item.span,
|
||||||
stab: self.stability(item.id),
|
stab: self.stability(item.id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,6 +245,7 @@ pub struct TyParam {
|
||||||
pub struct Generics {
|
pub struct Generics {
|
||||||
pub lifetimes: Vec<LifetimeDef>,
|
pub lifetimes: Vec<LifetimeDef>,
|
||||||
pub ty_params: OwnedSlice<TyParam>,
|
pub ty_params: OwnedSlice<TyParam>,
|
||||||
|
pub where_clause: WhereClause,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Generics {
|
impl Generics {
|
||||||
|
@ -259,9 +260,23 @@ impl Generics {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
|
||||||
|
pub struct WhereClause {
|
||||||
|
pub id: NodeId,
|
||||||
|
pub predicates: Vec<WherePredicate>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
|
||||||
|
pub struct WherePredicate {
|
||||||
|
pub id: NodeId,
|
||||||
|
pub span: Span,
|
||||||
|
pub ident: Ident,
|
||||||
|
pub bounds: OwnedSlice<TyParamBound>,
|
||||||
|
}
|
||||||
|
|
||||||
/// The set of MetaItems that define the compilation environment of the crate,
|
/// The set of MetaItems that define the compilation environment of the crate,
|
||||||
/// used to drive conditional compilation
|
/// used to drive conditional compilation
|
||||||
pub type CrateConfig = Vec<Gc<MetaItem>> ;
|
pub type CrateConfig = Vec<Gc<MetaItem>>;
|
||||||
|
|
||||||
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
|
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
|
||||||
pub struct Crate {
|
pub struct Crate {
|
||||||
|
|
|
@ -431,11 +431,14 @@ impl Map {
|
||||||
/// the iterator will produce node id's for items with paths
|
/// the iterator will produce node id's for items with paths
|
||||||
/// such as `foo::bar::quux`, `bar::quux`, `other::bar::quux`, and
|
/// such as `foo::bar::quux`, `bar::quux`, `other::bar::quux`, and
|
||||||
/// any other such items it can find in the map.
|
/// 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> {
|
pub fn nodes_matching_suffix<'a, S:Str>(&'a self, parts: &'a [S])
|
||||||
NodesMatchingSuffix { map: self,
|
-> NodesMatchingSuffix<'a,S> {
|
||||||
item_name: parts.last().unwrap(),
|
NodesMatchingSuffix {
|
||||||
where: parts.slice_to(parts.len() - 1),
|
map: self,
|
||||||
idx: 0 }
|
item_name: parts.last().unwrap(),
|
||||||
|
in_which: parts.slice_to(parts.len() - 1),
|
||||||
|
idx: 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn opt_span(&self, id: NodeId) -> Option<Span> {
|
pub fn opt_span(&self, id: NodeId) -> Option<Span> {
|
||||||
|
@ -478,20 +481,20 @@ impl Map {
|
||||||
pub struct NodesMatchingSuffix<'a, S> {
|
pub struct NodesMatchingSuffix<'a, S> {
|
||||||
map: &'a Map,
|
map: &'a Map,
|
||||||
item_name: &'a S,
|
item_name: &'a S,
|
||||||
where: &'a [S],
|
in_which: &'a [S],
|
||||||
idx: NodeId,
|
idx: NodeId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a,S:Str> NodesMatchingSuffix<'a,S> {
|
impl<'a,S:Str> NodesMatchingSuffix<'a,S> {
|
||||||
/// Returns true only if some suffix of the module path for parent
|
/// 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
|
/// returns true if parent's path ends with the suffix
|
||||||
/// `x_0::x_1::...::x_k`.
|
/// `x_0::x_1::...::x_k`.
|
||||||
fn suffix_matches(&self, parent: NodeId) -> bool {
|
fn suffix_matches(&self, parent: NodeId) -> bool {
|
||||||
let mut cursor = parent;
|
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) {
|
let (mod_id, mod_name) = match find_first_mod_parent(self.map, cursor) {
|
||||||
None => return false,
|
None => return false,
|
||||||
Some((node_id, name)) => (node_id, name),
|
Some((node_id, name)) => (node_id, name),
|
||||||
|
|
|
@ -320,8 +320,14 @@ pub fn operator_prec(op: ast::BinOp) -> uint {
|
||||||
pub static as_prec: uint = 12u;
|
pub static as_prec: uint = 12u;
|
||||||
|
|
||||||
pub fn empty_generics() -> Generics {
|
pub fn empty_generics() -> Generics {
|
||||||
Generics {lifetimes: Vec::new(),
|
Generics {
|
||||||
ty_params: OwnedSlice::empty()}
|
lifetimes: Vec::new(),
|
||||||
|
ty_params: OwnedSlice::empty(),
|
||||||
|
where_clause: WhereClause {
|
||||||
|
id: DUMMY_NODE_ID,
|
||||||
|
predicates: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ______________________________________________________________________
|
// ______________________________________________________________________
|
||||||
|
|
|
@ -390,7 +390,7 @@ impl<'a> TraitDef<'a> {
|
||||||
methods: Vec<Gc<ast::Method>> ) -> Gc<ast::Item> {
|
methods: Vec<Gc<ast::Method>> ) -> Gc<ast::Item> {
|
||||||
let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
|
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);
|
self.generics.to_generics(cx, self.span, type_ident, generics);
|
||||||
let mut ty_params = ty_params.into_vec();
|
let mut ty_params = ty_params.into_vec();
|
||||||
|
|
||||||
|
@ -418,7 +418,11 @@ impl<'a> TraitDef<'a> {
|
||||||
}));
|
}));
|
||||||
let trait_generics = Generics {
|
let trait_generics = Generics {
|
||||||
lifetimes: lifetimes,
|
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.
|
// Create the reference to the trait.
|
||||||
|
|
|
@ -202,10 +202,15 @@ fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str,
|
||||||
cx.typaram(span, cx.ident_of(name), bounds, unbound, None)
|
cx.typaram(span, cx.ident_of(name), bounds, unbound, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam> ) -> Generics {
|
fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>)
|
||||||
|
-> Generics {
|
||||||
Generics {
|
Generics {
|
||||||
lifetimes: lifetimes,
|
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(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -244,6 +244,16 @@ pub trait Folder {
|
||||||
noop_fold_field(field, self)
|
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:
|
// Helper methods:
|
||||||
|
|
||||||
fn map_exprs(&self, f: |Gc<Expr>| -> Gc<Expr>,
|
fn map_exprs(&self, f: |Gc<Expr>| -> Gc<Expr>,
|
||||||
|
@ -698,8 +708,37 @@ pub fn noop_fold_opt_lifetime<T: Folder>(o_lt: &Option<Lifetime>, fld: &mut T)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn noop_fold_generics<T: Folder>(generics: &Generics, fld: &mut T) -> Generics {
|
pub fn noop_fold_generics<T: Folder>(generics: &Generics, fld: &mut T) -> Generics {
|
||||||
Generics {ty_params: fld.fold_ty_params(generics.ty_params.as_slice()),
|
Generics {
|
||||||
lifetimes: fld.fold_lifetime_defs(generics.lifetimes.as_slice())}
|
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<T: Folder>(
|
||||||
|
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<T: Folder>(
|
||||||
|
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<T: Folder>(struct_def: Gc<StructDef>,
|
pub fn noop_fold_struct_def<T: Folder>(struct_def: Gc<StructDef>,
|
||||||
|
|
|
@ -543,7 +543,7 @@ impl<'a> StringReader<'a> {
|
||||||
// favors rustc debugging effectiveness over runtime efficiency.
|
// favors rustc debugging effectiveness over runtime efficiency.
|
||||||
|
|
||||||
/// Scan through input of form \x00name_NNNNNN,ctxt_CCCCCCC\x00
|
/// 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
|
/// (the name) and `CCCCCCC` is a string of characters forming an
|
||||||
/// integer (the ctxt), separate by a comma and delimited by a
|
/// integer (the ctxt), separate by a comma and delimited by a
|
||||||
/// `\x00` marker.
|
/// `\x00` marker.
|
||||||
|
@ -552,22 +552,22 @@ impl<'a> StringReader<'a> {
|
||||||
fn bump_expecting_char<'a,D:fmt::Show>(r: &mut StringReader<'a>,
|
fn bump_expecting_char<'a,D:fmt::Show>(r: &mut StringReader<'a>,
|
||||||
c: char,
|
c: char,
|
||||||
described_c: D,
|
described_c: D,
|
||||||
where: &str) {
|
whence: &str) {
|
||||||
match r.curr {
|
match r.curr {
|
||||||
Some(r_c) if r_c == c => r.bump(),
|
Some(r_c) if r_c == c => r.bump(),
|
||||||
Some(r_c) => fail!("expected {}, hit {}, {}", described_c, r_c, where),
|
Some(r_c) => fail!("expected {}, hit {}, {}", described_c, r_c, whence),
|
||||||
None => fail!("expected {}, hit EOF, {}", described_c, where),
|
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`
|
// 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_"
|
// skip over the "name_"
|
||||||
for c in "name_".chars() {
|
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;
|
let start_bpos = self.last_pos;
|
||||||
|
@ -578,16 +578,16 @@ impl<'a> StringReader<'a> {
|
||||||
let encoded_name : u32 = self.with_str_from(start_bpos, |s| {
|
let encoded_name : u32 = self.with_str_from(start_bpos, |s| {
|
||||||
num::from_str_radix(s, 10).unwrap_or_else(|| {
|
num::from_str_radix(s, 10).unwrap_or_else(|| {
|
||||||
fail!("expected digits representing a name, got `{}`, {}, range [{},{}]",
|
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 `,`
|
// skip over the `,`
|
||||||
bump_expecting_char(self, ',', "comma", where);
|
bump_expecting_char(self, ',', "comma", whence);
|
||||||
|
|
||||||
// skip over the "ctxt_"
|
// skip over the "ctxt_"
|
||||||
for c in "ctxt_".chars() {
|
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
|
// find the integer representing the ctxt
|
||||||
|
@ -595,12 +595,12 @@ impl<'a> StringReader<'a> {
|
||||||
self.scan_digits(base);
|
self.scan_digits(base);
|
||||||
let encoded_ctxt : ast::SyntaxContext = self.with_str_from(start_bpos, |s| {
|
let encoded_ctxt : ast::SyntaxContext = self.with_str_from(start_bpos, |s| {
|
||||||
num::from_str_radix(s, 10).unwrap_or_else(|| {
|
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`
|
// 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),
|
ast::Ident { name: ast::Name(encoded_name),
|
||||||
ctxt: encoded_ctxt, }
|
ctxt: encoded_ctxt, }
|
||||||
|
|
|
@ -1053,6 +1053,10 @@ mod test {
|
||||||
ast::Generics{ // no idea on either of these:
|
ast::Generics{ // no idea on either of these:
|
||||||
lifetimes: Vec::new(),
|
lifetimes: Vec::new(),
|
||||||
ty_params: OwnedSlice::empty(),
|
ty_params: OwnedSlice::empty(),
|
||||||
|
where_clause: ast::WhereClause {
|
||||||
|
id: ast::DUMMY_NODE_ID,
|
||||||
|
predicates: Vec::new(),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ast::P(ast::Block {
|
ast::P(ast::Block {
|
||||||
view_items: Vec::new(),
|
view_items: Vec::new(),
|
||||||
|
|
|
@ -60,7 +60,7 @@ use ast::{UnboxedClosureKind, UnboxedFnTy, UnboxedFnTyParamBound};
|
||||||
use ast::{UnnamedField, UnsafeBlock};
|
use ast::{UnnamedField, UnsafeBlock};
|
||||||
use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse};
|
use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse};
|
||||||
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
|
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
|
||||||
use ast::Visibility;
|
use ast::{Visibility, WhereClause, WherePredicate};
|
||||||
use ast;
|
use ast;
|
||||||
use ast_util::{as_prec, ident_to_path, lit_is_str, operator_prec};
|
use ast_util::{as_prec, ident_to_path, lit_is_str, operator_prec};
|
||||||
use ast_util;
|
use ast_util;
|
||||||
|
@ -1264,7 +1264,7 @@ impl<'a> Parser<'a> {
|
||||||
let style = p.parse_fn_style();
|
let style = p.parse_fn_style();
|
||||||
let ident = p.parse_ident();
|
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| {
|
let (explicit_self, d) = p.parse_fn_decl_with_self(|p| {
|
||||||
// This is somewhat dubious; We don't want to allow argument
|
// This is somewhat dubious; We don't want to allow argument
|
||||||
|
@ -1272,6 +1272,8 @@ impl<'a> Parser<'a> {
|
||||||
p.parse_arg_general(false)
|
p.parse_arg_general(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
p.parse_where_clause(&mut generics);
|
||||||
|
|
||||||
let hi = p.last_span.hi;
|
let hi = p.last_span.hi;
|
||||||
match p.token {
|
match p.token {
|
||||||
token::SEMI => {
|
token::SEMI => {
|
||||||
|
@ -3742,7 +3744,10 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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 ( , )? > )
|
/// matches generics = ( ) | ( < > ) | ( < typaramseq ( , )? > ) | ( < lifetimes ( , )? > )
|
||||||
/// | ( < lifetimes , typaramseq ( , )? > )
|
/// | ( < lifetimes , typaramseq ( , )? > )
|
||||||
/// where typaramseq = ( typaram ) | ( typaram , typaramseq )
|
/// where typaramseq = ( typaram ) | ( typaram , typaramseq )
|
||||||
|
@ -3762,7 +3767,14 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
ty_param
|
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 {
|
} else {
|
||||||
ast_util::empty_generics()
|
ast_util::empty_generics()
|
||||||
}
|
}
|
||||||
|
@ -3788,6 +3800,52 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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)
|
fn parse_fn_args(&mut self, named_args: bool, allow_variadic: bool)
|
||||||
-> (Vec<Arg> , bool) {
|
-> (Vec<Arg> , bool) {
|
||||||
let sp = self.span;
|
let sp = self.span;
|
||||||
|
@ -4143,8 +4201,9 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
/// Parse an item-position function declaration.
|
/// Parse an item-position function declaration.
|
||||||
fn parse_item_fn(&mut self, fn_style: FnStyle, abi: abi::Abi) -> ItemInfo {
|
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);
|
let decl = self.parse_fn_decl(false);
|
||||||
|
self.parse_where_clause(&mut generics);
|
||||||
let (inner_attrs, body) = self.parse_inner_attrs_and_block();
|
let (inner_attrs, body) = self.parse_inner_attrs_and_block();
|
||||||
(ident, ItemFn(decl, fn_style, abi, generics, body), Some(inner_attrs))
|
(ident, ItemFn(decl, fn_style, abi, generics, body), Some(inner_attrs))
|
||||||
}
|
}
|
||||||
|
@ -4200,10 +4259,11 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
let fn_style = self.parse_fn_style();
|
let fn_style = self.parse_fn_style();
|
||||||
let ident = self.parse_ident();
|
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| {
|
let (explicit_self, decl) = self.parse_fn_decl_with_self(|p| {
|
||||||
p.parse_arg()
|
p.parse_arg()
|
||||||
});
|
});
|
||||||
|
self.parse_where_clause(&mut generics);
|
||||||
let (inner_attrs, body) = self.parse_inner_attrs_and_block();
|
let (inner_attrs, body) = self.parse_inner_attrs_and_block();
|
||||||
let new_attrs = attrs.append(inner_attrs.as_slice());
|
let new_attrs = attrs.append(inner_attrs.as_slice());
|
||||||
(ast::MethDecl(ident,
|
(ast::MethDecl(ident,
|
||||||
|
@ -4228,7 +4288,7 @@ impl<'a> Parser<'a> {
|
||||||
/// Parse trait Foo { ... }
|
/// Parse trait Foo { ... }
|
||||||
fn parse_item_trait(&mut self) -> ItemInfo {
|
fn parse_item_trait(&mut self) -> ItemInfo {
|
||||||
let ident = self.parse_ident();
|
let ident = self.parse_ident();
|
||||||
let tps = self.parse_generics();
|
let mut tps = self.parse_generics();
|
||||||
let sized = self.parse_for_sized();
|
let sized = self.parse_for_sized();
|
||||||
|
|
||||||
// Parse traits, if necessary.
|
// Parse traits, if necessary.
|
||||||
|
@ -4240,6 +4300,8 @@ impl<'a> Parser<'a> {
|
||||||
traits = Vec::new();
|
traits = Vec::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.parse_where_clause(&mut tps);
|
||||||
|
|
||||||
let meths = self.parse_trait_methods();
|
let meths = self.parse_trait_methods();
|
||||||
(ident, ItemTrait(tps, sized, traits, meths), None)
|
(ident, ItemTrait(tps, sized, traits, meths), None)
|
||||||
}
|
}
|
||||||
|
@ -4261,7 +4323,7 @@ impl<'a> Parser<'a> {
|
||||||
/// impl<T> ToString for ~[T] { ... }
|
/// impl<T> ToString for ~[T] { ... }
|
||||||
fn parse_item_impl(&mut self) -> ItemInfo {
|
fn parse_item_impl(&mut self) -> ItemInfo {
|
||||||
// First, parse type parameters if necessary.
|
// 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
|
// Special case: if the next identifier that follows is '(', don't
|
||||||
// allow this to be parsed as a trait.
|
// allow this to be parsed as a trait.
|
||||||
|
@ -4297,6 +4359,7 @@ impl<'a> Parser<'a> {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.parse_where_clause(&mut generics);
|
||||||
let (impl_items, attrs) = self.parse_impl_items();
|
let (impl_items, attrs) = self.parse_impl_items();
|
||||||
|
|
||||||
let ident = ast_util::impl_pretty_name(&opt_trait, &*ty);
|
let ident = ast_util::impl_pretty_name(&opt_trait, &*ty);
|
||||||
|
@ -4326,7 +4389,7 @@ impl<'a> Parser<'a> {
|
||||||
/// Parse struct Foo { ... }
|
/// Parse struct Foo { ... }
|
||||||
fn parse_item_struct(&mut self, is_virtual: bool) -> ItemInfo {
|
fn parse_item_struct(&mut self, is_virtual: bool) -> ItemInfo {
|
||||||
let class_name = self.parse_ident();
|
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 super_struct = if self.eat(&token::COLON) {
|
||||||
let ty = self.parse_ty(true);
|
let ty = self.parse_ty(true);
|
||||||
|
@ -4343,6 +4406,8 @@ impl<'a> Parser<'a> {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.parse_where_clause(&mut generics);
|
||||||
|
|
||||||
let mut fields: Vec<StructField>;
|
let mut fields: Vec<StructField>;
|
||||||
let is_tuple_like;
|
let is_tuple_like;
|
||||||
|
|
||||||
|
@ -4683,8 +4748,9 @@ impl<'a> Parser<'a> {
|
||||||
let lo = self.span.lo;
|
let lo = self.span.lo;
|
||||||
self.expect_keyword(keywords::Fn);
|
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);
|
let decl = self.parse_fn_decl(true);
|
||||||
|
self.parse_where_clause(&mut generics);
|
||||||
let hi = self.span.hi;
|
let hi = self.span.hi;
|
||||||
self.expect(&token::SEMI);
|
self.expect(&token::SEMI);
|
||||||
box(GC) ast::ForeignItem { ident: ident,
|
box(GC) ast::ForeignItem { ident: ident,
|
||||||
|
@ -4834,7 +4900,8 @@ impl<'a> Parser<'a> {
|
||||||
/// Parse type Foo = Bar;
|
/// Parse type Foo = Bar;
|
||||||
fn parse_item_type(&mut self) -> ItemInfo {
|
fn parse_item_type(&mut self) -> ItemInfo {
|
||||||
let ident = self.parse_ident();
|
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);
|
self.expect(&token::EQ);
|
||||||
let ty = self.parse_ty(true);
|
let ty = self.parse_ty(true);
|
||||||
self.expect(&token::SEMI);
|
self.expect(&token::SEMI);
|
||||||
|
@ -4925,7 +4992,8 @@ impl<'a> Parser<'a> {
|
||||||
/// Parse an "enum" declaration
|
/// Parse an "enum" declaration
|
||||||
fn parse_item_enum(&mut self) -> ItemInfo {
|
fn parse_item_enum(&mut self) -> ItemInfo {
|
||||||
let id = self.parse_ident();
|
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);
|
self.expect(&token::LBRACE);
|
||||||
|
|
||||||
let enum_definition = self.parse_enum_def(&generics);
|
let enum_definition = self.parse_enum_def(&generics);
|
||||||
|
|
|
@ -499,18 +499,19 @@ declare_special_idents_and_keywords! {
|
||||||
(41, Proc, "proc");
|
(41, Proc, "proc");
|
||||||
(42, Box, "box");
|
(42, Box, "box");
|
||||||
(43, Const, "const");
|
(43, Const, "const");
|
||||||
|
(44, Where, "where");
|
||||||
|
|
||||||
'reserved:
|
'reserved:
|
||||||
(44, Alignof, "alignof");
|
(45, Alignof, "alignof");
|
||||||
(45, Be, "be");
|
(46, Be, "be");
|
||||||
(46, Offsetof, "offsetof");
|
(47, Offsetof, "offsetof");
|
||||||
(47, Priv, "priv");
|
(48, Priv, "priv");
|
||||||
(48, Pure, "pure");
|
(49, Pure, "pure");
|
||||||
(49, Sizeof, "sizeof");
|
(50, Sizeof, "sizeof");
|
||||||
(50, Typeof, "typeof");
|
(51, Typeof, "typeof");
|
||||||
(51, Unsized, "unsized");
|
(52, Unsized, "unsized");
|
||||||
(52, Yield, "yield");
|
(53, Yield, "yield");
|
||||||
(53, Do, "do");
|
(54, Do, "do");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -584,7 +584,11 @@ impl<'a> State<'a> {
|
||||||
ast::TyBareFn(f) => {
|
ast::TyBareFn(f) => {
|
||||||
let generics = ast::Generics {
|
let generics = ast::Generics {
|
||||||
lifetimes: f.lifetimes.clone(),
|
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),
|
try!(self.print_ty_fn(Some(f.abi),
|
||||||
None,
|
None,
|
||||||
|
@ -601,7 +605,11 @@ impl<'a> State<'a> {
|
||||||
ast::TyClosure(f, ref region) => {
|
ast::TyClosure(f, ref region) => {
|
||||||
let generics = ast::Generics {
|
let generics = ast::Generics {
|
||||||
lifetimes: f.lifetimes.clone(),
|
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,
|
try!(self.print_ty_fn(None,
|
||||||
Some('&'),
|
Some('&'),
|
||||||
|
@ -618,7 +626,11 @@ impl<'a> State<'a> {
|
||||||
ast::TyProc(ref f) => {
|
ast::TyProc(ref f) => {
|
||||||
let generics = ast::Generics {
|
let generics = ast::Generics {
|
||||||
lifetimes: f.lifetimes.clone(),
|
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,
|
try!(self.print_ty_fn(None,
|
||||||
Some('~'),
|
Some('~'),
|
||||||
|
@ -765,6 +777,7 @@ impl<'a> State<'a> {
|
||||||
try!(space(&mut self.s));
|
try!(space(&mut self.s));
|
||||||
try!(self.word_space("="));
|
try!(self.word_space("="));
|
||||||
try!(self.print_type(&**ty));
|
try!(self.print_type(&**ty));
|
||||||
|
try!(self.print_where_clause(params));
|
||||||
try!(word(&mut self.s, ";"));
|
try!(word(&mut self.s, ";"));
|
||||||
try!(self.end()); // end the outer ibox
|
try!(self.end()); // end the outer ibox
|
||||||
}
|
}
|
||||||
|
@ -808,6 +821,7 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
try!(self.print_type(&**ty));
|
try!(self.print_type(&**ty));
|
||||||
|
try!(self.print_where_clause(generics));
|
||||||
|
|
||||||
try!(space(&mut self.s));
|
try!(space(&mut self.s));
|
||||||
try!(self.bopen());
|
try!(self.bopen());
|
||||||
|
@ -845,6 +859,7 @@ impl<'a> State<'a> {
|
||||||
try!(self.print_path(&trait_.path, false));
|
try!(self.print_path(&trait_.path, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
try!(self.print_where_clause(generics));
|
||||||
try!(word(&mut self.s, " "));
|
try!(word(&mut self.s, " "));
|
||||||
try!(self.bopen());
|
try!(self.bopen());
|
||||||
for meth in methods.iter() {
|
for meth in methods.iter() {
|
||||||
|
@ -880,6 +895,7 @@ impl<'a> State<'a> {
|
||||||
try!(self.head(visibility_qualified(visibility, "enum").as_slice()));
|
try!(self.head(visibility_qualified(visibility, "enum").as_slice()));
|
||||||
try!(self.print_ident(ident));
|
try!(self.print_ident(ident));
|
||||||
try!(self.print_generics(generics));
|
try!(self.print_generics(generics));
|
||||||
|
try!(self.print_where_clause(generics));
|
||||||
try!(space(&mut self.s));
|
try!(space(&mut self.s));
|
||||||
self.print_variants(enum_definition.variants.as_slice(), span)
|
self.print_variants(enum_definition.variants.as_slice(), span)
|
||||||
}
|
}
|
||||||
|
@ -2010,7 +2026,8 @@ impl<'a> State<'a> {
|
||||||
try!(self.nbsp());
|
try!(self.nbsp());
|
||||||
try!(self.print_ident(name));
|
try!(self.print_ident(name));
|
||||||
try!(self.print_generics(generics));
|
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,
|
pub fn print_fn_args(&mut self, decl: &ast::FnDecl,
|
||||||
|
@ -2201,54 +2218,83 @@ impl<'a> State<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_generics(&mut self,
|
fn print_type_parameters(&mut self,
|
||||||
generics: &ast::Generics) -> IoResult<()> {
|
lifetimes: &[ast::LifetimeDef],
|
||||||
let total = generics.lifetimes.len() + generics.ty_params.len();
|
ty_params: &[ast::TyParam])
|
||||||
if total > 0 {
|
-> IoResult<()> {
|
||||||
try!(word(&mut self.s, "<"));
|
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();
|
self.commasep(Inconsistent, ints.as_slice(), |s, &idx| {
|
||||||
for i in range(0u, total) {
|
if idx < lifetimes.len() {
|
||||||
ints.push(i);
|
let lifetime = &lifetimes[idx];
|
||||||
}
|
s.print_lifetime_def(lifetime)
|
||||||
|
} else {
|
||||||
try!(self.commasep(
|
let idx = idx - lifetimes.len();
|
||||||
Inconsistent, ints.as_slice(),
|
let param = &ty_params[idx];
|
||||||
|s, &idx| {
|
match param.unbound {
|
||||||
if idx < generics.lifetimes.len() {
|
Some(TraitTyParamBound(ref tref)) => {
|
||||||
let lifetime = generics.lifetimes.get(idx);
|
try!(s.print_trait_ref(tref));
|
||||||
s.print_lifetime_def(lifetime)
|
try!(s.word_space("?"));
|
||||||
} 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(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}));
|
_ => {}
|
||||||
|
}
|
||||||
|
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, ">")
|
word(&mut self.s, ">")
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
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<()> {
|
pub fn print_meta_item(&mut self, item: &ast::MetaItem) -> IoResult<()> {
|
||||||
try!(self.ibox(indent_unit));
|
try!(self.ibox(indent_unit));
|
||||||
match item.node {
|
match item.node {
|
||||||
|
@ -2476,6 +2522,11 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match generics {
|
||||||
|
Some(generics) => try!(self.print_where_clause(generics)),
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
self.end()
|
self.end()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
use abi::Abi;
|
use abi::Abi;
|
||||||
use ast::*;
|
use ast::*;
|
||||||
use ast;
|
use ast;
|
||||||
|
use ast_util;
|
||||||
use codemap::Span;
|
use codemap::Span;
|
||||||
use parse;
|
use parse;
|
||||||
use owned_slice::OwnedSlice;
|
use owned_slice::OwnedSlice;
|
||||||
|
@ -58,12 +59,7 @@ pub fn generics_of_fn(fk: &FnKind) -> Generics {
|
||||||
FkMethod(_, generics, _) => {
|
FkMethod(_, generics, _) => {
|
||||||
(*generics).clone()
|
(*generics).clone()
|
||||||
}
|
}
|
||||||
FkFnBlock(..) => {
|
FkFnBlock(..) => ast_util::empty_generics(),
|
||||||
Generics {
|
|
||||||
lifetimes: Vec::new(),
|
|
||||||
ty_params: OwnedSlice::empty(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,7 +555,11 @@ pub fn walk_generics<E: Clone, V: Visitor<E>>(visitor: &mut V,
|
||||||
None => {}
|
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<E: Clone, V: Visitor<E>>(visitor: &mut V,
|
pub fn walk_fn_decl<E: Clone, V: Visitor<E>>(visitor: &mut V,
|
||||||
|
|
30
src/test/auxiliary/where_clauses_xc.rs
Normal file
30
src/test/auxiliary/where_clauses_xc.rs
Normal file
|
@ -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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T,U>(&self, this: &T, that: &T, x: &U, y: &U) -> bool
|
||||||
|
where T: Eq, U: Eq;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Equal for T where T: Eq {
|
||||||
|
fn equal(&self, other: &T) -> bool {
|
||||||
|
self == other
|
||||||
|
}
|
||||||
|
fn equals<U,X>(&self, this: &U, other: &U, x: &X, y: &X) -> bool
|
||||||
|
where U: Eq, X: Eq {
|
||||||
|
this == other && x == y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn equal<T>(x: &T, y: &T) -> bool where T: Eq {
|
||||||
|
x == y
|
||||||
|
}
|
||||||
|
|
|
@ -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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
fn equal1<T>(_: &T, _: &T) -> bool where {
|
||||||
|
//~^ ERROR a `where` clause must have at least one predicate in it
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn equal2<T>(_: &T, _: &T) -> bool where T: {
|
||||||
|
//~^ ERROR each predicate in a `where` clause must have at least one bound
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
||||||
|
|
17
src/test/compile-fail/where-clauses-not-parameter.rs
Normal file
17
src/test/compile-fail/where-clauses-not-parameter.rs
Normal file
|
@ -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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
fn equal<T>(_: &T, _: &T) -> bool where int : Eq {
|
||||||
|
//~^ ERROR undeclared type parameter
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
||||||
|
|
20
src/test/compile-fail/where-clauses-unsatisfied.rs
Normal file
20
src/test/compile-fail/where-clauses-unsatisfied.rs
Normal file
|
@ -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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
fn equal<T>(_: &T, _: &T) -> bool where T : Eq {
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Struct;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
equal(&Struct, &Struct)
|
||||||
|
//~^ ERROR failed to find an implementation of trait
|
||||||
|
}
|
||||||
|
|
23
src/test/run-pass/where-clauses-cross-crate.rs
Normal file
23
src/test/run-pass/where-clauses-cross-crate.rs
Normal file
|
@ -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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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::<int,&str>(&1i, &1i, &"foo", &"bar"));
|
||||||
|
}
|
||||||
|
|
37
src/test/run-pass/where-clauses.rs
Normal file
37
src/test/run-pass/where-clauses.rs
Normal file
|
@ -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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T,U>(&self, this: &T, that: &T, x: &U, y: &U) -> bool
|
||||||
|
where T: Eq, U: Eq;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Equal for T where T: Eq {
|
||||||
|
fn equal(&self, other: &T) -> bool {
|
||||||
|
self == other
|
||||||
|
}
|
||||||
|
fn equals<U,X>(&self, this: &U, other: &U, x: &X, y: &X) -> bool
|
||||||
|
where U: Eq, X: Eq {
|
||||||
|
this == other && x == y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn equal<T>(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::<int,&str>(&1i, &1i, &"foo", &"bar"));
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue