1
Fork 0

Update parser with for syntax

This commit is contained in:
Niko Matsakis 2014-11-07 06:53:45 -05:00
parent c18a1327e3
commit 244231720d
28 changed files with 543 additions and 404 deletions

View file

@ -1690,8 +1690,8 @@ impl LintPass for Stability {
for t in supertraits.iter() { for t in supertraits.iter() {
match *t { match *t {
ast::TraitTyParamBound(ref t) => { ast::TraitTyParamBound(ref t) => {
let id = ty::trait_ref_to_def_id(cx.tcx, t); let id = ty::trait_ref_to_def_id(cx.tcx, &t.trait_ref);
self.lint(cx, id, t.path.span); self.lint(cx, id, t.trait_ref.path.span);
} }
_ => (/* pass */) _ => (/* pass */)
} }

View file

@ -1291,7 +1291,7 @@ impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> {
match *ty_param_bound { match *ty_param_bound {
ast::TraitTyParamBound(ref trait_ref) => { ast::TraitTyParamBound(ref trait_ref) => {
if !self.tcx.sess.features.borrow().visible_private_types && if !self.tcx.sess.features.borrow().visible_private_types &&
self.path_is_private_type(trait_ref.ref_id) { self.path_is_private_type(trait_ref.trait_ref.ref_id) {
self.tcx.sess.span_err(span, self.tcx.sess.span_err(span,
"private type in exported type \ "private type in exported type \
parameter bound"); parameter bound");
@ -1432,7 +1432,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
// //
// Those in 2. are warned via walk_generics and this // Those in 2. are warned via walk_generics and this
// call here. // call here.
visit::walk_trait_ref_helper(self, tr) self.visit_trait_ref(tr)
} }
} }
} else if trait_ref.is_none() && self_is_public_path { } else if trait_ref.is_none() && self_is_public_path {

View file

@ -33,12 +33,12 @@ use syntax::ast::{ItemTrait, ItemTy, LOCAL_CRATE, Local, ItemConst};
use syntax::ast::{MethodImplItem, Mod, Name, NamedField, NodeId}; use syntax::ast::{MethodImplItem, Mod, Name, NamedField, NodeId};
use syntax::ast::{Pat, PatEnum, PatIdent, PatLit}; use syntax::ast::{Pat, PatEnum, PatIdent, PatLit};
use syntax::ast::{PatRange, PatStruct, Path, PathListIdent, PathListMod}; use syntax::ast::{PatRange, PatStruct, Path, PathListIdent, PathListMod};
use syntax::ast::{PrimTy, Public, SelfExplicit, SelfStatic}; use syntax::ast::{PolyTraitRef, PrimTy, Public, SelfExplicit, SelfStatic};
use syntax::ast::{RegionTyParamBound, StmtDecl, StructField}; use syntax::ast::{RegionTyParamBound, StmtDecl, StructField};
use syntax::ast::{StructVariantKind, TraitRef, TraitTyParamBound}; use syntax::ast::{StructVariantKind, TraitRef, TraitTyParamBound};
use syntax::ast::{TupleVariantKind, Ty, TyBool, TyChar, TyClosure, TyF32}; use syntax::ast::{TupleVariantKind, Ty, TyBool, TyChar, TyClosure, TyF32};
use syntax::ast::{TyF64, TyFloat, TyI, TyI8, TyI16, TyI32, TyI64, TyInt}; use syntax::ast::{TyF64, TyFloat, TyI, TyI8, TyI16, TyI32, TyI64, TyInt};
use syntax::ast::{TyParam, TyParamBound, TyPath, TyPtr, TyProc, TyQPath}; use syntax::ast::{TyParam, TyParamBound, TyPath, TyPtr, TyPolyTraitRef, TyProc, TyQPath};
use syntax::ast::{TyRptr, TyStr, TyU, TyU8, TyU16, TyU32, TyU64, TyUint}; use syntax::ast::{TyRptr, TyStr, TyU, TyU8, TyU16, TyU32, TyU64, TyUint};
use syntax::ast::{TypeImplItem, UnnamedField}; use syntax::ast::{TypeImplItem, UnnamedField};
use syntax::ast::{Variant, ViewItem, ViewItemExternCrate}; use syntax::ast::{Variant, ViewItem, ViewItemExternCrate};
@ -607,6 +607,7 @@ enum TraitReferenceType {
TraitImplementation, // impl SomeTrait for T { ... } TraitImplementation, // impl SomeTrait for T { ... }
TraitDerivation, // trait T : SomeTrait { ... } TraitDerivation, // trait T : SomeTrait { ... }
TraitBoundingTypeParameter, // fn f<T:SomeTrait>() { ... } TraitBoundingTypeParameter, // fn f<T:SomeTrait>() { ... }
TraitObject, // Box<for<'a> SomeTrait>
} }
impl NameBindings { impl NameBindings {
@ -4244,11 +4245,11 @@ impl<'a> Resolver<'a> {
this.resolve_type_parameter_bounds(item.id, bounds, this.resolve_type_parameter_bounds(item.id, bounds,
TraitDerivation); TraitDerivation);
match unbound { match *unbound {
&Some(ast::TraitTyParamBound(ref tpb)) => { Some(ref tpb) => {
this.resolve_trait_reference(item.id, tpb, TraitDerivation); this.resolve_trait_reference(item.id, tpb, TraitDerivation);
} }
_ => {} None => {}
} }
for trait_item in (*trait_items).iter() { for trait_item in (*trait_items).iter() {
@ -4495,7 +4496,7 @@ impl<'a> Resolver<'a> {
} }
match &type_parameter.unbound { match &type_parameter.unbound {
&Some(ref unbound) => &Some(ref unbound) =>
self.resolve_type_parameter_bound( self.resolve_trait_reference(
type_parameter.id, unbound, TraitBoundingTypeParameter), type_parameter.id, unbound, TraitBoundingTypeParameter),
&None => {} &None => {}
} }
@ -4521,12 +4522,19 @@ impl<'a> Resolver<'a> {
reference_type: TraitReferenceType) { reference_type: TraitReferenceType) {
match *type_parameter_bound { match *type_parameter_bound {
TraitTyParamBound(ref tref) => { TraitTyParamBound(ref tref) => {
self.resolve_trait_reference(id, tref, reference_type) self.resolve_poly_trait_reference(id, tref, reference_type)
} }
RegionTyParamBound(..) => {} RegionTyParamBound(..) => {}
} }
} }
fn resolve_poly_trait_reference(&mut self,
id: NodeId,
poly_trait_reference: &PolyTraitRef,
reference_type: TraitReferenceType) {
self.resolve_trait_reference(id, &poly_trait_reference.trait_ref, reference_type)
}
fn resolve_trait_reference(&mut self, fn resolve_trait_reference(&mut self,
id: NodeId, id: NodeId,
trait_reference: &TraitRef, trait_reference: &TraitRef,
@ -4538,6 +4546,7 @@ impl<'a> Resolver<'a> {
TraitBoundingTypeParameter => "bound type parameter with", TraitBoundingTypeParameter => "bound type parameter with",
TraitImplementation => "implement", TraitImplementation => "implement",
TraitDerivation => "derive", TraitDerivation => "derive",
TraitObject => "reference",
}; };
let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str); let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str);
@ -5044,6 +5053,13 @@ impl<'a> Resolver<'a> {
visit::walk_ty(self, ty); visit::walk_ty(self, ty);
} }
TyPolyTraitRef(ref poly_trait_ref) => {
self.resolve_poly_trait_reference(
ty.id,
&**poly_trait_ref,
TraitObject);
visit::walk_ty(self, ty);
}
_ => { _ => {
// Just resolve embedded types. // Just resolve embedded types.
visit::walk_ty(self, ty); visit::walk_ty(self, ty);

View file

@ -19,6 +19,7 @@
use driver::session::Session; use driver::session::Session;
use middle::subst; use middle::subst;
use std::fmt;
use syntax::ast; use syntax::ast;
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::owned_slice::OwnedSlice; use syntax::owned_slice::OwnedSlice;
@ -46,18 +47,12 @@ pub enum DefRegion {
// that it corresponds to // that it corresponds to
pub type NamedRegionMap = NodeMap<DefRegion>; pub type NamedRegionMap = NodeMap<DefRegion>;
// Returns an instance of some type that implements std::fmt::Show
fn lifetime_show(lt_name: &ast::Name) -> token::InternedString {
token::get_name(*lt_name)
}
struct LifetimeContext<'a> { struct LifetimeContext<'a> {
sess: &'a Session, sess: &'a Session,
named_region_map: &'a mut NamedRegionMap, named_region_map: &'a mut NamedRegionMap,
scope: Scope<'a> scope: Scope<'a>
} }
#[deriving(Show)]
enum ScopeChain<'a> { enum ScopeChain<'a> {
/// EarlyScope(i, ['a, 'b, ...], s) extends s with early-bound /// EarlyScope(i, ['a, 'b, ...], s) extends s with early-bound
/// lifetimes, assigning indexes 'a => i, 'b => i+1, ... etc. /// lifetimes, assigning indexes 'a => i, 'b => i+1, ... etc.
@ -88,42 +83,32 @@ pub fn krate(sess: &Session, krate: &ast::Crate) -> NamedRegionMap {
impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
fn visit_item(&mut self, item: &ast::Item) { fn visit_item(&mut self, item: &ast::Item) {
let lifetimes = match item.node { match item.node {
ast::ItemFn(..) | // fn lifetimes get added in visit_fn below ast::ItemFn(..) => {
// Fn lifetimes get added in visit_fn below:
self.with(RootScope, |this| visit::walk_item(this, item));
}
ast::ItemMod(..) | ast::ItemMod(..) |
ast::ItemMac(..) | ast::ItemMac(..) |
ast::ItemForeignMod(..) | ast::ItemForeignMod(..) |
ast::ItemStatic(..) | ast::ItemConst(..) => { ast::ItemStatic(..) |
self.with(|_, f| f(RootScope), |v| visit::walk_item(v, item)); ast::ItemConst(..) => {
return; // These sorts of items have no lifetime parameters at all.
self.with(RootScope, |this| visit::walk_item(this, item));
} }
ast::ItemTy(_, ref generics) | ast::ItemTy(_, ref generics) |
ast::ItemEnum(_, ref generics) | ast::ItemEnum(_, ref generics) |
ast::ItemStruct(_, ref generics) | ast::ItemStruct(_, ref generics) |
ast::ItemTrait(ref generics, _, _, _) => { ast::ItemTrait(ref generics, _, _, _) |
self.with(|scope, f| {
f(EarlyScope(subst::TypeSpace,
&generics.lifetimes,
scope))
}, |v| v.check_lifetime_defs(&generics.lifetimes));
&generics.lifetimes
}
ast::ItemImpl(ref generics, _, _, _) => { ast::ItemImpl(ref generics, _, _, _) => {
self.with(|scope, f| { // These kinds of items have only early bound lifetime parameters.
f(EarlyScope(subst::TypeSpace, let lifetimes = &generics.lifetimes;
&generics.lifetimes, self.with(EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE), |this| {
scope)) this.check_lifetime_defs(lifetimes);
}, |v| v.check_lifetime_defs(&generics.lifetimes)); visit::walk_item(this, item);
&generics.lifetimes });
} }
}; }
self.with(|_, f| f(EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE)), |v| {
debug!("entering scope {}", v.scope);
v.check_lifetime_defs(lifetimes);
visit::walk_item(v, item);
debug!("exiting scope {}", v.scope);
});
} }
fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl, fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl,
@ -131,7 +116,9 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
match fk { match fk {
visit::FkItemFn(_, generics, _, _) | visit::FkItemFn(_, generics, _, _) |
visit::FkMethod(_, generics, _) => { visit::FkMethod(_, generics, _) => {
self.visit_fn_decl(n, generics, |v| visit::walk_fn(v, fk, fd, b, s)) self.visit_early_late(
subst::FnSpace, n, generics,
|this| visit::walk_fn(this, fk, fd, b, s))
} }
visit::FkFnBlock(..) => { visit::FkFnBlock(..) => {
visit::walk_fn(self, fk, fd, b, s) visit::walk_fn(self, fk, fd, b, s)
@ -146,22 +133,20 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
_ => return visit::walk_ty(self, ty) _ => return visit::walk_ty(self, ty)
}; };
self.with(|scope, f| f(LateScope(ty.id, lifetimes, scope)), |v| { self.with(LateScope(ty.id, lifetimes, self.scope), |this| {
v.check_lifetime_defs(lifetimes); this.check_lifetime_defs(lifetimes);
debug!("pushing fn scope id={} due to type", ty.id); visit::walk_ty(this, ty);
visit::walk_ty(v, ty);
debug!("popping fn scope id={} due to type", ty.id);
}); });
} }
fn visit_ty_method(&mut self, m: &ast::TypeMethod) { fn visit_ty_method(&mut self, m: &ast::TypeMethod) {
self.visit_fn_decl(m.id, &m.generics, |v| visit::walk_ty_method(v, m)) self.visit_early_late(
subst::FnSpace, m.id, &m.generics,
|this| visit::walk_ty_method(this, m))
} }
fn visit_block(&mut self, b: &ast::Block) { fn visit_block(&mut self, b: &ast::Block) {
debug!("pushing block scope {}", b.id); self.with(BlockScope(b.id, self.scope), |this| visit::walk_block(this, b));
self.with(|scope, f| f(BlockScope(b.id, scope)), |v| visit::walk_block(v, b));
debug!("popping block scope {}", b.id);
} }
fn visit_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) { fn visit_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) {
@ -188,13 +173,16 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
} }
impl<'a> LifetimeContext<'a> { impl<'a> LifetimeContext<'a> {
fn with(&mut self, wrap_scope: |Scope, |ScopeChain||, f: |&mut LifetimeContext|) { fn with(&mut self, wrap_scope: ScopeChain, f: |&mut LifetimeContext|) {
let LifetimeContext { sess, ref mut named_region_map, scope} = *self; let LifetimeContext {sess, ref mut named_region_map, ..} = *self;
wrap_scope(scope, |scope1| f(&mut LifetimeContext { let mut this = LifetimeContext {
sess: sess, sess: sess,
named_region_map: *named_region_map, named_region_map: *named_region_map,
scope: &scope1 scope: &wrap_scope
})) };
debug!("entering scope {}", this.scope);
f(&mut this);
debug!("exiting scope {}", this.scope);
} }
fn visit_ty_param_bounds(&mut self, fn visit_ty_param_bounds(&mut self,
@ -202,7 +190,7 @@ impl<'a> LifetimeContext<'a> {
for bound in bounds.iter() { for bound in bounds.iter() {
match *bound { match *bound {
ast::TraitTyParamBound(ref trait_ref) => { ast::TraitTyParamBound(ref trait_ref) => {
self.visit_trait_ref(trait_ref); self.visit_poly_trait_ref(trait_ref);
} }
ast::RegionTyParamBound(ref lifetime) => { ast::RegionTyParamBound(ref lifetime) => {
self.visit_lifetime_ref(lifetime); self.visit_lifetime_ref(lifetime);
@ -211,23 +199,27 @@ impl<'a> LifetimeContext<'a> {
} }
} }
fn visit_trait_ref(&mut self, trait_ref: &ast::TraitRef) { fn visit_poly_trait_ref(&mut self, trait_ref: &ast::PolyTraitRef) {
self.with(|scope, f| { let ref_id = trait_ref.trait_ref.ref_id;
f(LateScope(trait_ref.ref_id, &trait_ref.lifetimes, scope)) self.with(LateScope(ref_id, &trait_ref.bound_lifetimes, self.scope), |this| {
}, |v| { this.check_lifetime_defs(&trait_ref.bound_lifetimes);
v.check_lifetime_defs(&trait_ref.lifetimes); for lifetime in trait_ref.bound_lifetimes.iter() {
for lifetime in trait_ref.lifetimes.iter() { this.visit_lifetime_decl(lifetime);
v.visit_lifetime_decl(lifetime);
} }
v.visit_path(&trait_ref.path, trait_ref.ref_id); this.visit_trait_ref(&trait_ref.trait_ref)
}) })
} }
fn visit_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
self.visit_path(&trait_ref.path, trait_ref.ref_id);
}
/// Visits self by adding a scope and handling recursive walk over the contents with `walk`. /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
fn visit_fn_decl(&mut self, fn visit_early_late(&mut self,
n: ast::NodeId, early_space: subst::ParamSpace,
generics: &ast::Generics, binder_id: ast::NodeId,
walk: |&mut LifetimeContext|) { generics: &ast::Generics,
walk: |&mut LifetimeContext|) {
/*! /*!
* Handles visiting fns and methods. These are a bit * Handles visiting fns and methods. These are a bit
* complicated because we must distinguish early- vs late-bound * complicated because we must distinguish early- vs late-bound
@ -248,33 +240,25 @@ impl<'a> LifetimeContext<'a> {
* numbered sequentially, starting from the lowest index that * numbered sequentially, starting from the lowest index that
* is already in scope (for a fn item, that will be 0, but for * is already in scope (for a fn item, that will be 0, but for
* a method it might not be). Late bound lifetimes are * a method it might not be). Late bound lifetimes are
* resolved by name and associated with a binder id (`n`), so * resolved by name and associated with a binder id (`binder_id`), so
* the ordering is not important there. * the ordering is not important there.
*/ */
let referenced_idents = early_bound_lifetime_names(generics); let referenced_idents = early_bound_lifetime_names(generics);
debug!("pushing fn scope id={} due to fn item/method\
referenced_idents={}",
n,
referenced_idents.iter().map(lifetime_show).collect::<Vec<token::InternedString>>());
let lifetimes = &generics.lifetimes;
if referenced_idents.is_empty() {
self.with(|scope, f| f(LateScope(n, lifetimes, scope)), |v| {
v.check_lifetime_defs(lifetimes);
walk(v);
});
} else {
let (early, late) = lifetimes.clone().partition(
|l| referenced_idents.iter().any(|&i| i == l.lifetime.name));
self.with(|scope, f| f(EarlyScope(subst::FnSpace, &early, scope)), |v| { debug!("visit_early_late: binder_id={} referenced_idents={}",
v.with(|scope1, f| f(LateScope(n, &late, scope1)), |v| { binder_id,
v.check_lifetime_defs(lifetimes); referenced_idents);
walk(v);
}); let (early, late) = generics.lifetimes.clone().partition(
|l| referenced_idents.iter().any(|&i| i == l.lifetime.name));
self.with(EarlyScope(early_space, &early, self.scope), |this| {
this.with(LateScope(binder_id, &late, this.scope), |this| {
this.check_lifetime_defs(&generics.lifetimes);
walk(this);
}); });
} });
debug!("popping fn scope id={} due to fn item/method", n);
} }
fn resolve_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) { fn resolve_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) {
@ -525,3 +509,14 @@ fn early_bound_lifetime_names(generics: &ast::Generics) -> Vec<ast::Name> {
} }
} }
} }
impl<'a> fmt::Show for ScopeChain<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
EarlyScope(space, defs, _) => write!(fmt, "EarlyScope({}, {})", space, defs),
LateScope(id, defs, _) => write!(fmt, "LateScope({}, {})", id, defs),
BlockScope(id, _) => write!(fmt, "BlockScope({})", id),
RootScope => write!(fmt, "RootScope"),
}
}
}

View file

@ -710,6 +710,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
} }
}; };
let trait_ref = &trait_ref.trait_ref;
match self.lookup_type_ref(trait_ref.ref_id) { match self.lookup_type_ref(trait_ref.ref_id) {
Some(id) => { Some(id) => {
let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span); let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
@ -1068,7 +1069,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
for bound in param.bounds.iter() { for bound in param.bounds.iter() {
match *bound { match *bound {
ast::TraitTyParamBound(ref trait_ref) => { ast::TraitTyParamBound(ref trait_ref) => {
self.process_trait_ref(trait_ref, None); self.process_trait_ref(&trait_ref.trait_ref, None);
} }
_ => {} _ => {}
} }

View file

@ -5546,7 +5546,8 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
ty_param(_) | ty_param(_) |
ty_infer(_) | ty_infer(_) |
ty_open(_) | ty_open(_) |
ty_err => {} ty_err => {
}
} }
}); });

View file

@ -51,8 +51,6 @@
use middle::const_eval; use middle::const_eval;
use middle::def; use middle::def;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem};
use middle::lang_items::{FnOnceTraitLangItem};
use middle::resolve_lifetime as rl; use middle::resolve_lifetime as rl;
use middle::subst::{FnSpace, TypeSpace, AssocSpace, SelfSpace, Subst, Substs}; use middle::subst::{FnSpace, TypeSpace, AssocSpace, SelfSpace, Subst, Substs};
use middle::subst::{VecPerParamSpace}; use middle::subst::{VecPerParamSpace};
@ -398,6 +396,46 @@ fn ast_path_substs<'tcx,AC,RS>(
} }
} }
pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC,
rscope: &RS,
ast_trait_ref: &ast::TraitRef,
self_ty: Option<ty::t>,
associated_type: Option<ty::t>)
-> Rc<ty::TraitRef>
where AC: AstConv<'tcx>,
RS: RegionScope
{
/*!
* Instantiates the path for the given trait reference, assuming that
* it's bound to a valid trait type. Returns the def_id for the defining
* trait. Fails if the type is a type other than a trait type.
*/
match lookup_def_tcx(this.tcx(),
ast_trait_ref.path.span,
ast_trait_ref.ref_id) {
def::DefTrait(trait_did) => {
let trait_ref =
Rc::new(ast_path_to_trait_ref(this,
rscope,
trait_did,
self_ty,
associated_type,
&ast_trait_ref.path,
ast_trait_ref.ref_id));
this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id,
trait_ref.clone());
trait_ref
}
_ => {
this.tcx().sess.span_fatal(
ast_trait_ref.path.span,
format!("`{}` is not a trait", ast_trait_ref.path.user_string(this.tcx()))[]);
}
}
}
pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC, pub fn ast_path_to_trait_ref<'tcx,AC,RS>(this: &AC,
rscope: &RS, rscope: &RS,
trait_def_id: ast::DefId, trait_def_id: ast::DefId,
@ -620,41 +658,6 @@ enum PointerTy {
Uniq Uniq
} }
pub fn trait_ref_for_unboxed_function<'tcx, AC: AstConv<'tcx>,
RS:RegionScope>(
this: &AC,
rscope: &RS,
kind: ast::UnboxedClosureKind,
decl: &ast::FnDecl,
self_ty: Option<ty::t>)
-> ty::TraitRef {
let lang_item = match kind {
ast::FnUnboxedClosureKind => FnTraitLangItem,
ast::FnMutUnboxedClosureKind => FnMutTraitLangItem,
ast::FnOnceUnboxedClosureKind => FnOnceTraitLangItem,
};
let trait_did = this.tcx().lang_items.require(lang_item).unwrap();
let input_types = decl.inputs
.iter()
.map(|input| {
ast_ty_to_ty(this, rscope, &*input.ty)
}).collect::<Vec<_>>();
let input_tuple = ty::mk_tup_or_nil(this.tcx(), input_types);
let output_type = ast_ty_to_ty(this, rscope, &*decl.output);
let mut substs = Substs::new_type(vec!(input_tuple, output_type),
Vec::new());
match self_ty {
Some(s) => substs.types.push(SelfSpace, s),
None => ()
}
ty::TraitRef {
def_id: trait_did,
substs: substs,
}
}
// Handle `~`, `Box`, and `&` being able to mean strs and vecs. // Handle `~`, `Box`, and `&` being able to mean strs and vecs.
// If a_seq_ty is a str or a vec, make it a str/vec. // If a_seq_ty is a str or a vec, make it a str/vec.
// Also handle first-class trait types. // Also handle first-class trait types.
@ -898,6 +901,16 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
ty::mk_closure(tcx, fn_decl) ty::mk_closure(tcx, fn_decl)
} }
ast::TyPolyTraitRef(ref data) => {
// FIXME(#18639) this is just a placeholder for code to come
let principal = instantiate_trait_ref(this, rscope, &data.trait_ref, None, None);
let bounds = conv_existential_bounds(this,
rscope,
ast_ty.span,
&[principal.clone()],
&[]);
ty::mk_trait(tcx, (*principal).clone(), bounds)
}
ast::TyPath(ref path, ref bounds, id) => { ast::TyPath(ref path, ref bounds, id) => {
let a_def = match tcx.def_map.borrow().get(&id) { let a_def = match tcx.def_map.borrow().get(&id) {
None => { None => {
@ -1536,6 +1549,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt,
for &ast_bound in ast_bounds.iter() { for &ast_bound in ast_bounds.iter() {
match *ast_bound { match *ast_bound {
ast::TraitTyParamBound(ref b) => { ast::TraitTyParamBound(ref b) => {
let b = &b.trait_ref; // FIXME
match lookup_def_tcx(tcx, b.path.span, b.ref_id) { match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
def::DefTrait(trait_did) => { def::DefTrait(trait_did) => {
match trait_def_ids.get(&trait_did) { match trait_def_ids.get(&trait_did) {

View file

@ -61,7 +61,6 @@ use syntax::ast_util::{local_def, PostExpansionMethod};
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::parse::token::{special_idents}; use syntax::parse::token::{special_idents};
use syntax::parse::token; use syntax::parse::token;
use syntax::print::pprust::{path_to_string};
use syntax::ptr::P; use syntax::ptr::P;
use syntax::visit; use syntax::visit;
@ -633,24 +632,33 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
span: Span, span: Span,
generics: &ast::Generics, generics: &ast::Generics,
thing: &'static str) { thing: &'static str) {
let mut warn = false;
for ty_param in generics.ty_params.iter() { for ty_param in generics.ty_params.iter() {
let bounds = ty_param.bounds.iter(); for bound in ty_param.bounds.iter() {
let mut bounds = bounds.chain(ty_param.unbound.iter());
for bound in bounds {
match *bound { match *bound {
ast::TraitTyParamBound(..) => { ast::TraitTyParamBound(..) => {
// According to accepted RFC #XXX, we should warn = true;
// eventually accept these, but it will not be
// part of this PR. Still, convert to warning to
// make bootstrapping easier.
span_warn!(ccx.tcx.sess, span, E0122,
"trait bounds are not (yet) enforced \
in {} definitions",
thing);
} }
ast::RegionTyParamBound(..) => { } ast::RegionTyParamBound(..) => { }
} }
} }
match ty_param.unbound {
Some(_) => { warn = true; }
None => { }
}
}
if warn {
// According to accepted RFC #XXX, we should
// eventually accept these, but it will not be
// part of this PR. Still, convert to warning to
// make bootstrapping easier.
span_warn!(ccx.tcx.sess, span, E0122,
"trait bounds are not (yet) enforced \
in {} definitions",
thing);
} }
} }
@ -1147,7 +1155,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
parent_visibility); parent_visibility);
for trait_ref in opt_trait_ref.iter() { for trait_ref in opt_trait_ref.iter() {
instantiate_trait_ref(&icx, trait_ref, selfty, None); astconv::instantiate_trait_ref(&icx, &ExplicitRscope, trait_ref, Some(selfty), None);
} }
}, },
ast::ItemTrait(_, _, _, ref trait_methods) => { ast::ItemTrait(_, _, _, ref trait_methods) => {
@ -1315,47 +1323,6 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: &ast::ForeignItem) {
ccx.tcx.tcache.borrow_mut().insert(local_def(i.id), pty); ccx.tcx.tcache.borrow_mut().insert(local_def(i.id), pty);
} }
pub fn instantiate_trait_ref<'tcx,AC>(this: &AC,
ast_trait_ref: &ast::TraitRef,
self_ty: ty::t,
associated_type: Option<ty::t>)
-> Rc<ty::TraitRef>
where AC: AstConv<'tcx> {
/*!
* Instantiates the path for the given trait reference, assuming that
* it's bound to a valid trait type. Returns the def_id for the defining
* trait. Fails if the type is a type other than a trait type.
*/
// FIXME(#5121) -- distinguish early vs late lifetime params
let rscope = ExplicitRscope;
match lookup_def_tcx(this.tcx(),
ast_trait_ref.path.span,
ast_trait_ref.ref_id) {
def::DefTrait(trait_did) => {
let trait_ref =
Rc::new(astconv::ast_path_to_trait_ref(this,
&rscope,
trait_did,
Some(self_ty),
associated_type,
&ast_trait_ref.path,
ast_trait_ref.ref_id));
this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id,
trait_ref.clone());
trait_ref
}
_ => {
this.tcx().sess.span_fatal(
ast_trait_ref.path.span,
format!("`{}` is not a trait",
path_to_string(&ast_trait_ref.path)).as_slice());
}
}
}
fn get_trait_def(ccx: &CrateCtxt, trait_id: ast::DefId) -> Rc<ty::TraitDef> { fn get_trait_def(ccx: &CrateCtxt, trait_id: ast::DefId) -> Rc<ty::TraitDef> {
if trait_id.krate != ast::LOCAL_CRATE { if trait_id.krate != ast::LOCAL_CRATE {
return ty::lookup_trait_def(ccx.tcx, trait_id) return ty::lookup_trait_def(ccx.tcx, trait_id)
@ -1720,14 +1687,14 @@ fn ty_generics_for_fn_or_method<'tcx,AC>(
// Add the Sized bound, unless the type parameter is marked as `Sized?`. // Add the Sized bound, unless the type parameter is marked as `Sized?`.
fn add_unsized_bound<'tcx,AC>(this: &AC, fn add_unsized_bound<'tcx,AC>(this: &AC,
unbound: &Option<ast::TyParamBound>, unbound: &Option<ast::TraitRef>,
bounds: &mut ty::BuiltinBounds, bounds: &mut ty::BuiltinBounds,
desc: &str, desc: &str,
span: Span) span: Span)
where AC: AstConv<'tcx> { where AC: AstConv<'tcx> {
let kind_id = this.tcx().lang_items.require(SizedTraitLangItem); let kind_id = this.tcx().lang_items.require(SizedTraitLangItem);
match unbound { match unbound {
&Some(ast::TraitTyParamBound(ref tpb)) => { &Some(ref tpb) => {
// FIXME(#8559) currently requires the unbound to be built-in. // FIXME(#8559) currently requires the unbound to be built-in.
let trait_def_id = ty::trait_ref_to_def_id(this.tcx(), tpb); let trait_def_id = ty::trait_ref_to_def_id(this.tcx(), tpb);
match kind_id { match kind_id {
@ -1752,7 +1719,7 @@ fn add_unsized_bound<'tcx,AC>(this: &AC,
ty::try_add_builtin_trait(this.tcx(), kind_id.unwrap(), bounds); ty::try_add_builtin_trait(this.tcx(), kind_id.unwrap(), bounds);
} }
// No lang item for Sized, so we can't add it as a bound. // No lang item for Sized, so we can't add it as a bound.
_ => {} &None => {}
} }
} }
@ -1870,11 +1837,11 @@ fn ty_generics<'tcx,AC>(this: &AC,
let trait_def_id = let trait_def_id =
match lookup_def_tcx(this.tcx(), match lookup_def_tcx(this.tcx(),
ast_trait_ref.path.span, ast_trait_ref.trait_ref.path.span,
ast_trait_ref.ref_id) { ast_trait_ref.trait_ref.ref_id) {
def::DefTrait(trait_def_id) => trait_def_id, def::DefTrait(trait_def_id) => trait_def_id,
_ => { _ => {
this.tcx().sess.span_bug(ast_trait_ref.path.span, this.tcx().sess.span_bug(ast_trait_ref.trait_ref.path.span,
"not a trait?!") "not a trait?!")
} }
}; };
@ -1972,7 +1939,7 @@ fn compute_bounds<'tcx,AC>(this: &AC,
name_of_bounded_thing: ast::Name, name_of_bounded_thing: ast::Name,
param_ty: ty::ParamTy, param_ty: ty::ParamTy,
ast_bounds: &[ast::TyParamBound], ast_bounds: &[ast::TyParamBound],
unbound: &Option<ast::TyParamBound>, unbound: &Option<ast::TraitRef>,
span: Span, span: Span,
where_clause: &ast::WhereClause) where_clause: &ast::WhereClause)
-> ty::ParamBounds -> ty::ParamBounds
@ -2047,10 +2014,11 @@ fn conv_param_bounds<'tcx,AC>(this: &AC,
let trait_bounds: Vec<Rc<ty::TraitRef>> = let trait_bounds: Vec<Rc<ty::TraitRef>> =
trait_bounds.into_iter() trait_bounds.into_iter()
.map(|b| { .map(|b| {
instantiate_trait_ref(this, astconv::instantiate_trait_ref(this,
b, &ExplicitRscope,
param_ty.to_ty(this.tcx()), b,
Some(param_ty.to_ty(this.tcx()))) Some(param_ty.to_ty(this.tcx())),
Some(param_ty.to_ty(this.tcx())))
}) })
.collect(); .collect();
let region_bounds: Vec<ty::Region> = let region_bounds: Vec<ty::Region> =

View file

@ -52,7 +52,6 @@ use middle::typeck::infer::type_variable::{RelationDir, EqTo,
use middle::ty_fold::{TypeFoldable}; use middle::ty_fold::{TypeFoldable};
use util::ppaux::Repr; use util::ppaux::Repr;
use syntax::ast::{Onceness, FnStyle}; use syntax::ast::{Onceness, FnStyle};
use syntax::ast; use syntax::ast;
use syntax::abi; use syntax::abi;

View file

@ -1102,7 +1102,8 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
// be passing down a map. // be passing down a map.
ast::RegionTyParamBound(lt) ast::RegionTyParamBound(lt)
} }
&ast::TraitTyParamBound(ref tr) => { &ast::TraitTyParamBound(ref poly_tr) => {
let tr = &poly_tr.trait_ref;
let last_seg = tr.path.segments.last().unwrap(); let last_seg = tr.path.segments.last().unwrap();
let mut insert = Vec::new(); let mut insert = Vec::new();
let lifetimes = last_seg.parameters.lifetimes(); let lifetimes = last_seg.parameters.lifetimes();
@ -1119,10 +1120,12 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
region_names: region_names region_names: region_names
}; };
let new_path = self.rebuild_path(rebuild_info, lifetime); let new_path = self.rebuild_path(rebuild_info, lifetime);
ast::TraitTyParamBound(ast::TraitRef { ast::TraitTyParamBound(ast::PolyTraitRef {
path: new_path, bound_lifetimes: poly_tr.bound_lifetimes.clone(),
ref_id: tr.ref_id, trait_ref: ast::TraitRef {
lifetimes: tr.lifetimes.clone(), path: new_path,
ref_id: tr.ref_id,
}
}) })
} }
} }

View file

@ -963,6 +963,12 @@ impl Clean<Type> for ast::TraitRef {
} }
} }
impl Clean<Type> for ast::PolyTraitRef {
fn clean(&self, cx: &DocContext) -> Type {
self.trait_ref.clean(cx)
}
}
#[deriving(Clone, Encodable, Decodable)] #[deriving(Clone, Encodable, Decodable)]
pub enum TraitMethod { pub enum TraitMethod {
RequiredMethod(Item), RequiredMethod(Item),
@ -1306,7 +1312,8 @@ impl Clean<Type> for ty::t {
} }
ty::ty_struct(did, ref substs) | ty::ty_struct(did, ref substs) |
ty::ty_enum(did, ref substs) | ty::ty_enum(did, ref substs) |
ty::ty_trait(box ty::TyTrait { def_id: did, ref substs, .. }) => { ty::ty_trait(box ty::TyTrait { principal: ty::TraitRef { def_id: did, ref substs },
.. }) => {
let fqn = csearch::get_item_path(cx.tcx(), did); let fqn = csearch::get_item_path(cx.tcx(), did);
let fqn: Vec<String> = fqn.into_iter().map(|i| { let fqn: Vec<String> = fqn.into_iter().map(|i| {
i.to_string() i.to_string()

View file

@ -307,7 +307,7 @@ pub const DUMMY_NODE_ID: NodeId = -1;
/// detects Copy, Send and Sync. /// detects Copy, Send and Sync.
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum TyParamBound { pub enum TyParamBound {
TraitTyParamBound(TraitRef), TraitTyParamBound(PolyTraitRef),
RegionTyParamBound(Lifetime) RegionTyParamBound(Lifetime)
} }
@ -318,7 +318,7 @@ pub struct TyParam {
pub ident: Ident, pub ident: Ident,
pub id: NodeId, pub id: NodeId,
pub bounds: TyParamBounds, pub bounds: TyParamBounds,
pub unbound: Option<TyParamBound>, pub unbound: Option<TraitRef>,
pub default: Option<P<Ty>>, pub default: Option<P<Ty>>,
pub span: Span pub span: Span
} }
@ -1097,6 +1097,7 @@ pub enum Ty_ {
TyBareFn(P<BareFnTy>), TyBareFn(P<BareFnTy>),
TyTup(Vec<P<Ty>> ), TyTup(Vec<P<Ty>> ),
TyPath(Path, Option<TyParamBounds>, NodeId), // for #7264; see above TyPath(Path, Option<TyParamBounds>, NodeId), // for #7264; see above
TyPolyTraitRef(P<PolyTraitRef>), // a type like `for<'a> Foo<&'a Bar>`
/// A "qualified path", e.g. `<Vec<T> as SomeTrait>::SomeType` /// A "qualified path", e.g. `<Vec<T> as SomeTrait>::SomeType`
TyQPath(P<QPath>), TyQPath(P<QPath>),
/// No-op; kept solely so that we can pretty-print faithfully /// No-op; kept solely so that we can pretty-print faithfully
@ -1350,7 +1351,6 @@ pub struct Attribute_ {
pub is_sugared_doc: bool, pub is_sugared_doc: bool,
} }
/// TraitRef's appear in impls. /// TraitRef's appear in impls.
/// resolve maps each TraitRef's ref_id to its defining trait; that's all /// resolve maps each TraitRef's ref_id to its defining trait; that's all
/// that the ref_id is for. The impl_id maps to the "self type" of this impl. /// that the ref_id is for. The impl_id maps to the "self type" of this impl.
@ -1360,7 +1360,15 @@ pub struct Attribute_ {
pub struct TraitRef { pub struct TraitRef {
pub path: Path, pub path: Path,
pub ref_id: NodeId, pub ref_id: NodeId,
pub lifetimes: Vec<LifetimeDef>, }
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct PolyTraitRef {
/// The `'a` in `<'a> Foo<&'a T>`
pub bound_lifetimes: Vec<LifetimeDef>,
/// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
pub trait_ref: TraitRef
} }
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
@ -1448,8 +1456,8 @@ pub enum Item_ {
ItemStruct(P<StructDef>, Generics), ItemStruct(P<StructDef>, Generics),
/// Represents a Trait Declaration /// Represents a Trait Declaration
ItemTrait(Generics, ItemTrait(Generics,
Option<TyParamBound>, // (optional) default bound not required for Self. Option<TraitRef>, // (optional) default bound not required for Self.
// Currently, only Sized makes sense here. // Currently, only Sized makes sense here.
TyParamBounds, TyParamBounds,
Vec<TraitItem>), Vec<TraitItem>),
ItemImpl(Generics, ItemImpl(Generics,

View file

@ -770,7 +770,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
for b in bounds.iter() { for b in bounds.iter() {
match *b { match *b {
TraitTyParamBound(ref t) => { TraitTyParamBound(ref t) => {
self.insert(t.ref_id, NodeItem(i)); self.insert(t.trait_ref.ref_id, NodeItem(i));
} }
_ => {} _ => {}
} }

View file

@ -68,10 +68,11 @@ pub trait AstBuilder {
span: Span, span: Span,
id: ast::Ident, id: ast::Ident,
bounds: OwnedSlice<ast::TyParamBound>, bounds: OwnedSlice<ast::TyParamBound>,
unbound: Option<ast::TyParamBound>, unbound: Option<ast::TraitRef>,
default: Option<P<ast::Ty>>) -> ast::TyParam; default: Option<P<ast::Ty>>) -> ast::TyParam;
fn trait_ref(&self, path: ast::Path) -> ast::TraitRef; fn trait_ref(&self, path: ast::Path) -> ast::TraitRef;
fn poly_trait_ref(&self, path: ast::Path) -> ast::PolyTraitRef;
fn typarambound(&self, path: ast::Path) -> ast::TyParamBound; fn typarambound(&self, path: ast::Path) -> ast::TyParamBound;
fn lifetime(&self, span: Span, ident: ast::Name) -> ast::Lifetime; fn lifetime(&self, span: Span, ident: ast::Name) -> ast::Lifetime;
fn lifetime_def(&self, fn lifetime_def(&self,
@ -417,7 +418,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
span: Span, span: Span,
id: ast::Ident, id: ast::Ident,
bounds: OwnedSlice<ast::TyParamBound>, bounds: OwnedSlice<ast::TyParamBound>,
unbound: Option<ast::TyParamBound>, unbound: Option<ast::TraitRef>,
default: Option<P<ast::Ty>>) -> ast::TyParam { default: Option<P<ast::Ty>>) -> ast::TyParam {
ast::TyParam { ast::TyParam {
ident: id, ident: id,
@ -445,12 +446,18 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
ast::TraitRef { ast::TraitRef {
path: path, path: path,
ref_id: ast::DUMMY_NODE_ID, ref_id: ast::DUMMY_NODE_ID,
lifetimes: Vec::new(), }
}
fn poly_trait_ref(&self, path: ast::Path) -> ast::PolyTraitRef {
ast::PolyTraitRef {
bound_lifetimes: Vec::new(),
trait_ref: self.trait_ref(path)
} }
} }
fn typarambound(&self, path: ast::Path) -> ast::TyParamBound { fn typarambound(&self, path: ast::Path) -> ast::TyParamBound {
ast::TraitTyParamBound(self.trait_ref(path)) ast::TraitTyParamBound(self.poly_trait_ref(path))
} }
fn lifetime(&self, span: Span, name: ast::Name) -> ast::Lifetime { fn lifetime(&self, span: Span, name: ast::Name) -> ast::Lifetime {

View file

@ -194,7 +194,7 @@ impl<'a> Ty<'a> {
fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str, fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str,
bounds: &[Path], unbound: Option<ast::TyParamBound>, bounds: &[Path], unbound: Option<ast::TraitRef>,
self_ident: Ident, self_generics: &Generics) -> ast::TyParam { self_ident: Ident, self_generics: &Generics) -> ast::TyParam {
let bounds = let bounds =
bounds.iter().map(|b| { bounds.iter().map(|b| {
@ -220,7 +220,7 @@ fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>)
#[deriving(Clone)] #[deriving(Clone)]
pub struct LifetimeBounds<'a> { pub struct LifetimeBounds<'a> {
pub lifetimes: Vec<(&'a str, Vec<&'a str>)>, pub lifetimes: Vec<(&'a str, Vec<&'a str>)>,
pub bounds: Vec<(&'a str, Option<ast::TyParamBound>, Vec<Path<'a>>)>, pub bounds: Vec<(&'a str, Option<ast::TraitRef>, Vec<Path<'a>>)>,
} }
impl<'a> LifetimeBounds<'a> { impl<'a> LifetimeBounds<'a> {

View file

@ -227,6 +227,10 @@ pub trait Folder {
noop_fold_trait_ref(p, self) noop_fold_trait_ref(p, self)
} }
fn fold_poly_trait_ref(&mut self, p: PolyTraitRef) -> PolyTraitRef {
noop_fold_poly_trait_ref(p, self)
}
fn fold_struct_def(&mut self, struct_def: P<StructDef>) -> P<StructDef> { fn fold_struct_def(&mut self, struct_def: P<StructDef>) -> P<StructDef> {
noop_fold_struct_def(struct_def, self) noop_fold_struct_def(struct_def, self)
} }
@ -442,7 +446,10 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
TyFixedLengthVec(ty, e) => { TyFixedLengthVec(ty, e) => {
TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e)) TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e))
} }
TyTypeof(expr) => TyTypeof(fld.fold_expr(expr)) TyTypeof(expr) => TyTypeof(fld.fold_expr(expr)),
TyPolyTraitRef(poly_trait_ref) => {
TyPolyTraitRef(poly_trait_ref.map(|p| fld.fold_poly_trait_ref(p)))
},
}, },
span: fld.new_span(span) span: fld.new_span(span)
}) })
@ -711,7 +718,7 @@ pub fn noop_fold_ty_param_bound<T>(tpb: TyParamBound, fld: &mut T)
-> TyParamBound -> TyParamBound
where T: Folder { where T: Folder {
match tpb { match tpb {
TraitTyParamBound(ty) => TraitTyParamBound(fld.fold_trait_ref(ty)), TraitTyParamBound(ty) => TraitTyParamBound(fld.fold_poly_trait_ref(ty)),
RegionTyParamBound(lifetime) => RegionTyParamBound(fld.fold_lifetime(lifetime)), RegionTyParamBound(lifetime) => RegionTyParamBound(fld.fold_lifetime(lifetime)),
} }
} }
@ -722,7 +729,7 @@ pub fn noop_fold_ty_param<T: Folder>(tp: TyParam, fld: &mut T) -> TyParam {
id: fld.new_id(id), id: fld.new_id(id),
ident: ident, ident: ident,
bounds: fld.fold_bounds(bounds), bounds: fld.fold_bounds(bounds),
unbound: unbound.map(|x| fld.fold_ty_param_bound(x)), unbound: unbound.map(|x| fld.fold_trait_ref(x)),
default: default.map(|x| fld.fold_ty(x)), default: default.map(|x| fld.fold_ty(x)),
span: span span: span
} }
@ -842,13 +849,18 @@ pub fn noop_fold_trait_ref<T: Folder>(p: TraitRef, fld: &mut T) -> TraitRef {
let id = fld.new_id(p.ref_id); let id = fld.new_id(p.ref_id);
let TraitRef { let TraitRef {
path, path,
lifetimes, ref_id: _,
..
} = p; } = p;
ast::TraitRef { ast::TraitRef {
path: fld.fold_path(path), path: fld.fold_path(path),
ref_id: id, ref_id: id,
lifetimes: fld.fold_lifetime_defs(lifetimes), }
}
pub fn noop_fold_poly_trait_ref<T: Folder>(p: PolyTraitRef, fld: &mut T) -> PolyTraitRef {
ast::PolyTraitRef {
bound_lifetimes: fld.fold_lifetime_defs(p.bound_lifetimes),
trait_ref: fld.fold_trait_ref(p.trait_ref)
} }
} }

View file

@ -42,6 +42,7 @@ use ast::{Method, MutTy, BiMul, Mutability};
use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot}; use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot};
use ast::{Pat, PatEnum, PatIdent, PatLit, PatRange, PatRegion, PatStruct}; use ast::{Pat, PatEnum, PatIdent, PatLit, PatRange, PatRegion, PatStruct};
use ast::{PatTup, PatBox, PatWild, PatWildMulti, PatWildSingle}; use ast::{PatTup, PatBox, PatWild, PatWildMulti, PatWildSingle};
use ast::{PolyTraitRef};
use ast::{QPath, RequiredMethod}; use ast::{QPath, RequiredMethod};
use ast::{RetStyle, Return, BiShl, BiShr, Stmt, StmtDecl}; use ast::{RetStyle, Return, BiShl, BiShr, Stmt, StmtDecl};
use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField}; use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField};
@ -53,7 +54,7 @@ use ast::{TtDelimited, TtSequence, TtToken};
use ast::{TupleVariantKind, Ty, Ty_, TyBot}; use ast::{TupleVariantKind, Ty, Ty_, TyBot};
use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn}; use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn};
use ast::{TyTypeof, TyInfer, TypeMethod}; use ast::{TyTypeof, TyInfer, TypeMethod};
use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPtr, TyQPath}; use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath};
use ast::{TyRptr, TyTup, TyU32, TyUniq, TyVec, UnUniq}; use ast::{TyRptr, TyTup, TyU32, TyUniq, TyVec, UnUniq};
use ast::{TypeImplItem, TypeTraitItem, Typedef, UnboxedClosureKind}; use ast::{TypeImplItem, TypeTraitItem, Typedef, UnboxedClosureKind};
use ast::{UnnamedField, UnsafeBlock}; use ast::{UnnamedField, UnsafeBlock};
@ -968,30 +969,14 @@ impl<'a> Parser<'a> {
/// Is the current token one of the keywords that signals a bare function /// Is the current token one of the keywords that signals a bare function
/// type? /// type?
pub fn token_is_bare_fn_keyword(&mut self) -> bool { pub fn token_is_bare_fn_keyword(&mut self) -> bool {
if self.token.is_keyword(keywords::Fn) { self.token.is_keyword(keywords::Fn) ||
return true self.token.is_keyword(keywords::Unsafe) ||
} self.token.is_keyword(keywords::Extern)
if self.token.is_keyword(keywords::Unsafe) ||
self.token.is_keyword(keywords::Once) {
return self.look_ahead(1, |t| t.is_keyword(keywords::Fn))
}
false
} }
/// Is the current token one of the keywords that signals a closure type? /// Is the current token one of the keywords that signals a closure type?
pub fn token_is_closure_keyword(&mut self) -> bool { pub fn token_is_closure_keyword(&mut self) -> bool {
self.token.is_keyword(keywords::Unsafe) || self.token.is_keyword(keywords::Unsafe)
self.token.is_keyword(keywords::Once)
}
/// Is the current token one of the keywords that signals an old-style
/// closure type (with explicit sigil)?
pub fn token_is_old_style_closure_keyword(&mut self) -> bool {
self.token.is_keyword(keywords::Unsafe) ||
self.token.is_keyword(keywords::Once) ||
self.token.is_keyword(keywords::Fn)
} }
pub fn get_lifetime(&mut self) -> ast::Ident { pub fn get_lifetime(&mut self) -> ast::Ident {
@ -1001,8 +986,57 @@ impl<'a> Parser<'a> {
} }
} }
pub fn parse_for_in_type(&mut self) -> Ty_ {
/*
Parses whatever can come after a `for` keyword in a type.
The `for` has already been consumed.
Deprecated:
- for <'lt> |S| -> T
- for <'lt> proc(S) -> T
Eventually:
- for <'lt> [unsafe] [extern "ABI"] fn (S) -> T
- for <'lt> path::foo(a, b)
*/
// parse <'lt>
let lifetime_defs = self.parse_late_bound_lifetime_defs();
// examine next token to decide to do
if self.eat_keyword(keywords::Proc) {
self.parse_proc_type(lifetime_defs)
} else if self.token_is_bare_fn_keyword() || self.token_is_closure_keyword() {
self.parse_ty_bare_fn_or_ty_closure(lifetime_defs)
} else if self.token == token::ModSep ||
self.token.is_ident() ||
self.token.is_path() {
let trait_ref = self.parse_trait_ref();
TyPolyTraitRef(P(PolyTraitRef { bound_lifetimes: lifetime_defs,
trait_ref: trait_ref }))
} else {
self.parse_ty_closure(lifetime_defs)
}
}
pub fn parse_ty_path(&mut self, plus_allowed: bool) -> Ty_ {
let mode = if plus_allowed {
LifetimeAndTypesAndBounds
} else {
LifetimeAndTypesWithoutColons
};
let PathAndBounds {
path,
bounds
} = self.parse_path(mode);
TyPath(path, bounds, ast::DUMMY_NODE_ID)
}
/// parse a TyBareFn type: /// parse a TyBareFn type:
pub fn parse_ty_bare_fn(&mut self) -> Ty_ { pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec<ast::LifetimeDef>) -> Ty_ {
/* /*
[unsafe] [extern "ABI"] fn <'lt> (S) -> T [unsafe] [extern "ABI"] fn <'lt> (S) -> T
@ -1023,18 +1057,26 @@ impl<'a> Parser<'a> {
}; };
self.expect_keyword(keywords::Fn); self.expect_keyword(keywords::Fn);
let (decl, lifetimes) = self.parse_ty_fn_decl(true); let lifetime_defs = self.parse_legacy_lifetime_defs(lifetime_defs);
let (inputs, variadic) = self.parse_fn_args(false, true);
let (ret_style, ret_ty) = self.parse_ret_ty();
let decl = P(FnDecl {
inputs: inputs,
output: ret_ty,
cf: ret_style,
variadic: variadic
});
TyBareFn(P(BareFnTy { TyBareFn(P(BareFnTy {
abi: abi, abi: abi,
fn_style: fn_style, fn_style: fn_style,
lifetimes: lifetimes, lifetimes: lifetime_defs,
decl: decl decl: decl
})) }))
} }
/// Parses a procedure type (`proc`). The initial `proc` keyword must /// Parses a procedure type (`proc`). The initial `proc` keyword must
/// already have been parsed. /// already have been parsed.
pub fn parse_proc_type(&mut self) -> Ty_ { pub fn parse_proc_type(&mut self, lifetime_defs: Vec<ast::LifetimeDef>) -> Ty_ {
/* /*
proc <'lt> (S) [:Bounds] -> T proc <'lt> (S) [:Bounds] -> T
@ -1043,19 +1085,12 @@ impl<'a> Parser<'a> {
| | | | Return type | | | | Return type
| | | Bounds | | | Bounds
| | Argument types | | Argument types
| Lifetimes | Legacy lifetimes
the `proc` keyword the `proc` keyword
*/ */
let lifetime_defs = if self.eat(&token::Lt) { let lifetime_defs = self.parse_legacy_lifetime_defs(lifetime_defs);
let lifetime_defs = self.parse_lifetime_defs();
self.expect_gt();
lifetime_defs
} else {
Vec::new()
};
let (inputs, variadic) = self.parse_fn_args(false, false); let (inputs, variadic) = self.parse_fn_args(false, false);
let bounds = self.parse_colon_then_ty_param_bounds(); let bounds = self.parse_colon_then_ty_param_bounds();
let (ret_style, ret_ty) = self.parse_ret_ty(); let (ret_style, ret_ty) = self.parse_ret_ty();
@ -1100,33 +1135,49 @@ impl<'a> Parser<'a> {
return None return None
} }
pub fn parse_ty_bare_fn_or_ty_closure(&mut self, lifetime_defs: Vec<LifetimeDef>) -> Ty_ {
// Both bare fns and closures can begin with stuff like unsafe
// and extern. So we just scan ahead a few tokens to see if we see
// a `fn`.
//
// Closure: [unsafe] <'lt> |S| [:Bounds] -> T
// Fn: [unsafe] [extern "ABI"] fn <'lt> (S) -> T
if self.token.is_keyword(keywords::Fn) {
self.parse_ty_bare_fn(lifetime_defs)
} else if self.token.is_keyword(keywords::Extern) {
self.parse_ty_bare_fn(lifetime_defs)
} else if self.token.is_keyword(keywords::Unsafe) {
if self.look_ahead(1, |t| t.is_keyword(keywords::Fn) ||
t.is_keyword(keywords::Extern)) {
self.parse_ty_bare_fn(lifetime_defs)
} else {
self.parse_ty_closure(lifetime_defs)
}
} else {
self.parse_ty_closure(lifetime_defs)
}
}
/// Parse a TyClosure type /// Parse a TyClosure type
pub fn parse_ty_closure(&mut self) -> Ty_ { pub fn parse_ty_closure(&mut self, lifetime_defs: Vec<ast::LifetimeDef>) -> Ty_ {
/* /*
[unsafe] [once] <'lt> |S| [:Bounds] -> T [unsafe] <'lt> |S| [:Bounds] -> T
^~~~~~~^ ^~~~~^ ^~~~^ ^ ^~~~~~~~^ ^ ^~~~~~~^ ^~~~^ ^ ^~~~~~~~^ ^
| | | | | | | | | | |
| | | | | Return type | | | | Return type
| | | | Closure bounds | | | Closure bounds
| | | Argument types | | Argument types
| | Lifetime defs | Deprecated lifetime defs
| Once-ness (a.k.a., affine) |
Function Style Function Style
*/ */
let fn_style = self.parse_unsafety(); let fn_style = self.parse_unsafety();
let onceness = if self.eat_keyword(keywords::Once) {Once} else {Many};
let lifetime_defs = if self.eat(&token::Lt) { let lifetime_defs = self.parse_legacy_lifetime_defs(lifetime_defs);
let lifetime_defs = self.parse_lifetime_defs();
self.expect_gt();
lifetime_defs
} else {
Vec::new()
};
let inputs = if self.eat(&token::OrOr) { let inputs = if self.eat(&token::OrOr) {
Vec::new() Vec::new()
@ -1152,7 +1203,7 @@ impl<'a> Parser<'a> {
TyClosure(P(ClosureTy { TyClosure(P(ClosureTy {
fn_style: fn_style, fn_style: fn_style,
onceness: onceness, onceness: Many,
bounds: bounds, bounds: bounds,
decl: decl, decl: decl,
lifetimes: lifetime_defs, lifetimes: lifetime_defs,
@ -1167,36 +1218,23 @@ impl<'a> Parser<'a> {
} }
} }
/// Parse a function type (following the 'fn') /// Parses `[ 'for' '<' lifetime_defs '>' ]'
pub fn parse_ty_fn_decl(&mut self, allow_variadic: bool) fn parse_legacy_lifetime_defs(&mut self,
-> (P<FnDecl>, Vec<ast::LifetimeDef>) { lifetime_defs: Vec<ast::LifetimeDef>)
/* -> Vec<ast::LifetimeDef>
{
(fn) <'lt> (S) -> T if self.eat(&token::Lt) {
^~~~^ ^~^ ^ if lifetime_defs.is_empty() {
| | | self.warn("deprecated syntax, use `for` keyword now");
| | Return type let lifetime_defs = self.parse_lifetime_defs();
| Argument types self.expect_gt();
Lifetime_defs lifetime_defs
} else {
*/ self.fatal("cannot use new `for` keyword and older syntax together");
let lifetime_defs = if self.eat(&token::Lt) { }
let lifetime_defs = self.parse_lifetime_defs();
self.expect_gt();
lifetime_defs
} else { } else {
Vec::new() lifetime_defs
}; }
let (inputs, variadic) = self.parse_fn_args(false, allow_variadic);
let (ret_style, ret_ty) = self.parse_ret_ty();
let decl = P(FnDecl {
inputs: inputs,
output: ret_ty,
cf: ret_style,
variadic: variadic
});
(decl, lifetime_defs)
} }
/// Parses `type Foo;` in a trait declaration only. The `type` keyword has /// Parses `type Foo;` in a trait declaration only. The `type` keyword has
@ -1433,25 +1471,24 @@ impl<'a> Parser<'a> {
self.expect(&token::CloseDelim(token::Bracket)); self.expect(&token::CloseDelim(token::Bracket));
t t
} else if self.token == token::BinOp(token::And) || } else if self.token == token::BinOp(token::And) ||
self.token == token::AndAnd { self.token == token::AndAnd {
// BORROWED POINTER // BORROWED POINTER
self.expect_and(); self.expect_and();
self.parse_borrowed_pointee() self.parse_borrowed_pointee()
} else if self.token.is_keyword(keywords::Extern) || } else if self.token.is_keyword(keywords::For) {
self.token.is_keyword(keywords::Unsafe) || self.parse_for_in_type()
self.token_is_bare_fn_keyword() { } else if self.token_is_bare_fn_keyword() ||
// BARE FUNCTION self.token_is_closure_keyword() {
self.parse_ty_bare_fn() // BARE FUNCTION OR CLOSURE
} else if self.token_is_closure_keyword() || self.parse_ty_bare_fn_or_ty_closure(Vec::new())
self.token == token::BinOp(token::Or) || } else if self.token == token::BinOp(token::Or) ||
self.token == token::OrOr || self.token == token::OrOr ||
(self.token == token::Lt && (self.token == token::Lt &&
self.look_ahead(1, |t| { self.look_ahead(1, |t| {
*t == token::Gt || t.is_lifetime() *t == token::Gt || t.is_lifetime()
})) { })) {
// CLOSURE // CLOSURE
self.parse_ty_closure(Vec::new())
self.parse_ty_closure()
} else if self.eat_keyword(keywords::Typeof) { } else if self.eat_keyword(keywords::Typeof) {
// TYPEOF // TYPEOF
// In order to not be ambiguous, the type must be surrounded by parens. // In order to not be ambiguous, the type must be surrounded by parens.
@ -1460,7 +1497,7 @@ impl<'a> Parser<'a> {
self.expect(&token::CloseDelim(token::Paren)); self.expect(&token::CloseDelim(token::Paren));
TyTypeof(e) TyTypeof(e)
} else if self.eat_keyword(keywords::Proc) { } else if self.eat_keyword(keywords::Proc) {
self.parse_proc_type() self.parse_proc_type(Vec::new())
} else if self.token == token::Lt { } else if self.token == token::Lt {
// QUALIFIED PATH // QUALIFIED PATH
self.bump(); self.bump();
@ -1479,16 +1516,7 @@ impl<'a> Parser<'a> {
self.token.is_ident() || self.token.is_ident() ||
self.token.is_path() { self.token.is_path() {
// NAMED TYPE // NAMED TYPE
let mode = if plus_allowed { self.parse_ty_path(plus_allowed)
LifetimeAndTypesAndBounds
} else {
LifetimeAndTypesWithoutColons
};
let PathAndBounds {
path,
bounds
} = self.parse_path(mode);
TyPath(path, bounds, ast::DUMMY_NODE_ID)
} else if self.eat(&token::Underscore) { } else if self.eat(&token::Underscore) {
// TYPE TO BE INFERRED // TYPE TO BE INFERRED
TyInfer TyInfer
@ -3848,29 +3876,17 @@ impl<'a> Parser<'a> {
} }
// matches bounds = ( boundseq )? // matches bounds = ( boundseq )?
// where boundseq = ( bound + boundseq ) | bound // where boundseq = ( polybound + boundseq ) | polybound
// and bound = 'region | ty // and polybound = ( 'for' '<' 'region '>' )? bound
// and bound = 'region | trait_ref
// NB: The None/Some distinction is important for issue #7264. // NB: The None/Some distinction is important for issue #7264.
fn parse_ty_param_bounds(&mut self) fn parse_ty_param_bounds(&mut self)
-> OwnedSlice<TyParamBound> -> OwnedSlice<TyParamBound>
{ {
let mut result = vec!(); let mut result = vec!();
loop { loop {
let lifetime_defs = if self.eat(&token::Lt) {
let lifetime_defs = self.parse_lifetime_defs();
self.expect_gt();
lifetime_defs
} else {
Vec::new()
};
match self.token { match self.token {
token::Lifetime(lifetime) => { token::Lifetime(lifetime) => {
if lifetime_defs.len() > 0 {
let span = self.last_span;
self.span_err(span, "lifetime declarations are not \
allowed here")
}
result.push(RegionTyParamBound(ast::Lifetime { result.push(RegionTyParamBound(ast::Lifetime {
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
span: self.span, span: self.span,
@ -3879,13 +3895,8 @@ impl<'a> Parser<'a> {
self.bump(); self.bump();
} }
token::ModSep | token::Ident(..) => { token::ModSep | token::Ident(..) => {
let path = let poly_trait_ref = self.parse_poly_trait_ref();
self.parse_path(LifetimeAndTypesWithoutColons).path; result.push(TraitTyParamBound(poly_trait_ref))
result.push(TraitTyParamBound(ast::TraitRef {
path: path,
ref_id: ast::DUMMY_NODE_ID,
lifetimes: lifetime_defs,
}))
} }
_ => break, _ => break,
} }
@ -3898,7 +3909,7 @@ impl<'a> Parser<'a> {
return OwnedSlice::from_vec(result); return OwnedSlice::from_vec(result);
} }
fn trait_ref_from_ident(ident: Ident, span: Span) -> ast::TraitRef { fn trait_ref_from_ident(ident: Ident, span: Span) -> TraitRef {
let segment = ast::PathSegment { let segment = ast::PathSegment {
identifier: ident, identifier: ident,
parameters: ast::PathParameters::none() parameters: ast::PathParameters::none()
@ -3911,7 +3922,6 @@ impl<'a> Parser<'a> {
ast::TraitRef { ast::TraitRef {
path: path, path: path,
ref_id: ast::DUMMY_NODE_ID, ref_id: ast::DUMMY_NODE_ID,
lifetimes: Vec::new(),
} }
} }
@ -3927,7 +3937,7 @@ impl<'a> Parser<'a> {
let mut unbound = None; let mut unbound = None;
if self.eat(&token::Question) { if self.eat(&token::Question) {
let tref = Parser::trait_ref_from_ident(ident, span); let tref = Parser::trait_ref_from_ident(ident, span);
unbound = Some(TraitTyParamBound(tref)); unbound = Some(tref);
span = self.span; span = self.span;
ident = self.parse_ident(); ident = self.parse_ident();
} }
@ -4538,7 +4548,6 @@ impl<'a> Parser<'a> {
Some(TraitRef { Some(TraitRef {
path: (*path).clone(), path: (*path).clone(),
ref_id: node_id, ref_id: node_id,
lifetimes: Vec::new(),
}) })
} }
TyPath(_, Some(_), _) => { TyPath(_, Some(_), _) => {
@ -4568,6 +4577,35 @@ impl<'a> Parser<'a> {
Some(attrs)) Some(attrs))
} }
/// Parse a::B<String,int>
fn parse_trait_ref(&mut self) -> TraitRef {
ast::TraitRef {
path: self.parse_path(LifetimeAndTypesWithoutColons).path,
ref_id: ast::DUMMY_NODE_ID,
}
}
fn parse_late_bound_lifetime_defs(&mut self) -> Vec<ast::LifetimeDef> {
if self.eat_keyword(keywords::For) {
self.expect(&token::Lt);
let lifetime_defs = self.parse_lifetime_defs();
self.expect_gt();
lifetime_defs
} else {
Vec::new()
}
}
/// Parse for<'l> a::B<String,int>
fn parse_poly_trait_ref(&mut self) -> PolyTraitRef {
let lifetime_defs = self.parse_late_bound_lifetime_defs();
ast::PolyTraitRef {
bound_lifetimes: lifetime_defs,
trait_ref: self.parse_trait_ref()
}
}
/// Parse struct Foo { ... } /// Parse struct Foo { ... }
fn parse_item_struct(&mut self) -> ItemInfo { fn parse_item_struct(&mut self) -> ItemInfo {
let class_name = self.parse_ident(); let class_name = self.parse_ident();
@ -4681,7 +4719,7 @@ impl<'a> Parser<'a> {
else { Inherited } else { Inherited }
} }
fn parse_for_sized(&mut self) -> Option<ast::TyParamBound> { fn parse_for_sized(&mut self) -> Option<ast::TraitRef> {
if self.eat_keyword(keywords::For) { if self.eat_keyword(keywords::For) {
let span = self.span; let span = self.span;
let ident = self.parse_ident(); let ident = self.parse_ident();
@ -4691,7 +4729,7 @@ impl<'a> Parser<'a> {
return None; return None;
} }
let tref = Parser::trait_ref_from_ident(ident, span); let tref = Parser::trait_ref_from_ident(ident, span);
Some(TraitTyParamBound(tref)) Some(tref)
} else { } else {
None None
} }

View file

@ -743,6 +743,9 @@ impl<'a> State<'a> {
ast::TyPath(ref path, ref bounds, _) => { ast::TyPath(ref path, ref bounds, _) => {
try!(self.print_bounded_path(path, bounds)); try!(self.print_bounded_path(path, bounds));
} }
ast::TyPolyTraitRef(ref poly_trait_ref) => {
try!(self.print_poly_trait_ref(&**poly_trait_ref));
}
ast::TyQPath(ref qpath) => { ast::TyQPath(ref qpath) => {
try!(word(&mut self.s, "<")); try!(word(&mut self.s, "<"));
try!(self.print_type(&*qpath.for_type)); try!(self.print_type(&*qpath.for_type));
@ -960,7 +963,7 @@ impl<'a> State<'a> {
try!(self.print_ident(item.ident)); try!(self.print_ident(item.ident));
try!(self.print_generics(generics)); try!(self.print_generics(generics));
match unbound { match unbound {
&Some(TraitTyParamBound(ref tref)) => { &Some(ref tref) => {
try!(space(&mut self.s)); try!(space(&mut self.s));
try!(self.word_space("for")); try!(self.word_space("for"));
try!(self.print_trait_ref(tref)); try!(self.print_trait_ref(tref));
@ -995,19 +998,21 @@ impl<'a> State<'a> {
} }
fn print_trait_ref(&mut self, t: &ast::TraitRef) -> IoResult<()> { fn print_trait_ref(&mut self, t: &ast::TraitRef) -> IoResult<()> {
if t.lifetimes.len() > 0 {
try!(self.print_generics(&ast::Generics {
lifetimes: t.lifetimes.clone(),
ty_params: OwnedSlice::empty(),
where_clause: ast::WhereClause {
id: ast::DUMMY_NODE_ID,
predicates: Vec::new(),
},
}));
}
self.print_path(&t.path, false) self.print_path(&t.path, false)
} }
fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) -> IoResult<()> {
if !t.bound_lifetimes.is_empty() {
try!(word(&mut self.s, "for<"));
for lifetime_def in t.bound_lifetimes.iter() {
try!(self.print_lifetime_def(lifetime_def));
}
try!(word(&mut self.s, ">"));
}
self.print_trait_ref(&t.trait_ref)
}
pub fn print_enum_def(&mut self, enum_definition: &ast::EnumDef, pub fn print_enum_def(&mut self, enum_definition: &ast::EnumDef,
generics: &ast::Generics, ident: ast::Ident, generics: &ast::Generics, ident: ast::Ident,
span: codemap::Span, span: codemap::Span,
@ -2383,7 +2388,7 @@ impl<'a> State<'a> {
try!(match *bound { try!(match *bound {
TraitTyParamBound(ref tref) => { TraitTyParamBound(ref tref) => {
self.print_trait_ref(tref) self.print_poly_trait_ref(tref)
} }
RegionTyParamBound(ref lt) => { RegionTyParamBound(ref lt) => {
self.print_lifetime(lt) self.print_lifetime(lt)
@ -2450,7 +2455,7 @@ impl<'a> State<'a> {
pub fn print_ty_param(&mut self, param: &ast::TyParam) -> IoResult<()> { pub fn print_ty_param(&mut self, param: &ast::TyParam) -> IoResult<()> {
match param.unbound { match param.unbound {
Some(TraitTyParamBound(ref tref)) => { Some(ref tref) => {
try!(self.print_trait_ref(tref)); try!(self.print_trait_ref(tref));
try!(self.word_space("?")); try!(self.word_space("?"));
} }

View file

@ -75,6 +75,10 @@ pub trait Visitor<'v> {
} }
fn visit_ty_method(&mut self, t: &'v TypeMethod) { walk_ty_method(self, t) } fn visit_ty_method(&mut self, t: &'v TypeMethod) { walk_ty_method(self, t) }
fn visit_trait_item(&mut self, t: &'v TraitItem) { walk_trait_item(self, t) } fn visit_trait_item(&mut self, t: &'v TraitItem) { walk_trait_item(self, t) }
fn visit_trait_ref(&mut self, t: &'v TraitRef) { walk_trait_ref(self, t) }
fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef) {
walk_poly_trait_ref(self, t)
}
fn visit_struct_def(&mut self, s: &'v StructDef, _: Ident, _: &'v Generics, _: NodeId) { fn visit_struct_def(&mut self, s: &'v StructDef, _: Ident, _: &'v Generics, _: NodeId) {
walk_struct_def(self, s) walk_struct_def(self, s)
} }
@ -202,9 +206,20 @@ pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V,
/// Like with walk_method_helper this doesn't correspond to a method /// Like with walk_method_helper this doesn't correspond to a method
/// in Visitor, and so it gets a _helper suffix. /// in Visitor, and so it gets a _helper suffix.
pub fn walk_trait_ref_helper<'v,V>(visitor: &mut V, trait_ref: &'v TraitRef) pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V,
where V: Visitor<'v> { trait_ref: &'v PolyTraitRef)
walk_lifetime_decls(visitor, &trait_ref.lifetimes); where V: Visitor<'v>
{
walk_lifetime_decls(visitor, &trait_ref.bound_lifetimes);
visitor.visit_trait_ref(&trait_ref.trait_ref);
}
/// Like with walk_method_helper this doesn't correspond to a method
/// in Visitor, and so it gets a _helper suffix.
pub fn walk_trait_ref<'v,V>(visitor: &mut V,
trait_ref: &'v TraitRef)
where V: Visitor<'v>
{
visitor.visit_path(&trait_ref.path, trait_ref.ref_id) visitor.visit_path(&trait_ref.path, trait_ref.ref_id)
} }
@ -248,8 +263,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
ref impl_items) => { ref impl_items) => {
visitor.visit_generics(type_parameters); visitor.visit_generics(type_parameters);
match *trait_reference { match *trait_reference {
Some(ref trait_reference) => walk_trait_ref_helper(visitor, Some(ref trait_reference) => visitor.visit_trait_ref(trait_reference),
trait_reference),
None => () None => ()
} }
visitor.visit_ty(&**typ); visitor.visit_ty(&**typ);
@ -383,6 +397,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
visitor.visit_ty(&**ty); visitor.visit_ty(&**ty);
visitor.visit_expr(&**expression) visitor.visit_expr(&**expression)
} }
TyPolyTraitRef(ref poly_trait_ref) => {
visitor.visit_poly_trait_ref(&**poly_trait_ref)
}
TyTypeof(ref expression) => { TyTypeof(ref expression) => {
visitor.visit_expr(&**expression) visitor.visit_expr(&**expression)
} }
@ -497,7 +514,7 @@ pub fn walk_ty_param_bounds<'v, V: Visitor<'v>>(visitor: &mut V,
for bound in bounds.iter() { for bound in bounds.iter() {
match *bound { match *bound {
TraitTyParamBound(ref typ) => { TraitTyParamBound(ref typ) => {
walk_trait_ref_helper(visitor, typ) visitor.visit_poly_trait_ref(typ)
} }
RegionTyParamBound(ref lifetime) => { RegionTyParamBound(ref lifetime) => {
visitor.visit_lifetime_ref(lifetime); visitor.visit_lifetime_ref(lifetime);

View file

@ -9,7 +9,7 @@
// except according to those terms. // except according to those terms.
fn test<'x>(x: &'x int) { fn test<'x>(x: &'x int) {
drop::< <'z>|&'z int| -> &'z int >(|z| { drop::< for<'z>|&'z int| -> &'z int >(|z| {
x x
//~^ ERROR cannot infer an appropriate lifetime //~^ ERROR cannot infer an appropriate lifetime
}); });

View file

@ -22,11 +22,11 @@
struct S; struct S;
// Given 'cx, return 'cx // Given 'cx, return 'cx
type F = fn<'cx>(&'cx S) -> &'cx S; type F = for<'cx> fn(&'cx S) -> &'cx S;
fn want_F(f: F) { } fn want_F(f: F) { }
// Given anything, return 'static // Given anything, return 'static
type G = fn<'cx>(&'cx S) -> &'static S; type G = for<'cx> fn(&'cx S) -> &'static S;
fn want_G(f: G) { } fn want_G(f: G) { }
// Should meet both. // Should meet both.

View file

@ -17,29 +17,29 @@ fn test_fn<'x,'y,'z,T>(_x: &'x T, _y: &'y T, _z: &'z T) {
// subtype::<T1>(of::<T2>()) will typecheck // subtype::<T1>(of::<T2>()) will typecheck
// iff T1 <: T2. // iff T1 <: T2.
subtype::< <'a>|&'a T|>( subtype::< for<'a>|&'a T|>(
of::< <'a>|&'a T|>()); of::< for<'a>|&'a T|>());
subtype::< <'a>|&'a T|>( subtype::< for<'a>|&'a T|>(
of::< <'b>|&'b T|>()); of::< for<'b>|&'b T|>());
subtype::< <'b>|&'b T|>( subtype::< for<'b>|&'b T|>(
of::<|&'x T|>()); of::<|&'x T|>());
subtype::<|&'x T|>( subtype::<|&'x T|>(
of::< <'b>|&'b T|>()); //~ ERROR mismatched types of::< for<'b>|&'b T|>()); //~ ERROR mismatched types
subtype::< <'a,'b>|&'a T, &'b T|>( subtype::< for<'a,'b>|&'a T, &'b T|>(
of::< <'a>|&'a T, &'a T|>()); of::< for<'a>|&'a T, &'a T|>());
subtype::< <'a>|&'a T, &'a T|>( subtype::< for<'a>|&'a T, &'a T|>(
of::< <'a,'b>|&'a T, &'b T|>()); //~ ERROR mismatched types of::< for<'a,'b>|&'a T, &'b T|>()); //~ ERROR mismatched types
subtype::< <'a,'b>|&'a T, &'b T|>( subtype::< for<'a,'b>|&'a T, &'b T|>(
of::<|&'x T, &'y T|>()); of::<|&'x T, &'y T|>());
subtype::<|&'x T, &'y T|>( subtype::<|&'x T, &'y T|>(
of::< <'a,'b>|&'a T, &'b T|>()); //~ ERROR mismatched types of::< for<'a,'b>|&'a T, &'b T|>()); //~ ERROR mismatched types
} }
fn main() {} fn main() {}

View file

@ -43,16 +43,16 @@ fn bar<'a>(x: &'a int) {
// &'a CAN be declared on functions and used then: // &'a CAN be declared on functions and used then:
fn g<'a>(a: &'a int) { } // OK fn g<'a>(a: &'a int) { } // OK
fn h(a: <'a>|&'a int|) { } // OK fn h(a: for<'a>|&'a int|) { } // OK
} }
// Test nesting of lifetimes in fn type declarations // Test nesting of lifetimes in fn type declarations
fn fn_types(a: &'a int, //~ ERROR undeclared lifetime fn fn_types(a: &'a int, //~ ERROR undeclared lifetime
b: <'a>|a: &'a int, b: for<'a>|a: &'a int,
b: &'b int, //~ ERROR undeclared lifetime b: &'b int, //~ ERROR undeclared lifetime
c: <'b>|a: &'a int, c: for<'b>|a: &'a int,
b: &'b int|, b: &'b int|,
d: &'b int|, //~ ERROR undeclared lifetime d: &'b int|, //~ ERROR undeclared lifetime
c: &'a int) //~ ERROR undeclared lifetime c: &'a int) //~ ERROR undeclared lifetime
{ {
} }

View file

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
fn ignore(_f: <'z>|&'z int| -> &'z int) {} fn ignore(_f: for<'z>|&'z int| -> &'z int) {}
fn nested() { fn nested() {
let y = 3; let y = 3;

View file

@ -14,13 +14,13 @@ fn nested<'x>(x: &'x int) {
let y = 3; let y = 3;
let mut ay = &y; //~ ERROR cannot infer let mut ay = &y; //~ ERROR cannot infer
ignore::< <'z>|&'z int|>(|z| { ignore::< for<'z>|&'z int|>(|z| {
ay = x; ay = x;
ay = &y; ay = &y;
ay = z; ay = z;
}); });
ignore::< <'z>|&'z int| -> &'z int>(|z| { ignore::< for<'z>|&'z int| -> &'z int>(|z| {
if false { return x; } //~ ERROR cannot infer an appropriate lifetime for automatic if false { return x; } //~ ERROR cannot infer an appropriate lifetime for automatic
if false { return ay; } if false { return ay; }
return z; return z;

View file

@ -12,7 +12,7 @@
// some point regions-ret-borrowed reported an error but this file did // some point regions-ret-borrowed reported an error but this file did
// not, due to special hardcoding around the anonymous region. // not, due to special hardcoding around the anonymous region.
fn with<R>(f: <'a>|x: &'a int| -> R) -> R { fn with<R>(f: for<'a>|x: &'a int| -> R) -> R {
f(&3) f(&3)
} }

View file

@ -0,0 +1,48 @@
// 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.
// Test that we can parse all the various places that a `for` keyword
// can appear representing universal quantification.
#![allow(unused_variables)]
#![allow(dead_code)]
trait Get<A,R> {
fn get(&self, arg: A) -> R;
}
// Parse HRTB with explicit `for` in a where-clause:
fn foo00<T>(t: T)
where T : for<'a> Get<&'a int, &'a int>
{
}
fn foo01<T: for<'a> Get<&'a int, &'a int>>(t: T)
{
}
// Parse HRTB with explicit `for` in various sorts of types:
fn foo10(t: Box<for<'a> Get<int, int>>) { }
fn foo11(t: Box<for<'a> Get(int) -> int>) { }
fn foo20(t: for<'a> fn(int) -> int) { }
fn foo21(t: for<'a> unsafe fn(int) -> int) { }
fn foo22(t: for<'a> extern "C" fn(int) -> int) { }
fn foo23(t: for<'a> unsafe extern "C" fn(int) -> int) { }
fn foo30(t: for<'a> |int| -> int) { }
fn foo31(t: for<'a> unsafe |int| -> int) { }
//fn foo40(t: for<'a> proc(int) -> int) { }
fn main() {
}

View file

@ -29,7 +29,7 @@ static FOO: int = 0xDEADBEE;
pub fn main() { pub fn main() {
unsafe { unsafe {
let f: extern "C" fn<'a>(&'a int) -> &'a int = mem::transmute(foo); let f: for<'a> extern "C" fn(&'a int) -> &'a int = mem::transmute(foo);
assert_eq!(*f(&FOO), FOO); assert_eq!(*f(&FOO), FOO);
} }
} }