diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2014-11-07 06:53:45 -0500 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2014-11-07 15:51:30 -0500 |
| commit | 244231720d29db856c5a28c0dda6c2efd7c9219a (patch) | |
| tree | 41648e7c6c16102a7a602be441b4f1cdad8e7411 | |
| parent | c18a1327e3ccf02ae9f755ca280d53177eeb298d (diff) | |
Update parser with `for` syntax
28 files changed, 544 insertions, 405 deletions
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 2858a830081..6f1287014d7 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1690,8 +1690,8 @@ impl LintPass for Stability { for t in supertraits.iter() { match *t { ast::TraitTyParamBound(ref t) => { - let id = ty::trait_ref_to_def_id(cx.tcx, t); - self.lint(cx, id, t.path.span); + let id = ty::trait_ref_to_def_id(cx.tcx, &t.trait_ref); + self.lint(cx, id, t.trait_ref.path.span); } _ => (/* pass */) } diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 21b94babcb6..eddd616e616 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -1291,7 +1291,7 @@ impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> { match *ty_param_bound { ast::TraitTyParamBound(ref trait_ref) => { 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, "private type in exported type \ 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 // call here. - visit::walk_trait_ref_helper(self, tr) + self.visit_trait_ref(tr) } } } else if trait_ref.is_none() && self_is_public_path { diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index a1a8cccf55a..62d1e13d41f 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -33,12 +33,12 @@ use syntax::ast::{ItemTrait, ItemTy, LOCAL_CRATE, Local, ItemConst}; use syntax::ast::{MethodImplItem, Mod, Name, NamedField, NodeId}; use syntax::ast::{Pat, PatEnum, PatIdent, PatLit}; 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::{StructVariantKind, TraitRef, TraitTyParamBound}; use syntax::ast::{TupleVariantKind, Ty, TyBool, TyChar, TyClosure, TyF32}; 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::{TypeImplItem, UnnamedField}; use syntax::ast::{Variant, ViewItem, ViewItemExternCrate}; @@ -607,6 +607,7 @@ enum TraitReferenceType { TraitImplementation, // impl SomeTrait for T { ... } TraitDerivation, // trait T : SomeTrait { ... } TraitBoundingTypeParameter, // fn f<T:SomeTrait>() { ... } + TraitObject, // Box<for<'a> SomeTrait> } impl NameBindings { @@ -4244,11 +4245,11 @@ impl<'a> Resolver<'a> { this.resolve_type_parameter_bounds(item.id, bounds, TraitDerivation); - match unbound { - &Some(ast::TraitTyParamBound(ref tpb)) => { + match *unbound { + Some(ref tpb) => { this.resolve_trait_reference(item.id, tpb, TraitDerivation); } - _ => {} + None => {} } for trait_item in (*trait_items).iter() { @@ -4495,7 +4496,7 @@ impl<'a> Resolver<'a> { } match &type_parameter.unbound { &Some(ref unbound) => - self.resolve_type_parameter_bound( + self.resolve_trait_reference( type_parameter.id, unbound, TraitBoundingTypeParameter), &None => {} } @@ -4521,12 +4522,19 @@ impl<'a> Resolver<'a> { reference_type: TraitReferenceType) { match *type_parameter_bound { TraitTyParamBound(ref tref) => { - self.resolve_trait_reference(id, tref, reference_type) + self.resolve_poly_trait_reference(id, tref, reference_type) } 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, id: NodeId, trait_reference: &TraitRef, @@ -4538,6 +4546,7 @@ impl<'a> Resolver<'a> { TraitBoundingTypeParameter => "bound type parameter with", TraitImplementation => "implement", TraitDerivation => "derive", + TraitObject => "reference", }; 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); } + 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. visit::walk_ty(self, ty); diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 8246970c24a..8ac52b891b9 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -19,6 +19,7 @@ use driver::session::Session; use middle::subst; +use std::fmt; use syntax::ast; use syntax::codemap::Span; use syntax::owned_slice::OwnedSlice; @@ -46,18 +47,12 @@ pub enum DefRegion { // that it corresponds to 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> { sess: &'a Session, named_region_map: &'a mut NamedRegionMap, scope: Scope<'a> } -#[deriving(Show)] enum ScopeChain<'a> { /// EarlyScope(i, ['a, 'b, ...], s) extends s with early-bound /// 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> { fn visit_item(&mut self, item: &ast::Item) { - let lifetimes = match item.node { - ast::ItemFn(..) | // fn lifetimes get added in visit_fn below + match item.node { + ast::ItemFn(..) => { + // Fn lifetimes get added in visit_fn below: + self.with(RootScope, |this| visit::walk_item(this, item)); + } ast::ItemMod(..) | ast::ItemMac(..) | ast::ItemForeignMod(..) | - ast::ItemStatic(..) | ast::ItemConst(..) => { - self.with(|_, f| f(RootScope), |v| visit::walk_item(v, item)); - return; + ast::ItemStatic(..) | + ast::ItemConst(..) => { + // These sorts of items have no lifetime parameters at all. + self.with(RootScope, |this| visit::walk_item(this, item)); } ast::ItemTy(_, ref generics) | ast::ItemEnum(_, ref generics) | ast::ItemStruct(_, 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::ItemTrait(ref generics, _, _, _) | ast::ItemImpl(ref generics, _, _, _) => { - self.with(|scope, f| { - f(EarlyScope(subst::TypeSpace, - &generics.lifetimes, - scope)) - }, |v| v.check_lifetime_defs(&generics.lifetimes)); - &generics.lifetimes + // These kinds of items have only early bound lifetime parameters. + let lifetimes = &generics.lifetimes; + self.with(EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE), |this| { + this.check_lifetime_defs(lifetimes); + visit::walk_item(this, item); + }); } - }; - - 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, @@ -131,7 +116,9 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { match fk { visit::FkItemFn(_, 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::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) }; - self.with(|scope, f| f(LateScope(ty.id, lifetimes, scope)), |v| { - v.check_lifetime_defs(lifetimes); - debug!("pushing fn scope id={} due to type", ty.id); - visit::walk_ty(v, ty); - debug!("popping fn scope id={} due to type", ty.id); + self.with(LateScope(ty.id, lifetimes, self.scope), |this| { + this.check_lifetime_defs(lifetimes); + visit::walk_ty(this, ty); }); } 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) { - debug!("pushing block scope {}", b.id); - self.with(|scope, f| f(BlockScope(b.id, scope)), |v| visit::walk_block(v, b)); - debug!("popping block scope {}", b.id); + self.with(BlockScope(b.id, self.scope), |this| visit::walk_block(this, b)); } 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> { - fn with(&mut self, wrap_scope: |Scope, |ScopeChain||, f: |&mut LifetimeContext|) { - let LifetimeContext { sess, ref mut named_region_map, scope} = *self; - wrap_scope(scope, |scope1| f(&mut LifetimeContext { + fn with(&mut self, wrap_scope: ScopeChain, f: |&mut LifetimeContext|) { + let LifetimeContext {sess, ref mut named_region_map, ..} = *self; + let mut this = LifetimeContext { sess: sess, 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, @@ -202,7 +190,7 @@ impl<'a> LifetimeContext<'a> { for bound in bounds.iter() { match *bound { ast::TraitTyParamBound(ref trait_ref) => { - self.visit_trait_ref(trait_ref); + self.visit_poly_trait_ref(trait_ref); } ast::RegionTyParamBound(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) { - self.with(|scope, f| { - f(LateScope(trait_ref.ref_id, &trait_ref.lifetimes, scope)) - }, |v| { - v.check_lifetime_defs(&trait_ref.lifetimes); - for lifetime in trait_ref.lifetimes.iter() { - v.visit_lifetime_decl(lifetime); + fn visit_poly_trait_ref(&mut self, trait_ref: &ast::PolyTraitRef) { + let ref_id = trait_ref.trait_ref.ref_id; + self.with(LateScope(ref_id, &trait_ref.bound_lifetimes, self.scope), |this| { + this.check_lifetime_defs(&trait_ref.bound_lifetimes); + for lifetime in trait_ref.bound_lifetimes.iter() { + this.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`. - fn visit_fn_decl(&mut self, - n: ast::NodeId, - generics: &ast::Generics, - walk: |&mut LifetimeContext|) { + fn visit_early_late(&mut self, + early_space: subst::ParamSpace, + binder_id: ast::NodeId, + generics: &ast::Generics, + walk: |&mut LifetimeContext|) { /*! * Handles visiting fns and methods. These are a bit * 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 * is already in scope (for a fn item, that will be 0, but for * 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. */ 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| { - v.with(|scope1, f| f(LateScope(n, &late, scope1)), |v| { - v.check_lifetime_defs(lifetimes); - walk(v); - }); + + debug!("visit_early_late: binder_id={} referenced_idents={}", + binder_id, + referenced_idents); + + 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) { @@ -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"), + } + } +} diff --git a/src/librustc/middle/save/mod.rs b/src/librustc/middle/save/mod.rs index b64a160ab1f..a2b80686d01 100644 --- a/src/librustc/middle/save/mod.rs +++ b/src/librustc/middle/save/mod.rs @@ -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) { Some(id) => { 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() { match *bound { ast::TraitTyParamBound(ref trait_ref) => { - self.process_trait_ref(trait_ref, None); + self.process_trait_ref(&trait_ref.trait_ref, None); } _ => {} } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 3e8a7bb842c..1a6e8eeb320 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -5546,7 +5546,8 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>, ty_param(_) | ty_infer(_) | ty_open(_) | - ty_err => {} + ty_err => { + } } }); diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 6430362f9cd..e27ff636a2a 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -51,8 +51,6 @@ use middle::const_eval; use middle::def; -use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem}; -use middle::lang_items::{FnOnceTraitLangItem}; use middle::resolve_lifetime as rl; use middle::subst::{FnSpace, TypeSpace, AssocSpace, SelfSpace, Subst, Substs}; 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, rscope: &RS, trait_def_id: ast::DefId, @@ -620,41 +658,6 @@ enum PointerTy { 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. // If a_seq_ty is a str or a vec, make it a str/vec. // 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) } + 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) => { let a_def = match tcx.def_map.borrow().get(&id) { None => { @@ -1536,6 +1549,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt, for &ast_bound in ast_bounds.iter() { match *ast_bound { ast::TraitTyParamBound(ref b) => { + let b = &b.trait_ref; // FIXME match lookup_def_tcx(tcx, b.path.span, b.ref_id) { def::DefTrait(trait_did) => { match trait_def_ids.get(&trait_did) { diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index d365c54c701..42411b598bf 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -61,7 +61,6 @@ use syntax::ast_util::{local_def, PostExpansionMethod}; use syntax::codemap::Span; use syntax::parse::token::{special_idents}; use syntax::parse::token; -use syntax::print::pprust::{path_to_string}; use syntax::ptr::P; use syntax::visit; @@ -633,24 +632,33 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, span: Span, generics: &ast::Generics, thing: &'static str) { + let mut warn = false; + for ty_param in generics.ty_params.iter() { - let bounds = ty_param.bounds.iter(); - let mut bounds = bounds.chain(ty_param.unbound.iter()); - for bound in bounds { + for bound in ty_param.bounds.iter() { match *bound { ast::TraitTyParamBound(..) => { - // 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); + warn = true; } 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); 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) => { @@ -1315,47 +1323,6 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: &ast::ForeignItem) { 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> { if trait_id.krate != ast::LOCAL_CRATE { 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?`. fn add_unsized_bound<'tcx,AC>(this: &AC, - unbound: &Option<ast::TyParamBound>, + unbound: &Option<ast::TraitRef>, bounds: &mut ty::BuiltinBounds, desc: &str, span: Span) where AC: AstConv<'tcx> { let kind_id = this.tcx().lang_items.require(SizedTraitLangItem); match unbound { - &Some(ast::TraitTyParamBound(ref tpb)) => { + &Some(ref tpb) => { // FIXME(#8559) currently requires the unbound to be built-in. let trait_def_id = ty::trait_ref_to_def_id(this.tcx(), tpb); 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); } // 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 = match lookup_def_tcx(this.tcx(), - ast_trait_ref.path.span, - ast_trait_ref.ref_id) { + ast_trait_ref.trait_ref.path.span, + ast_trait_ref.trait_ref.ref_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?!") } }; @@ -1972,7 +1939,7 @@ fn compute_bounds<'tcx,AC>(this: &AC, name_of_bounded_thing: ast::Name, param_ty: ty::ParamTy, ast_bounds: &[ast::TyParamBound], - unbound: &Option<ast::TyParamBound>, + unbound: &Option<ast::TraitRef>, span: Span, where_clause: &ast::WhereClause) -> ty::ParamBounds @@ -2047,10 +2014,11 @@ fn conv_param_bounds<'tcx,AC>(this: &AC, let trait_bounds: Vec<Rc<ty::TraitRef>> = trait_bounds.into_iter() .map(|b| { - instantiate_trait_ref(this, - b, - param_ty.to_ty(this.tcx()), - Some(param_ty.to_ty(this.tcx()))) + astconv::instantiate_trait_ref(this, + &ExplicitRscope, + b, + Some(param_ty.to_ty(this.tcx())), + Some(param_ty.to_ty(this.tcx()))) }) .collect(); let region_bounds: Vec<ty::Region> = diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index ab3ec4991c3..83d90274fd3 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -52,7 +52,6 @@ use middle::typeck::infer::type_variable::{RelationDir, EqTo, use middle::ty_fold::{TypeFoldable}; use util::ppaux::Repr; - use syntax::ast::{Onceness, FnStyle}; use syntax::ast; use syntax::abi; diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index 4ca62253467..80b4948f6fb 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -1102,7 +1102,8 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { // be passing down a map. 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 mut insert = Vec::new(); let lifetimes = last_seg.parameters.lifetimes(); @@ -1119,10 +1120,12 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { region_names: region_names }; let new_path = self.rebuild_path(rebuild_info, lifetime); - ast::TraitTyParamBound(ast::TraitRef { - path: new_path, - ref_id: tr.ref_id, - lifetimes: tr.lifetimes.clone(), + ast::TraitTyParamBound(ast::PolyTraitRef { + bound_lifetimes: poly_tr.bound_lifetimes.clone(), + trait_ref: ast::TraitRef { + path: new_path, + ref_id: tr.ref_id, + } }) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4478c29f66a..38e0c4fe040 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -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)] pub enum TraitMethod { RequiredMethod(Item), @@ -1306,7 +1312,8 @@ impl Clean<Type> for ty::t { } ty::ty_struct(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: Vec<String> = fqn.into_iter().map(|i| { i.to_string() diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 20f7caac482..145978bb73f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -307,7 +307,7 @@ pub const DUMMY_NODE_ID: NodeId = -1; /// detects Copy, Send and Sync. #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum TyParamBound { - TraitTyParamBound(TraitRef), + TraitTyParamBound(PolyTraitRef), RegionTyParamBound(Lifetime) } @@ -318,7 +318,7 @@ pub struct TyParam { pub ident: Ident, pub id: NodeId, pub bounds: TyParamBounds, - pub unbound: Option<TyParamBound>, + pub unbound: Option<TraitRef>, pub default: Option<P<Ty>>, pub span: Span } @@ -1097,6 +1097,7 @@ pub enum Ty_ { TyBareFn(P<BareFnTy>), TyTup(Vec<P<Ty>> ), 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` TyQPath(P<QPath>), /// No-op; kept solely so that we can pretty-print faithfully @@ -1350,7 +1351,6 @@ pub struct Attribute_ { pub is_sugared_doc: bool, } - /// TraitRef's appear in impls. /// 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. @@ -1360,7 +1360,15 @@ pub struct Attribute_ { pub struct TraitRef { pub path: Path, 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)] @@ -1448,8 +1456,8 @@ pub enum Item_ { ItemStruct(P<StructDef>, Generics), /// Represents a Trait Declaration ItemTrait(Generics, - Option<TyParamBound>, // (optional) default bound not required for Self. - // Currently, only Sized makes sense here. + Option<TraitRef>, // (optional) default bound not required for Self. + // Currently, only Sized makes sense here. TyParamBounds, Vec<TraitItem>), ItemImpl(Generics, diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index 3adb062864e..d65be4c45e8 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -770,7 +770,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { for b in bounds.iter() { match *b { TraitTyParamBound(ref t) => { - self.insert(t.ref_id, NodeItem(i)); + self.insert(t.trait_ref.ref_id, NodeItem(i)); } _ => {} } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 5921d630b89..862cbf3d7ca 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -68,10 +68,11 @@ pub trait AstBuilder { span: Span, id: ast::Ident, bounds: OwnedSlice<ast::TyParamBound>, - unbound: Option<ast::TyParamBound>, + unbound: Option<ast::TraitRef>, default: Option<P<ast::Ty>>) -> ast::TyParam; 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 lifetime(&self, span: Span, ident: ast::Name) -> ast::Lifetime; fn lifetime_def(&self, @@ -417,7 +418,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { span: Span, id: ast::Ident, bounds: OwnedSlice<ast::TyParamBound>, - unbound: Option<ast::TyParamBound>, + unbound: Option<ast::TraitRef>, default: Option<P<ast::Ty>>) -> ast::TyParam { ast::TyParam { ident: id, @@ -445,12 +446,18 @@ impl<'a> AstBuilder for ExtCtxt<'a> { ast::TraitRef { path: path, 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 { - ast::TraitTyParamBound(self.trait_ref(path)) + ast::TraitTyParamBound(self.poly_trait_ref(path)) } fn lifetime(&self, span: Span, name: ast::Name) -> ast::Lifetime { diff --git a/src/libsyntax/ext/deriving/generic/ty.rs b/src/libsyntax/ext/deriving/generic/ty.rs index a90618a30b6..1ec1e3b1224 100644 --- a/src/libsyntax/ext/deriving/generic/ty.rs +++ b/src/libsyntax/ext/deriving/generic/ty.rs @@ -194,7 +194,7 @@ impl<'a> Ty<'a> { 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 { let bounds = bounds.iter().map(|b| { @@ -220,7 +220,7 @@ fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>) #[deriving(Clone)] pub struct LifetimeBounds<'a> { 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> { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 2074a6bfab9..85d4e157b7b 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -227,6 +227,10 @@ pub trait Folder { 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> { 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(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) }) @@ -711,7 +718,7 @@ pub fn noop_fold_ty_param_bound<T>(tpb: TyParamBound, fld: &mut T) -> TyParamBound where T: Folder { 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)), } } @@ -722,7 +729,7 @@ pub fn noop_fold_ty_param<T: Folder>(tp: TyParam, fld: &mut T) -> TyParam { id: fld.new_id(id), ident: ident, 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)), 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 TraitRef { path, - lifetimes, - .. + ref_id: _, } = p; ast::TraitRef { path: fld.fold_path(path), 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) } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9ba11d63da5..6873c015fd5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -42,6 +42,7 @@ use ast::{Method, MutTy, BiMul, Mutability}; use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot}; use ast::{Pat, PatEnum, PatIdent, PatLit, PatRange, PatRegion, PatStruct}; use ast::{PatTup, PatBox, PatWild, PatWildMulti, PatWildSingle}; +use ast::{PolyTraitRef}; use ast::{QPath, RequiredMethod}; use ast::{RetStyle, Return, BiShl, BiShr, Stmt, StmtDecl}; use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField}; @@ -53,7 +54,7 @@ use ast::{TtDelimited, TtSequence, TtToken}; use ast::{TupleVariantKind, Ty, Ty_, TyBot}; use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn}; 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::{TypeImplItem, TypeTraitItem, Typedef, UnboxedClosureKind}; 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 /// type? pub fn token_is_bare_fn_keyword(&mut self) -> bool { - if self.token.is_keyword(keywords::Fn) { - return true - } - - 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 + self.token.is_keyword(keywords::Fn) || + self.token.is_keyword(keywords::Unsafe) || + self.token.is_keyword(keywords::Extern) } /// Is the current token one of the keywords that signals a closure type? pub fn token_is_closure_keyword(&mut self) -> bool { - 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) + self.token.is_keyword(keywords::Unsafe) } 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: - 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 @@ -1023,18 +1057,26 @@ impl<'a> Parser<'a> { }; 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 { abi: abi, fn_style: fn_style, - lifetimes: lifetimes, + lifetimes: lifetime_defs, decl: decl })) } /// Parses a procedure type (`proc`). The initial `proc` keyword must /// 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 @@ -1043,19 +1085,12 @@ impl<'a> Parser<'a> { | | | | Return type | | | Bounds | | Argument types - | Lifetimes + | Legacy lifetimes the `proc` keyword */ - let lifetime_defs = if self.eat(&token::Lt) { - let lifetime_defs = self.parse_lifetime_defs(); - self.expect_gt(); - lifetime_defs - } else { - Vec::new() - }; - + let lifetime_defs = self.parse_legacy_lifetime_defs(lifetime_defs); let (inputs, variadic) = self.parse_fn_args(false, false); let bounds = self.parse_colon_then_ty_param_bounds(); let (ret_style, ret_ty) = self.parse_ret_ty(); @@ -1100,33 +1135,49 @@ impl<'a> Parser<'a> { 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 - 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 - ^~~~~~~^ ^~~~~^ ^~~~^ ^ ^~~~~~~~^ ^ - | | | | | | - | | | | | Return type - | | | | Closure bounds - | | | Argument types - | | Lifetime defs - | Once-ness (a.k.a., affine) + [unsafe] <'lt> |S| [:Bounds] -> T + ^~~~~~~^ ^~~~^ ^ ^~~~~~~~^ ^ + | | | | | + | | | | Return type + | | | Closure bounds + | | Argument types + | Deprecated lifetime defs + | Function Style */ 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_lifetime_defs(); - self.expect_gt(); - - lifetime_defs - } else { - Vec::new() - }; + let lifetime_defs = self.parse_legacy_lifetime_defs(lifetime_defs); let inputs = if self.eat(&token::OrOr) { Vec::new() @@ -1152,7 +1203,7 @@ impl<'a> Parser<'a> { TyClosure(P(ClosureTy { fn_style: fn_style, - onceness: onceness, + onceness: Many, bounds: bounds, decl: decl, lifetimes: lifetime_defs, @@ -1167,36 +1218,23 @@ impl<'a> Parser<'a> { } } - /// Parse a function type (following the 'fn') - pub fn parse_ty_fn_decl(&mut self, allow_variadic: bool) - -> (P<FnDecl>, Vec<ast::LifetimeDef>) { - /* - - (fn) <'lt> (S) -> T - ^~~~^ ^~^ ^ - | | | - | | Return type - | Argument types - Lifetime_defs - - */ - let lifetime_defs = if self.eat(&token::Lt) { - let lifetime_defs = self.parse_lifetime_defs(); - self.expect_gt(); - lifetime_defs + /// Parses `[ 'for' '<' lifetime_defs '>' ]' + fn parse_legacy_lifetime_defs(&mut self, + lifetime_defs: Vec<ast::LifetimeDef>) + -> Vec<ast::LifetimeDef> + { + if self.eat(&token::Lt) { + if lifetime_defs.is_empty() { + self.warn("deprecated syntax, use `for` keyword now"); + let lifetime_defs = self.parse_lifetime_defs(); + self.expect_gt(); + lifetime_defs + } else { + self.fatal("cannot use new `for` keyword and older syntax together"); + } } else { - Vec::new() - }; - - 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) + lifetime_defs + } } /// 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)); t } else if self.token == token::BinOp(token::And) || - self.token == token::AndAnd { + self.token == token::AndAnd { // BORROWED POINTER self.expect_and(); self.parse_borrowed_pointee() - } else if self.token.is_keyword(keywords::Extern) || - self.token.is_keyword(keywords::Unsafe) || - self.token_is_bare_fn_keyword() { - // BARE FUNCTION - self.parse_ty_bare_fn() - } else if self.token_is_closure_keyword() || - self.token == token::BinOp(token::Or) || - self.token == token::OrOr || - (self.token == token::Lt && - self.look_ahead(1, |t| { - *t == token::Gt || t.is_lifetime() - })) { + } else if self.token.is_keyword(keywords::For) { + self.parse_for_in_type() + } else if self.token_is_bare_fn_keyword() || + self.token_is_closure_keyword() { + // BARE FUNCTION OR CLOSURE + self.parse_ty_bare_fn_or_ty_closure(Vec::new()) + } else if self.token == token::BinOp(token::Or) || + self.token == token::OrOr || + (self.token == token::Lt && + self.look_ahead(1, |t| { + *t == token::Gt || t.is_lifetime() + })) { // CLOSURE - - self.parse_ty_closure() + self.parse_ty_closure(Vec::new()) } else if self.eat_keyword(keywords::Typeof) { // TYPEOF // 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)); TyTypeof(e) } else if self.eat_keyword(keywords::Proc) { - self.parse_proc_type() + self.parse_proc_type(Vec::new()) } else if self.token == token::Lt { // QUALIFIED PATH self.bump(); @@ -1479,16 +1516,7 @@ impl<'a> Parser<'a> { self.token.is_ident() || self.token.is_path() { // NAMED TYPE - let mode = if plus_allowed { - LifetimeAndTypesAndBounds - } else { - LifetimeAndTypesWithoutColons - }; - let PathAndBounds { - path, - bounds - } = self.parse_path(mode); - TyPath(path, bounds, ast::DUMMY_NODE_ID) + self.parse_ty_path(plus_allowed) } else if self.eat(&token::Underscore) { // TYPE TO BE INFERRED TyInfer @@ -3848,29 +3876,17 @@ impl<'a> Parser<'a> { } // matches bounds = ( boundseq )? - // where boundseq = ( bound + boundseq ) | bound - // and bound = 'region | ty + // where boundseq = ( polybound + boundseq ) | polybound + // and polybound = ( 'for' '<' 'region '>' )? bound + // and bound = 'region | trait_ref // NB: The None/Some distinction is important for issue #7264. fn parse_ty_param_bounds(&mut self) -> OwnedSlice<TyParamBound> { let mut result = vec!(); 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 { 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 { id: ast::DUMMY_NODE_ID, span: self.span, @@ -3879,13 +3895,8 @@ impl<'a> Parser<'a> { self.bump(); } token::ModSep | token::Ident(..) => { - let path = - self.parse_path(LifetimeAndTypesWithoutColons).path; - result.push(TraitTyParamBound(ast::TraitRef { - path: path, - ref_id: ast::DUMMY_NODE_ID, - lifetimes: lifetime_defs, - })) + let poly_trait_ref = self.parse_poly_trait_ref(); + result.push(TraitTyParamBound(poly_trait_ref)) } _ => break, } @@ -3898,7 +3909,7 @@ impl<'a> Parser<'a> { 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 { identifier: ident, parameters: ast::PathParameters::none() @@ -3911,7 +3922,6 @@ impl<'a> Parser<'a> { ast::TraitRef { path: path, ref_id: ast::DUMMY_NODE_ID, - lifetimes: Vec::new(), } } @@ -3927,7 +3937,7 @@ impl<'a> Parser<'a> { let mut unbound = None; if self.eat(&token::Question) { let tref = Parser::trait_ref_from_ident(ident, span); - unbound = Some(TraitTyParamBound(tref)); + unbound = Some(tref); span = self.span; ident = self.parse_ident(); } @@ -4538,7 +4548,6 @@ impl<'a> Parser<'a> { Some(TraitRef { path: (*path).clone(), ref_id: node_id, - lifetimes: Vec::new(), }) } TyPath(_, Some(_), _) => { @@ -4568,6 +4577,35 @@ impl<'a> Parser<'a> { 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 { ... } fn parse_item_struct(&mut self) -> ItemInfo { let class_name = self.parse_ident(); @@ -4681,7 +4719,7 @@ impl<'a> Parser<'a> { 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) { let span = self.span; let ident = self.parse_ident(); @@ -4691,7 +4729,7 @@ impl<'a> Parser<'a> { return None; } let tref = Parser::trait_ref_from_ident(ident, span); - Some(TraitTyParamBound(tref)) + Some(tref) } else { None } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 63e2c5499e8..5b57a875c4a 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -743,6 +743,9 @@ impl<'a> State<'a> { ast::TyPath(ref path, ref 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) => { try!(word(&mut self.s, "<")); try!(self.print_type(&*qpath.for_type)); @@ -960,7 +963,7 @@ impl<'a> State<'a> { try!(self.print_ident(item.ident)); try!(self.print_generics(generics)); match unbound { - &Some(TraitTyParamBound(ref tref)) => { + &Some(ref tref) => { try!(space(&mut self.s)); try!(self.word_space("for")); try!(self.print_trait_ref(tref)); @@ -995,19 +998,21 @@ impl<'a> State<'a> { } 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) } + 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, generics: &ast::Generics, ident: ast::Ident, span: codemap::Span, @@ -2383,7 +2388,7 @@ impl<'a> State<'a> { try!(match *bound { TraitTyParamBound(ref tref) => { - self.print_trait_ref(tref) + self.print_poly_trait_ref(tref) } RegionTyParamBound(ref lt) => { self.print_lifetime(lt) @@ -2450,7 +2455,7 @@ impl<'a> State<'a> { pub fn print_ty_param(&mut self, param: &ast::TyParam) -> IoResult<()> { match param.unbound { - Some(TraitTyParamBound(ref tref)) => { + Some(ref tref) => { try!(self.print_trait_ref(tref)); try!(self.word_space("?")); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 9751abacbd3..1b1d1e9cace 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -75,6 +75,10 @@ pub trait Visitor<'v> { } 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_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) { 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 /// in Visitor, and so it gets a _helper suffix. -pub fn walk_trait_ref_helper<'v,V>(visitor: &mut V, trait_ref: &'v TraitRef) - where V: Visitor<'v> { - walk_lifetime_decls(visitor, &trait_ref.lifetimes); +pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V, + trait_ref: &'v PolyTraitRef) + 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) } @@ -248,8 +263,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { ref impl_items) => { visitor.visit_generics(type_parameters); match *trait_reference { - Some(ref trait_reference) => walk_trait_ref_helper(visitor, - trait_reference), + Some(ref trait_reference) => visitor.visit_trait_ref(trait_reference), None => () } 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_expr(&**expression) } + TyPolyTraitRef(ref poly_trait_ref) => { + visitor.visit_poly_trait_ref(&**poly_trait_ref) + } TyTypeof(ref 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() { match *bound { TraitTyParamBound(ref typ) => { - walk_trait_ref_helper(visitor, typ) + visitor.visit_poly_trait_ref(typ) } RegionTyParamBound(ref lifetime) => { visitor.visit_lifetime_ref(lifetime); diff --git a/src/test/compile-fail/issue-10291.rs b/src/test/compile-fail/issue-10291.rs index 995ae7b3d44..924132c6de2 100644 --- a/src/test/compile-fail/issue-10291.rs +++ b/src/test/compile-fail/issue-10291.rs @@ -9,7 +9,7 @@ // except according to those terms. fn test<'x>(x: &'x int) { - drop::< <'z>|&'z int| -> &'z int >(|z| { + drop::< for<'z>|&'z int| -> &'z int >(|z| { x //~^ ERROR cannot infer an appropriate lifetime }); diff --git a/src/test/compile-fail/regions-fn-subtyping-return-static.rs b/src/test/compile-fail/regions-fn-subtyping-return-static.rs index 4c90b1f0eea..ac56e8ce14d 100644 --- a/src/test/compile-fail/regions-fn-subtyping-return-static.rs +++ b/src/test/compile-fail/regions-fn-subtyping-return-static.rs @@ -22,11 +22,11 @@ struct S; // 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) { } // 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) { } // Should meet both. diff --git a/src/test/compile-fail/regions-fn-subtyping.rs b/src/test/compile-fail/regions-fn-subtyping.rs index 8e8d892a39f..91a6ff789ea 100644 --- a/src/test/compile-fail/regions-fn-subtyping.rs +++ b/src/test/compile-fail/regions-fn-subtyping.rs @@ -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 // iff T1 <: T2. - subtype::< <'a>|&'a T|>( - of::< <'a>|&'a T|>()); + subtype::< for<'a>|&'a T|>( + of::< for<'a>|&'a T|>()); - subtype::< <'a>|&'a T|>( - of::< <'b>|&'b T|>()); + subtype::< for<'a>|&'a T|>( + of::< for<'b>|&'b T|>()); - subtype::< <'b>|&'b T|>( + subtype::< for<'b>|&'b T|>( of::<|&'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|>( - of::< <'a>|&'a T, &'a T|>()); + subtype::< for<'a,'b>|&'a T, &'b T|>( + of::< for<'a>|&'a T, &'a T|>()); - subtype::< <'a>|&'a T, &'a T|>( - of::< <'a,'b>|&'a T, &'b T|>()); //~ ERROR mismatched types + subtype::< for<'a>|&'a T, &'a T|>( + 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|>()); 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() {} diff --git a/src/test/compile-fail/regions-name-undeclared.rs b/src/test/compile-fail/regions-name-undeclared.rs index ba3d7bd29f4..e9e585e84d0 100644 --- a/src/test/compile-fail/regions-name-undeclared.rs +++ b/src/test/compile-fail/regions-name-undeclared.rs @@ -43,16 +43,16 @@ fn bar<'a>(x: &'a int) { // &'a CAN be declared on functions and used then: 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 fn fn_types(a: &'a int, //~ ERROR undeclared lifetime - b: <'a>|a: &'a int, - b: &'b int, //~ ERROR undeclared lifetime - c: <'b>|a: &'a int, - b: &'b int|, - d: &'b int|, //~ ERROR undeclared lifetime + b: for<'a>|a: &'a int, + b: &'b int, //~ ERROR undeclared lifetime + c: for<'b>|a: &'a int, + b: &'b int|, + d: &'b int|, //~ ERROR undeclared lifetime c: &'a int) //~ ERROR undeclared lifetime { } diff --git a/src/test/compile-fail/regions-nested-fns-2.rs b/src/test/compile-fail/regions-nested-fns-2.rs index 60eae9ce80a..a08cf226389 100644 --- a/src/test/compile-fail/regions-nested-fns-2.rs +++ b/src/test/compile-fail/regions-nested-fns-2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn ignore(_f: <'z>|&'z int| -> &'z int) {} +fn ignore(_f: for<'z>|&'z int| -> &'z int) {} fn nested() { let y = 3; diff --git a/src/test/compile-fail/regions-nested-fns.rs b/src/test/compile-fail/regions-nested-fns.rs index 7dc57d37e24..cf0b615bb01 100644 --- a/src/test/compile-fail/regions-nested-fns.rs +++ b/src/test/compile-fail/regions-nested-fns.rs @@ -14,13 +14,13 @@ fn nested<'x>(x: &'x int) { let y = 3; let mut ay = &y; //~ ERROR cannot infer - ignore::< <'z>|&'z int|>(|z| { + ignore::< for<'z>|&'z int|>(|z| { ay = x; ay = &y; 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 ay; } return z; diff --git a/src/test/compile-fail/regions-ret-borrowed-1.rs b/src/test/compile-fail/regions-ret-borrowed-1.rs index 6d9b2619171..997775efa84 100644 --- a/src/test/compile-fail/regions-ret-borrowed-1.rs +++ b/src/test/compile-fail/regions-ret-borrowed-1.rs @@ -12,7 +12,7 @@ // some point regions-ret-borrowed reported an error but this file did // 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) } diff --git a/src/test/run-pass/hrtb-parse.rs b/src/test/run-pass/hrtb-parse.rs new file mode 100644 index 00000000000..080523f0060 --- /dev/null +++ b/src/test/run-pass/hrtb-parse.rs @@ -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() { +} diff --git a/src/test/run-pass/nullable-pointer-ffi-compat.rs b/src/test/run-pass/nullable-pointer-ffi-compat.rs index b5c541b0c63..32432c07dcf 100644 --- a/src/test/run-pass/nullable-pointer-ffi-compat.rs +++ b/src/test/run-pass/nullable-pointer-ffi-compat.rs @@ -29,7 +29,7 @@ static FOO: int = 0xDEADBEE; pub fn main() { 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); } } |
