reimplementation is as safe as the `Box` type.
```
+#![feature(unsafe_destructor)]
+
extern crate libc;
use libc::{c_void, size_t, malloc, free};
use std::mem;
// A key ingredient for safety, we associate a destructor with
// Unique<T>, making the struct manage the raw pointer: when the
// struct goes out of scope, it will automatically free the raw pointer.
+//
// NB: This is an unsafe destructor, because rustc will not normally
-// allow destructors to be associated with parametrized types, due to
+// allow destructors to be associated with parameterized types, due to
// bad interaction with managed boxes. (With the Send restriction,
-// we don't have this problem.)
+// we don't have this problem.) Note that the `#[unsafe_destructor]`
+// feature gate is required to use unsafe destructors.
#[unsafe_destructor]
impl<T: Send> Drop for Unique<T> {
fn drop(&mut self) {
enum representation in C is undefined, and this may be incorrect when the C
code is compiled with certain flags.
- `simd` - on certain tuple structs, derive the arithmetic operators, which
- lower to the target's SIMD instructions, if any.
+ lower to the target's SIMD instructions, if any; the `simd` feature gate
+ is necessary to use this attribute.
- `static_assert` - on statics whose type is `bool`, terminates compilation
with an error if it is not initialized to `true`.
- `unsafe_destructor` - allow implementations of the "drop" language item
where the type it is implemented for does not implement the "send" language
- item.
+ item; the `unsafe_destructor` feature gate is needed to use this attribute
- `unsafe_no_drop_flag` - on structs, remove the flag that prevents
destructors from being run twice. Destructors might be run multiple times on
the same object with this attribute.
These levels are directly inspired by
[Node.js' "stability index"](http://nodejs.org/api/documentation.html).
-There are lints for disallowing items marked with certain levels:
-`deprecated`, `experimental` and `unstable`; the first two will warn
-by default. Items with not marked with a stability are considered to
-be unstable for the purposes of the lint. One can give an optional
+Stability levels are inherited, so an items's stability attribute is the
+default stability for everything nested underneath it.
+
+There are lints for disallowing items marked with certain levels: `deprecated`,
+`experimental` and `unstable`. For now, only `deprecated` warns by default, but
+this will change once the standard library has been stabilized.
+Stability levels are meant to be promises at the crate
+ level, so these lints only apply when referencing
+items from an _external_ crate, not to items defined within the
+current crate. Items with no stability level are considered
+to be unstable for the purposes of the lint. One can give an optional
string that will be displayed when the lint flags the use of an item.
-~~~~ {.ignore}
-#![warn(unstable)]
+For example, if we define one crate called `stability_levels`:
+~~~~ {.ignore}
#[deprecated="replaced by `best`"]
-fn bad() {
+pub fn bad() {
// delete everything
}
-fn better() {
+pub fn better() {
// delete fewer things
}
#[stable]
-fn best() {
+pub fn best() {
// delete nothing
}
+~~~~
+
+then the lints will work as follows for a client crate:
+
+~~~~ {.ignore}
+#![warn(unstable)]
+extern crate stability_levels;
+use stability_levels::{bad, better, best};
fn main() {
bad(); // "warning: use of deprecated item: replaced by `best`"
html_root_url = "http://doc.rust-lang.org/")]
#![no_std]
-#![feature(phase)]
+#![feature(phase, unsafe_destructor)]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
#[phase(plugin, link)]
extern crate core;
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/")]
+
+#![feature(unsafe_destructor)]
#![allow(missing_doc)]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
use std::cell::{Cell, RefCell};
use std::cmp;
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, managed_boxes, default_type_params, phase, globs)]
+#![feature(unsafe_destructor)]
#![no_std]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
#[phase(plugin, link)] extern crate core;
extern crate alloc;
html_playground_url = "http://play.rust-lang.org/")]
#![no_std]
-#![feature(globs, macro_rules, managed_boxes, phase, simd)]
+#![feature(globs, macro_rules, managed_boxes, phase, simd, unsafe_destructor)]
#![deny(missing_doc)]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
#[cfg(test)] extern crate realcore = "core";
#[cfg(test)] extern crate libc;
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/")]
+
#![deny(unused_result, unused_must_use)]
#![allow(non_camel_case_types)]
#![allow(deprecated)]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
#![feature(default_type_params)]
// NB this crate explicitly does *not* allow glob imports, please seriously
// consider whether they're needed before adding that feature here (the
// answer is that you don't need them)
-#![feature(macro_rules)]
+#![feature(macro_rules, unsafe_destructor)]
extern crate alloc;
extern crate libc;
use metadata::creader;
use middle::cfg;
use middle::cfg::graphviz::LabelledCFG;
-use middle::{trans, freevars, kind, ty, typeck, lint, reachable};
+use middle::{trans, freevars, stability, kind, ty, typeck, lint, reachable};
use middle::dependency_format;
use middle;
use plugin::load::Plugins;
time(time_passes, "loop checking", (), |_|
middle::check_loop::check_crate(&sess, krate));
+ let stability_index = time(time_passes, "stability index", (), |_|
+ stability::Index::build(krate));
+
let ty_cx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map,
- freevars, region_map, lang_items);
+ freevars, region_map, lang_items, stability_index);
// passes are timed inside typeck
typeck::check_crate(&ty_cx, trait_map, krate);
("log_syntax", Active),
("trace_macros", Active),
("concat_idents", Active),
+ ("unsafe_destructor", Active),
("simd", Active),
("default_type_params", Active),
}
}
+ ast::ItemImpl(..) => {
+ if attr::contains_name(i.attrs.as_slice(),
+ "unsafe_destructor") {
+ self.gate_feature("unsafe_destructor",
+ i.span,
+ "`#[unsafe_destructor]` allows too \
+ many unsafe patterns and may be \
+ removed in the future");
+ }
+ }
+
_ => {}
}
html_root_url = "http://doc.rust-lang.org/")]
#![allow(deprecated)]
-#![feature(macro_rules, globs, struct_variant, managed_boxes, quote,
- default_type_params, phase)]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
+#![feature(macro_rules, globs, struct_variant, managed_boxes, quote)]
+#![feature(default_type_params, phase, unsafe_destructor)]
extern crate arena;
extern crate debug;
pub mod weak_lang_items;
pub mod save;
pub mod intrinsicck;
+ pub mod stability;
}
pub mod front {
pub static tag_reachable_extern_fns: uint = 0x90;
pub static tag_reachable_extern_fn_id: uint = 0x91;
+pub static tag_items_data_item_stability: uint = 0x92;
+
+
#[deriving(Clone, Show)]
pub struct LinkMeta {
pub crateid: CrateId,
use std::rc::Rc;
use syntax::ast;
use syntax::ast_map;
+use syntax::attr;
use syntax::diagnostic::expect;
use syntax::parse::token;
let cdata = cstore.get_crate_data(did.krate);
decoder::is_typedef(&*cdata, did.node)
}
+
+pub fn get_stability(cstore: &cstore::CStore,
+ def: ast::DefId)
+ -> Option<attr::Stability> {
+ let cdata = cstore.get_crate_data(def.krate);
+ decoder::get_stability(&*cdata, def.node)
+}
}
}
+pub fn get_stability(cdata: Cmd, id: ast::NodeId) -> Option<attr::Stability> {
+ let item = lookup_item(id, cdata.data());
+ reader::maybe_get_doc(item, tag_items_data_item_stability).map(|doc| {
+ let mut decoder = reader::Decoder::new(doc);
+ Decodable::decode(&mut decoder).unwrap()
+ })
+}
+
pub fn get_impl_trait(cdata: Cmd,
id: ast::NodeId,
tcx: &ty::ctxt) -> Option<Rc<ty::TraitRef>>
encode_parent_item(ebml_w, local_def(id));
encode_visibility(ebml_w, variant.node.vis);
encode_attributes(ebml_w, variant.node.attrs.as_slice());
+
+ let stab = ecx.tcx.stability.borrow().lookup_local(variant.node.id);
+ encode_stability(ebml_w, stab);
+
match variant.node.kind {
ast::TupleVariantKind(ref args)
if args.len() > 0 && generics.ty_params.len() == 0 => {
encode_path(ebml_w, path.clone());
encode_visibility(ebml_w, vis);
+ encode_stability(ebml_w, ecx.tcx.stability.borrow().lookup_local(id));
// Encode the reexports of this module, if this module is public.
if vis == Public {
encode_symbol(ecx, ebml_w, ctor_id);
}
+ encode_stability(ebml_w, ecx.tcx.stability.borrow().lookup_local(ctor_id));
+
// indicate that this is a tuple struct ctor, because downstream users will normally want
// the tuple struct definition, but without this there is no way for them to tell that
// they actually have a ctor rather than a normal function
encode_method_ty_fields(ecx, ebml_w, m);
encode_parent_item(ebml_w, local_def(parent_id));
+ let stab = ecx.tcx.stability.borrow().lookup_local(m.def_id.node);
+ encode_stability(ebml_w, stab);
+
// The type for methods gets encoded twice, which is unfortunate.
let tpt = lookup_item_type(ecx.tcx, m.def_id);
encode_bounds_and_type(ebml_w, ecx, &tpt);
ebml_w.end_tag();
}
+fn encode_stability(ebml_w: &mut Encoder, stab_opt: Option<attr::Stability>) {
+ stab_opt.map(|stab| {
+ ebml_w.start_tag(tag_items_data_item_stability);
+ stab.encode(ebml_w).unwrap();
+ ebml_w.end_tag();
+ });
+}
+
fn encode_info_for_item(ecx: &EncodeContext,
ebml_w: &mut Encoder,
item: &Item,
ecx.tcx.sess.codemap().span_to_str(item.span));
let def_id = local_def(item.id);
+ let stab = tcx.stability.borrow().lookup_local(item.id);
+
match item.node {
ItemStatic(_, m, _) => {
add_to_index(item, ebml_w, index);
encode_inlined_item(ecx, ebml_w, IIItemRef(item));
}
encode_visibility(ebml_w, vis);
+ encode_stability(ebml_w, stab);
ebml_w.end_tag();
}
ItemFn(ref decl, fn_style, _, ref generics, _) => {
encode_symbol(ecx, ebml_w, item.id);
}
encode_visibility(ebml_w, vis);
+ encode_stability(ebml_w, stab);
encode_method_argument_names(ebml_w, &**decl);
ebml_w.end_tag();
}
ebml_w.end_tag();
}
encode_visibility(ebml_w, vis);
+ encode_stability(ebml_w, stab);
ebml_w.end_tag();
}
ItemTy(..) => {
encode_name(ebml_w, item.ident.name);
encode_path(ebml_w, path);
encode_visibility(ebml_w, vis);
+ encode_stability(ebml_w, stab);
ebml_w.end_tag();
}
ItemEnum(ref enum_definition, ref generics) => {
encode_inherent_implementations(ecx, ebml_w, def_id);
encode_visibility(ebml_w, vis);
+ encode_stability(ebml_w, stab);
ebml_w.end_tag();
encode_enum_variant_info(ecx,
encode_name(ebml_w, item.ident.name);
encode_attributes(ebml_w, item.attrs.as_slice());
encode_path(ebml_w, path.clone());
+ encode_stability(ebml_w, stab);
encode_visibility(ebml_w, vis);
/* Encode def_ids for each field and method
encode_impl_vtables(ebml_w, ecx, &impl_vtables);
}
encode_path(ebml_w, path.clone());
+ encode_stability(ebml_w, stab);
ebml_w.end_tag();
// Iterate down the methods, emitting them. We rely on the
// should no longer need this ugly little hack either.
encode_sized(ebml_w, sized);
encode_visibility(ebml_w, vis);
+ encode_stability(ebml_w, stab);
for &method_def_id in ty::trait_method_def_ids(tcx, def_id).iter() {
ebml_w.start_tag(tag_item_trait_method);
encode_def_id(ebml_w, method_def_id);
ebml_w.start_tag(tag_items_data_item);
encode_method_ty_fields(ecx, ebml_w, &*method_ty);
-
encode_parent_item(ebml_w, def_id);
+ let stab = tcx.stability.borrow().lookup_local(method_def_id.node);
+ encode_stability(ebml_w, stab);
+
let elem = ast_map::PathName(method_ty.ident.name);
encode_path(ebml_w, path.clone().chain(Some(elem).move_iter()));
#![allow(non_camel_case_types)]
-use middle::const_eval::{compare_const_vals, lookup_const_by_id};
-use middle::const_eval::{eval_const_expr, const_val, const_bool, const_float};
+use middle::const_eval::{compare_const_vals, const_bool, const_float, const_val};
+use middle::const_eval::{eval_const_expr, lookup_const_by_id};
use middle::def::*;
use middle::pat_util::*;
use middle::ty::*;
use middle::ty;
-use util::ppaux::ty_to_str;
-use std::cmp;
use std::gc::{Gc, GC};
use std::iter;
use syntax::ast::*;
use syntax::ast_util::{is_unguarded, walk_pat};
-use syntax::codemap::{DUMMY_SP, Span};
-use syntax::parse::token;
+use syntax::codemap::{Span, Spanned, DUMMY_SP};
+use syntax::owned_slice::OwnedSlice;
+use syntax::print::pprust::pat_to_str;
use syntax::visit;
use syntax::visit::{Visitor, FnKind};
+use util::ppaux::ty_to_str;
+
+type Matrix = Vec<Vec<Gc<Pat>>>;
+
+#[deriving(Clone)]
+enum Usefulness {
+ Useful(Vec<Gc<Pat>>),
+ NotUseful
+}
+
+enum WitnessPreference {
+ ConstructWitness,
+ LeaveOutWitness
+}
+
+impl Usefulness {
+ fn useful(self) -> Option<Vec<Gc<Pat>>> {
+ match self {
+ Useful(pats) => Some(pats),
+ _ => None
+ }
+ }
+}
+
+fn def_to_path(tcx: &ty::ctxt, id: DefId) -> Path {
+ ty::with_path(tcx, id, |mut path| Path {
+ global: false,
+ segments: path.last().map(|elem| PathSegment {
+ identifier: Ident::new(elem.name()),
+ lifetimes: vec!(),
+ types: OwnedSlice::empty()
+ }).move_iter().collect(),
+ span: DUMMY_SP,
+ })
+}
struct MatchCheckCtxt<'a> {
tcx: &'a ty::ctxt,
fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
visit::walk_expr(cx, ex, ());
match ex.node {
- ExprMatch(scrut, ref arms) => {
- // First, check legality of move bindings.
- for arm in arms.iter() {
- check_legality_of_move_bindings(cx,
- arm.guard.is_some(),
- arm.pats.as_slice());
- }
+ ExprMatch(scrut, ref arms) => {
+ // First, check legality of move bindings.
+ for arm in arms.iter() {
+ check_legality_of_move_bindings(cx,
+ arm.guard.is_some(),
+ arm.pats.as_slice());
+ }
- check_arms(cx, arms.as_slice());
- /* Check for exhaustiveness */
- // Check for empty enum, because is_useful only works on inhabited
- // types.
- let pat_ty = node_id_to_type(cx.tcx, scrut.id);
- if (*arms).is_empty() {
- if !type_is_empty(cx.tcx, pat_ty) {
- // We know the type is inhabited, so this must be wrong
- cx.tcx.sess.span_err(ex.span, format!("non-exhaustive patterns: \
- type {} is non-empty",
- ty_to_str(cx.tcx, pat_ty)).as_slice());
- }
- // If the type *is* empty, it's vacuously exhaustive
- return;
- }
- let m: matrix = arms
- .iter()
- .filter(|&arm| is_unguarded(arm))
- .flat_map(|arm| arm.pats.iter())
- .map(|pat| vec!(pat.clone()))
- .collect();
- check_exhaustive(cx, ex.span, &m);
- }
- _ => ()
+ // Second, check for unreachable arms.
+ check_arms(cx, arms.as_slice());
+
+ // Finally, check if the whole match expression is exhaustive.
+ // Check for empty enum, because is_useful only works on inhabited types.
+ let pat_ty = node_id_to_type(cx.tcx, scrut.id);
+ if (*arms).is_empty() {
+ if !type_is_empty(cx.tcx, pat_ty) {
+ // We know the type is inhabited, so this must be wrong
+ cx.tcx.sess.span_err(ex.span, format!("non-exhaustive patterns: \
+ type {} is non-empty",
+ ty_to_str(cx.tcx, pat_ty)).as_slice());
+ }
+ // If the type *is* empty, it's vacuously exhaustive
+ return;
+ }
+ let m: Matrix = arms
+ .iter()
+ .filter(|&arm| is_unguarded(arm))
+ .flat_map(|arm| arm.pats.iter())
+ .map(|pat| vec!(pat.clone()))
+ .collect();
+ check_exhaustive(cx, ex.span, &m);
+ },
+ _ => ()
}
}
let mut seen = Vec::new();
for arm in arms.iter() {
for pat in arm.pats.iter() {
-
// Check that we do not match against a static NaN (#6804)
let pat_matches_nan: |&Pat| -> bool = |p| {
let opt_def = cx.tcx.def_map.borrow().find_copy(&p.id);
});
let v = vec!(*pat);
- match is_useful(cx, &seen, v.as_slice()) {
- not_useful => {
- cx.tcx.sess.span_err(pat.span, "unreachable pattern");
- }
- _ => ()
+ match is_useful(cx, &seen, v.as_slice(), LeaveOutWitness) {
+ NotUseful => cx.tcx.sess.span_err(pat.span, "unreachable pattern"),
+ _ => ()
}
if arm.guard.is_none() { seen.push(v); }
}
fn raw_pat(p: Gc<Pat>) -> Gc<Pat> {
match p.node {
- PatIdent(_, _, Some(s)) => { raw_pat(s) }
- _ => { p }
+ PatIdent(_, _, Some(s)) => { raw_pat(s) }
+ _ => { p }
}
}
-fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, m: &matrix) {
- let ext = match is_useful(cx, m, [wild()]) {
- not_useful => {
+fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, m: &Matrix) {
+ match is_useful(cx, m, [wild()], ConstructWitness) {
+ NotUseful => {
// This is good, wildcard pattern isn't reachable
return;
}
- useful_ => None,
- useful(ty, ref ctor) => {
+ Useful(pats) => {
+ let witness = match pats.as_slice() {
+ [witness] => witness,
+ [] => wild(),
+ _ => unreachable!()
+ };
+ let msg = format!("non-exhaustive patterns: `{0}` not covered", pat_to_str(&*witness));
+ cx.tcx.sess.span_err(sp, msg.as_slice());
+ }
+ }
+}
+
+#[deriving(Clone, PartialEq)]
+enum ctor {
+ single,
+ variant(DefId /* variant */, bool /* is_structure */),
+ val(const_val),
+ range(const_val, const_val),
+ vec(uint)
+}
+
+fn const_val_to_expr(value: &const_val) -> Gc<Expr> {
+ let node = match value {
+ &const_bool(b) => LitBool(b),
+ _ => unreachable!()
+ };
+ box(GC) Expr {
+ id: 0,
+ node: ExprLit(box(GC) Spanned { node: node, span: DUMMY_SP }),
+ span: DUMMY_SP
+ }
+}
+
+fn construct_witness(cx: &MatchCheckCtxt, ctor: &ctor, pats: Vec<Gc<Pat>>, lty: ty::t) -> Gc<Pat> {
+ let pat = match ty::get(lty).sty {
+ ty::ty_tup(_) => PatTup(pats),
+
+ ty::ty_enum(cid, _) | ty::ty_struct(cid, _) => {
+ let (vid, is_structure) = match ctor {
+ &variant(vid, is_structure) => (vid, is_structure),
+ _ => (cid, true)
+ };
+ if is_structure {
+ let fields = ty::lookup_struct_fields(cx.tcx, vid);
+ let field_pats = fields.move_iter()
+ .zip(pats.iter())
+ .map(|(field, pat)| FieldPat {
+ ident: Ident::new(field.name),
+ pat: pat.clone()
+ }).collect();
+ PatStruct(def_to_path(cx.tcx, vid), field_pats, false)
+ } else {
+ PatEnum(def_to_path(cx.tcx, vid), Some(pats))
+ }
+ },
+
+ ty::ty_rptr(_, ty::mt { ty: ty, .. }) => {
match ty::get(ty).sty {
- ty::ty_bool => {
- match *ctor {
- val(const_bool(true)) => Some("true".to_string()),
- val(const_bool(false)) => Some("false".to_string()),
- _ => None
- }
- }
- ty::ty_enum(id, _) => {
- let vid = match *ctor {
- variant(id) => id,
- _ => fail!("check_exhaustive: non-variant ctor"),
- };
- let variants = ty::enum_variants(cx.tcx, id);
-
- match variants.iter().find(|v| v.id == vid) {
- Some(v) => {
- Some(token::get_ident(v.name).get()
- .to_str()
- .into_string())
- }
- None => {
- fail!("check_exhaustive: bad variant in ctor")
- }
- }
- }
- ty::ty_vec(..) | ty::ty_rptr(..) => {
- match *ctor {
- vec(n) => {
- Some(format!("vectors of length {}", n))
- }
- _ => None
- }
+ ty::ty_vec(_, None) => match ctor {
+ &vec(_) => PatVec(pats, None, vec!()),
+ _ => unreachable!()
+ },
+ ty::ty_str => PatWild,
+ _ => {
+ assert_eq!(pats.len(), 1);
+ PatRegion(pats.get(0).clone())
}
- _ => None
+ }
+ },
+
+ ty::ty_box(_) => {
+ assert_eq!(pats.len(), 1);
+ PatBox(pats.get(0).clone())
+ },
+
+ _ => {
+ match ctor {
+ &vec(_) => PatVec(pats, None, vec!()),
+ &val(ref v) => PatLit(const_val_to_expr(v)),
+ _ => PatWild
}
}
};
- let msg = format!("non-exhaustive patterns{}", match ext {
- Some(ref s) => format!(": {} not covered", *s),
- None => "".to_string()
- });
- cx.tcx.sess.span_err(sp, msg.as_slice());
+
+ box(GC) Pat {
+ id: 0,
+ node: pat,
+ span: DUMMY_SP
+ }
}
-type matrix = Vec<Vec<Gc<Pat>>>;
+fn missing_constructor(cx: &MatchCheckCtxt, m: &Matrix, left_ty: ty::t) -> Option<ctor> {
+ let used_constructors: Vec<ctor> = m.iter()
+ .filter_map(|r| pat_ctor_id(cx, left_ty, *r.get(0)))
+ .collect();
-#[deriving(Clone)]
-enum useful {
- useful(ty::t, ctor),
- useful_,
- not_useful,
+ all_constructors(cx, m, left_ty)
+ .move_iter()
+ .find(|c| !used_constructors.contains(c))
}
-#[deriving(Clone, PartialEq)]
-enum ctor {
- single,
- variant(DefId),
- val(const_val),
- range(const_val, const_val),
- vec(uint)
+fn all_constructors(cx: &MatchCheckCtxt, m: &Matrix, left_ty: ty::t) -> Vec<ctor> {
+ fn vec_constructors(m: &Matrix) -> Vec<ctor> {
+ let max_vec_len = m.iter().map(|r| match r.get(0).node {
+ PatVec(ref before, _, ref after) => before.len() + after.len(),
+ _ => 0u
+ }).max().unwrap_or(0u);
+ let contains_slice = m.iter().any(|r| match r.get(0).node {
+ PatVec(_, ref slice, _) => slice.is_some(),
+ _ => false
+ });
+ let lengths = iter::range_inclusive(0u, if contains_slice {
+ max_vec_len
+ } else {
+ max_vec_len + 1
+ });
+ lengths.map(|len| vec(len)).collect()
+ }
+
+ match ty::get(left_ty).sty {
+ ty::ty_bool =>
+ [true, false].iter().map(|b| val(const_bool(*b))).collect(),
+
+ ty::ty_rptr(_, ty::mt { ty: ty, .. }) => match ty::get(ty).sty {
+ ty::ty_vec(_, None) => vec_constructors(m),
+ _ => vec!(single)
+ },
+
+ ty::ty_enum(eid, _) =>
+ ty::enum_variants(cx.tcx, eid)
+ .iter()
+ .map(|va| variant(va.id, va.arg_names.is_some()))
+ .collect(),
+
+ ty::ty_vec(_, None) =>
+ vec_constructors(m),
+
+ ty::ty_vec(_, Some(n)) =>
+ vec!(vec(n)),
+
+ ty::ty_nil if !m.iter().all(|r| is_wild(cx, *r.get(0))) =>
+ vec!(),
+
+ _ =>
+ vec!(single)
+ }
}
// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html
// Note: is_useful doesn't work on empty types, as the paper notes.
// So it assumes that v is non-empty.
-fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[Gc<Pat>]) -> useful {
+fn is_useful(cx: &MatchCheckCtxt, m: &Matrix, v: &[Gc<Pat>],
+ witness: WitnessPreference) -> Usefulness {
if m.len() == 0u {
- return useful_;
+ return Useful(vec!());
}
if m.get(0).len() == 0u {
- return not_useful
+ return NotUseful;
}
let real_pat = match m.iter().find(|r| r.get(0).id != 0) {
Some(r) => {
_ => *r.get(0)
}
}
- None if v.len() == 0 => return not_useful,
+ None if v.len() == 0 => return NotUseful,
None => v[0]
};
- let left_ty = if real_pat.id == 0 { ty::mk_nil() }
- else { ty::node_id_to_type(cx.tcx, real_pat.id) };
-
- match pat_ctor_id(cx, v[0]) {
- None => {
- match missing_ctor(cx, m, left_ty) {
- None => {
- match ty::get(left_ty).sty {
- ty::ty_bool => {
- match is_useful_specialized(cx, m, v,
- val(const_bool(true)),
- 0u, left_ty){
- not_useful => {
- is_useful_specialized(cx, m, v,
- val(const_bool(false)),
- 0u, left_ty)
- }
- u => u,
- }
- }
- ty::ty_enum(eid, _) => {
- for va in (*ty::enum_variants(cx.tcx, eid)).iter() {
- match is_useful_specialized(cx, m, v, variant(va.id),
- va.args.len(), left_ty) {
- not_useful => (),
- u => return u,
- }
- }
- not_useful
- }
- ty::ty_vec(_, Some(n)) => {
- is_useful_specialized(cx, m, v, vec(n), n, left_ty)
- }
- ty::ty_vec(..) => fail!("impossible case"),
- ty::ty_rptr(_, ty::mt{ty: ty, ..}) | ty::ty_uniq(ty) => match ty::get(ty).sty {
- ty::ty_vec(_, None) => {
- let max_len = m.iter().rev().fold(0, |max_len, r| {
- match r.get(0).node {
- PatVec(ref before, _, ref after) => {
- cmp::max(before.len() + after.len(), max_len)
- }
- _ => max_len
- }
- });
- for n in iter::range(0u, max_len + 1) {
- match is_useful_specialized(cx, m, v, vec(n), n, left_ty) {
- not_useful => (),
- u => return u,
- }
- }
- not_useful
- }
- _ => {
- let arity = ctor_arity(cx, &single, left_ty);
- is_useful_specialized(cx, m, v, single, arity, left_ty)
- }
- },
- _ => {
- let arity = ctor_arity(cx, &single, left_ty);
- is_useful_specialized(cx, m, v, single, arity, left_ty)
- }
- }
- }
- Some(ctor) => {
- match is_useful(cx,
- &m.iter().filter_map(|r| {
- default(cx, r.as_slice())
- }).collect::<matrix>(),
- v.tail()) {
- useful_ => useful(left_ty, ctor),
- u => u,
+ let left_ty = if real_pat.id == 0 {
+ ty::mk_nil()
+ } else {
+ ty::pat_ty(cx.tcx, &*real_pat)
+ };
+
+ match pat_ctor_id(cx, left_ty, v[0]) {
+ None => match missing_constructor(cx, m, left_ty) {
+ None => {
+ all_constructors(cx, m, left_ty).move_iter().filter_map(|c| {
+ is_useful_specialized(cx, m, v, c.clone(),
+ left_ty, witness).useful().map(|pats| {
+ Useful(match witness {
+ ConstructWitness => {
+ let arity = constructor_arity(cx, &c, left_ty);
+ let subpats = {
+ let pat_slice = pats.as_slice();
+ Vec::from_fn(arity, |i| {
+ pat_slice.get(i).map(|p| p.clone())
+ .unwrap_or_else(|| wild())
+ })
+ };
+ let mut result = vec!(construct_witness(cx, &c, subpats, left_ty));
+ result.extend(pats.move_iter().skip(arity));
+ result
+ }
+ LeaveOutWitness => vec!()
+ })
+ })
+ }).nth(0).unwrap_or(NotUseful)
+ },
+
+ Some(ctor) => {
+ let matrix = m.iter().filter_map(|r| default(cx, r.as_slice())).collect();
+ match is_useful(cx, &matrix, v.tail(), witness) {
+ Useful(pats) => Useful(match witness {
+ ConstructWitness => {
+ let arity = constructor_arity(cx, &ctor, left_ty);
+ let wild_pats = Vec::from_elem(arity, wild());
+ let enum_pat = construct_witness(cx, &ctor, wild_pats, left_ty);
+ (vec!(enum_pat)).append(pats.as_slice())
+ }
+ LeaveOutWitness => vec!()
+ }),
+ result => result
+ }
}
- }
- }
- }
- Some(v0_ctor) => {
- let arity = ctor_arity(cx, &v0_ctor, left_ty);
- is_useful_specialized(cx, m, v, v0_ctor, arity, left_ty)
- }
+ },
+
+ Some(v0_ctor) => is_useful_specialized(cx, m, v, v0_ctor, left_ty, witness)
}
}
-fn is_useful_specialized(cx: &MatchCheckCtxt,
- m: &matrix,
- v: &[Gc<Pat>],
- ctor: ctor,
- arity: uint,
- lty: ty::t)
- -> useful {
- let ms = m.iter().filter_map(|r| {
- specialize(cx, r.as_slice(), &ctor, arity, lty)
- }).collect::<matrix>();
- let could_be_useful = match specialize(cx, v, &ctor, arity, lty) {
- Some(v) => is_useful(cx, &ms, v.as_slice()),
- None => return not_useful,
- };
- match could_be_useful {
- useful_ => useful(lty, ctor),
- u => u,
+fn is_useful_specialized(cx: &MatchCheckCtxt, m: &Matrix, v: &[Gc<Pat>],
+ ctor: ctor, lty: ty::t, witness: WitnessPreference) -> Usefulness {
+ let arity = constructor_arity(cx, &ctor, lty);
+ let matrix = m.iter().filter_map(|r| {
+ specialize(cx, r.as_slice(), &ctor, arity)
+ }).collect();
+ match specialize(cx, v, &ctor, arity) {
+ Some(v) => is_useful(cx, &matrix, v.as_slice(), witness),
+ None => NotUseful
}
}
-fn pat_ctor_id(cx: &MatchCheckCtxt, p: Gc<Pat>) -> Option<ctor> {
+fn pat_ctor_id(cx: &MatchCheckCtxt, left_ty: ty::t, p: Gc<Pat>) -> Option<ctor> {
let pat = raw_pat(p);
match pat.node {
- PatWild | PatWildMulti => { None }
- PatIdent(_, _, _) | PatEnum(_, _) => {
- let opt_def = cx.tcx.def_map.borrow().find_copy(&pat.id);
- match opt_def {
- Some(DefVariant(_, id, _)) => Some(variant(id)),
- Some(DefStatic(did, false)) => {
- let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
- Some(val(eval_const_expr(cx.tcx, &*const_expr)))
- }
- _ => None
- }
- }
- PatLit(ref expr) => { Some(val(eval_const_expr(cx.tcx, &**expr))) }
- PatRange(ref lo, ref hi) => {
- Some(range(eval_const_expr(cx.tcx, &**lo), eval_const_expr(cx.tcx, &**hi)))
- }
- PatStruct(..) => {
- match cx.tcx.def_map.borrow().find(&pat.id) {
- Some(&DefVariant(_, id, _)) => Some(variant(id)),
- _ => Some(single)
- }
- }
- PatBox(_) | PatTup(_) | PatRegion(..) => {
- Some(single)
- }
- PatVec(ref before, slice, ref after) => {
- match slice {
- Some(_) => None,
- None => Some(vec(before.len() + after.len()))
- }
- }
- PatMac(_) => cx.tcx.sess.bug("unexpanded macro"),
+ PatIdent(..) =>
+ match cx.tcx.def_map.borrow().find(&pat.id) {
+ Some(&DefStatic(did, false)) => {
+ let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
+ Some(val(eval_const_expr(cx.tcx, &*const_expr)))
+ },
+ Some(&DefVariant(_, id, is_structure)) => Some(variant(id, is_structure)),
+ _ => None
+ },
+ PatEnum(..) =>
+ match cx.tcx.def_map.borrow().find(&pat.id) {
+ Some(&DefStatic(did, false)) => {
+ let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
+ Some(val(eval_const_expr(cx.tcx, &*const_expr)))
+ },
+ Some(&DefVariant(_, id, is_structure)) => Some(variant(id, is_structure)),
+ _ => Some(single)
+ },
+ PatStruct(..) =>
+ match cx.tcx.def_map.borrow().find(&pat.id) {
+ Some(&DefVariant(_, id, is_structure)) => Some(variant(id, is_structure)),
+ _ => Some(single)
+ },
+ PatLit(expr) =>
+ Some(val(eval_const_expr(cx.tcx, &*expr))),
+ PatRange(lo, hi) =>
+ Some(range(eval_const_expr(cx.tcx, &*lo), eval_const_expr(cx.tcx, &*hi))),
+ PatVec(ref before, _, ref after) => match ty::get(left_ty).sty {
+ ty::ty_vec(_, Some(n)) =>
+ Some(vec(n)),
+ _ =>
+ Some(vec(before.len() + after.len()))
+ },
+ PatBox(_) | PatTup(_) | PatRegion(..) =>
+ Some(single),
+ PatWild | PatWildMulti =>
+ None,
+ PatMac(_) =>
+ cx.tcx.sess.bug("unexpanded macro")
}
}
fn is_wild(cx: &MatchCheckCtxt, p: Gc<Pat>) -> bool {
let pat = raw_pat(p);
match pat.node {
- PatWild | PatWildMulti => { true }
- PatIdent(_, _, _) => {
- match cx.tcx.def_map.borrow().find(&pat.id) {
- Some(&DefVariant(_, _, _)) | Some(&DefStatic(..)) => { false }
- _ => { true }
- }
- }
- _ => { false }
- }
-}
-
-fn missing_ctor(cx: &MatchCheckCtxt,
- m: &matrix,
- left_ty: ty::t)
- -> Option<ctor> {
- return match ty::get(left_ty).sty {
- ty::ty_box(_) | ty::ty_tup(_) |
- ty::ty_struct(..) => check_matrix_for_wild(cx, m),
- ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty: ty, ..}) => match ty::get(ty).sty {
- ty::ty_vec(_, None) => ctor_for_slice(m),
- ty::ty_str => Some(single),
- _ => check_matrix_for_wild(cx, m),
- },
- ty::ty_enum(eid, _) => {
- let pat_ctors: Vec<ctor> = m
- .iter()
- .filter_map(|r| pat_ctor_id(cx, *r.get(0)))
- .collect();
- let variants = ty::enum_variants(cx.tcx, eid);
- variants.iter().map(|v| variant(v.id)).find(|c| !pat_ctors.contains(c))
- }
- ty::ty_nil => None,
- ty::ty_bool => {
- let mut true_found = false;
- let mut false_found = false;
- for r in m.iter() {
- match pat_ctor_id(cx, *r.get(0)) {
- None => (),
- Some(val(const_bool(true))) => true_found = true,
- Some(val(const_bool(false))) => false_found = true,
- _ => fail!("impossible case")
+ PatWild | PatWildMulti => true,
+ PatIdent(_, _, _) => {
+ match cx.tcx.def_map.borrow().find(&pat.id) {
+ Some(&DefVariant(_, _, _)) | Some(&DefStatic(..)) => false,
+ _ => true
}
}
- if true_found && false_found { None }
- else if true_found { Some(val(const_bool(false))) }
- else { Some(val(const_bool(true))) }
- }
- ty::ty_vec(_, Some(n)) => {
- let mut missing = true;
- let mut wrong = false;
- for r in m.iter() {
- match r.get(0).node {
- PatVec(ref before, ref slice, ref after) => {
- let count = before.len() + after.len();
- if (count < n && slice.is_none()) || count > n {
- wrong = true;
- }
- if count == n || (count < n && slice.is_some()) {
- missing = false;
- }
- }
- _ => {}
- }
- }
- match (wrong, missing) {
- (true, _) => Some(vec(n)), // should be compile-time error
- (_, true) => Some(vec(n)),
- _ => None
- }
- }
- ty::ty_vec(..) => fail!("impossible case"),
- _ => Some(single)
- };
-
- fn check_matrix_for_wild(cx: &MatchCheckCtxt, m: &matrix) -> Option<ctor> {
- for r in m.iter() {
- if !is_wild(cx, *r.get(0)) { return None; }
- }
- return Some(single);
- }
-
- // For slice and ~[T].
- fn ctor_for_slice(m: &matrix) -> Option<ctor> {
- // Find the lengths and slices of all vector patterns.
- let mut vec_pat_lens = m.iter().filter_map(|r| {
- match r.get(0).node {
- PatVec(ref before, ref slice, ref after) => {
- Some((before.len() + after.len(), slice.is_some()))
- }
- _ => None
- }
- }).collect::<Vec<(uint, bool)> >();
-
- // Sort them by length such that for patterns of the same length,
- // those with a destructured slice come first.
- vec_pat_lens.sort_by(|&(len1, slice1), &(len2, slice2)| {
- if len1 == len2 {
- slice2.cmp(&slice1)
- } else {
- len1.cmp(&len2)
- }
- });
- vec_pat_lens.dedup();
-
- let mut found_slice = false;
- let mut next = 0;
- let mut missing = None;
- for &(length, slice) in vec_pat_lens.iter() {
- if length != next {
- missing = Some(next);
- break;
- }
- if slice {
- found_slice = true;
- break;
- }
- next += 1;
- }
-
- // We found patterns of all lengths within <0, next), yet there was no
- // pattern with a slice - therefore, we report vec(next) as missing.
- if !found_slice {
- missing = Some(next);
- }
- match missing {
- Some(k) => Some(vec(k)),
- None => None
- }
+ _ => false
}
}
-fn ctor_arity(cx: &MatchCheckCtxt, ctor: &ctor, ty: ty::t) -> uint {
- fn vec_ctor_arity(ctor: &ctor) -> uint {
- match *ctor {
- vec(n) => n,
- _ => 0u
- }
- }
-
+fn constructor_arity(cx: &MatchCheckCtxt, ctor: &ctor, ty: ty::t) -> uint {
match ty::get(ty).sty {
ty::ty_tup(ref fs) => fs.len(),
- ty::ty_box(_) => 1u,
- ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty: ty, ..}) => match ty::get(ty).sty {
- ty::ty_vec(_, None) => vec_ctor_arity(ctor),
- _ => 1u,
+ ty::ty_box(_) | ty::ty_uniq(_) => 1u,
+ ty::ty_rptr(_, ty::mt { ty: ty, .. }) => match ty::get(ty).sty {
+ ty::ty_vec(_, None) => match *ctor {
+ vec(n) => n,
+ _ => 0u
+ },
+ ty::ty_str => 0u,
+ _ => 1u
},
ty::ty_enum(eid, _) => {
- let id = match *ctor {
- variant(id) => id,
- _ => fail!("impossible case")
- };
- match ty::enum_variants(cx.tcx, eid).iter().find(|v| v.id == id ) {
- Some(v) => v.args.len(),
- None => fail!("impossible case")
+ match *ctor {
+ variant(id, _) => enum_variant_with_id(cx.tcx, eid, id).args.len(),
+ _ => unreachable!()
}
}
ty::ty_struct(cid, _) => ty::lookup_struct_fields(cx.tcx, cid).len(),
- ty::ty_vec(_, Some(_)) => vec_ctor_arity(ctor),
+ ty::ty_vec(_, _) => match *ctor {
+ vec(n) => n,
+ _ => 0u
+ },
_ => 0u
}
}
box(GC) Pat {id: 0, node: PatWild, span: DUMMY_SP}
}
-fn wild_multi() -> Gc<Pat> {
- box(GC) Pat {id: 0, node: PatWildMulti, span: DUMMY_SP}
-}
-
fn range_covered_by_constructor(ctor_id: &ctor, from: &const_val, to: &const_val) -> Option<bool> {
let (c_from, c_to) = match *ctor_id {
val(ref value) => (value, value),
}
}
-fn specialize(cx: &MatchCheckCtxt,
- r: &[Gc<Pat>],
- ctor_id: &ctor,
- arity: uint,
- left_ty: ty::t)
- -> Option<Vec<Gc<Pat>>> {
- let &Pat{id: ref pat_id, node: ref n, span: ref pat_span} = &(*raw_pat(r[0]));
+fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
+ ctor_id: &ctor, arity: uint) -> Option<Vec<Gc<Pat>>> {
+ let &Pat {
+ id: ref pat_id, node: ref n, span: ref pat_span
+ } = &(*raw_pat(r[0]));
let head: Option<Vec<Gc<Pat>>> = match n {
- &PatWild => {
- Some(Vec::from_elem(arity, wild()))
- }
- &PatWildMulti => {
- Some(Vec::from_elem(arity, wild_multi()))
- }
- &PatIdent(_, _, _) => {
- let opt_def = cx.tcx.def_map.borrow().find_copy(pat_id);
- match opt_def {
- Some(DefVariant(_, id, _)) => {
- if variant(id) == *ctor_id {
- Some(vec!())
- } else {
+ &PatWild => {
+ Some(Vec::from_elem(arity, wild()))
+ }
+ &PatWildMulti => {
+ Some(Vec::from_elem(arity, wild()))
+ }
+ &PatIdent(_, _, _) => {
+ let opt_def = cx.tcx.def_map.borrow().find_copy(pat_id);
+ match opt_def {
+ Some(DefVariant(_, id, _)) => match *ctor_id {
+ variant(vid, _) if vid == id => Some(vec!()),
+ _ => None
+ },
+ Some(DefStatic(did, _)) => {
+ let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
+ let e_v = eval_const_expr(cx.tcx, &*const_expr);
+ match range_covered_by_constructor(ctor_id, &e_v, &e_v) {
+ Some(true) => Some(vec!()),
+ Some(false) => None,
+ None => {
+ cx.tcx.sess.span_err(*pat_span, "mismatched types between arms");
None
}
}
- Some(DefStatic(did, _)) => {
- let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
- let e_v = eval_const_expr(cx.tcx, &*const_expr);
- match range_covered_by_constructor(ctor_id, &e_v, &e_v) {
- Some(true) => Some(vec!()),
- Some(false) => None,
- None => {
- cx.tcx.sess.span_err(*pat_span, "mismatched types between arms");
- None
- }
- }
- }
- _ => {
- Some(Vec::from_elem(arity, wild()))
- }
+ }
+ _ => {
+ Some(Vec::from_elem(arity, wild()))
}
}
- &PatEnum(_, ref args) => {
- let def = cx.tcx.def_map.borrow().get_copy(pat_id);
- match def {
- DefStatic(did, _) => {
- let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
- let e_v = eval_const_expr(cx.tcx, &*const_expr);
- match range_covered_by_constructor(ctor_id, &e_v, &e_v) {
- Some(true) => Some(vec!()),
- Some(false) => None,
- None => {
- cx.tcx.sess.span_err(*pat_span, "mismatched types between arms");
- None
- }
+ }
+ &PatEnum(_, ref args) => {
+ let def = cx.tcx.def_map.borrow().get_copy(pat_id);
+ match def {
+ DefStatic(did, _) => {
+ let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
+ let e_v = eval_const_expr(cx.tcx, &*const_expr);
+ match range_covered_by_constructor(ctor_id, &e_v, &e_v) {
+ Some(true) => Some(vec!()),
+ Some(false) => None,
+ None => {
+ cx.tcx.sess.span_err(*pat_span, "mismatched types between arms");
+ None
}
}
- DefVariant(_, id, _) if variant(id) != *ctor_id => None,
- DefVariant(..) | DefFn(..) | DefStruct(..) => {
- Some(match args {
- &Some(ref args) => args.clone(),
- &None => Vec::from_elem(arity, wild())
- })
- }
- _ => None
}
+ DefVariant(_, id, _) if variant(id, false) != *ctor_id => None,
+ DefVariant(..) | DefFn(..) | DefStruct(..) => {
+ Some(match args {
+ &Some(ref args) => args.clone(),
+ &None => Vec::from_elem(arity, wild())
+ })
+ }
+ _ => None
}
- &PatStruct(_, ref pattern_fields, _) => {
- // Is this a struct or an enum variant?
- let def = cx.tcx.def_map.borrow().get_copy(pat_id);
- let class_id = match def {
- DefVariant(_, variant_id, _) => {
- if variant(variant_id) == *ctor_id {
- Some(variant_id)
- } else {
- None
- }
- }
- _ => {
- match ty::get(left_ty).sty {
- ty::ty_struct(cid, _) => Some(cid),
- _ => {
- cx.tcx.sess.span_bug(
- *pat_span,
- format!("struct pattern resolved to {}, \
- not a struct",
- ty_to_str(cx.tcx,
- left_ty)).as_slice());
- }
- }
+ }
+
+ &PatStruct(_, ref pattern_fields, _) => {
+ // Is this a struct or an enum variant?
+ let def = cx.tcx.def_map.borrow().get_copy(pat_id);
+ let class_id = match def {
+ DefVariant(_, variant_id, _) => if *ctor_id == variant(variant_id, true) {
+ Some(variant_id)
+ } else {
+ None
+ },
+ DefStruct(struct_id) => Some(struct_id),
+ _ => None
+ };
+ class_id.map(|variant_id| {
+ let struct_fields = ty::lookup_struct_fields(cx.tcx, variant_id);
+ let args = struct_fields.iter().map(|sf| {
+ match pattern_fields.iter().find(|f| f.ident.name == sf.name) {
+ Some(f) => f.pat,
+ _ => wild()
}
- };
- class_id.map(|variant_id| {
- let struct_fields = ty::lookup_struct_fields(cx.tcx, variant_id);
- let args = struct_fields.iter().map(|sf| {
- match pattern_fields.iter().find(|f| f.ident.name == sf.name) {
- Some(f) => f.pat,
- _ => wild()
- }
- }).collect();
- args
- })
+ }).collect();
+ args
+ })
+ }
- }
- &PatTup(ref args) => {
- Some(args.clone())
- }
- &PatBox(ref inner) | &PatRegion(ref inner) => {
- Some(vec!(inner.clone()))
- }
- &PatLit(ref expr) => {
- let expr_value = eval_const_expr(cx.tcx, &**expr);
- match range_covered_by_constructor(ctor_id, &expr_value, &expr_value) {
- Some(true) => Some(vec!()),
- Some(false) => None,
- None => {
+ &PatTup(ref args) =>
+ Some(args.clone()),
+
+ &PatBox(ref inner) | &PatRegion(ref inner) =>
+ Some(vec!(inner.clone())),
+
+ &PatLit(ref expr) => {
+ let expr_value = eval_const_expr(cx.tcx, &**expr);
+ match range_covered_by_constructor(ctor_id, &expr_value, &expr_value) {
+ Some(true) => Some(vec!()),
+ Some(false) => None,
+ None => {
cx.tcx.sess.span_err(*pat_span, "mismatched types between arms");
None
- }
- }
+ }
}
- &PatRange(ref from, ref to) => {
- let from_value = eval_const_expr(cx.tcx, &**from);
- let to_value = eval_const_expr(cx.tcx, &**to);
- match range_covered_by_constructor(ctor_id, &from_value, &to_value) {
- Some(true) => Some(vec!()),
- Some(false) => None,
- None => {
+ }
+
+ &PatRange(ref from, ref to) => {
+ let from_value = eval_const_expr(cx.tcx, &**from);
+ let to_value = eval_const_expr(cx.tcx, &**to);
+ match range_covered_by_constructor(ctor_id, &from_value, &to_value) {
+ Some(true) => Some(vec!()),
+ Some(false) => None,
+ None => {
cx.tcx.sess.span_err(*pat_span, "mismatched types between arms");
None
- }
- }
+ }
}
- &PatVec(ref before, ref slice, ref after) => {
- match *ctor_id {
- vec(_) => {
- let num_elements = before.len() + after.len();
- if num_elements < arity && slice.is_some() {
- let mut result = Vec::new();
- result.push_all(before.as_slice());
- result.grow_fn(arity - num_elements, |_| wild());
- result.push_all(after.as_slice());
- Some(result)
- } else if num_elements == arity {
- let mut result = Vec::new();
- result.push_all(before.as_slice());
- result.push_all(after.as_slice());
- Some(result)
- } else {
- None
- }
+ }
+
+ &PatVec(ref before, ref slice, ref after) => {
+ match *ctor_id {
+ vec(_) => {
+ let num_elements = before.len() + after.len();
+ if num_elements < arity && slice.is_some() {
+ let mut result = Vec::new();
+ result.push_all(before.as_slice());
+ result.grow_fn(arity - num_elements, |_| wild());
+ result.push_all(after.as_slice());
+ Some(result)
+ } else if num_elements == arity {
+ let mut result = Vec::new();
+ result.push_all(before.as_slice());
+ result.push_all(after.as_slice());
+ Some(result)
+ } else {
+ None
}
- _ => None
}
+ _ => None
}
- &PatMac(_) => {
- cx.tcx.sess.span_err(*pat_span, "unexpanded macro");
- None
- }
+ }
+
+ &PatMac(_) => {
+ cx.tcx.sess.span_err(*pat_span, "unexpanded macro");
+ None
+ }
};
head.map(|head| head.append(r.tail()))
}
LocalFor => "`for` loop"
};
- let mut spans = vec![];
- find_refutable(cx, &*loc.pat, &mut spans);
-
- for span in spans.iter() {
- cx.tcx.sess.span_err(*span,
- format!("refutable pattern in {} binding", name).as_slice());
+ match is_refutable(cx, loc.pat) {
+ Some(pat) => {
+ let msg = format!(
+ "refutable pattern in {} binding: `{}` not covered",
+ name, pat_to_str(&*pat)
+ );
+ cx.tcx.sess.span_err(loc.pat.span, msg.as_slice());
+ },
+ None => ()
}
// Check legality of move bindings.
sp: Span) {
visit::walk_fn(cx, kind, decl, body, sp, ());
for input in decl.inputs.iter() {
- let mut spans = vec![];
- find_refutable(cx, &*input.pat, &mut spans);
-
- for span in spans.iter() {
- cx.tcx.sess.span_err(*span,
- "refutable pattern in function argument");
+ match is_refutable(cx, input.pat) {
+ Some(pat) => {
+ let msg = format!(
+ "refutable pattern in function argument: `{}` not covered",
+ pat_to_str(&*pat)
+ );
+ cx.tcx.sess.span_err(input.pat.span, msg.as_slice());
+ },
+ None => ()
}
}
}
-fn find_refutable(cx: &MatchCheckCtxt, pat: &Pat, spans: &mut Vec<Span>) {
- macro_rules! this_pattern {
- () => {
- {
- spans.push(pat.span);
- return
- }
- }
- }
- let opt_def = cx.tcx.def_map.borrow().find_copy(&pat.id);
- match opt_def {
- Some(DefVariant(enum_id, _, _)) => {
- if ty::enum_variants(cx.tcx, enum_id).len() != 1u {
- this_pattern!()
- }
- }
- Some(DefStatic(..)) => this_pattern!(),
- _ => ()
- }
-
- match pat.node {
- PatBox(ref sub) | PatRegion(ref sub) | PatIdent(_, _, Some(ref sub)) => {
- find_refutable(cx, &**sub, spans)
- }
- PatWild | PatWildMulti | PatIdent(_, _, None) => {}
- PatLit(lit) => {
- match lit.node {
- ExprLit(lit) => {
- match lit.node {
- LitNil => {} // `()`
- _ => this_pattern!(),
- }
- }
- _ => this_pattern!(),
- }
- }
- PatRange(_, _) => { this_pattern!() }
- PatStruct(_, ref fields, _) => {
- for f in fields.iter() {
- find_refutable(cx, &*f.pat, spans);
- }
- }
- PatTup(ref elts) | PatEnum(_, Some(ref elts))=> {
- for elt in elts.iter() {
- find_refutable(cx, &**elt, spans)
- }
- }
- PatEnum(_,_) => {}
- PatVec(..) => { this_pattern!() }
- PatMac(_) => cx.tcx.sess.bug("unexpanded macro"),
- }
+fn is_refutable(cx: &MatchCheckCtxt, pat: Gc<Pat>) -> Option<Gc<Pat>> {
+ let pats = vec!(vec!(pat));
+ is_useful(cx, &pats, [wild()], ConstructWitness)
+ .useful()
+ .map(|pats| {
+ assert_eq!(pats.len(), 1);
+ pats.get(0).clone()
+ })
}
// Legality of move bindings checking
LintSpec {
lint: Experimental,
desc: "detects use of #[experimental] items",
- default: Warn
+ // FIXME #6875: Change to Warn after std library stabilization is complete
+ default: Allow
}),
("unstable",
/// Checks for use of items with #[deprecated], #[experimental] and
/// #[unstable] (or none of them) attributes.
fn check_stability(cx: &Context, e: &ast::Expr) {
+ let tcx = cx.tcx;
+
let id = match e.node {
ast::ExprPath(..) | ast::ExprStruct(..) => {
match cx.tcx.def_map.borrow().find(&e.id) {
}
ast::ExprMethodCall(..) => {
let method_call = typeck::MethodCall::expr(e.id);
- match cx.tcx.method_map.borrow().find(&method_call) {
+ match tcx.method_map.borrow().find(&method_call) {
Some(method) => {
match method.origin {
typeck::MethodStatic(def_id) => {
// of the method inside trait definition.
// Otherwise, use the current def_id (which refers
// to the method inside impl).
- ty::trait_method_of_method(
- cx.tcx, def_id).unwrap_or(def_id)
+ ty::trait_method_of_method(cx.tcx, def_id)
+ .unwrap_or(def_id)
}
typeck::MethodParam(typeck::MethodParam {
trait_id: trait_id,
_ => return
};
- let stability = if ast_util::is_local(id) {
- // this crate
- let s = cx.tcx.map.with_attrs(id.node, |attrs| {
- attrs.map(|a| attr::find_stability(a.as_slice()))
- });
- match s {
- Some(s) => s,
+ // stability attributes are promises made across crates; do not
+ // check anything for crate-local usage.
+ if ast_util::is_local(id) { return }
- // no possibility of having attributes
- // (e.g. it's a local variable), so just
- // ignore it.
- None => return
- }
- } else {
- // cross-crate
-
- let mut s = None;
- // run through all the attributes and take the first
- // stability one.
- csearch::get_item_attrs(&cx.tcx.sess.cstore, id, |attrs| {
- if s.is_none() {
- s = attr::find_stability(attrs.as_slice())
- }
- });
- s
- };
+ let stability = tcx.stability.borrow_mut().lookup(&tcx.sess.cstore, id);
let (lint, label) = match stability {
// no stability attributes == Unstable
--- /dev/null
+// 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.
+
+//! A pass that annotates every item and method with its stability level,
+//! propagating default levels lexically from parent to children ast nodes.
+
+use util::nodemap::{NodeMap, DefIdMap};
+use syntax::codemap::Span;
+use syntax::{attr, visit};
+use syntax::ast::{Attribute, Block, Crate, DefId, FnDecl, NodeId, Variant};
+use syntax::ast::{Item, Required, Provided, TraitMethod, TypeMethod, Method};
+use syntax::ast::{Generics, StructDef, Ident};
+use syntax::ast_util::is_local;
+use syntax::attr::Stability;
+use syntax::visit::{FnKind, FkMethod, Visitor};
+use metadata::{cstore, csearch};
+
+/// A stability index, giving the stability level for items and methods.
+pub struct Index {
+ // stability for crate-local items; unmarked stability == no entry
+ local: NodeMap<Stability>,
+ // cache for extern-crate items; unmarked stability == entry with None
+ extern_cache: DefIdMap<Option<Stability>>
+}
+
+// A private tree-walker for producing an Index.
+struct Annotator {
+ index: Index
+}
+
+impl Annotator {
+ // Determine the stability for a node based on its attributes and inherited
+ // stability. The stability is recorded in the index and returned.
+ fn annotate(&mut self, id: NodeId, attrs: &[Attribute],
+ parent: Option<Stability>) -> Option<Stability> {
+ match attr::find_stability(attrs).or(parent) {
+ Some(stab) => {
+ self.index.local.insert(id, stab.clone());
+ Some(stab)
+ }
+ None => None
+ }
+ }
+}
+
+impl Visitor<Option<Stability>> for Annotator {
+ fn visit_item(&mut self, i: &Item, parent: Option<Stability>) {
+ let stab = self.annotate(i.id, i.attrs.as_slice(), parent);
+ visit::walk_item(self, i, stab)
+ }
+
+ fn visit_fn(&mut self, fk: &FnKind, fd: &FnDecl, b: &Block,
+ s: Span, _: NodeId, parent: Option<Stability>) {
+ let stab = match *fk {
+ FkMethod(_, _, meth) =>
+ self.annotate(meth.id, meth.attrs.as_slice(), parent),
+ _ => parent
+ };
+ visit::walk_fn(self, fk, fd, b, s, stab)
+ }
+
+ fn visit_trait_method(&mut self, t: &TraitMethod, parent: Option<Stability>) {
+ let stab = match *t {
+ Required(TypeMethod {attrs: ref attrs, id: id, ..}) =>
+ self.annotate(id, attrs.as_slice(), parent),
+
+ // work around lack of pattern matching for @ types
+ Provided(method) => match *method {
+ Method {attrs: ref attrs, id: id, ..} =>
+ self.annotate(id, attrs.as_slice(), parent)
+ }
+ };
+ visit::walk_trait_method(self, t, stab)
+ }
+
+ fn visit_variant(&mut self, v: &Variant, g: &Generics, parent: Option<Stability>) {
+ let stab = self.annotate(v.node.id, v.node.attrs.as_slice(), parent);
+ visit::walk_variant(self, v, g, stab)
+ }
+
+ fn visit_struct_def(&mut self, s: &StructDef, _: Ident, _: &Generics,
+ _: NodeId, parent: Option<Stability>) {
+ s.ctor_id.map(|id| self.annotate(id, &[], parent.clone()));
+ visit::walk_struct_def(self, s, parent)
+ }
+}
+
+impl Index {
+ /// Construct the stability index for a crate being compiled.
+ pub fn build(krate: &Crate) -> Index {
+ let mut annotator = Annotator {
+ index: Index {
+ local: NodeMap::new(),
+ extern_cache: DefIdMap::new()
+ }
+ };
+ visit::walk_crate(&mut annotator, krate,
+ attr::find_stability(krate.attrs.as_slice()));
+ annotator.index
+ }
+
+ /// Lookup the stability for a node, loading external crate
+ /// metadata as necessary.
+ pub fn lookup(&mut self, cstore: &cstore::CStore, id: DefId) -> Option<Stability> {
+ if is_local(id) {
+ self.lookup_local(id.node)
+ } else {
+ let stab = csearch::get_stability(cstore, id);
+ self.extern_cache.insert(id, stab.clone());
+ stab
+ }
+ }
+
+ /// Lookup the stability for a local node without loading any external crates
+ pub fn lookup_local(&self, id: NodeId) -> Option<Stability> {
+ self.local.find_copy(&id)
+ }
+}
pat_id: ast::NodeId,
elem_count: uint,
slice: Option<uint>,
- val: ValueRef,
- count: ValueRef)
+ val: ValueRef)
-> ExtractedBlock<'a> {
let _icx = push_ctxt("match::extract_vec_elems");
let vec_datum = match_datum(bcx, val, pat_id);
Some(n) if i < n => GEPi(bcx, base, [i]),
Some(n) if i > n => {
InBoundsGEP(bcx, base, [
- Sub(bcx, count,
+ Sub(bcx, len,
C_int(bcx.ccx(), (elem_count - i) as int))])
}
_ => unsafe { llvm::LLVMGetUndef(vt.llunit_ty.to_ref()) }
vec_len_eq => (n, None)
};
let args = extract_vec_elems(opt_cx, pat_id, n,
- slice, val, test_val);
+ slice, val);
size = args.vals.len();
unpacked = args.vals.clone();
opt_cx = args.bcx;
let loaded_val = Load(bcx, val);
bcx = bind_irrefutable_pat(bcx, inner, loaded_val, binding_mode, cleanup_scope);
}
- ast::PatVec(..) => {
- bcx.sess().span_bug(pat.span,
- "vector patterns are never irrefutable!");
+ ast::PatVec(ref before, ref slice, ref after) => {
+ let extracted = extract_vec_elems(
+ bcx, pat.id, before.len() + 1u + after.len(),
+ slice.map(|_| before.len()), val
+ );
+ bcx = before
+ .iter().map(|v| Some(*v))
+ .chain(Some(*slice).move_iter())
+ .chain(after.iter().map(|v| Some(*v)))
+ .zip(extracted.vals.iter())
+ .fold(bcx, |bcx, (inner, elem)| {
+ inner.map_or(bcx, |inner| {
+ bind_irrefutable_pat(bcx, inner, *elem, binding_mode, cleanup_scope)
+ })
+ });
}
ast::PatMac(..) => {
bcx.sess().span_bug(pat.span, "unexpanded macro");
use middle::resolve_lifetime;
use middle::subst;
use middle::subst::{Subst, Substs, VecPerParamSpace};
+use middle::stability;
use middle::ty;
use middle::typeck;
use middle::typeck::MethodCall;
/// to be valid. We gather up these restrictions in the intrinsicck pass
/// and check them in trans.
pub transmute_restrictions: RefCell<Vec<TransmuteRestriction>>,
+
+ /// Maps any item's def-id to its stability index.
+ pub stability: RefCell<stability::Index>,
}
pub enum tbox_flag {
map: ast_map::Map,
freevars: freevars::freevar_map,
region_maps: middle::region::RegionMaps,
- lang_items: middle::lang_items::LanguageItems)
+ lang_items: middle::lang_items::LanguageItems,
+ stability: stability::Index)
-> ctxt {
ctxt {
named_region_map: named_region_map,
dependency_formats: RefCell::new(HashMap::new()),
node_lint_levels: RefCell::new(HashMap::new()),
transmute_restrictions: RefCell::new(Vec::new()),
+ stability: RefCell::new(stability)
}
}
fcx.infcx().next_region_var(
infer::PatternRegion(pat.span));
- let check_err = || {
- for elt in before.iter() {
- check_pat(pcx, &**elt, ty::mk_err());
+ let check_err = |found: String| {
+ for &elt in before.iter() {
+ check_pat(pcx, &*elt, ty::mk_err());
}
for elt in slice.iter() {
check_pat(pcx, &**elt, ty::mk_err());
})
},
Some(expected),
- "a vector pattern".to_string(),
+ found,
None);
fcx.write_error(pat.id);
};
- let (elt_type, region_var, mutbl) = match *structure_of(fcx,
+ let (elt_type, region_var, mutbl, fixed) = match *structure_of(fcx,
pat.span,
expected) {
- ty::ty_vec(mt, Some(_)) => (mt.ty, default_region_var, ast::MutImmutable),
+ ty::ty_vec(mt, Some(fixed)) =>
+ (mt.ty, default_region_var, ast::MutImmutable, Some(fixed)),
ty::ty_uniq(t) => match ty::get(t).sty {
ty::ty_vec(mt, None) => {
fcx.type_error_message(pat.span,
},
expected,
None);
- (mt.ty, default_region_var, ast::MutImmutable)
+ (mt.ty, default_region_var, ast::MutImmutable, None)
}
_ => {
- check_err();
+ check_err("a vector pattern".to_string());
return;
}
},
ty::ty_rptr(r, mt) => match ty::get(mt.ty).sty {
- ty::ty_vec(mt, None) => (mt.ty, r, mt.mutbl),
+ ty::ty_vec(mt, None) => (mt.ty, r, mt.mutbl, None),
_ => {
- check_err();
+ check_err("a vector pattern".to_string());
return;
}
},
_ => {
- check_err();
+ check_err("a vector pattern".to_string());
return;
}
};
+
+ let min_len = before.len() + after.len();
+ fixed.and_then(|count| match slice {
+ Some(_) if count < min_len =>
+ Some(format!("a fixed vector pattern of size at least {}", min_len)),
+
+ None if count != min_len =>
+ Some(format!("a fixed vector pattern of size {}", min_len)),
+
+ _ => None
+ }).map(check_err);
+
for elt in before.iter() {
check_pat(pcx, &**elt, elt_type);
}
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/")]
-#![feature(macro_rules, phase, globs, thread_local, managed_boxes, asm,
- linkage)]
+
+#![feature(macro_rules, phase, globs, thread_local, managed_boxes, asm)]
+#![feature(linkage, unsafe_destructor)]
#![no_std]
#![experimental]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
#[phase(plugin, link)] extern crate core;
extern crate alloc;
#![crate_type = "rlib"]
#![crate_type = "dylib"]
-#![feature(macro_rules)]
+#![feature(macro_rules, unsafe_destructor)]
#![deny(unused_result, unused_must_use)]
#![allow(visible_private_types)]
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/",
html_playground_url = "http://play.rust-lang.org/")]
-#![feature(macro_rules, globs, managed_boxes,
- linkage, default_type_params, phase)]
+
+#![feature(macro_rules, globs, managed_boxes)]
+#![feature(linkage, default_type_params, phase, unsafe_destructor)]
// Don't link to std. We are std.
#![no_std]
#![allow(deprecated)]
#![deny(missing_doc)]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
// When testing libstd, bring in libuv as the I/O backend so tests can print
// things and all of the std::io tests have an I/O interface to run on top
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/",
html_playground_url = "http://play.rust-lang.org/")]
-#![feature(phase, globs, macro_rules)]
+#![feature(phase, globs, macro_rules, unsafe_destructor)]
#![deny(missing_doc)]
#![no_std]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
#[phase(plugin, link)] extern crate core;
extern crate alloc;
}
/// Represents the #[deprecated="foo"] and friends attributes.
+#[deriving(Encodable,Decodable,Clone,Show)]
pub struct Stability {
pub level: StabilityLevel,
pub text: Option<InternedString>
}
/// The available stability levels.
-#[deriving(PartialEq,PartialOrd,Clone,Show)]
+#[deriving(Encodable,Decodable,PartialEq,PartialOrd,Clone,Show)]
pub enum StabilityLevel {
Deprecated,
Experimental,
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/")]
-#![feature(macro_rules, globs, managed_boxes, default_type_params, phase,
- quote)]
+#![feature(macro_rules, globs, managed_boxes, default_type_params, phase)]
+#![feature(quote, unsafe_destructor)]
#![allow(deprecated)]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
extern crate serialize;
extern crate term;
let lo = span.lo + BytePos(1);
self.replace_token(token::GT, lo, span.hi)
}
+ token::BINOPEQ(token::SHR) => {
+ let span = self.span;
+ let lo = span.lo + BytePos(1);
+ self.replace_token(token::GE, lo, span.hi)
+ }
+ token::GE => {
+ let span = self.span;
+ let lo = span.lo + BytePos(1);
+ self.replace_token(token::EQ, lo, span.hi)
+ }
_ => {
let gt_str = Parser::token_to_str(&token::GT);
let this_token_str = self.this_token_to_str();
let mut first = true;
let mut v = Vec::new();
while self.token != token::GT
- && self.token != token::BINOP(token::SHR) {
+ && self.token != token::BINOP(token::SHR)
+ && self.token != token::GE
+ && self.token != token::BINOPEQ(token::SHR) {
match sep {
Some(ref t) => {
if first { first = false; }
--- /dev/null
+// 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.
+#![crate_id="inherited_stability#0.1"]
+#![crate_type = "lib"]
+#![experimental]
+
+pub fn experimental() {}
+
+#[stable]
+pub fn stable() {}
+
+#[stable]
+pub mod stable_mod {
+ #[experimental]
+ pub fn experimental() {}
+
+ pub fn stable() {}
+}
+
+pub mod experimental_mod {
+ pub fn experimental() {}
+
+ #[stable]
+ pub fn stable() {}
+}
+
+#[stable]
+pub trait Stable {
+ #[experimental]
+ fn experimental(&self);
+
+ fn stable(&self);
+}
+
+impl Stable for uint {
+ fn experimental(&self) {}
+ fn stable(&self) {}
+}
+
+pub enum Experimental {
+ ExperimentalVariant,
+ #[stable]
+ StableVariant
+}
#![crate_id="issue_2526#0.2"]
#![crate_type = "lib"]
+#![feature(unsafe_destructor)]
+
struct arc_destruct<T> {
_data: int,
}
--- /dev/null
+// 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.
+
+#![crate_id="lint_output_format#0.1"]
+#![crate_type = "lib"]
+
+#[deprecated]
+pub fn foo() -> uint {
+ 20
+}
+
+#[experimental]
+pub fn bar() -> uint {
+ 40
+}
+
+#[unstable]
+pub fn baz() -> uint {
+ 30
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
extern crate collections;
extern crate time;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(unsafe_destructor)]
+
extern crate debug;
struct defer<'a> {
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let x = [1,2];
+ let y = match x {
+ [] => None,
+//~^ ERROR expected `[<generic integer #1>, .. 2]` but found a fixed vector pattern of size 0
+ [a,_] => Some(a)
+ };
+}
// except according to those terms.
fn foo(a: Option<uint>, b: Option<uint>) {
- match (a,b) { //~ ERROR: non-exhaustive patterns: None not covered
+ match (a,b) {
+ //~^ ERROR: non-exhaustive patterns: `(None, None)` not covered
(Some(a), Some(b)) if a == b => { }
(Some(_), None) |
(None, Some(_)) => { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let tup = (true, true);
+ println!("foo {:}", match tup { //~ ERROR non-exhaustive patterns: `(true, false)` not covered
+ (false, false) => "foo",
+ (false, true) => "bar",
+ (true, true) => "baz"
+ });
+}
// except according to those terms.
// compile-flags:-F experimental -D unstable
+// aux-build:lint_output_format.rs
-#[deprecated]
-fn foo() -> uint {
- 20
-}
-
-#[experimental]
-fn bar() -> uint {
- 40
-}
-
-#[unstable]
-fn baz() -> uint {
- 30
-}
+extern crate lint_output_format;
+use lint_output_format::{foo, bar, baz};
fn main() {
let _x = foo(); //~ WARNING #[warn(deprecated)] on by default
// except according to those terms.
// aux-build:lint_stability.rs
+// aux-build:inherited_stability.rs
#![feature(globs)]
#![deny(unstable)]
use self::lint_stability::*;
fn test() {
- // FIXME: attributes on methods are not encoded cross crate.
let foo = MethodTester;
deprecated(); //~ ERROR use of deprecated item
}
}
+mod inheritance {
+ extern crate inherited_stability;
+ use self::inherited_stability::*;
+
+ fn test_inheritance() {
+ experimental(); //~ ERROR use of experimental item
+ stable();
+
+ stable_mod::experimental(); //~ ERROR use of experimental item
+ stable_mod::stable();
+
+ experimental_mod::experimental(); //~ ERROR use of experimental item
+ experimental_mod::stable();
+
+ let _ = ExperimentalVariant; //~ ERROR use of experimental item
+ let _ = StableVariant;
+
+ let x: uint = 0;
+ x.experimental(); //~ ERROR use of experimental item
+ x.stable();
+ }
+}
+
mod this_crate {
#[deprecated]
pub fn deprecated() {}
pub struct LockedTupleStruct(int);
fn test() {
+ // None of the following should generate errors, because
+ // stability attributes now have meaning only *across* crates,
+ // not within a single crate.
+
let foo = MethodTester;
- deprecated(); //~ ERROR use of deprecated item
- foo.method_deprecated(); //~ ERROR use of deprecated item
- foo.trait_deprecated(); //~ ERROR use of deprecated item
+ deprecated();
+ foo.method_deprecated();
+ foo.trait_deprecated();
- deprecated_text(); //~ ERROR use of deprecated item: text
- foo.method_deprecated_text(); //~ ERROR use of deprecated item: text
- foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
+ deprecated_text();
+ foo.method_deprecated_text();
+ foo.trait_deprecated_text();
- experimental(); //~ ERROR use of experimental item
- foo.method_experimental(); //~ ERROR use of experimental item
- foo.trait_experimental(); //~ ERROR use of experimental item
+ experimental();
+ foo.method_experimental();
+ foo.trait_experimental();
- experimental_text(); //~ ERROR use of experimental item: text
- foo.method_experimental_text(); //~ ERROR use of experimental item: text
- foo.trait_experimental_text(); //~ ERROR use of experimental item: text
+ experimental_text();
+ foo.method_experimental_text();
+ foo.trait_experimental_text();
- unstable(); //~ ERROR use of unstable item
- foo.method_unstable(); //~ ERROR use of unstable item
- foo.trait_unstable(); //~ ERROR use of unstable item
+ unstable();
+ foo.method_unstable();
+ foo.trait_unstable();
- unstable_text(); //~ ERROR use of unstable item: text
- foo.method_unstable_text(); //~ ERROR use of unstable item: text
- foo.trait_unstable_text(); //~ ERROR use of unstable item: text
+ unstable_text();
+ foo.method_unstable_text();
+ foo.trait_unstable_text();
- unmarked(); //~ ERROR use of unmarked item
- foo.method_unmarked(); //~ ERROR use of unmarked item
- foo.trait_unmarked(); //~ ERROR use of unmarked item
+ unmarked();
+ foo.method_unmarked();
+ foo.trait_unmarked();
stable();
foo.method_stable();
foo.trait_locked_text();
- let _ = DeprecatedStruct { i: 0 }; //~ ERROR use of deprecated item
- let _ = ExperimentalStruct { i: 0 }; //~ ERROR use of experimental item
- let _ = UnstableStruct { i: 0 }; //~ ERROR use of unstable item
- let _ = UnmarkedStruct { i: 0 }; //~ ERROR use of unmarked item
+ let _ = DeprecatedStruct { i: 0 };
+ let _ = ExperimentalStruct { i: 0 };
+ let _ = UnstableStruct { i: 0 };
+ let _ = UnmarkedStruct { i: 0 };
let _ = StableStruct { i: 0 };
let _ = FrozenStruct { i: 0 };
let _ = LockedStruct { i: 0 };
- let _ = DeprecatedUnitStruct; //~ ERROR use of deprecated item
- let _ = ExperimentalUnitStruct; //~ ERROR use of experimental item
- let _ = UnstableUnitStruct; //~ ERROR use of unstable item
- let _ = UnmarkedUnitStruct; //~ ERROR use of unmarked item
+ let _ = DeprecatedUnitStruct;
+ let _ = ExperimentalUnitStruct;
+ let _ = UnstableUnitStruct;
+ let _ = UnmarkedUnitStruct;
let _ = StableUnitStruct;
let _ = FrozenUnitStruct;
let _ = LockedUnitStruct;
- let _ = DeprecatedVariant; //~ ERROR use of deprecated item
- let _ = ExperimentalVariant; //~ ERROR use of experimental item
- let _ = UnstableVariant; //~ ERROR use of unstable item
- let _ = UnmarkedVariant; //~ ERROR use of unmarked item
+ let _ = DeprecatedVariant;
+ let _ = ExperimentalVariant;
+ let _ = UnstableVariant;
+ let _ = UnmarkedVariant;
let _ = StableVariant;
let _ = FrozenVariant;
let _ = LockedVariant;
- let _ = DeprecatedTupleStruct (1); //~ ERROR use of deprecated item
- let _ = ExperimentalTupleStruct (1); //~ ERROR use of experimental item
- let _ = UnstableTupleStruct (1); //~ ERROR use of unstable item
- let _ = UnmarkedTupleStruct (1); //~ ERROR use of unmarked item
+ let _ = DeprecatedTupleStruct (1);
+ let _ = ExperimentalTupleStruct (1);
+ let _ = UnstableTupleStruct (1);
+ let _ = UnmarkedTupleStruct (1);
let _ = StableTupleStruct (1);
let _ = FrozenTupleStruct (1);
let _ = LockedTupleStruct (1);
}
fn test_method_param<F: Trait>(foo: F) {
- foo.trait_deprecated(); //~ ERROR use of deprecated item
- foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
- foo.trait_experimental(); //~ ERROR use of experimental item
- foo.trait_experimental_text(); //~ ERROR use of experimental item: text
- foo.trait_unstable(); //~ ERROR use of unstable item
- foo.trait_unstable_text(); //~ ERROR use of unstable item: text
- foo.trait_unmarked(); //~ ERROR use of unmarked item
+ foo.trait_deprecated();
+ foo.trait_deprecated_text();
+ foo.trait_experimental();
+ foo.trait_experimental_text();
+ foo.trait_unstable();
+ foo.trait_unstable_text();
+ foo.trait_unmarked();
foo.trait_stable();
}
fn test_method_object(foo: &Trait) {
- foo.trait_deprecated(); //~ ERROR use of deprecated item
- foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
- foo.trait_experimental(); //~ ERROR use of experimental item
- foo.trait_experimental_text(); //~ ERROR use of experimental item: text
- foo.trait_unstable(); //~ ERROR use of unstable item
- foo.trait_unstable_text(); //~ ERROR use of unstable item: text
- foo.trait_unmarked(); //~ ERROR use of unmarked item
+ foo.trait_deprecated();
+ foo.trait_deprecated_text();
+ foo.trait_experimental();
+ foo.trait_experimental_text();
+ foo.trait_unstable();
+ foo.trait_unstable_text();
+ foo.trait_unmarked();
foo.trait_stable();
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
extern crate debug;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: non-exhaustive patterns
enum t { a(u), b }
enum u { c, d }
fn main() {
let x = a(c);
- match x {
+ match x { //~ ERROR non-exhaustive patterns: `a(c)` not covered
a(d) => { fail!("hello"); }
b => { fail!("goodbye"); }
}
fn main() {
let x = a;
- match x { b => { } } //~ ERROR non-exhaustive patterns
- match true { //~ ERROR non-exhaustive patterns
+ match x { b => { } } //~ ERROR non-exhaustive patterns: `a` not covered
+ match true { //~ ERROR non-exhaustive patterns: `false` not covered
true => {}
}
- match Some(10) { //~ ERROR non-exhaustive patterns
+ match Some(10) { //~ ERROR non-exhaustive patterns: `Some(_)` not covered
None => {}
}
- match (2, 3, 4) { //~ ERROR non-exhaustive patterns
+ match (2, 3, 4) { //~ ERROR non-exhaustive patterns: `(_, _, _)` not covered
(_, _, 4) => {}
}
- match (a, a) { //~ ERROR non-exhaustive patterns
+ match (a, a) { //~ ERROR non-exhaustive patterns: `(a, a)` not covered
(a, b) => {}
(b, a) => {}
}
- match a { //~ ERROR b not covered
+ match a { //~ ERROR non-exhaustive patterns: `b` not covered
a => {}
}
// This is exhaustive, though the algorithm got it wrong at one point
}
let vec = vec!(Some(42), None, Some(21));
let vec: &[Option<int>] = vec.as_slice();
- match vec {
- //~^ ERROR non-exhaustive patterns: vectors of length 0 not covered
+ match vec { //~ ERROR non-exhaustive patterns: `[]` not covered
[Some(..), None, ..tail] => {}
[Some(..), Some(..), ..tail] => {}
[None] => {}
}
let vec = vec!(0.5);
let vec: &[f32] = vec.as_slice();
- match vec { //~ ERROR non-exhaustive patterns: vectors of length 4 not covered
+ match vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _]` not covered
[0.1, 0.2, 0.3] => (),
[0.1, 0.2] => (),
[0.1] => (),
--- /dev/null
+// 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.
+
+#![feature(struct_variant)]
+
+struct Foo {
+ first: bool,
+ second: Option<[uint, ..4]>
+}
+
+enum Color {
+ Red,
+ Green,
+ CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
+}
+
+fn struct_with_a_nested_enum_and_vector() {
+ match Foo { first: true, second: None } {
+ //~^ ERROR non-exhaustive patterns: `Foo{first: false, second: Some([_, _, _, _])}` not covered
+ Foo { first: true, second: None } => (),
+ Foo { first: true, second: Some(_) } => (),
+ Foo { first: false, second: None } => (),
+ Foo { first: false, second: Some([1u, 2u, 3u, 4u]) } => ()
+ }
+}
+
+fn enum_with_multiple_missing_variants() {
+ match Red {
+ //~^ ERROR non-exhaustive patterns: `Red` not covered
+ CustomRGBA { .. } => ()
+ }
+}
+
+fn enum_struct_variant() {
+ match Red {
+ //~^ ERROR non-exhaustive patterns: `CustomRGBA{a: true, r: _, g: _, b: _}` not covered
+ Red => (),
+ Green => (),
+ CustomRGBA { a: false, r: _, g: _, b: 0 } => (),
+ CustomRGBA { a: false, r: _, g: _, b: _ } => ()
+ }
+}
+
+enum Enum {
+ First,
+ Second(bool)
+}
+
+fn vectors_with_nested_enums() {
+ let x: &'static [Enum] = [First, Second(false)];
+ match x {
+ //~^ ERROR non-exhaustive patterns: `[Second(true), Second(false)]` not covered
+ [] => (),
+ [_] => (),
+ [First, _] => (),
+ [Second(true), First] => (),
+ [Second(true), Second(true)] => (),
+ [Second(false), _] => (),
+ [_, _, ..tail, _] => ()
+ }
+}
+
+fn main() {
+ struct_with_a_nested_enum_and_vector();
+ enum_with_multiple_missing_variants();
+ enum_struct_variant();
+}
\ No newline at end of file
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
extern crate debug;
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-
-fn func(
- (
- 1, //~ ERROR refutable pattern in function argument
- (
- Some( //~ ERROR refutable pattern in function argument
- 1), // nested, so no warning.
- 2..3 //~ ERROR refutable pattern in function argument
- )
- ): (int, (Option<int>, int))
- ) {}
-
-fn main() {
- let (
- 1, //~ ERROR refutable pattern in local binding
- (
- Some( //~ ERROR refutable pattern in local binding
- 1), // nested, so no warning.
- 2..3 //~ ERROR refutable pattern in local binding
- )
- ) = (1, (None, 2));
-}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+fn func((1, (Some(1), 2..3)): (int, (Option<int>, int))) { }
+//~^ ERROR refutable pattern in function argument: `(_, _)` not covered
+
+fn main() {
+ let (1, (Some(1), 2..3)) = (1, (None, 2));
+ //~^ ERROR refutable pattern in local binding: `(_, _)` not covered
+}
// except according to those terms.
fn main() {
- let f = |3: int| println!("hello"); //~ ERROR refutable pattern
+ let f = |3: int| println!("hello");
+ //~^ ERROR refutable pattern in function argument: `_` not covered
f(4);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
extern crate debug;
use std::cell::Cell;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
// error-pattern:quux
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(unsafe_destructor)]
+
use std::mem::size_of;
#[unsafe_no_drop_flag]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(unsafe_destructor)]
+
struct S<T> {
x: T
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
use std::cell::Cell;
use std::gc::{Gc, GC};
--- /dev/null
+// 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.
+
+// ignore-win32: FIXME #13793
+
+fn main() {
+ match ("", 1u) {
+ (_, 42u) => (),
+ ("", _) => (),
+ _ => ()
+ }
+}
--- /dev/null
+// 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.
+
+#![allow(warnings)]
+
+struct S<T>(T);
+
+static s1: S<S<uint>>=S(S(0));
+static s2: S<uint>=S(0);
+
+fn main() {
+ let foo: S<S<uint>>=S(S(0));
+ let foo: S<uint>=S(0);
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(unsafe_destructor)]
+
pub type Task = int;
// tjc: I don't know why
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
use std::cell::Cell;
use std::gc::{Gc, GC};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
use std::cell::Cell;
use std::gc::{Gc, GC};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(unsafe_destructor)]
+
extern crate debug;
trait X {
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn foo<T: Add<T, T> + Clone>([x, y, z]: [T, ..3]) -> (T, T, T) {
+ (x.clone(), x.clone() + y.clone(), x + y + z)
+}
+fn bar(a: &'static str, b: &'static str) -> [&'static str, ..4] {
+ [a, b, b, a]
+}
+
+fn main() {
+ assert_eq!(foo([1, 2, 3]), (1, 3, 6));
+
+ let [a, b, c, d] = bar("foo", "bar");
+ assert_eq!(a, "foo");
+ assert_eq!(b, "bar");
+ assert_eq!(c, "bar");
+ assert_eq!(d, "foo");
+
+ let [a, _, _, d] = bar("baz", "foo");
+ assert_eq!(a, "baz");
+ assert_eq!(d, "baz");
+
+ let out = bar("baz", "foo");
+ let [a, ..xs, d] = out;
+ assert_eq!(a, "baz");
+ assert!(xs == ["foo", "foo"]);
+ assert_eq!(d, "baz");
+}
\ No newline at end of file
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
use std::cell::Cell;
use std::gc::{GC, Gc};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
// Make sure the destructor is run for newtype structs.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
use std::cell::Cell;
use std::gc::{GC, Gc};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
extern crate debug;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
use std::cell::Cell;
use std::gc::{GC, Gc};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
// Ensures that class dtors run if the object is inside an enum
// variant
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
use std::task;
use std::gc::{Gc, GC};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
use std::cell::Cell;
use std::gc::{Gc, GC};