From 3a5f146b12a3b6ba589d42fad3ca04afcf342152 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 9 Jan 2013 12:25:59 -0800 Subject: [PATCH 1/3] libcore: Use LLVM intrinsics for floor; add a new Perlin noise benchmark --- src/libcore/f32.rs | 17 ++++++- src/libcore/f64.rs | 19 ++++++- src/test/bench/noise.rs | 110 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 src/test/bench/noise.rs diff --git a/src/libcore/f32.rs b/src/libcore/f32.rs index ce90f757769be..94f71d6541cc6 100644 --- a/src/libcore/f32.rs +++ b/src/libcore/f32.rs @@ -17,7 +17,13 @@ use cmp; use num; -pub use cmath::c_float_utils::*; +pub use cmath::c_float_utils::{acos, asin, atan, atan2, cbrt, ceil}; +pub use cmath::c_float_utils::{copysign, cos, cosh, erf, erfc, exp, expm1}; +pub use cmath::c_float_utils::{exp2, abs, abs_sub, mul_add, fmax, fmin}; +pub use cmath::c_float_utils::{nextafter, frexp, hypot, ldexp, lgamma}; +pub use cmath::c_float_utils::{ln, log_radix, ln1p, log10, log2, ilog_radix}; +pub use cmath::c_float_utils::{modf, pow, round, sin, sinh, sqrt, tan}; +pub use cmath::c_float_utils::{tanh, tgamma, trunc}; pub use cmath::c_float_targ_consts::*; // These are not defined inside consts:: for consistency with @@ -53,6 +59,10 @@ pub pure fn ge(x: f32, y: f32) -> bool { return x >= y; } pub pure fn gt(x: f32, y: f32) -> bool { return x > y; } +/// Returns `x` rounded down +#[inline(always)] +pub pure fn floor(x: f32) -> f32 { unsafe { floorf32(x) } } + // FIXME (#1999): replace the predicates below with llvm intrinsics or // calls to the libmath macros in the rust runtime for performance. @@ -185,6 +195,11 @@ impl f32: num::One { static pure fn one() -> f32 { 1.0 } } +#[abi="rust-intrinsic"] +pub extern { + fn floorf32(val: f32) -> f32; +} + // // Local Variables: // mode: rust diff --git a/src/libcore/f64.rs b/src/libcore/f64.rs index 97d9e8e758452..fc6cd113ebf0f 100644 --- a/src/libcore/f64.rs +++ b/src/libcore/f64.rs @@ -19,7 +19,13 @@ use cmp; use libc; use num; -pub use cmath::c_double_utils::*; +pub use cmath::c_double_utils::{acos, asin, atan, atan2, cbrt, ceil}; +pub use cmath::c_double_utils::{copysign, cos, cosh, erf, erfc, exp, expm1}; +pub use cmath::c_double_utils::{exp2, abs, abs_sub, mul_add, fmax, fmin}; +pub use cmath::c_double_utils::{nextafter, frexp, hypot, ldexp, lgamma}; +pub use cmath::c_double_utils::{ln, log_radix, ln1p, log10, log2, ilog_radix}; +pub use cmath::c_double_utils::{modf, pow, round, sin, sinh, sqrt, tan}; +pub use cmath::c_double_utils::{tanh, tgamma, trunc, j0, j1, jn, y0, y1, yn}; pub use cmath::c_double_targ_consts::*; // FIXME (#1433): obtain these in a different way @@ -113,11 +119,15 @@ pub pure fn is_infinite(x: f64) -> bool { return x == infinity || x == neg_infinity; } -/// Returns true if `x`is a finite number +/// Returns true if `x` is a finite number pub pure fn is_finite(x: f64) -> bool { return !(is_NaN(x) || is_infinite(x)); } +/// Returns `x` rounded down +#[inline(always)] +pub pure fn floor(x: f64) -> f64 { unsafe { floorf64(x) } } + // FIXME (#1999): add is_normal, is_subnormal, and fpclassify /* Module: consts */ @@ -206,6 +216,11 @@ impl f64: num::One { static pure fn one() -> f64 { 1.0 } } +#[abi="rust-intrinsic"] +pub extern { + fn floorf64(val: f64) -> f64; +} + // // Local Variables: // mode: rust diff --git a/src/test/bench/noise.rs b/src/test/bench/noise.rs new file mode 100644 index 0000000000000..a07dcee35f4d3 --- /dev/null +++ b/src/test/bench/noise.rs @@ -0,0 +1,110 @@ +// Perlin noise benchmark from https://gist.github.com/1170424 + +struct Vec2 { + x: f32, + y: f32, +} + +fn lerp(a: f32, b: f32, v: f32) -> f32 { a * (1.0 - v) + b * v } +fn smooth(v: f32) -> f32 { v * v * (3.0 - 2.0 * v) } + +fn random_gradient(r: rand::Rng) -> Vec2 { + let v = r.gen_float() * float::consts::pi * 2.0; + Vec2{ + x: float::cos(v) as f32, + y: float::sin(v) as f32, + } +} + +fn gradient(orig: Vec2, grad: Vec2, p: Vec2) -> f32 { + let sp = Vec2{x: p.x - orig.x, y: p.y - orig.y}; + grad.x * sp.x + grad.y + sp.y +} + +struct Noise2DContext { + rgradients: [Vec2 * 256], + permutations: [int * 256], +} + +fn Noise2DContext() -> ~Noise2DContext { + let r = rand::Rng(); + let mut rgradients = [ Vec2 { x: 0.0, y: 0.0 }, ..256 ]; + for int::range(0, 256) |i| { rgradients[i] = random_gradient(r); } + let mut permutations = [ 0, ..256 ]; + for int::range(0, 256) |i| { permutations[i] = i; } + r.shuffle_mut(permutations); + + ~Noise2DContext{ + rgradients: move rgradients, + permutations: move permutations, + } +} + +impl Noise2DContext { + #[inline(always)] + fn get_gradient(&self, x: int, y: int) -> Vec2 { + let idx = self.permutations[x & 255] + self.permutations[y & 255]; + self.rgradients[idx & 255] + } + + #[inline(always)] + fn get_gradients(&self, gradients: &mut [Vec2 * 4], origins: &mut [Vec2 * 4], x: f32, y: f32) { + let x0f = f32::floor(x); + let y0f = f32::floor(y); + let x0 = x0f as int; + let y0 = y0f as int; + let x1 = x0 + 1; + let y1 = y0 + 1; + + gradients[0] = self.get_gradient(x0, y0); + gradients[1] = self.get_gradient(x1, y0); + gradients[2] = self.get_gradient(x0, y1); + gradients[3] = self.get_gradient(x1, y1); + + origins[0] = Vec2{x: x0f + 0.0, y: y0f + 0.0}; + origins[1] = Vec2{x: x0f + 1.0, y: y0f + 0.0}; + origins[2] = Vec2{x: x0f + 0.0, y: y0f + 1.0}; + origins[3] = Vec2{x: x0f + 1.0, y: y0f + 1.0}; + } + + fn get(&self, x: f32, y: f32) -> f32 { + let p = Vec2{x: x, y: y}; + let mut gradients = [ Vec2 { x: 0.0, y: 0.0 }, ..4 ]; + let mut origins = [ Vec2 { x: 0.0, y: 0.0 }, ..4 ]; + self.get_gradients(&mut gradients, &mut origins, x, y); + let v0 = gradient(origins[0], gradients[0], p); + let v1 = gradient(origins[1], gradients[1], p); + let v2 = gradient(origins[2], gradients[2], p); + let v3 = gradient(origins[3], gradients[3], p); + let fx = smooth(x - origins[0].x); + let vx0 = lerp(v0, v1, fx); + let vx1 = lerp(v2, v3, fx); + let fy = smooth(y - origins[0].y); + lerp(vx0, vx1, fy) + } +} + +fn main() { + let symbols = [" ", "░", "▒", "▓", "█", "█"]; + let mut pixels = vec::from_elem(256*256, 0f32); + let n2d = Noise2DContext(); + for int::range(0, 100) |_| { + for int::range(0, 256) |y| { + for int::range(0, 256) |x| { + let v = n2d.get( + x as f32 * 0.1f32, + y as f32 * 0.1f32 + ) * 0.5f32 + 0.5f32; + pixels[y*256+x] = v; + }; + }; + }; + + /*for int::range(0, 256) |y| { + for int::range(0, 256) |x| { + io::print(symbols[pixels[y*256+x] / 0.2f32 as int]); + } + io::println(""); + }*/ +} + From 4b51892a00fa45038550d42530b35f0f2936cf62 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 9 Jan 2013 14:12:28 -0800 Subject: [PATCH 2/3] librustc: Allow the type parameter version of `Self` to be spelled with a capital S --- src/librustc/middle/resolve.rs | 6 ++++ src/libsyntax/parse/token.rs | 47 ++++++++++++++++++++++------ src/test/run-pass/self-type-param.rs | 16 ++++++++++ 3 files changed, 60 insertions(+), 9 deletions(-) create mode 100644 src/test/run-pass/self-type-param.rs diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 4e5e9b97957e0..707b259db1f94 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -850,6 +850,8 @@ fn Resolver(session: Session, lang_items: LanguageItems, current_trait_refs: None, self_ident: special_idents::self_, + type_self_ident: special_idents::type_self, + primitive_type_table: @PrimitiveTypeTable(session. parse_sess.interner), @@ -905,6 +907,8 @@ struct Resolver { // The ident for the keyword "self". self_ident: ident, + // The ident for the non-keyword "Self". + type_self_ident: ident, // The idents for the primitive types. primitive_type_table: @PrimitiveTypeTable, @@ -3803,6 +3807,8 @@ impl Resolver { (*self.type_ribs).push(self_type_rib); self_type_rib.bindings.insert(self.self_ident, dl_def(def_self_ty(item.id))); + self_type_rib.bindings.insert(self.type_self_ident, + dl_def(def_self_ty(item.id))); // Create a new rib for the trait-wide type parameters. do self.with_type_parameter_rib diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 606247b8cbede..93c030636239a 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -340,6 +340,7 @@ mod special_idents { const clownshoes_foreign_mod: ident = ident { repr: 33 }; const unnamed_field: ident = ident { repr: 34 }; const c_abi: ident = ident { repr: 35 }; + const type_self: ident = ident { repr: 36 }; // `Self` } struct ident_interner { @@ -379,15 +380,43 @@ fn mk_ident_interner() -> @ident_interner { // the indices here must correspond to the numbers in // special_idents. let init_vec = ~[ - @~"_", @~"anon", @~"drop", @~"", @~"unary", @~"!", - @~"[]", @~"unary-", @~"__extensions__", @~"self", - @~"item", @~"block", @~"stmt", @~"pat", @~"expr", - @~"ty", @~"ident", @~"path", @~"tt", @~"matchers", - @~"str", @~"TyVisitor", @~"arg", @~"descrim", - @~"__rust_abi", @~"__rust_stack_shim", @~"TyDesc", - @~"dtor", @~"main", @~"", @~"blk", @~"static", - @~"intrinsic", @~"__foreign_mod__", @~"__field__", - @~"C" + @~"_", // 0 + @~"anon", // 1 + @~"drop", // 2 + @~"", // 3 + @~"unary", // 4 + @~"!", // 5 + @~"[]", // 6 + @~"unary-", // 7 + @~"__extensions__", // 8 + @~"self", // 9 + @~"item", // 10 + @~"block", // 11 + @~"stmt", // 12 + @~"pat", // 13 + @~"expr", // 14 + @~"ty", // 15 + @~"ident", // 16 + @~"path", // 17 + @~"tt", // 18 + @~"matchers", // 19 + @~"str", // 20 + @~"TyVisitor", // 21 + @~"arg", // 22 + @~"descrim", // 23 + @~"__rust_abi", // 24 + @~"__rust_stack_shim", // 25 + @~"TyDesc", // 26 + @~"dtor", // 27 + @~"main", // 28 + @~"", // 29 + @~"blk", // 30 + @~"static", // 31 + @~"intrinsic", // 32 + @~"__foreign_mod__", // 33 + @~"__field__", // 34 + @~"C", // 35 + @~"Self", // 36 ]; let rv = @ident_interner { diff --git a/src/test/run-pass/self-type-param.rs b/src/test/run-pass/self-type-param.rs new file mode 100644 index 0000000000000..ea42045fc46f1 --- /dev/null +++ b/src/test/run-pass/self-type-param.rs @@ -0,0 +1,16 @@ +trait MyTrait { + fn f(&self) -> Self; +} + +struct S { + x: int +} + +impl S : MyTrait { + fn f(&self) -> S { + S { x: 3 } + } +} + +fn main() {} + From f74a480580e8a7ce338322f2b9a10a7a1e6a9c69 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 9 Jan 2013 18:55:57 -0800 Subject: [PATCH 3/3] librustc: Implement `&static` as the replacement for `Durable` --- src/librustc/middle/kind.rs | 4 +- src/librustc/middle/resolve.rs | 11 ++-- src/librustc/middle/ty.rs | 2 +- src/librustc/middle/typeck/collect.rs | 59 +++++++++++--------- src/libsyntax/ast.rs | 5 +- src/libsyntax/ext/auto_encode.rs | 4 +- src/libsyntax/ext/deriving.rs | 16 +++--- src/libsyntax/fold.rs | 5 +- src/libsyntax/parse/parser.rs | 22 ++++++-- src/libsyntax/print/pprust.rs | 9 ++- src/libsyntax/visit.rs | 7 ++- src/test/compile-fail/static-region-bound.rs | 9 +++ 12 files changed, 97 insertions(+), 56 deletions(-) create mode 100644 src/test/compile-fail/static-region-bound.rs diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index f2a7dd0648cb3..216fc5c49029d 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -76,7 +76,7 @@ fn kind_to_str(k: Kind) -> ~str { if ty::kind_can_be_sent(k) { kinds.push(~"owned"); } else if ty::kind_is_durable(k) { - kinds.push(~"durable"); + kinds.push(~"&static"); } str::connect(kinds, ~" ") @@ -571,7 +571,7 @@ fn check_durable(tcx: ty::ctxt, ty: ty::t, sp: span) -> bool { match ty::get(ty).sty { ty::ty_param(*) => { tcx.sess.span_err(sp, ~"value may contain borrowed \ - pointers; use `durable` bound"); + pointers; use `&static` bound"); } _ => { tcx.sess.span_err(sp, ~"value may contain borrowed \ diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 707b259db1f94..a14fb1d73b212 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -22,8 +22,8 @@ use middle::pat_util::{pat_bindings}; use core::cmp; use core::str; use core::vec; -use syntax::ast::{_mod, add, arm, binding_mode, bitand, bitor, bitxor, blk}; -use syntax::ast::{capture_clause}; +use syntax::ast::{RegionTyParamBound, TraitTyParamBound, _mod, add, arm}; +use syntax::ast::{binding_mode, bitand, bitor, bitxor, blk, capture_clause}; use syntax::ast::{crate, crate_num, decl_item, def, def_arg, def_binding}; use syntax::ast::{def_const, def_foreign_mod, def_fn, def_id, def_label}; use syntax::ast::{def_local, def_mod, def_prim_ty, def_region, def_self}; @@ -4117,8 +4117,11 @@ impl Resolver { fn resolve_type_parameters(type_parameters: ~[ty_param], visitor: ResolveVisitor) { for type_parameters.each |type_parameter| { - for type_parameter.bounds.each |bound| { - self.resolve_type(**bound, visitor); + for type_parameter.bounds.each |&bound| { + match bound { + TraitTyParamBound(ty) => self.resolve_type(ty, visitor), + RegionTyParamBound => {} + } } } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index b894b9f50ebd8..8cc5eee3d54e0 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1592,7 +1592,7 @@ fn substs_to_str(cx: ctxt, substs: &substs) -> ~str { fn param_bound_to_str(cx: ctxt, pb: ¶m_bound) -> ~str { match *pb { bound_copy => ~"copy", - bound_durable => ~"durable", + bound_durable => ~"&static", bound_owned => ~"owned", bound_const => ~"const", bound_trait(t) => ::util::ppaux::ty_to_str(cx, t) diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 11a932db2879b..e2e3526ca9db0 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -50,6 +50,7 @@ use util::ppaux::bound_to_str; use core::dvec; use core::option; use core::vec; +use syntax::ast::{RegionTyParamBound, TraitTyParamBound}; use syntax::ast; use syntax::ast_map; use syntax::ast_util::{local_def, split_trait_methods}; @@ -906,36 +907,42 @@ fn ty_of_foreign_item(ccx: @crate_ctxt, it: @ast::foreign_item) } } -// Translate the AST's notion of ty param bounds (which are just newtyped Tys) -// to ty's notion of ty param bounds, which can either be user-defined traits, -// or one of the four built-in traits (formerly known as kinds): Const, Copy, -// Durable, and Send. +// Translate the AST's notion of ty param bounds (which are an enum consisting +// of a newtyped Ty or a region) to ty's notion of ty param bounds, which can +// either be user-defined traits, or one of the four built-in traits (formerly +// known as kinds): Const, Copy, Durable, and Send. fn compute_bounds(ccx: @crate_ctxt, - ast_bounds: @~[ast::ty_param_bound]) -> ty::param_bounds { + ast_bounds: @~[ast::ty_param_bound]) + -> ty::param_bounds { @do vec::flat_map(*ast_bounds) |b| { - let li = &ccx.tcx.lang_items; - let ity = ast_ty_to_ty(ccx, empty_rscope, **b); - match ty::get(ity).sty { - ty::ty_trait(did, _, _) => { - if did == li.owned_trait() { - ~[ty::bound_owned] - } else if did == li.copy_trait() { - ~[ty::bound_copy] - } else if did == li.const_trait() { - ~[ty::bound_const] - } else if did == li.durable_trait() { - ~[ty::bound_durable] - } else { - // Must be a user-defined trait - ~[ty::bound_trait(ity)] + match b { + &TraitTyParamBound(b) => { + let li = &ccx.tcx.lang_items; + let ity = ast_ty_to_ty(ccx, empty_rscope, b); + match ty::get(ity).sty { + ty::ty_trait(did, _, _) => { + if did == li.owned_trait() { + ~[ty::bound_owned] + } else if did == li.copy_trait() { + ~[ty::bound_copy] + } else if did == li.const_trait() { + ~[ty::bound_const] + } else if did == li.durable_trait() { + ~[ty::bound_durable] + } else { + // Must be a user-defined trait + ~[ty::bound_trait(ity)] + } + } + _ => { + ccx.tcx.sess.span_err( + (*b).span, ~"type parameter bounds must be \ + trait types"); + ~[] + } } } - _ => { - ccx.tcx.sess.span_err( - (*b).span, ~"type parameter bounds must be \ - trait types"); - ~[] - } + &RegionTyParamBound => ~[ty::bound_durable] } } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 42e722f8d5307..ef5e8d8df4a55 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -110,7 +110,10 @@ const crate_node_id: node_id = 0; // typeck::collect::compute_bounds matches these against // the "special" built-in traits (see middle::lang_items) and // detects Copy, Send, Owned, and Const. -enum ty_param_bound = @Ty; +enum ty_param_bound { + TraitTyParamBound(@Ty), + RegionTyParamBound +} #[auto_encode] #[auto_decode] diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs index 152c49461b87d..8404f49f8cfa8 100644 --- a/src/libsyntax/ext/auto_encode.rs +++ b/src/libsyntax/ext/auto_encode.rs @@ -245,7 +245,7 @@ priv impl ext_ctxt { path: @ast::path, bounds: @~[ast::ty_param_bound] ) -> ast::ty_param { - let bound = ast::ty_param_bound(@{ + let bound = ast::TraitTyParamBound(@{ id: self.next_id(), node: ast::ty_path(path, self.next_id()), span: span, @@ -397,7 +397,7 @@ fn mk_impl( let mut trait_tps = vec::append( ~[ty_param], do tps.map |tp| { - let t_bound = ast::ty_param_bound(@{ + let t_bound = ast::TraitTyParamBound(@{ id: cx.next_id(), node: ast::ty_path(path, cx.next_id()), span: span, diff --git a/src/libsyntax/ext/deriving.rs b/src/libsyntax/ext/deriving.rs index 41804b1022a3c..c187b74fdd215 100644 --- a/src/libsyntax/ext/deriving.rs +++ b/src/libsyntax/ext/deriving.rs @@ -13,13 +13,13 @@ use core::prelude::*; -use ast::{Ty, and, bind_by_ref, binop, deref, enum_def, enum_variant_kind}; -use ast::{expr, expr_match, ident, item, item_, item_struct, item_enum}; -use ast::{item_impl, m_imm, meta_item, method, named_field, or, pat}; -use ast::{pat_ident, pat_wild, public, pure_fn, re_anon, stmt, struct_def}; -use ast::{struct_variant_kind, sty_by_ref, sty_region, tuple_variant_kind}; -use ast::{ty_nil, ty_param, ty_param_bound, ty_path, ty_rptr, unnamed_field}; -use ast::{variant}; +use ast::{TraitTyParamBound, Ty, and, bind_by_ref, binop, deref, enum_def}; +use ast::{enum_variant_kind, expr, expr_match, ident, item, item_, item_enum}; +use ast::{item_impl, item_struct, m_imm, meta_item, method, named_field, or}; +use ast::{pat, pat_ident, pat_wild, public, pure_fn, re_anon, stmt}; +use ast::{struct_def, struct_variant_kind, sty_by_ref, sty_region}; +use ast::{tuple_variant_kind, ty_nil, ty_param, ty_path, ty_rptr}; +use ast::{unnamed_field, variant}; use ext::base::ext_ctxt; use ext::build; use codemap::span; @@ -211,7 +211,7 @@ fn create_derived_impl(cx: ext_ctxt, let bound = build::mk_ty_path_global(cx, span, trait_path.map(|x| *x)); - let bounds = @~[ ty_param_bound(bound) ]; + let bounds = @~[ TraitTyParamBound(bound) ]; let impl_ty_param = build::mk_ty_param(cx, ty_param.ident, bounds); impl_ty_params.push(move impl_ty_param); } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 7de4e3f1d5fb0..28bb9787646ec 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -138,7 +138,10 @@ fn fold_fn_decl(decl: ast::fn_decl, fld: ast_fold) -> ast::fn_decl { } fn fold_ty_param_bound(tpb: ty_param_bound, fld: ast_fold) -> ty_param_bound { - ty_param_bound(fld.fold_ty(*tpb)) + match tpb { + TraitTyParamBound(ty) => TraitTyParamBound(fld.fold_ty(ty)), + RegionTyParamBound => RegionTyParamBound + } } fn fold_ty_param(tp: ty_param, fld: ast_fold) -> ty_param { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 80fd04f0e1018..e5a20f84c4979 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -10,7 +10,8 @@ use core::prelude::*; -use ast::{ProtoBox, ProtoUniq, provided, public, pure_fn, purity, re_static}; +use ast::{ProtoBox, ProtoUniq, RegionTyParamBound, TraitTyParamBound}; +use ast::{provided, public, pure_fn, purity, re_static}; use ast::{_mod, add, arg, arm, attribute, bind_by_ref, bind_infer}; use ast::{bind_by_value, bind_by_move, bitand, bitor, bitxor, blk}; use ast::{blk_check_mode, box, by_copy, by_move, by_ref, by_val}; @@ -2399,8 +2400,16 @@ impl Parser { fn parse_optional_ty_param_bounds() -> @~[ty_param_bound] { let mut bounds = ~[]; if self.eat(token::COLON) { - while is_ident(self.token) { - if is_ident(self.token) { + loop { + if self.eat(token::BINOP(token::AND)) { + if self.eat_keyword(~"static") { + bounds.push(RegionTyParamBound); + } else { + self.span_err(copy self.span, + ~"`&static` is the only permissible \ + region bound here"); + } + } else if is_ident(self.token) { let maybe_bound = match self.token { token::IDENT(copy sid, _) => { match *self.id_to_str(sid) { @@ -2413,7 +2422,7 @@ impl Parser { ObsoleteLowerCaseKindBounds); // Bogus value, but doesn't matter, since // is an error - Some(ty_param_bound(self.mk_ty_path(sid))) + Some(TraitTyParamBound(self.mk_ty_path(sid))) } _ => None @@ -2428,11 +2437,12 @@ impl Parser { bounds.push(bound); } None => { - bounds.push(ty_param_bound(self.parse_ty(false))); + let ty = self.parse_ty(false); + bounds.push(TraitTyParamBound(ty)); } } } else { - bounds.push(ty_param_bound(self.parse_ty(false))); + break; } } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index c121bc30b96a3..a91dc11e9e223 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -10,7 +10,7 @@ use core::prelude::*; -use ast::{required, provided}; +use ast::{RegionTyParamBound, TraitTyParamBound, required, provided}; use ast; use ast_util; use ast_util::{operator_prec}; @@ -1787,9 +1787,12 @@ fn print_arg_mode(s: ps, m: ast::mode) { fn print_bounds(s: ps, bounds: @~[ast::ty_param_bound]) { if bounds.is_not_empty() { word(s.s, ~":"); - for vec::each(*bounds) |bound| { + for vec::each(*bounds) |&bound| { nbsp(s); - print_type(s, **bound); + match bound { + TraitTyParamBound(ty) => print_type(s, ty), + RegionTyParamBound => word(s.s, ~"&static"), + } } } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 3f7ba2dc37bd1..b99dd0385c12e 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -283,8 +283,11 @@ fn visit_foreign_item(ni: @foreign_item, e: E, v: vt) { } fn visit_ty_param_bounds(bounds: @~[ty_param_bound], e: E, v: vt) { - for vec::each(*bounds) |bound| { - (v.visit_ty)(**bound, e, v) + for bounds.each |&bound| { + match bound { + TraitTyParamBound(ty) => (v.visit_ty)(ty, e, v), + RegionTyParamBound => () + } } } diff --git a/src/test/compile-fail/static-region-bound.rs b/src/test/compile-fail/static-region-bound.rs new file mode 100644 index 0000000000000..b70b0cdf88191 --- /dev/null +++ b/src/test/compile-fail/static-region-bound.rs @@ -0,0 +1,9 @@ +fn f(_: T) {} + +fn main() { + let x = @3; + f(x); + let x = &3; + f(x); //~ ERROR instantiating a type parameter with an incompatible type +} +