From 47d384c1b82e984c0d15ab4471de82481ad35ea7 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 2 Aug 2013 21:41:06 -0700 Subject: [PATCH 01/16] librustc: Remove `&const` and `*const` from the language. They are still present as part of the borrow check. --- src/libextra/flate.rs | 4 +- src/librustc/metadata/decoder.rs | 9 +- src/librustc/metadata/encoder.rs | 11 +- src/librustc/metadata/tydecode.rs | 1 - src/librustc/metadata/tyencode.rs | 1 - src/librustc/middle/borrowck/check_loans.rs | 18 ++- .../middle/borrowck/gather_loans/lifetime.rs | 12 +- .../middle/borrowck/gather_loans/mod.rs | 82 ++++++---- .../borrowck/gather_loans/restrictions.rs | 9 +- src/librustc/middle/borrowck/mod.rs | 40 ++++- src/librustc/middle/mem_categorization.rs | 13 +- src/librustc/middle/typeck/astconv.rs | 3 +- src/librustc/middle/typeck/check/method.rs | 22 +-- src/librustc/middle/typeck/infer/glb.rs | 22 +-- src/librustc/middle/typeck/infer/lub.rs | 19 +-- src/librustc/middle/typeck/infer/sub.rs | 6 +- src/librustc/util/ppaux.rs | 1 - src/libstd/cast.rs | 5 +- src/libstd/cleanup.rs | 4 +- src/libstd/os.rs | 2 +- src/libstd/ptr.rs | 146 ++++++++++++++---- src/libstd/rt/borrowck.rs | 35 +++-- src/libstd/rt/sched.rs | 3 +- src/libstd/to_bytes.rs | 9 +- src/libstd/util.rs | 6 +- src/libstd/vec.rs | 9 +- src/libsyntax/ast.rs | 5 +- src/libsyntax/parse/obsolete.rs | 11 +- src/libsyntax/parse/parser.rs | 14 +- src/libsyntax/print/pprust.rs | 3 - .../borrowck-alias-mut-base-ptr.rs | 15 -- ...ck-borrow-mut-base-ptr-in-aliasable-loc.rs | 12 +- ...borrowck-call-method-from-mut-aliasable.rs | 11 -- src/test/compile-fail/borrowck-lend-flow.rs | 8 - .../compile-fail/borrowck-loan-vec-content.rs | 11 -- .../borrowck-pat-by-value-binding.rs | 45 ------ .../compile-fail/borrowck-uniq-via-lend.rs | 6 - src/test/compile-fail/fn-variance-3.rs | 13 +- src/test/compile-fail/issue-3969.rs | 25 --- .../compile-fail/mutable-huh-ptr-assign.rs | 23 --- .../resolve-inconsistent-binding-mode.rs | 7 - src/test/run-pass/auto-ref-slice-plus-ref.rs | 12 -- .../autoderef-and-borrow-method-receiver.rs | 2 +- .../borrowck-pat-enum.rs | 23 --- .../borrowck-uniq-via-ref.rs | 13 -- .../class-impl-very-parameterized-trait.rs | 4 +- .../run-pass/coerce-reborrow-imm-ptr-rcvr.rs | 6 +- src/test/run-pass/const-vec-syntax.rs | 2 +- 48 files changed, 306 insertions(+), 457 deletions(-) delete mode 100644 src/test/compile-fail/borrowck-alias-mut-base-ptr.rs delete mode 100644 src/test/compile-fail/borrowck-pat-by-value-binding.rs delete mode 100644 src/test/compile-fail/issue-3969.rs delete mode 100644 src/test/compile-fail/mutable-huh-ptr-assign.rs rename src/test/{compile-fail => run-pass}/borrowck-pat-enum.rs (65%) rename src/test/{compile-fail => run-pass}/borrowck-uniq-via-ref.rs (77%) diff --git a/src/libextra/flate.rs b/src/libextra/flate.rs index ed8cbcd0663f3..a066ea92ba1d1 100644 --- a/src/libextra/flate.rs +++ b/src/libextra/flate.rs @@ -25,13 +25,13 @@ pub mod rustrt { #[link_name = "rustrt"] extern { - pub fn tdefl_compress_mem_to_heap(psrc_buf: *const c_void, + pub fn tdefl_compress_mem_to_heap(psrc_buf: *c_void, src_buf_len: size_t, pout_len: *mut size_t, flags: c_int) -> *c_void; - pub fn tinfl_decompress_mem_to_heap(psrc_buf: *const c_void, + pub fn tinfl_decompress_mem_to_heap(psrc_buf: *c_void, src_buf_len: size_t, pout_len: *mut size_t, flags: c_int) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 81a2e863bde00..ffb09e1cb8f74 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -792,12 +792,9 @@ pub fn get_enum_variants(intr: @ident_interner, cdata: cmd, id: ast::NodeId, fn get_explicit_self(item: ebml::Doc) -> ast::explicit_self_ { fn get_mutability(ch: u8) -> ast::mutability { match ch as char { - 'i' => { ast::m_imm } - 'm' => { ast::m_mutbl } - 'c' => { ast::m_const } - _ => { - fail!("unknown mutability character: `%c`", ch as char) - } + 'i' => ast::m_imm, + 'm' => ast::m_mutbl, + _ => fail!("unknown mutability character: `%c`", ch as char), } } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 4a3704dc3aa4e..afc28342ad01f 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -645,15 +645,8 @@ fn encode_explicit_self(ebml_w: &mut writer::Encoder, explicit_self: ast::explic fn encode_mutability(ebml_w: &writer::Encoder, m: ast::mutability) { match m { - m_imm => { - ebml_w.writer.write(&[ 'i' as u8 ]); - } - m_mutbl => { - ebml_w.writer.write(&[ 'm' as u8 ]); - } - m_const => { - ebml_w.writer.write(&[ 'c' as u8 ]); - } + m_imm => ebml_w.writer.write(&[ 'i' as u8 ]), + m_mutbl => ebml_w.writer.write(&[ 'm' as u8 ]), } } } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 89b30e46ac06d..a03266649ab0a 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -417,7 +417,6 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { fn parse_mutability(st: &mut PState) -> ast::mutability { match peek(st) { 'm' => { next(st); ast::m_mutbl } - '?' => { next(st); ast::m_const } _ => { ast::m_imm } } } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 915729d254f94..82b79f864848d 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -100,7 +100,6 @@ fn enc_mutability(w: @io::Writer, mt: ast::mutability) { match mt { m_imm => (), m_mutbl => w.write_char('m'), - m_const => w.write_char('?') } } diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 620a1e9efe33f..975d13a1e63e2 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -23,7 +23,7 @@ use mc = middle::mem_categorization; use middle::borrowck::*; use middle::moves; use middle::ty; -use syntax::ast::{m_mutbl, m_imm, m_const}; +use syntax::ast::m_mutbl; use syntax::ast; use syntax::ast_util; use syntax::codemap::span; @@ -205,9 +205,9 @@ impl<'self> CheckLoanCtxt<'self> { // Restrictions that would cause the new loan to be illegal: let illegal_if = match loan2.mutbl { - m_mutbl => RESTR_ALIAS | RESTR_FREEZE | RESTR_CLAIM, - m_imm => RESTR_ALIAS | RESTR_FREEZE, - m_const => RESTR_ALIAS, + MutableMutability => RESTR_ALIAS | RESTR_FREEZE | RESTR_CLAIM, + ImmutableMutability => RESTR_ALIAS | RESTR_FREEZE, + ConstMutability => RESTR_ALIAS, }; debug!("illegal_if=%?", illegal_if); @@ -216,7 +216,7 @@ impl<'self> CheckLoanCtxt<'self> { if restr.loan_path != loan2.loan_path { loop; } match (new_loan.mutbl, old_loan.mutbl) { - (m_mutbl, m_mutbl) => { + (MutableMutability, MutableMutability) => { self.bccx.span_err( new_loan.span, fmt!("cannot borrow `%s` as mutable \ @@ -522,7 +522,6 @@ impl<'self> CheckLoanCtxt<'self> { // Otherwise stop iterating LpExtend(_, mc::McDeclared, _) | LpExtend(_, mc::McImmutable, _) | - LpExtend(_, mc::McReadOnly, _) | LpVar(_) => { return true; } @@ -530,8 +529,11 @@ impl<'self> CheckLoanCtxt<'self> { // Check for a non-const loan of `loan_path` let cont = do this.each_in_scope_loan(expr.id) |loan| { - if loan.loan_path == loan_path && loan.mutbl != m_const { - this.report_illegal_mutation(expr, full_loan_path, loan); + if loan.loan_path == loan_path && + loan.mutbl != ConstMutability { + this.report_illegal_mutation(expr, + full_loan_path, + loan); false } else { true diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index b315a7a2e7290..5bb7e63485e63 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -15,7 +15,7 @@ use middle::borrowck::*; use mc = middle::mem_categorization; use middle::ty; -use syntax::ast::{m_const, m_imm, m_mutbl}; +use syntax::ast::{m_imm, m_mutbl}; use syntax::ast; use syntax::codemap::span; use util::ppaux::{note_and_explain_region}; @@ -26,7 +26,7 @@ pub fn guarantee_lifetime(bccx: @BorrowckCtxt, span: span, cmt: mc::cmt, loan_region: ty::Region, - loan_mutbl: ast::mutability) { + loan_mutbl: LoanMutability) { debug!("guarantee_lifetime(cmt=%s, loan_region=%s)", cmt.repr(bccx.tcx), loan_region.repr(bccx.tcx)); let ctxt = GuaranteeLifetimeContext {bccx: bccx, @@ -54,7 +54,7 @@ struct GuaranteeLifetimeContext { span: span, loan_region: ty::Region, - loan_mutbl: ast::mutability, + loan_mutbl: LoanMutability, cmt_original: mc::cmt } @@ -236,11 +236,11 @@ impl GuaranteeLifetimeContext { // we need to dynamically mark it to prevent incompatible // borrows from happening later. let opt_dyna = match ptr_mutbl { - m_imm | m_const => None, + m_imm => None, m_mutbl => { match self.loan_mutbl { - m_mutbl => Some(DynaMut), - m_imm | m_const => Some(DynaImm) + MutableMutability => Some(DynaMut), + ImmutableMutability | ConstMutability => Some(DynaImm) } } }; diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index 6d2a4fcc9f31a..8c5da2f3d0f84 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -26,7 +26,6 @@ use middle::ty; use util::common::indenter; use util::ppaux::{Repr}; -use syntax::ast::{m_const, m_imm, m_mutbl}; use syntax::ast; use syntax::ast_util::id_range; use syntax::codemap::span; @@ -237,7 +236,11 @@ fn gather_loans_in_expr(v: &mut GatherLoanVisitor, // make sure that the thing we are pointing out stays valid // for the lifetime `scope_r` of the resulting ptr: let scope_r = ty_region(tcx, ex.span, ty::expr_ty(tcx, ex)); - this.guarantee_valid(ex.id, ex.span, base_cmt, mutbl, scope_r); + this.guarantee_valid(ex.id, + ex.span, + base_cmt, + LoanMutability::from_ast_mutability(mutbl), + scope_r); visit::walk_expr(v, ex, this); } @@ -278,7 +281,11 @@ fn gather_loans_in_expr(v: &mut GatherLoanVisitor, // adjustments). let scope_r = ty::re_scope(ex.id); let arg_cmt = this.bccx.cat_expr(arg); - this.guarantee_valid(arg.id, arg.span, arg_cmt, m_imm, scope_r); + this.guarantee_valid(arg.id, + arg.span, + arg_cmt, + ImmutableMutability, + scope_r); visit::walk_expr(v, ex, this); } @@ -357,18 +364,22 @@ impl GatherLoanCtxt { match *autoref { ty::AutoPtr(r, m) => { + let loan_mutability = + LoanMutability::from_ast_mutability(m); self.guarantee_valid(expr.id, expr.span, cmt, - m, + loan_mutability, r) } ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => { let cmt_index = mcx.cat_index(expr, cmt, autoderefs+1); + let loan_mutability = + LoanMutability::from_ast_mutability(m); self.guarantee_valid(expr.id, expr.span, cmt_index, - m, + loan_mutability, r) } ty::AutoBorrowFn(r) => { @@ -376,7 +387,7 @@ impl GatherLoanCtxt { self.guarantee_valid(expr.id, expr.span, cmt_deref, - m_imm, + ImmutableMutability, r) } ty::AutoBorrowObj(r, m) => { @@ -402,7 +413,7 @@ impl GatherLoanCtxt { borrow_id: ast::NodeId, borrow_span: span, cmt: mc::cmt, - req_mutbl: ast::mutability, + req_mutbl: LoanMutability, loan_region: ty::Region) { debug!("guarantee_valid(borrow_id=%?, cmt=%s, \ req_mutbl=%?, loan_region=%?)", @@ -473,7 +484,7 @@ impl GatherLoanCtxt { let kill_scope = self.compute_kill_scope(loan_scope, loan_path); debug!("kill_scope = %?", kill_scope); - if req_mutbl == m_mutbl { + if req_mutbl == MutableMutability { self.mark_loan_path_as_mutated(loan_path); } @@ -516,7 +527,7 @@ impl GatherLoanCtxt { // index: all_loans.len(), // loan_path: loan_path, // cmt: cmt, - // mutbl: m_const, + // mutbl: ConstMutability, // gen_scope: borrow_id, // kill_scope: kill_scope, // span: borrow_span, @@ -527,29 +538,20 @@ impl GatherLoanCtxt { fn check_mutability(bccx: @BorrowckCtxt, borrow_span: span, cmt: mc::cmt, - req_mutbl: ast::mutability) { + req_mutbl: LoanMutability) { //! Implements the M-* rules in doc.rs. match req_mutbl { - m_const => { + ConstMutability => { // Data of any mutability can be lent as const. } - m_imm => { - match cmt.mutbl { - mc::McImmutable | mc::McDeclared | mc::McInherited => { - // both imm and mut data can be lent as imm; - // for mutable data, this is a freeze - } - mc::McReadOnly => { - bccx.report(BckError {span: borrow_span, - cmt: cmt, - code: err_mutbl(req_mutbl)}); - } - } + ImmutableMutability => { + // both imm and mut data can be lent as imm; + // for mutable data, this is a freeze } - m_mutbl => { + MutableMutability => { // Only mutable data can be lent as mutable. if !cmt.mutbl.is_mutable() { bccx.report(BckError {span: borrow_span, @@ -561,12 +563,14 @@ impl GatherLoanCtxt { } } - pub fn restriction_set(&self, req_mutbl: ast::mutability) + pub fn restriction_set(&self, req_mutbl: LoanMutability) -> RestrictionSet { match req_mutbl { - m_const => RESTR_EMPTY, - m_imm => RESTR_EMPTY | RESTR_MUTATE | RESTR_CLAIM, - m_mutbl => RESTR_EMPTY | RESTR_MUTATE | RESTR_CLAIM | RESTR_FREEZE + ConstMutability => RESTR_EMPTY, + ImmutableMutability => RESTR_EMPTY | RESTR_MUTATE | RESTR_CLAIM, + MutableMutability => { + RESTR_EMPTY | RESTR_MUTATE | RESTR_CLAIM | RESTR_FREEZE + } } } @@ -582,8 +586,8 @@ impl GatherLoanCtxt { self.mark_loan_path_as_mutated(base); } LpExtend(_, mc::McDeclared, _) | - LpExtend(_, mc::McImmutable, _) | - LpExtend(_, mc::McReadOnly, _) => { + LpExtend(_, mc::McImmutable, _) => { + // Nothing to do. } } } @@ -701,8 +705,13 @@ impl GatherLoanCtxt { } } }; - self.guarantee_valid(pat.id, pat.span, - cmt_discr, mutbl, scope_r); + let loan_mutability = + LoanMutability::from_ast_mutability(mutbl); + self.guarantee_valid(pat.id, + pat.span, + cmt_discr, + loan_mutability, + scope_r); } ast::bind_infer => { // No borrows here, but there may be moves @@ -725,6 +734,8 @@ impl GatherLoanCtxt { self.vec_slice_info(slice_pat, slice_ty); let mcx = self.bccx.mc_ctxt(); let cmt_index = mcx.cat_index(slice_pat, cmt, 0); + let slice_loan_mutability = + LoanMutability::from_ast_mutability(slice_mutbl); // Note: We declare here that the borrow occurs upon // entering the `[...]` pattern. This implies that @@ -743,8 +754,11 @@ impl GatherLoanCtxt { // trans do the right thing, and it would only work // for `~` vectors. It seems simpler to just require // that people call `vec.pop()` or `vec.unshift()`. - self.guarantee_valid(pat.id, pat.span, - cmt_index, slice_mutbl, slice_r); + self.guarantee_valid(pat.id, + pat.span, + cmt_index, + slice_loan_mutability, + slice_r); } _ => {} diff --git a/src/librustc/middle/borrowck/gather_loans/restrictions.rs b/src/librustc/middle/borrowck/gather_loans/restrictions.rs index 46bb23e400ee5..cdd6ed71114a3 100644 --- a/src/librustc/middle/borrowck/gather_loans/restrictions.rs +++ b/src/librustc/middle/borrowck/gather_loans/restrictions.rs @@ -15,7 +15,7 @@ use std::vec; use middle::borrowck::*; use mc = middle::mem_categorization; use middle::ty; -use syntax::ast::{m_const, m_imm, m_mutbl}; +use syntax::ast::{m_imm, m_mutbl}; use syntax::codemap::span; pub enum RestrictionResult { @@ -122,13 +122,6 @@ impl RestrictionsContext { Safe } - mc::cat_deref(_, _, mc::region_ptr(m_const, _)) | - mc::cat_deref(_, _, mc::gc_ptr(m_const)) => { - // R-Deref-Freeze-Borrowed - self.check_no_mutability_control(cmt, restrictions); - Safe - } - mc::cat_deref(cmt_base, _, mc::gc_ptr(m_mutbl)) => { // R-Deref-Managed-Borrowed // diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 95eae32922b7f..7414cefe8bd13 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -241,12 +241,39 @@ pub enum PartialTotal { /////////////////////////////////////////////////////////////////////////// // Loans and loan paths +#[deriving(Clone, Eq)] +pub enum LoanMutability { + ImmutableMutability, + ConstMutability, + MutableMutability, +} + +impl LoanMutability { + pub fn from_ast_mutability(ast_mutability: ast::mutability) + -> LoanMutability { + match ast_mutability { + ast::m_imm => ImmutableMutability, + ast::m_mutbl => MutableMutability, + } + } +} + +impl ToStr for LoanMutability { + fn to_str(&self) -> ~str { + match *self { + ImmutableMutability => ~"immutable", + ConstMutability => ~"read-only", + MutableMutability => ~"mutable", + } + } +} + /// Record of a loan that was issued. pub struct Loan { index: uint, loan_path: @LoanPath, cmt: mc::cmt, - mutbl: ast::mutability, + mutbl: LoanMutability, restrictions: ~[Restriction], gen_scope: ast::NodeId, kill_scope: ast::NodeId, @@ -418,7 +445,7 @@ impl ToStr for DynaFreezeKind { // Errors that can occur #[deriving(Eq)] pub enum bckerr_code { - err_mutbl(ast::mutability), + err_mutbl(LoanMutability), err_out_of_root_scope(ty::Region, ty::Region), // superscope, subscope err_out_of_scope(ty::Region, ty::Region), // superscope, subscope err_freeze_aliasable_const @@ -795,17 +822,14 @@ impl BorrowckCtxt { mc.cmt_to_str(cmt) } - pub fn mut_to_str(&self, mutbl: ast::mutability) -> ~str { - let mc = &mc::mem_categorization_ctxt {tcx: self.tcx, - method_map: self.method_map}; - mc.mut_to_str(mutbl) + pub fn mut_to_str(&self, mutbl: LoanMutability) -> ~str { + mutbl.to_str() } pub fn mut_to_keyword(&self, mutbl: ast::mutability) -> &'static str { match mutbl { ast::m_imm => "", - ast::m_const => "const", - ast::m_mutbl => "mut" + ast::m_mutbl => "mut", } } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 283724447f831..8bf3f4900b5d9 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -52,7 +52,7 @@ use middle::typeck; use util::ppaux::{ty_to_str, region_ptr_to_str, Repr}; use util::common::indenter; -use syntax::ast::{m_imm, m_const, m_mutbl}; +use syntax::ast::{m_imm, m_mutbl}; use syntax::ast; use syntax::codemap::span; use syntax::print::pprust; @@ -114,7 +114,6 @@ pub enum ElementKind { #[deriving(Eq, IterBytes)] pub enum MutabilityCategory { McImmutable, // Immutable. - McReadOnly, // Read-only (`const`) McDeclared, // Directly declared as mutable. McInherited // Inherited from the fact that owner is mutable. } @@ -298,7 +297,6 @@ impl MutabilityCategory { pub fn from_mutbl(m: ast::mutability) -> MutabilityCategory { match m { m_imm => McImmutable, - m_const => McReadOnly, m_mutbl => McDeclared } } @@ -306,7 +304,6 @@ impl MutabilityCategory { pub fn inherit(&self) -> MutabilityCategory { match *self { McImmutable => McImmutable, - McReadOnly => McReadOnly, McDeclared => McInherited, McInherited => McInherited } @@ -314,7 +311,7 @@ impl MutabilityCategory { pub fn is_mutable(&self) -> bool { match *self { - McImmutable | McReadOnly => false, + McImmutable => false, McDeclared | McInherited => true } } @@ -322,7 +319,7 @@ impl MutabilityCategory { pub fn is_immutable(&self) -> bool { match *self { McImmutable => true, - McReadOnly | McDeclared | McInherited => false + McDeclared | McInherited => false } } @@ -330,7 +327,6 @@ impl MutabilityCategory { match *self { McDeclared | McInherited => "mutable", McImmutable => "immutable", - McReadOnly => "const" } } } @@ -617,7 +613,6 @@ impl mem_categorization_ctxt { -> MutabilityCategory { match interior_m { m_imm => base_m.inherit(), - m_const => McReadOnly, m_mutbl => McDeclared } } @@ -1006,7 +1001,6 @@ impl mem_categorization_ctxt { pub fn mut_to_str(&self, mutbl: ast::mutability) -> ~str { match mutbl { m_mutbl => ~"mutable", - m_const => ~"const", m_imm => ~"immutable" } } @@ -1175,7 +1169,6 @@ impl cmt_ { Some(AliasableManaged(m)) } - cat_deref(_, _, region_ptr(m @ m_const, _)) | cat_deref(_, _, region_ptr(m @ m_imm, _)) => { Some(AliasableBorrowed(m)) } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index c666e98c9c15f..b958890a6a014 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -272,8 +272,7 @@ pub fn ast_ty_to_ty( match a_seq_ty.ty.node { ast::ty_vec(ref mt) => { let mut mt = ast_mt_to_mt(this, rscope, mt); - if a_seq_ty.mutbl == ast::m_mutbl || - a_seq_ty.mutbl == ast::m_const { + if a_seq_ty.mutbl == ast::m_mutbl { mt = ty::mt { ty: mt.ty, mutbl: a_seq_ty.mutbl }; } return ty::mk_evec(tcx, mt, vst); diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 352836d81e459..f0179388a67c6 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -102,7 +102,7 @@ use std::vec; use extra::list::Nil; use syntax::ast::{def_id, sty_value, sty_region, sty_box}; use syntax::ast::{sty_uniq, sty_static, NodeId}; -use syntax::ast::{m_const, m_mutbl, m_imm}; +use syntax::ast::{m_mutbl, m_imm}; use syntax::ast; use syntax::ast_map; @@ -653,7 +653,7 @@ impl<'self> LookupContext<'self> { ty_evec(mt, vstore_fixed(_)) => { // First try to borrow to a slice let entry = self.search_for_some_kind_of_autorefd_method( - AutoBorrowVec, autoderefs, [m_const, m_imm, m_mutbl], + AutoBorrowVec, autoderefs, [m_imm, m_mutbl], |m,r| ty::mk_evec(tcx, ty::mt {ty:mt.ty, mutbl:m}, vstore_slice(r))); @@ -662,7 +662,7 @@ impl<'self> LookupContext<'self> { // Then try to borrow to a slice *and* borrow a pointer. self.search_for_some_kind_of_autorefd_method( - AutoBorrowVecRef, autoderefs, [m_const, m_imm, m_mutbl], + AutoBorrowVecRef, autoderefs, [m_imm, m_mutbl], |m,r| { let slice_ty = ty::mk_evec(tcx, ty::mt {ty:mt.ty, mutbl:m}, @@ -732,7 +732,7 @@ impl<'self> LookupContext<'self> { ty_float(*) | ty_enum(*) | ty_ptr(*) | ty_struct(*) | ty_tup(*) | ty_estr(*) | ty_evec(*) | ty_trait(*) | ty_closure(*) => { self.search_for_some_kind_of_autorefd_method( - AutoPtr, autoderefs, [m_const, m_imm, m_mutbl], + AutoPtr, autoderefs, [m_imm, m_mutbl], |m,r| ty::mk_rptr(tcx, r, ty::mt {ty:self_ty, mutbl:m})) } @@ -1220,18 +1220,10 @@ impl<'self> LookupContext<'self> { } fn mutability_matches(self_mutbl: ast::mutability, - candidate_mutbl: ast::mutability) -> bool { + candidate_mutbl: ast::mutability) + -> bool { //! True if `self_mutbl <: candidate_mutbl` - - match (self_mutbl, candidate_mutbl) { - (_, m_const) => true, - (m_mutbl, m_mutbl) => true, - (m_imm, m_imm) => true, - (m_mutbl, m_imm) => false, - (m_imm, m_mutbl) => false, - (m_const, m_imm) => false, - (m_const, m_mutbl) => false, - } + self_mutbl == candidate_mutbl } } diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs index f05388344bc71..4b951d00677d6 100644 --- a/src/librustc/middle/typeck/infer/glb.rs +++ b/src/librustc/middle/typeck/infer/glb.rs @@ -22,7 +22,7 @@ use middle::typeck::infer::{TypeTrace, Subtype}; use middle::typeck::infer::fold_regions_in_sig; use middle::typeck::isr_alist; use syntax::ast; -use syntax::ast::{Many, Once, extern_fn, impure_fn, m_const, m_imm, m_mutbl}; +use syntax::ast::{Many, Once, extern_fn, impure_fn, m_imm, m_mutbl}; use syntax::ast::{unsafe_fn}; use syntax::ast::{Onceness, purity}; use syntax::abi::AbiSet; @@ -54,16 +54,6 @@ impl Combine for Glb { match (a.mutbl, b.mutbl) { // If one side or both is mut, then the GLB must use // the precise type from the mut side. - (m_mutbl, m_const) => { - Sub(**self).tys(a.ty, b.ty).chain(|_t| { - Ok(ty::mt {ty: a.ty, mutbl: m_mutbl}) - }) - } - (m_const, m_mutbl) => { - Sub(**self).tys(b.ty, a.ty).chain(|_t| { - Ok(ty::mt {ty: b.ty, mutbl: m_mutbl}) - }) - } (m_mutbl, m_mutbl) => { eq_tys(self, a.ty, b.ty).then(|| { Ok(ty::mt {ty: a.ty, mutbl: m_mutbl}) @@ -72,22 +62,12 @@ impl Combine for Glb { // If one side or both is immutable, we can use the GLB of // both sides but mutbl must be `m_imm`. - (m_imm, m_const) | - (m_const, m_imm) | (m_imm, m_imm) => { self.tys(a.ty, b.ty).chain(|t| { Ok(ty::mt {ty: t, mutbl: m_imm}) }) } - // If both sides are const, then we can use GLB of both - // sides and mutbl of only `m_const`. - (m_const, m_const) => { - self.tys(a.ty, b.ty).chain(|t| { - Ok(ty::mt {ty: t, mutbl: m_const}) - }) - } - // There is no mutual subtype of these combinations. (m_mutbl, m_imm) | (m_imm, m_mutbl) => { diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/typeck/infer/lub.rs index 8afb5a18d4f6f..c97b99aaf0c08 100644 --- a/src/librustc/middle/typeck/infer/lub.rs +++ b/src/librustc/middle/typeck/infer/lub.rs @@ -26,7 +26,7 @@ use util::ppaux::mt_to_str; use extra::list; use syntax::abi::AbiSet; use syntax::ast; -use syntax::ast::{Many, Once, extern_fn, m_const, impure_fn}; +use syntax::ast::{Many, Once, extern_fn, impure_fn}; use syntax::ast::{unsafe_fn}; use syntax::ast::{Onceness, purity}; @@ -57,14 +57,13 @@ impl Combine for Lub { mt_to_str(tcx, a), mt_to_str(tcx, b)); - let m = if a.mutbl == b.mutbl { - a.mutbl - } else { - m_const - }; + if a.mutbl != b.mutbl { + return Err(ty::terr_mutability) + } + let m = a.mutbl; match m { - m_imm | m_const => { + m_imm => { self.tys(a.ty, b.ty).chain(|t| Ok(ty::mt {ty: t, mutbl: m}) ) } @@ -73,11 +72,7 @@ impl Combine for Lub { eq_tys(self, a.ty, b.ty).then(|| { Ok(ty::mt {ty: a.ty, mutbl: m}) }) - }).chain_err(|_e| { - self.tys(a.ty, b.ty).chain(|t| { - Ok(ty::mt {ty: t, mutbl: m_const}) - }) - }) + }).chain_err(|e| Err(e)) } } } diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index 441e71d4722b8..3a4d7df6a5b93 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -28,7 +28,7 @@ use extra::list::Nil; use extra::list; use syntax::abi::AbiSet; use syntax::ast; -use syntax::ast::{Onceness, m_const, purity}; +use syntax::ast::{Onceness, purity}; pub struct Sub(CombineFields); // "subtype", "subregion" etc @@ -69,7 +69,7 @@ impl Combine for Sub { fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres { debug!("mts(%s <: %s)", a.inf_str(self.infcx), b.inf_str(self.infcx)); - if a.mutbl != b.mutbl && b.mutbl != m_const { + if a.mutbl != b.mutbl { return Err(ty::terr_mutability); } @@ -79,7 +79,7 @@ impl Combine for Sub { // (i.e., invariant if mut): eq_tys(self, a.ty, b.ty).then(|| Ok(*a)) } - m_imm | m_const => { + m_imm => { // Otherwise we can be covariant: self.tys(a.ty, b.ty).chain(|_t| Ok(*a) ) } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 3bc0a7167e9bd..7002e1a0858b1 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -239,7 +239,6 @@ fn mutability_to_str(m: ast::mutability) -> ~str { match m { ast::m_mutbl => ~"mut ", ast::m_imm => ~"", - ast::m_const => ~"const " } } diff --git a/src/libstd/cast.rs b/src/libstd/cast.rs index 9d1d6e65901ae..7512dd3457a3a 100644 --- a/src/libstd/cast.rs +++ b/src/libstd/cast.rs @@ -10,6 +10,7 @@ //! Unsafe casting functions +use ptr::RawPtr; use sys; use unstable::intrinsics; @@ -91,13 +92,13 @@ pub unsafe fn transmute_region<'a,'b,T>(ptr: &'a T) -> &'b T { /// Coerce an immutable reference to be mutable. #[inline] -pub unsafe fn transmute_mut_unsafe(ptr: *const T) -> *mut T { +pub unsafe fn transmute_mut_unsafe>(ptr: P) -> *mut T { transmute(ptr) } /// Coerce an immutable reference to be mutable. #[inline] -pub unsafe fn transmute_immut_unsafe(ptr: *const T) -> *T { +pub unsafe fn transmute_immut_unsafe>(ptr: P) -> *T { transmute(ptr) } diff --git a/src/libstd/cleanup.rs b/src/libstd/cleanup.rs index 7c2348a3533df..b8be0927664e8 100644 --- a/src/libstd/cleanup.rs +++ b/src/libstd/cleanup.rs @@ -11,7 +11,7 @@ #[doc(hidden)]; use libc::c_void; -use ptr::{mut_null}; +use ptr::null; use unstable::intrinsics::TyDesc; use unstable::raw; @@ -37,7 +37,7 @@ unsafe fn each_live_alloc(read_next_before: bool, use rt::local_heap; let mut box = local_heap::live_allocs(); - while box != mut_null() { + while box != null() { let next_before = (*box).next; let uniq = (*box).ref_count == managed::RC_MANAGED_UNIQUE; diff --git a/src/libstd/os.rs b/src/libstd/os.rs index b357489d62ff8..fbc5193cacbac 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -1434,7 +1434,7 @@ impl MemoryMap { let r = unsafe { libc::mmap(addr, len, prot, flags, fd, offset) }; - if r == libc::MAP_FAILED { + if r.equiv(&libc::MAP_FAILED) { Err(match errno() as c_int { libc::EACCES => ErrFdNotAvail, libc::EBADF => ErrInvalidFd, diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs index de8f8c69e8432..b1c5110165299 100644 --- a/src/libstd/ptr.rs +++ b/src/libstd/ptr.rs @@ -12,8 +12,11 @@ use cast; use clone::Clone; +use cmp::Equiv; use iterator::{range, Iterator}; use option::{Option, Some, None}; +#[cfg(stage0)] +use sys; use unstable::intrinsics; use util::swap; @@ -24,18 +27,28 @@ use util::swap; /// Calculate the offset from a pointer #[inline] +#[cfg(stage0)] pub fn offset(ptr: *T, count: int) -> *T { - unsafe { intrinsics::offset(ptr, count) } + (ptr as uint + (count as uint) * sys::size_of::()) as *T } -/// Calculate the offset from a const pointer +/// Calculate the offset from a mut pointer #[inline] -pub fn const_offset(ptr: *const T, count: int) -> *const T { - unsafe { intrinsics::offset(ptr as *T, count) } +#[cfg(stage0)] +pub fn mut_offset(ptr: *mut T, count: int) -> *mut T { + (ptr as uint + (count as uint) * sys::size_of::()) as *mut T +} + +/// Calculate the offset from a pointer +#[inline] +#[cfg(not(stage0))] +pub fn offset(ptr: *T, count: int) -> *T { + unsafe { intrinsics::offset(ptr, count) } } /// Calculate the offset from a mut pointer #[inline] +#[cfg(not(stage0))] pub fn mut_offset(ptr: *mut T, count: int) -> *mut T { unsafe { intrinsics::offset(ptr as *T, count) as *mut T } } @@ -73,11 +86,11 @@ pub fn mut_null() -> *mut T { 0 as *mut T } /// Returns true if the pointer is equal to the null pointer. #[inline] -pub fn is_null(ptr: *const T) -> bool { ptr == null() } +pub fn is_null>(ptr: P) -> bool { ptr.is_null() } /// Returns true if the pointer is not equal to the null pointer. #[inline] -pub fn is_not_null(ptr: *const T) -> bool { !is_null(ptr) } +pub fn is_not_null>(ptr: P) -> bool { ptr.is_not_null() } /** * Copies data from one location to another. @@ -87,8 +100,10 @@ pub fn is_not_null(ptr: *const T) -> bool { !is_null(ptr) } */ #[inline] #[cfg(target_word_size = "32")] -pub unsafe fn copy_memory(dst: *mut T, src: *const T, count: uint) { - intrinsics::memmove32(dst, src as *T, count as u32); +pub unsafe fn copy_memory>(dst: *mut T, src: P, count: uint) { + intrinsics::memmove32(dst, + cast::transmute_immut_unsafe(src), + count as u32); } /** @@ -99,8 +114,10 @@ pub unsafe fn copy_memory(dst: *mut T, src: *const T, count: uint) { */ #[inline] #[cfg(target_word_size = "64")] -pub unsafe fn copy_memory(dst: *mut T, src: *const T, count: uint) { - intrinsics::memmove64(dst, src as *T, count as u64); +pub unsafe fn copy_memory>(dst: *mut T, src: P, count: uint) { + intrinsics::memmove64(dst, + cast::transmute_immut_unsafe(src), + count as u64); } /** @@ -111,8 +128,12 @@ pub unsafe fn copy_memory(dst: *mut T, src: *const T, count: uint) { */ #[inline] #[cfg(target_word_size = "32")] -pub unsafe fn copy_nonoverlapping_memory(dst: *mut T, src: *const T, count: uint) { - intrinsics::memcpy32(dst, src as *T, count as u32); +pub unsafe fn copy_nonoverlapping_memory>(dst: *mut T, + src: P, + count: uint) { + intrinsics::memcpy32(dst, + cast::transmute_immut_unsafe(src), + count as u32); } /** @@ -123,8 +144,12 @@ pub unsafe fn copy_nonoverlapping_memory(dst: *mut T, src: *const T, count: u */ #[inline] #[cfg(target_word_size = "64")] -pub unsafe fn copy_nonoverlapping_memory(dst: *mut T, src: *const T, count: uint) { - intrinsics::memcpy64(dst, src as *T, count as u64); +pub unsafe fn copy_nonoverlapping_memory>(dst: *mut T, + src: P, + count: uint) { + intrinsics::memcpy64(dst, + cast::transmute_immut_unsafe(src), + count as u64); } /** @@ -216,12 +241,6 @@ pub fn to_unsafe_ptr(thing: &T) -> *T { thing as *T } -/// Transform a const region pointer - &const T - to a const unsafe pointer - *const T. -#[inline] -pub fn to_const_unsafe_ptr(thing: &const T) -> *const T { - thing as *const T -} - /// Transform a mutable region pointer - &mut T - to a mutable unsafe pointer - *mut T. #[inline] pub fn to_mut_unsafe_ptr(thing: &mut T) -> *mut T { @@ -269,8 +288,10 @@ pub unsafe fn array_each(arr: **T, cb: &fn(*T)) { #[allow(missing_doc)] pub trait RawPtr { + fn null() -> Self; fn is_null(&self) -> bool; fn is_not_null(&self) -> bool; + fn to_uint(&self) -> uint; unsafe fn to_option(&self) -> Option<&T>; fn offset(&self, count: int) -> Self; unsafe fn offset_inbounds(self, count: int) -> Self; @@ -278,13 +299,21 @@ pub trait RawPtr { /// Extension methods for immutable pointers impl RawPtr for *T { + /// Returns the null pointer. + #[inline] + fn null() -> *T { null() } + /// Returns true if the pointer is equal to the null pointer. #[inline] - fn is_null(&self) -> bool { is_null(*self) } + fn is_null(&self) -> bool { *self == RawPtr::null() } /// Returns true if the pointer is not equal to the null pointer. #[inline] - fn is_not_null(&self) -> bool { is_not_null(*self) } + fn is_not_null(&self) -> bool { *self != RawPtr::null() } + + /// Returns the address of this pointer. + #[inline] + fn to_uint(&self) -> uint { *self as uint } /// /// Returns `None` if the pointer is null, or else returns the value wrapped @@ -317,13 +346,21 @@ impl RawPtr for *T { /// Extension methods for mutable pointers impl RawPtr for *mut T { + /// Returns the null pointer. + #[inline] + fn null() -> *mut T { mut_null() } + /// Returns true if the pointer is equal to the null pointer. #[inline] - fn is_null(&self) -> bool { is_null(*self) } + fn is_null(&self) -> bool { *self == RawPtr::null() } /// Returns true if the pointer is not equal to the null pointer. #[inline] - fn is_not_null(&self) -> bool { is_not_null(*self) } + fn is_not_null(&self) -> bool { *self != RawPtr::null() } + + /// Returns the address of this pointer. + #[inline] + fn to_uint(&self) -> uint { *self as uint } /// /// Returns `None` if the pointer is null, or else returns the value wrapped @@ -360,32 +397,77 @@ impl RawPtr for *mut T { // Equality for pointers #[cfg(not(test))] -impl Eq for *const T { +impl Eq for *T { + #[inline] + fn eq(&self, other: &*T) -> bool { + (*self as uint) == (*other as uint) + } + #[inline] + fn ne(&self, other: &*T) -> bool { !self.eq(other) } +} + +#[cfg(not(test))] +impl Eq for *mut T { #[inline] - fn eq(&self, other: &*const T) -> bool { + fn eq(&self, other: &*mut T) -> bool { (*self as uint) == (*other as uint) } #[inline] - fn ne(&self, other: &*const T) -> bool { !self.eq(other) } + fn ne(&self, other: &*mut T) -> bool { !self.eq(other) } +} + +// Equivalence for pointers +#[cfg(not(test))] +impl Equiv<*mut T> for *T { + fn equiv(&self, other: &*mut T) -> bool { + self.to_uint() == other.to_uint() + } +} + +#[cfg(not(test))] +impl Equiv<*T> for *mut T { + fn equiv(&self, other: &*T) -> bool { + self.to_uint() == other.to_uint() + } } // Comparison for pointers #[cfg(not(test))] -impl Ord for *const T { +impl Ord for *T { + #[inline] + fn lt(&self, other: &*T) -> bool { + (*self as uint) < (*other as uint) + } + #[inline] + fn le(&self, other: &*T) -> bool { + (*self as uint) <= (*other as uint) + } + #[inline] + fn ge(&self, other: &*T) -> bool { + (*self as uint) >= (*other as uint) + } + #[inline] + fn gt(&self, other: &*T) -> bool { + (*self as uint) > (*other as uint) + } +} + +#[cfg(not(test))] +impl Ord for *mut T { #[inline] - fn lt(&self, other: &*const T) -> bool { + fn lt(&self, other: &*mut T) -> bool { (*self as uint) < (*other as uint) } #[inline] - fn le(&self, other: &*const T) -> bool { + fn le(&self, other: &*mut T) -> bool { (*self as uint) <= (*other as uint) } #[inline] - fn ge(&self, other: &*const T) -> bool { + fn ge(&self, other: &*mut T) -> bool { (*self as uint) >= (*other as uint) } #[inline] - fn gt(&self, other: &*const T) -> bool { + fn gt(&self, other: &*mut T) -> bool { (*self as uint) > (*other as uint) } } diff --git a/src/libstd/rt/borrowck.rs b/src/libstd/rt/borrowck.rs index ba4cbc668038f..5e481fac307a3 100644 --- a/src/libstd/rt/borrowck.rs +++ b/src/libstd/rt/borrowck.rs @@ -10,14 +10,15 @@ use c_str::ToCStr; use cast::transmute; -use libc::{c_char, size_t, STDERR_FILENO}; -use io; use io::{Writer, WriterUtil}; +use io; +use libc::{c_char, c_void, size_t, STDERR_FILENO}; use option::{Option, None, Some}; -use uint; -use str; +use ptr::RawPtr; use str::{OwnedStr, StrSlice}; +use str; use sys; +use uint; use unstable::raw; use vec::ImmutableVector; @@ -80,12 +81,12 @@ unsafe fn fail_borrowed(box: *mut raw::Box<()>, file: *c_char, line: size_t) { static ENABLE_DEBUG: bool = false; #[inline] -unsafe fn debug_borrow(tag: &'static str, - p: *const T, - old_bits: uint, - new_bits: uint, - filename: *c_char, - line: size_t) { +unsafe fn debug_borrow>(tag: &'static str, + p: P, + old_bits: uint, + new_bits: uint, + filename: *c_char, + line: size_t) { //! A useful debugging function that prints a pointer + tag + newline //! without allocating memory. @@ -94,15 +95,15 @@ unsafe fn debug_borrow(tag: &'static str, debug_borrow_slow(tag, p, old_bits, new_bits, filename, line); } - unsafe fn debug_borrow_slow(tag: &'static str, - p: *const T, - old_bits: uint, - new_bits: uint, - filename: *c_char, - line: size_t) { + unsafe fn debug_borrow_slow>(tag: &'static str, + p: P, + old_bits: uint, + new_bits: uint, + filename: *c_char, + line: size_t) { let dbg = STDERR_FILENO as io::fd_t; dbg.write_str(tag); - dbg.write_hex(p as uint); + dbg.write_hex(p.to_uint()); dbg.write_str(" "); dbg.write_hex(old_bits); dbg.write_str(" "); diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index ce4e64c47d2ef..92657167c5fdd 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -646,7 +646,8 @@ impl Scheduler { let current_task: &mut Task = match sched.cleanup_job { Some(GiveTask(ref task, _)) => { - transmute_mut_region(*transmute_mut_unsafe(task)) + let task_ptr: *~Task = task; + transmute_mut_region(*transmute_mut_unsafe(task_ptr)) } Some(DoNothing) => { rtabort!("no next task"); diff --git a/src/libstd/to_bytes.rs b/src/libstd/to_bytes.rs index f871f4ef6d6ac..c5163a8cb9442 100644 --- a/src/libstd/to_bytes.rs +++ b/src/libstd/to_bytes.rs @@ -335,7 +335,14 @@ impl IterBytes for ~A { // NB: raw-pointer IterBytes does _not_ dereference // to the target; it just gives you the pointer-bytes. -impl IterBytes for *const A { +impl IterBytes for *A { + #[inline] + fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { + (*self as uint).iter_bytes(lsb0, f) + } +} + +impl IterBytes for *mut A { #[inline] fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { (*self as uint).iter_bytes(lsb0, f) diff --git a/src/libstd/util.rs b/src/libstd/util.rs index b46876ad3fe44..5085f337d4bba 100644 --- a/src/libstd/util.rs +++ b/src/libstd/util.rs @@ -54,8 +54,10 @@ pub fn swap(x: &mut T, y: &mut T) { let t: *mut T = &mut tmp; // Perform the swap, `&mut` pointers never alias - ptr::copy_nonoverlapping_memory(t, x, 1); - ptr::copy_nonoverlapping_memory(x, y, 1); + let x_raw: *mut T = x; + let y_raw: *mut T = y; + ptr::copy_nonoverlapping_memory(t, x_raw, 1); + ptr::copy_nonoverlapping_memory(x, y_raw, 1); ptr::copy_nonoverlapping_memory(y, t, 1); // y and t now point to the same thing, but we need to completely forget `tmp` diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 7748c040a1ddc..f35ca9ab40453 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -1062,14 +1062,7 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { * foreign interop. */ #[inline] - fn as_imm_buf(&self, - /* NB---this CANNOT be const, see below */ - f: &fn(*T, uint) -> U) -> U { - // NB---Do not change the type of s to `&const [T]`. This is - // unsound. The reason is that we are going to create immutable pointers - // into `s` and pass them to `f()`, but in fact they are potentially - // pointing at *mutable memory*. Use `as_mut_buf` instead! - + fn as_imm_buf(&self, f: &fn(*T, uint) -> U) -> U { let s = self.repr(); f(s.data, s.len / sys::nonzero_size_of::()) } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 17247222c3ff9..35e0db98d8e2f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -298,7 +298,10 @@ pub enum pat_ { } #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)] -pub enum mutability { m_mutbl, m_imm, m_const, } +pub enum mutability { + m_mutbl, + m_imm, +} #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)] pub enum Sigil { diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index 01c1af7464db6..6e43e7ca8684a 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -54,7 +54,6 @@ pub enum ObsoleteSyntax { ObsoleteMode, ObsoleteImplicitSelf, ObsoleteLifetimeNotation, - ObsoleteConstManagedPointer, ObsoletePurity, ObsoleteStaticMethod, ObsoleteConstItem, @@ -66,6 +65,7 @@ pub enum ObsoleteSyntax { ObsoleteUnsafeExternFn, ObsoletePrivVisibility, ObsoleteTraitFuncVisibility, + ObsoleteConstPointer, } impl to_bytes::IterBytes for ObsoleteSyntax { @@ -209,10 +209,6 @@ impl ParserObsoleteMethods for Parser { "instead of `&foo/bar`, write `&'foo bar`; instead of \ `bar/&foo`, write `&bar<'foo>" ), - ObsoleteConstManagedPointer => ( - "const `@` pointer", - "instead of `@const Foo`, write `@Foo`" - ), ObsoletePurity => ( "pure function", "remove `pure`" @@ -263,6 +259,11 @@ impl ParserObsoleteMethods for Parser { "visibility not necessary", "trait functions inherit the visibility of the trait itself" ), + ObsoleteConstPointer => ( + "const pointer", + "instead of `&const Foo` or `@const Foo`, write `&Foo` or \ + `@Foo`" + ), }; self.report(sp, kind, kind_str, desc); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a2664dcf890ad..9c8ca651f80e5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -38,7 +38,7 @@ use ast::{ident, impure_fn, inherited, item, item_, item_static}; use ast::{item_enum, item_fn, item_foreign_mod, item_impl}; use ast::{item_mac, item_mod, item_struct, item_trait, item_ty, lit, lit_}; use ast::{lit_bool, lit_float, lit_float_unsuffixed, lit_int}; -use ast::{lit_int_unsuffixed, lit_nil, lit_str, lit_uint, Local, m_const}; +use ast::{lit_int_unsuffixed, lit_nil, lit_str, lit_uint, Local}; use ast::{m_imm, m_mutbl, mac_, mac_invoc_tt, matcher, match_nonterminal}; use ast::{match_seq, match_tok, method, mt, mul, mutability}; use ast::{named_field, neg, NodeId, noreturn, not, pat, pat_box, pat_enum}; @@ -1154,9 +1154,6 @@ impl Parser { if mt.mutbl != m_imm && sigil == OwnedSigil { self.obsolete(*self.last_span, ObsoleteMutOwnedPointer); } - if mt.mutbl == m_const && sigil == ManagedSigil { - self.obsolete(*self.last_span, ObsoleteConstManagedPointer); - } ctor(mt) } @@ -1569,7 +1566,8 @@ impl Parser { if self.eat_keyword(keywords::Mut) { m_mutbl } else if self.eat_keyword(keywords::Const) { - m_const + self.obsolete(*self.last_span, ObsoleteConstPointer); + m_imm } else { m_imm } @@ -1728,7 +1726,7 @@ impl Parser { } else if *self.token == token::LBRACKET { self.bump(); let mutbl = self.parse_mutability(); - if mutbl == m_mutbl || mutbl == m_const { + if mutbl == m_mutbl { self.obsolete(*self.last_span, ObsoleteMutVector); } @@ -2183,10 +2181,6 @@ impl Parser { token::AT => { self.bump(); let m = self.parse_mutability(); - if m == m_const { - self.obsolete(*self.last_span, ObsoleteConstManagedPointer); - } - let e = self.parse_prefix_expr(); hi = e.span.hi; // HACK: turn @[...] into a @-evec diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 6a3d829aca0b0..037e306ba00a0 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -387,7 +387,6 @@ pub fn print_type(s: @ps, ty: &ast::Ty) { word(s.s, "["); match mt.mutbl { ast::m_mutbl => word_space(s, "mut"), - ast::m_const => word_space(s, "const"), ast::m_imm => () } print_type(s, mt.ty); @@ -430,7 +429,6 @@ pub fn print_type(s: @ps, ty: &ast::Ty) { word(s.s, "["); match mt.mutbl { ast::m_mutbl => word_space(s, "mut"), - ast::m_const => word_space(s, "const"), ast::m_imm => () } print_type(s, mt.ty); @@ -1883,7 +1881,6 @@ pub fn print_view_item(s: @ps, item: &ast::view_item) { pub fn print_mutability(s: @ps, mutbl: ast::mutability) { match mutbl { ast::m_mutbl => word_nbsp(s, "mut"), - ast::m_const => word_nbsp(s, "const"), ast::m_imm => {/* nothing */ } } } diff --git a/src/test/compile-fail/borrowck-alias-mut-base-ptr.rs b/src/test/compile-fail/borrowck-alias-mut-base-ptr.rs deleted file mode 100644 index c51cf5b9538d9..0000000000000 --- a/src/test/compile-fail/borrowck-alias-mut-base-ptr.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Test that attempt to alias `&mut` pointer while pointee is borrowed -// yields an error. -// -// Example from src/middle/borrowck/doc.rs - -use std::util::swap; - -fn foo(t0: &mut int) { - let p: &int = &*t0; // Freezes `*t0` - let q: &const &mut int = &const t0; //~ ERROR cannot borrow `t0` - **q = 22; //~ ERROR cannot assign to an `&mut` in a `&const` pointer -} - -fn main() { -} \ No newline at end of file diff --git a/src/test/compile-fail/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs b/src/test/compile-fail/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs index 7e9c298ba4732..843b5436d842c 100644 --- a/src/test/compile-fail/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs +++ b/src/test/compile-fail/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs @@ -11,16 +11,6 @@ fn foo(t0: & &mut int) { **t1 = 22; //~ ERROR cannot assign } -fn foo2(t0: &const &mut int) { - // Note: reborrowing from an &const actually yields two errors, since it - // is unsafe in two ways: we can't control the aliasing, and we can't - // control the mutation. - let t1 = t0; - let p: &int = &**t0; //~ ERROR cannot borrow an `&mut` in a `&const` pointer - //~^ ERROR unsafe borrow of aliasable, const value - **t1 = 22; //~ ERROR cannot assign -} - fn foo3(t0: &mut &mut int) { let t1 = &mut *t0; let p: &int = &**t0; //~ ERROR cannot borrow @@ -28,4 +18,4 @@ fn foo3(t0: &mut &mut int) { } fn main() { -} \ No newline at end of file +} diff --git a/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs b/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs index 0aa7cbf50b7a3..537e52120d9f1 100644 --- a/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs +++ b/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs @@ -14,29 +14,18 @@ struct Foo { impl Foo { pub fn f(&self) {} - pub fn g(&const self) {} pub fn h(&mut self) {} } fn a(x: &mut Foo) { x.f(); - x.g(); x.h(); } fn b(x: &Foo) { x.f(); - x.g(); x.h(); //~ ERROR cannot borrow } -fn c(x: &const Foo) { - x.f(); //~ ERROR cannot borrow - //~^ ERROR unsafe borrow - x.g(); - x.h(); //~ ERROR cannot borrow - //~^ ERROR unsafe borrow -} - fn main() { } diff --git a/src/test/compile-fail/borrowck-lend-flow.rs b/src/test/compile-fail/borrowck-lend-flow.rs index 59cac0c5d953a..ea840a28b4e6a 100644 --- a/src/test/compile-fail/borrowck-lend-flow.rs +++ b/src/test/compile-fail/borrowck-lend-flow.rs @@ -32,14 +32,6 @@ fn pre_freeze() { borrow_mut(v); //~ ERROR cannot borrow } -fn pre_const() { - // In this instance, the freeze starts before the mut borrow. - - let mut v = ~3; - let _w = &const v; - borrow_mut(v); -} - fn post_freeze() { // In this instance, the const alias starts after the borrow. diff --git a/src/test/compile-fail/borrowck-loan-vec-content.rs b/src/test/compile-fail/borrowck-loan-vec-content.rs index 6a8e64377aab2..8a4a2cdedb230 100644 --- a/src/test/compile-fail/borrowck-loan-vec-content.rs +++ b/src/test/compile-fail/borrowck-loan-vec-content.rs @@ -29,16 +29,5 @@ fn has_mut_vec_but_tries_to_change_it() { } } -fn takes_const_elt(_v: &const int, f: &fn()) { - f(); -} - -fn has_mut_vec_and_tries_to_change_it() { - let mut v = ~[1, 2, 3]; - do takes_const_elt(&const v[0]) { - v[1] = 4; - } -} - fn main() { } diff --git a/src/test/compile-fail/borrowck-pat-by-value-binding.rs b/src/test/compile-fail/borrowck-pat-by-value-binding.rs deleted file mode 100644 index e77f5245d7d8b..0000000000000 --- a/src/test/compile-fail/borrowck-pat-by-value-binding.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn process(_t: T) {} - -fn match_const_opt_by_mut_ref(v: &const Option) { - match *v { - Some(ref mut i) => process(i), //~ ERROR cannot borrow - //~^ ERROR unsafe borrow of aliasable, const value - None => () - } -} - -fn match_const_opt_by_const_ref(v: &const Option) { - match *v { - Some(ref const i) => process(i), - //~^ ERROR unsafe borrow of aliasable, const value - None => () - } -} - -fn match_const_opt_by_imm_ref(v: &const Option) { - match *v { - Some(ref i) => process(i), //~ ERROR cannot borrow - //~^ ERROR unsafe borrow of aliasable, const value - None => () - } -} - -fn match_const_opt_by_value(v: &const Option) { - match *v { - Some(i) => process(i), - None => () - } -} - -fn main() { -} diff --git a/src/test/compile-fail/borrowck-uniq-via-lend.rs b/src/test/compile-fail/borrowck-uniq-via-lend.rs index 43459acaaf185..c87428cd300a7 100644 --- a/src/test/compile-fail/borrowck-uniq-via-lend.rs +++ b/src/test/compile-fail/borrowck-uniq-via-lend.rs @@ -35,12 +35,6 @@ fn aliased_imm() { borrow(v); } -fn aliased_const() { - let mut v = ~3; - let _w = &const v; - borrow(v); -} - fn aliased_mut() { let mut v = ~3; let _w = &mut v; diff --git a/src/test/compile-fail/fn-variance-3.rs b/src/test/compile-fail/fn-variance-3.rs index 630eb4b538d58..e42c6b658e4f7 100644 --- a/src/test/compile-fail/fn-variance-3.rs +++ b/src/test/compile-fail/fn-variance-3.rs @@ -23,13 +23,10 @@ fn main() { // @int <: X // - // This constraint forces X to be - // @const int. - r(@3); + // Here the type check fails because @const is gone and there is no + // supertype. + r(@3); //~ ERROR mismatched types - // Here the type check succeeds but the - // mutability check will fail, because the - // type of r has been inferred to be - // fn(@const int) -> @const int - *r(@mut 3) = 4; //~ ERROR cannot assign to const dereference of @ pointer + // Here the type check succeeds. + *r(@mut 3) = 4; } diff --git a/src/test/compile-fail/issue-3969.rs b/src/test/compile-fail/issue-3969.rs deleted file mode 100644 index b60a54a44bbfd..0000000000000 --- a/src/test/compile-fail/issue-3969.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -struct Bike { - name: ~str, -} - -trait BikeMethods { - fn woops(&const self) -> ~str; -} - -impl BikeMethods for Bike { - fn woops() -> ~str { ~"foo" } - //~^ ERROR has a `&const self` declaration in the trait, but not in the impl -} - -pub fn main() { -} diff --git a/src/test/compile-fail/mutable-huh-ptr-assign.rs b/src/test/compile-fail/mutable-huh-ptr-assign.rs deleted file mode 100644 index 4460da72e2059..0000000000000 --- a/src/test/compile-fail/mutable-huh-ptr-assign.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -extern mod extra; - -fn main() { - unsafe fn f(v: *const int) { - *v = 1 //~ ERROR cannot assign - } - - unsafe { - let mut a = 0; - let v = &mut a; - f(v); - } -} diff --git a/src/test/compile-fail/resolve-inconsistent-binding-mode.rs b/src/test/compile-fail/resolve-inconsistent-binding-mode.rs index 65fbbfc6e1985..351daf461d2fe 100644 --- a/src/test/compile-fail/resolve-inconsistent-binding-mode.rs +++ b/src/test/compile-fail/resolve-inconsistent-binding-mode.rs @@ -26,13 +26,6 @@ fn matcher2(x: opts) { } } -fn matcher3(x: opts) { - match x { - a(ref mut i) | b(ref const i) => {} //~ ERROR variable `i` is bound with different mode in pattern #2 than in pattern #1 - c(_) => {} - } -} - fn matcher4(x: opts) { match x { a(ref mut i) | b(ref i) => {} //~ ERROR variable `i` is bound with different mode in pattern #2 than in pattern #1 diff --git a/src/test/run-pass/auto-ref-slice-plus-ref.rs b/src/test/run-pass/auto-ref-slice-plus-ref.rs index 58a477900c324..d35341516f2a7 100644 --- a/src/test/run-pass/auto-ref-slice-plus-ref.rs +++ b/src/test/run-pass/auto-ref-slice-plus-ref.rs @@ -13,17 +13,14 @@ trait MyIter { fn test_imm(&self); - fn test_const(&const self); } impl<'self> MyIter for &'self [int] { fn test_imm(&self) { assert_eq!(self[0], 1) } - fn test_const(&const self) { assert_eq!(self[0], 1) } } impl<'self> MyIter for &'self str { fn test_imm(&self) { assert_eq!(*self, "test") } - fn test_const(&const self) { assert_eq!(self[0], 't' as u8) } } pub fn main() { @@ -40,15 +37,6 @@ pub fn main() { // XXX: Other types of mutable vecs don't currently exist - ([1]).test_const(); - (~[1]).test_const(); - (@[1]).test_const(); - (&[1]).test_const(); - ("test").test_const(); - (~"test").test_const(); - (@"test").test_const(); - (&"test").test_const(); - // NB: We don't do this double autoreffing for &mut self because that would // allow creating a mutable pointer to a temporary, which would be a source // of confusion diff --git a/src/test/run-pass/autoderef-and-borrow-method-receiver.rs b/src/test/run-pass/autoderef-and-borrow-method-receiver.rs index b00d8980c69fe..fc643ec594089 100644 --- a/src/test/run-pass/autoderef-and-borrow-method-receiver.rs +++ b/src/test/run-pass/autoderef-and-borrow-method-receiver.rs @@ -13,7 +13,7 @@ struct Foo { } impl Foo { - pub fn f(&const self) {} + pub fn f(&self) {} } fn g(x: &mut Foo) { diff --git a/src/test/compile-fail/borrowck-pat-enum.rs b/src/test/run-pass/borrowck-pat-enum.rs similarity index 65% rename from src/test/compile-fail/borrowck-pat-enum.rs rename to src/test/run-pass/borrowck-pat-enum.rs index f1cca89b227d6..6c00bea28b6e3 100644 --- a/src/test/compile-fail/borrowck-pat-enum.rs +++ b/src/test/run-pass/borrowck-pat-enum.rs @@ -24,32 +24,9 @@ fn match_ref_unused(v: Option) { } } -fn match_const_reg(v: &const Option) -> int { - match *v { - Some(ref i) => {*i} //~ ERROR cannot borrow - //~^ ERROR unsafe borrow - None => {0} - } -} - fn impure(_i: int) { } -fn match_const_reg_unused(v: &const Option) { - match *v { - Some(_) => {impure(0)} // OK because nothing is captured - None => {} - } -} - -fn match_const_reg_impure(v: &const Option) { - match *v { - Some(ref i) => {impure(*i)} //~ ERROR cannot borrow - //~^ ERROR unsafe borrow - None => {} - } -} - fn match_imm_reg(v: &Option) { match *v { Some(ref i) => {impure(*i)} // OK because immutable diff --git a/src/test/compile-fail/borrowck-uniq-via-ref.rs b/src/test/run-pass/borrowck-uniq-via-ref.rs similarity index 77% rename from src/test/compile-fail/borrowck-uniq-via-ref.rs rename to src/test/run-pass/borrowck-uniq-via-ref.rs index 8bf627d991911..44f3a8f518a15 100644 --- a/src/test/compile-fail/borrowck-uniq-via-ref.rs +++ b/src/test/run-pass/borrowck-uniq-via-ref.rs @@ -25,7 +25,6 @@ struct Innermost { } fn borrow(_v: &int) {} -fn borrow_const(_v: &const int) {} fn box_mut(v: &mut ~int) { borrow(*v); // OK: &mut -> &imm @@ -51,17 +50,5 @@ fn box_imm_recs(v: &Outer) { borrow(v.f.g.h); // OK } -fn box_const(v: &const ~int) { - borrow_const(*v); //~ ERROR unsafe borrow -} - -fn box_const_rec(v: &const Rec) { - borrow_const(v.f); //~ ERROR unsafe borrow -} - -fn box_const_recs(v: &const Outer) { - borrow_const(v.f.g.h); //~ ERROR unsafe borrow -} - fn main() { } diff --git a/src/test/run-pass/class-impl-very-parameterized-trait.rs b/src/test/run-pass/class-impl-very-parameterized-trait.rs index d42c57c3b81a0..725019fd9f516 100644 --- a/src/test/run-pass/class-impl-very-parameterized-trait.rs +++ b/src/test/run-pass/class-impl-very-parameterized-trait.rs @@ -51,8 +51,8 @@ impl cat { } impl Container for cat { - fn len(&const self) -> uint { self.meows as uint } - fn is_empty(&const self) -> bool { self.meows == 0 } + fn len(&self) -> uint { self.meows as uint } + fn is_empty(&self) -> bool { self.meows == 0 } } impl Mutable for cat { diff --git a/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs b/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs index 438c70c6583f4..69e5d692d0d3d 100644 --- a/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs +++ b/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs @@ -3,14 +3,14 @@ struct SpeechMaker { } impl SpeechMaker { - pub fn how_many(&const self) -> uint { self.speeches } + pub fn how_many(&self) -> uint { self.speeches } } -fn foo(speaker: &const SpeechMaker) -> uint { +fn foo(speaker: &SpeechMaker) -> uint { speaker.how_many() + 33 } pub fn main() { let mut lincoln = SpeechMaker {speeches: 22}; - assert_eq!(foo(&const lincoln), 55); + assert_eq!(foo(&lincoln), 55); } diff --git a/src/test/run-pass/const-vec-syntax.rs b/src/test/run-pass/const-vec-syntax.rs index 625f6ec30cc13..84ee54cfdde6d 100644 --- a/src/test/run-pass/const-vec-syntax.rs +++ b/src/test/run-pass/const-vec-syntax.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn f(_: &const [int]) {} +fn f(_: &[int]) {} pub fn main() { let v = [ 1, 2, 3 ]; From f29c1f82e429239c1f1324aac8275e04c302bee1 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 7 Aug 2013 09:47:28 -0700 Subject: [PATCH 02/16] librustc: Add support for type parameters in the middle of paths. For example, `foo::::bar::`. This doesn't enforce that the type parameters are in the right positions, however. --- src/librustc/front/std_inject.rs | 17 +- src/librustc/front/test.rs | 31 +- src/librustc/metadata/encoder.rs | 3 +- src/librustc/metadata/tydecode.rs | 20 +- src/librustc/middle/check_const.rs | 2 +- src/librustc/middle/privacy.rs | 16 +- src/librustc/middle/region.rs | 6 +- src/librustc/middle/resolve.rs | 101 +++--- src/librustc/middle/trans/consts.rs | 4 +- src/librustc/middle/typeck/astconv.rs | 34 +- src/librustc/middle/typeck/check/mod.rs | 28 +- src/libsyntax/ast.rs | 21 +- src/libsyntax/ast_util.rs | 24 +- src/libsyntax/ext/base.rs | 20 +- src/libsyntax/ext/build.rs | 25 +- src/libsyntax/ext/concat_idents.rs | 11 +- src/libsyntax/ext/expand.rs | 31 +- src/libsyntax/ext/tt/macro_parser.rs | 6 +- src/libsyntax/fold.rs | 8 +- src/libsyntax/oldvisit.rs | 6 +- src/libsyntax/parse/mod.rs | 227 +++++++++----- src/libsyntax/parse/parser.rs | 360 +++++++++++++--------- src/libsyntax/print/pprust.rs | 61 ++-- src/libsyntax/visit.rs | 6 +- src/test/run-pass/mid-path-type-params.rs | 16 + 25 files changed, 694 insertions(+), 390 deletions(-) create mode 100644 src/test/run-pass/mid-path-type-params.rs diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs index 2a61ea28e0c6b..429a1c35b3421 100644 --- a/src/librustc/front/std_inject.rs +++ b/src/librustc/front/std_inject.rs @@ -17,6 +17,7 @@ use syntax::attr; use syntax::codemap::dummy_sp; use syntax::codemap; use syntax::fold; +use syntax::opt_vec; static STD_VERSION: &'static str = "0.8-pre"; @@ -90,12 +91,18 @@ fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate { let prelude_path = ast::Path { span: dummy_sp(), global: false, - idents: ~[ - sess.ident_of("std"), - sess.ident_of("prelude") + segments: ~[ + ast::PathSegment { + identifier: sess.ident_of("std"), + lifetime: None, + types: opt_vec::Empty, + }, + ast::PathSegment { + identifier: sess.ident_of("prelude"), + lifetime: None, + types: opt_vec::Empty, + }, ], - rp: None, - types: ~[] }; let vp = @spanned(ast::view_path_glob(prelude_path, n2)); diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 597de440ae1fc..347ea5d740520 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -16,14 +16,15 @@ use front::config; use std::vec; use syntax::ast_util::*; +use syntax::attr::AttrMetaMethods; use syntax::attr; use syntax::codemap::{dummy_sp, span, ExpnInfo, NameAndSpan}; use syntax::codemap; use syntax::ext::base::ExtCtxt; use syntax::fold; +use syntax::opt_vec; use syntax::print::pprust; use syntax::{ast, ast_util}; -use syntax::attr::AttrMetaMethods; type node_id_gen = @fn() -> ast::NodeId; @@ -340,19 +341,27 @@ fn nospan(t: T) -> codemap::spanned { } fn path_node(ids: ~[ast::ident]) -> ast::Path { - ast::Path { span: dummy_sp(), - global: false, - idents: ids, - rp: None, - types: ~[] } + ast::Path { + span: dummy_sp(), + global: false, + segments: ids.consume_iter().transform(|identifier| ast::PathSegment { + identifier: identifier, + lifetime: None, + types: opt_vec::Empty, + }).collect() + } } fn path_node_global(ids: ~[ast::ident]) -> ast::Path { - ast::Path { span: dummy_sp(), - global: true, - idents: ids, - rp: None, - types: ~[] } + ast::Path { + span: dummy_sp(), + global: true, + segments: ids.consume_iter().transform(|identifier| ast::PathSegment { + identifier: identifier, + lifetime: None, + types: opt_vec::Empty, + }).collect() + } } fn mk_tests(cx: &TestCtxt) -> @ast::item { diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index afc28342ad01f..915eaad87f593 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -998,7 +998,8 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_name(ecx, ebml_w, item.ident); encode_attributes(ebml_w, item.attrs); match ty.node { - ast::ty_path(ref path, ref bounds, _) if path.idents.len() == 1 => { + ast::ty_path(ref path, ref bounds, _) if path.segments + .len() == 1 => { assert!(bounds.is_none()); encode_impl_type_basename(ecx, ebml_w, ast_util::path_to_ident(path)); diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index a03266649ab0a..3606ecd8d24c1 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -138,12 +138,20 @@ fn parse_path(st: &mut PState) -> @ast::Path { ':' => { next(st); next(st); } c => { if c == '(' { - return @ast::Path { span: dummy_sp(), - global: false, - idents: idents, - rp: None, - types: ~[] }; - } else { idents.push(parse_ident_(st, is_last)); } + return @ast::Path { + span: dummy_sp(), + global: false, + segments: idents.consume_iter().transform(|identifier| { + ast::PathSegment { + identifier: identifier, + lifetime: None, + types: opt_vec::Empty, + } + }).collect() + }; + } else { + idents.push(parse_ident_(st, is_last)); + } } } }; diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 160cc23bd19ff..ae3cb86ae5959 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -117,7 +117,7 @@ pub fn check_expr(sess: Session, // to handle on-demand instantiation of functions via // foo:: in a const. Currently that is only done on // a path in trans::callee that only works in block contexts. - if pth.types.len() != 0 { + if !pth.segments.iter().all(|segment| segment.types.is_empty()) { sess.span_err( e.span, "paths in constants may only refer to \ items without type parameters"); diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 54e7c79e97cc2..813792e36ad0e 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -33,8 +33,8 @@ use syntax::ast_util::{Private, Public, is_local}; use syntax::ast_util::{variant_visibility_to_privacy, visibility_to_privacy}; use syntax::attr; use syntax::codemap::span; -use syntax::parse::token; use syntax::oldvisit; +use syntax::parse::token; pub fn check_crate<'mm>(tcx: ty::ctxt, method_map: &'mm method_map, @@ -255,7 +255,9 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, match def { def_static_method(method_id, _, _) => { debug!("found static method def, checking it"); - check_method_common(span, method_id, path.idents.last()) + check_method_common(span, + method_id, + &path.segments.last().identifier) } def_fn(def_id, _) => { if def_id.crate == LOCAL_CRATE { @@ -263,13 +265,19 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, !privileged_items.iter().any(|x| x == &def_id.node) { tcx.sess.span_err(span, fmt!("function `%s` is private", - token::ident_to_str(path.idents.last()))); + token::ident_to_str( + &path.segments + .last() + .identifier))); } } else if csearch::get_item_visibility(tcx.sess.cstore, def_id) != public { tcx.sess.span_err(span, fmt!("function `%s` is private", - token::ident_to_str(path.idents.last()))); + token::ident_to_str( + &path.segments + .last() + .identifier))); } } _ => {} diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 4da22be4428e2..3c6b619e8b8ce 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -796,7 +796,7 @@ fn determine_rp_in_ty(ty: &ast::Ty, Some(&ast::def_trait(did)) | Some(&ast::def_struct(did)) => { if did.crate == ast::LOCAL_CRATE { - if cx.region_is_relevant(&path.rp) { + if cx.region_is_relevant(&path.segments.last().lifetime) { cx.add_dep(did.node); } } else { @@ -806,7 +806,7 @@ fn determine_rp_in_ty(ty: &ast::Ty, Some(variance) => { debug!("reference to external, rp'd type %s", pprust::ty_to_str(ty, sess.intr())); - if cx.region_is_relevant(&path.rp) { + if cx.region_is_relevant(&path.segments.last().lifetime) { let rv = cx.add_variance(variance); cx.add_rp(cx.item_id, rv) } @@ -829,7 +829,7 @@ fn determine_rp_in_ty(ty: &ast::Ty, ast::ty_path(ref path, _, _) => { // type parameters are---for now, anyway---always invariant do cx.with_ambient_variance(rv_invariant) { - for tp in path.types.iter() { + for tp in path.segments.iter().flat_map_(|s| s.types.iter()) { (visitor.visit_ty)(tp, (cx, visitor)); } } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 4d95909404e18..880ad3389b721 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -1230,7 +1230,7 @@ impl Resolver { &Ty { node: ty_path(ref path, _, _), _ - } if path.idents.len() == 1 => { + } if path.segments.len() == 1 => { let name = path_to_ident(path); let new_parent = match parent.children.find(&name) { @@ -1430,20 +1430,22 @@ impl Resolver { let mut module_path = ~[]; match view_path.node { view_path_simple(_, ref full_path, _) => { - let path_len = full_path.idents.len(); + let path_len = full_path.segments.len(); assert!(path_len != 0); - for (i, ident) in full_path.idents.iter().enumerate() { + for (i, segment) in full_path.segments + .iter() + .enumerate() { if i != path_len - 1 { - module_path.push(*ident); + module_path.push(segment.identifier) } } } view_path_glob(ref module_ident_path, _) | view_path_list(ref module_ident_path, _, _) => { - for ident in module_ident_path.idents.iter() { - module_path.push(*ident); + for segment in module_ident_path.segments.iter() { + module_path.push(segment.identifier) } } } @@ -1452,7 +1454,8 @@ impl Resolver { let module_ = self.get_module_from_parent(parent); match view_path.node { view_path_simple(binding, ref full_path, id) => { - let source_ident = *full_path.idents.last(); + let source_ident = + full_path.segments.last().identifier; let subclass = @SingleImport(binding, source_ident); self.build_import_directive(privacy, @@ -2063,6 +2066,14 @@ impl Resolver { return result; } + fn path_idents_to_str(@mut self, path: &Path) -> ~str { + let identifiers: ~[ast::ident] = path.segments + .iter() + .transform(|seg| seg.identifier) + .collect(); + self.idents_to_str(identifiers) + } + pub fn import_directive_subclass_to_str(@mut self, subclass: ImportDirectiveSubclass) -> @str { @@ -3811,8 +3822,7 @@ impl Resolver { reference_type: TraitReferenceType) { match self.resolve_path(id, &trait_reference.path, TypeNS, true, visitor) { None => { - let path_str = self.idents_to_str(trait_reference.path.idents); - + let path_str = self.path_idents_to_str(&trait_reference.path); let usage_str = match reference_type { TraitBoundingTypeParameter => "bound type parameter with", TraitImplementation => "implement", @@ -4111,8 +4121,8 @@ impl Resolver { let mut result_def = None; // First, check to see whether the name is a primitive type. - if path.idents.len() == 1 { - let name = *path.idents.last(); + if path.segments.len() == 1 { + let name = path.segments.last().identifier; match self.primitive_type_table .primitive_types @@ -4135,7 +4145,7 @@ impl Resolver { debug!("(resolving type) resolved `%s` to \ type %?", self.session.str_of( - *path.idents.last()), + path.segments.last().identifier), def); result_def = Some(def); } @@ -4154,14 +4164,15 @@ impl Resolver { // Write the result into the def map. debug!("(resolving type) writing resolution for `%s` \ (id %d)", - self.idents_to_str(path.idents), + self.path_idents_to_str(path), path_id); self.record_def(path_id, def); } None => { self.session.span_err - (ty.span, fmt!("use of undeclared type name `%s`", - self.idents_to_str(path.idents))); + (ty.span, + fmt!("use of undeclared type name `%s`", + self.path_idents_to_str(path))) } } @@ -4200,7 +4211,7 @@ impl Resolver { do walk_pat(pattern) |pattern| { match pattern.node { pat_ident(binding_mode, ref path, _) - if !path.global && path.idents.len() == 1 => { + if !path.global && path.segments.len() == 1 => { // The meaning of pat_ident with no type parameters // depends on whether an enum variant or unit-like struct @@ -4211,7 +4222,7 @@ impl Resolver { // such a value is simply disallowed (since it's rarely // what you want). - let ident = path.idents[0]; + let ident = path.segments[0].identifier; match self.resolve_bare_identifier_pattern(ident) { FoundStructOrEnumVariant(def) @@ -4321,7 +4332,9 @@ impl Resolver { } // Check the types in the path pattern. - for ty in path.types.iter() { + for ty in path.segments + .iter() + .flat_map_(|seg| seg.types.iter()) { self.resolve_type(ty, visitor); } } @@ -4345,7 +4358,7 @@ impl Resolver { path.span, fmt!("`%s` is not an enum variant or constant", self.session.str_of( - *path.idents.last()))); + path.segments.last().identifier))) } None => { self.session.span_err(path.span, @@ -4354,7 +4367,9 @@ impl Resolver { } // Check the types in the path pattern. - for ty in path.types.iter() { + for ty in path.segments + .iter() + .flat_map_(|s| s.types.iter()) { self.resolve_type(ty, visitor); } } @@ -4372,8 +4387,10 @@ impl Resolver { self.session.span_err( path.span, fmt!("`%s` is not an enum variant, struct or const", - self.session.str_of( - *path.idents.last()))); + self.session + .str_of(path.segments + .last() + .identifier))); } None => { self.session.span_err(path.span, @@ -4383,7 +4400,9 @@ impl Resolver { } // Check the types in the path pattern. - for ty in path.types.iter() { + for ty in path.segments + .iter() + .flat_map_(|s| s.types.iter()) { self.resolve_type(ty, visitor); } } @@ -4418,7 +4437,7 @@ impl Resolver { self.session.span_err( path.span, fmt!("`%s` does not name a structure", - self.idents_to_str(path.idents))); + self.path_idents_to_str(path))); } } } @@ -4480,7 +4499,7 @@ impl Resolver { visitor: ResolveVisitor) -> Option { // First, resolve the types. - for ty in path.types.iter() { + for ty in path.segments.iter().flat_map_(|s| s.types.iter()) { self.resolve_type(ty, visitor); } @@ -4490,12 +4509,17 @@ impl Resolver { namespace); } - let unqualified_def = self.resolve_identifier( - *path.idents.last(), namespace, check_ribs, path.span); + let unqualified_def = self.resolve_identifier(path.segments + .last() + .identifier, + namespace, + check_ribs, + path.span); - if path.idents.len() > 1 { - let def = self.resolve_module_relative_path( - path, self.xray_context, namespace); + if path.segments.len() > 1 { + let def = self.resolve_module_relative_path(path, + self.xray_context, + namespace); match (def, unqualified_def) { (Some(d), Some(ud)) if d == ud => { self.session.add_lint(unnecessary_qualification, @@ -4610,12 +4634,12 @@ impl Resolver { pub fn intern_module_part_of_path(@mut self, path: &Path) -> ~[ident] { let mut module_path_idents = ~[]; - for (index, ident) in path.idents.iter().enumerate() { - if index == path.idents.len() - 1 { + for (index, segment) in path.segments.iter().enumerate() { + if index == path.segments.len() - 1 { break; } - module_path_idents.push(*ident); + module_path_idents.push(segment.identifier); } return module_path_idents; @@ -4651,7 +4675,7 @@ impl Resolver { } } - let name = *path.idents.last(); + let name = path.segments.last().identifier; let def = match self.resolve_definition_of_name_in_module(containing_module, name, namespace, @@ -4719,7 +4743,7 @@ impl Resolver { } } - let name = *path.idents.last(); + let name = path.segments.last().identifier; match self.resolve_definition_of_name_in_module(containing_module, name, namespace, @@ -4922,7 +4946,7 @@ impl Resolver { Some(def) => { // Write the result into the def map. debug!("(resolving expr) resolved `%s`", - self.idents_to_str(path.idents)); + self.path_idents_to_str(path)); // First-class methods are not supported yet; error // out here. @@ -4942,8 +4966,7 @@ impl Resolver { self.record_def(expr.id, def); } None => { - let wrong_name = self.idents_to_str( - path.idents); + let wrong_name = self.path_idents_to_str(path); if self.name_exists_in_scope_struct(wrong_name) { self.session.span_err(expr.span, fmt!("unresolved name `%s`. \ @@ -5001,7 +5024,7 @@ impl Resolver { self.session.span_err( path.span, fmt!("`%s` does not name a structure", - self.idents_to_str(path.idents))); + self.path_idents_to_str(path))); } } diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 87d26fa5ba07c..771decb4e6c1b 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -559,7 +559,9 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::expr) -> ValueRef { v } ast::expr_path(ref pth) => { - assert_eq!(pth.types.len(), 0); + // Assert that there are no type parameters in this path. + assert!(pth.segments.iter().all(|seg| seg.types.is_empty())); + let tcx = cx.tcx; match tcx.def_map.find(&e.id) { Some(&ast::def_fn(def_id, _purity)) => { diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index b958890a6a014..8b93155b94d70 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -63,7 +63,6 @@ use middle::typeck::rscope::RegionParamNames; use middle::typeck::lookup_def_tcx; use std::result; -use std::vec; use syntax::abi::AbiSet; use syntax::{ast, ast_util}; use syntax::codemap::span; @@ -150,7 +149,8 @@ fn ast_path_substs( // If the type is parameterized by the this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). - let regions = match (&decl_generics.region_param, &path.rp) { + let regions = match (&decl_generics.region_param, + &path.segments.last().lifetime) { (&None, &None) => { opt_vec::Empty } @@ -169,20 +169,34 @@ fn ast_path_substs( } (&Some(_), &Some(_)) => { opt_vec::with( - ast_region_to_region(this, rscope, path.span, &path.rp)) + ast_region_to_region(this, + rscope, + path.span, + &path.segments.last().lifetime)) } }; // Convert the type parameters supplied by the user. - if !vec::same_length(*decl_generics.type_param_defs, path.types) { + let supplied_type_parameter_count = + path.segments.iter().flat_map_(|s| s.types.iter()).len_(); + if decl_generics.type_param_defs.len() != supplied_type_parameter_count { this.tcx().sess.span_fatal( path.span, fmt!("wrong number of type arguments: expected %u but found %u", - decl_generics.type_param_defs.len(), path.types.len())); + decl_generics.type_param_defs.len(), + supplied_type_parameter_count)); + } + let tps = path.segments + .iter() + .flat_map_(|s| s.types.iter()) + .transform(|a_t| ast_ty_to_ty(this, rscope, a_t)) + .collect(); + + substs { + regions: ty::NonerasedRegions(regions), + self_ty: self_ty, + tps: tps } - let tps = path.types.map(|a_t| ast_ty_to_ty(this, rscope, a_t)); - - substs {regions:ty::NonerasedRegions(regions), self_ty:self_ty, tps:tps} } pub fn ast_path_to_substs_and_ty( path: &ast::Path, flags: uint) { if (flags & NO_TPS) != 0u { - if path.types.len() > 0u { + if !path.segments.iter().all(|s| s.types.is_empty()) { tcx.sess.span_err( path.span, "type parameters are not allowed on this type"); @@ -333,7 +347,7 @@ pub fn ast_ty_to_ty( } if (flags & NO_REGIONS) != 0u { - if path.rp.is_some() { + if path.segments.last().lifetime.is_some() { tcx.sess.span_err( path.span, "region parameters are not allowed on this type"); diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index a46ee330a8579..00dc6ab9c580c 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -490,7 +490,7 @@ pub fn check_fn(ccx: @mut CrateCtxt, if pat_util::pat_is_binding(fcx.ccx.tcx.def_map, p) => { assign(p.id, None); debug!("Pattern binding %s is assigned to %s", - tcx.sess.str_of(path.idents[0]), + tcx.sess.str_of(path.segments[0].identifier), fcx.infcx().ty_to_str( fcx.inh.locals.get_copy(&p.id))); } @@ -3166,7 +3166,10 @@ pub fn instantiate_path(fcx: @mut FnCtxt, debug!(">>> instantiate_path"); let ty_param_count = tpt.generics.type_param_defs.len(); - let ty_substs_len = pth.types.len(); + let mut ty_substs_len = 0; + for segment in pth.segments.iter() { + ty_substs_len += segment.types.len() + } debug!("ty_param_count=%? ty_substs_len=%?", ty_param_count, @@ -3174,7 +3177,7 @@ pub fn instantiate_path(fcx: @mut FnCtxt, // determine the region bound, using the value given by the user // (if any) and otherwise using a fresh region variable - let regions = match pth.rp { + let regions = match pth.segments.last().lifetime { Some(_) => { // user supplied a lifetime parameter... match tpt.generics.region_param { None => { // ...but the type is not lifetime parameterized! @@ -3184,7 +3187,10 @@ pub fn instantiate_path(fcx: @mut FnCtxt, } Some(_) => { // ...and the type is lifetime parameterized, ok. opt_vec::with( - ast_region_to_region(fcx, fcx, span, &pth.rp)) + ast_region_to_region(fcx, + fcx, + span, + &pth.segments.last().lifetime)) } } } @@ -3223,12 +3229,18 @@ pub fn instantiate_path(fcx: @mut FnCtxt, } fcx.infcx().next_ty_vars(ty_param_count) } else { - pth.types.map(|aty| fcx.to_ty(aty)) + pth.segments + .iter() + .flat_map_(|s| s.types.iter()) + .transform(|aty| fcx.to_ty(aty)) + .collect() }; - let substs = substs {regions: ty::NonerasedRegions(regions), - self_ty: None, - tps: tps }; + let substs = substs { + regions: ty::NonerasedRegions(regions), + self_ty: None, + tps: tps + }; fcx.write_ty_substs(node_id, tpt.ty, substs); debug!("<<<"); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 35e0db98d8e2f..f44e031b84545 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -109,12 +109,21 @@ pub struct Path { /// A `::foo` path, is relative to the crate root rather than current /// module (like paths in an import). global: bool, - /// The segments in the path (the things separated by ::) - idents: ~[ident], - /// "Region parameter", currently only one lifetime is allowed in a path. - rp: Option, - /// These are the type parameters, ie, the `a, b` in `foo::bar::` - types: ~[Ty], + /// The segments in the path: the things separated by `::`. + segments: ~[PathSegment], +} + +/// A segment of a path: an identifier, an optional lifetime, and a set of +/// types. +#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)] +pub struct PathSegment { + /// The identifier portion of this path segment. + identifier: ident, + /// The lifetime parameter for this path segment. Currently only one + /// lifetime parameter is allowed. + lifetime: Option, + /// The type parameters for this path segment, if present. + types: OptVec, } pub type CrateNum = int; diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index cfbe61ca65e68..585db7171a2d0 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -28,8 +28,8 @@ pub fn path_name_i(idents: &[ident]) -> ~str { idents.map(|i| token::interner_get(i.name)).connect("::") } -pub fn path_to_ident(p: &Path) -> ident { - *p.idents.last() +pub fn path_to_ident(path: &Path) -> ident { + path.segments.last().identifier } pub fn local_def(id: NodeId) -> def_id { @@ -217,12 +217,18 @@ pub fn default_block( } } -pub fn ident_to_path(s: span, i: ident) -> Path { - ast::Path { span: s, - global: false, - idents: ~[i], - rp: None, - types: ~[] } +pub fn ident_to_path(s: span, identifier: ident) -> Path { + ast::Path { + span: s, + global: false, + segments: ~[ + ast::PathSegment { + identifier: identifier, + lifetime: None, + types: opt_vec::Empty, + } + ], + } } pub fn ident_to_pat(id: NodeId, s: span, i: ident) -> @pat { @@ -420,7 +426,7 @@ impl IdVisitor { impl Visitor<()> for IdVisitor { fn visit_mod(&mut self, module: &_mod, - _span: span, + _: span, node_id: NodeId, env: ()) { (self.visit_callback)(node_id); diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index dfaffa0c2759d..d666cf68e1563 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -325,20 +325,6 @@ pub fn expr_to_str(cx: @ExtCtxt, expr: @ast::expr, err_msg: &str) -> @str { } } -pub fn expr_to_ident(cx: @ExtCtxt, - expr: @ast::expr, - err_msg: &str) -> ast::ident { - match expr.node { - ast::expr_path(ref p) => { - if p.types.len() > 0u || p.idents.len() != 1u { - cx.span_fatal(expr.span, err_msg); - } - return p.idents[0]; - } - _ => cx.span_fatal(expr.span, err_msg) - } -} - pub fn check_zero_tts(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree], name: &str) { if tts.len() != 0 { @@ -349,15 +335,15 @@ pub fn check_zero_tts(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree], pub fn get_single_str_from_tts(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree], - name: &str) -> @str { + name: &str) + -> @str { if tts.len() != 1 { cx.span_fatal(sp, fmt!("%s takes 1 argument.", name)); } match tts[0] { ast::tt_tok(_, token::LIT_STR(ident)) => cx.str_of(ident), - _ => - cx.span_fatal(sp, fmt!("%s requires a string.", name)) + _ => cx.span_fatal(sp, fmt!("%s requires a string.", name)), } } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 65032642fda78..5a2fa4d58b4dd 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -233,18 +233,31 @@ impl AstBuilder for @ExtCtxt { fn path_global(&self, span: span, strs: ~[ast::ident]) -> ast::Path { self.path_all(span, true, strs, None, ~[]) } - fn path_all(&self, sp: span, + fn path_all(&self, + sp: span, global: bool, - idents: ~[ast::ident], + mut idents: ~[ast::ident], rp: Option, types: ~[ast::Ty]) - -> ast::Path { + -> ast::Path { + let last_identifier = idents.pop(); + let mut segments: ~[ast::PathSegment] = idents.consume_iter() + .transform(|ident| { + ast::PathSegment { + identifier: ident, + lifetime: None, + types: opt_vec::Empty, + } + }).collect(); + segments.push(ast::PathSegment { + identifier: last_identifier, + lifetime: rp, + types: opt_vec::from(types), + }); ast::Path { span: sp, global: global, - idents: idents, - rp: rp, - types: types + segments: segments, } } diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index edb5c634d5698..477f3fde99c73 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -12,6 +12,7 @@ use ast; use codemap::span; use ext::base::*; use ext::base; +use opt_vec; use parse::token; use parse::token::{str_to_ident}; @@ -39,9 +40,13 @@ pub fn expand_syntax_ext(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree]) ast::Path { span: sp, global: false, - idents: ~[res], - rp: None, - types: ~[], + segments: ~[ + ast::PathSegment { + identifier: res, + lifetime: None, + types: opt_vec::Empty, + } + ] } ), span: sp, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index c188326a4f1b0..8e3c8d08f555c 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -19,6 +19,7 @@ use codemap; use codemap::{span, spanned, ExpnInfo, NameAndSpan}; use ext::base::*; use fold::*; +use opt_vec; use parse; use parse::{parse_item_from_source_str}; use parse::token; @@ -42,13 +43,13 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv, match (*mac).node { // Token-tree macros: mac_invoc_tt(ref pth, ref tts) => { - if (pth.idents.len() > 1u) { + if (pth.segments.len() > 1u) { cx.span_fatal( pth.span, fmt!("expected macro name without module \ separators")); } - let extname = &pth.idents[0]; + let extname = &pth.segments[0].identifier; let extnamestr = ident_to_str(extname); // leaving explicit deref here to highlight unbox op: match (*extsbox).find(&extname.name) { @@ -143,9 +144,13 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv, ast::Path { span: span, global: false, - idents: ~[ident], - rp: None, - types: ~[] + segments: ~[ + ast::PathSegment { + identifier: ident, + lifetime: None, + types: opt_vec::Empty, + } + ], } } @@ -368,7 +373,7 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv, _ => cx.span_bug(it.span, "invalid item macro invocation") }; - let extname = &pth.idents[0]; + let extname = &pth.segments[0].identifier; let extnamestr = ident_to_str(extname); let expanded = match (*extsbox).find(&extname.name) { None => cx.span_fatal(pth.span, @@ -459,13 +464,13 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv, } _ => return orig(s, sp, fld) }; - if (pth.idents.len() > 1u) { + if (pth.segments.len() > 1u) { cx.span_fatal( pth.span, fmt!("expected macro name without module \ separators")); } - let extname = &pth.idents[0]; + let extname = &pth.segments[0].identifier; let extnamestr = ident_to_str(extname); let (fully_expanded, sp) = match (*extsbox).find(&extname.name) { None => @@ -534,10 +539,14 @@ impl Visitor<()> for NewNameFinderContext { // a path of length one: &ast::Path { global: false, - idents: [id], span: _, - rp: _, - types: _ + segments: [ + ast::PathSegment { + identifier: id, + lifetime: _, + types: _ + } + ] } => self.ident_accumulator.push(id), // I believe these must be enums... _ => () diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index c208a7f7e3e40..327ee331c3814 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -16,8 +16,8 @@ use codemap::{BytePos, mk_sp}; use codemap; use parse::lexer::*; //resolve bug? use parse::ParseSess; -use parse::parser::Parser; use parse::attr::parser_attr; +use parse::parser::{LifetimeAndTypesWithoutColons, Parser}; use parse::token::{Token, EOF, to_str, nonterminal, get_ident_interner, ident_to_str}; use parse::token; @@ -430,7 +430,9 @@ pub fn parse_nt(p: &Parser, name: &str) -> nonterminal { _ => p.fatal(~"expected ident, found " + token::to_str(get_ident_interner(), p.token)) }, - "path" => token::nt_path(~p.parse_path_with_tps(false)), + "path" => { + token::nt_path(~p.parse_path(LifetimeAndTypesWithoutColons).path) + } "attr" => token::nt_attr(@p.parse_attribute(false)), "tt" => { *p.quote_depth += 1u; //but in theory, non-quoted tts might be useful diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 65694f013f751..458737e2fbf0b 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -765,9 +765,11 @@ fn noop_fold_path(p: &Path, fld: @ast_fold) -> Path { ast::Path { span: fld.new_span(p.span), global: p.global, - idents: p.idents.map(|x| fld.fold_ident(*x)), - rp: p.rp, - types: p.types.map(|x| fld.fold_ty(x)), + segments: p.segments.map(|segment| ast::PathSegment { + identifier: fld.fold_ident(segment.identifier), + lifetime: segment.lifetime, + types: segment.types.map(|typ| fld.fold_ty(typ)), + }) } } diff --git a/src/libsyntax/oldvisit.rs b/src/libsyntax/oldvisit.rs index 295003c6ef538..56576ee359960 100644 --- a/src/libsyntax/oldvisit.rs +++ b/src/libsyntax/oldvisit.rs @@ -284,7 +284,11 @@ pub fn visit_ty(t: &Ty, (e, v): (E, vt)) { } pub fn visit_path(p: &Path, (e, v): (E, vt)) { - for tp in p.types.iter() { (v.visit_ty)(tp, (e.clone(), v)); } + for segment in p.segments.iter() { + for typ in segment.types.iter() { + (v.visit_ty)(typ, (e.clone(), v)) + } + } } pub fn visit_pat(p: &pat, (e, v): (E, vt)) { diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 23c6a8b97208b..73e17f551c9f7 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -361,27 +361,47 @@ mod test { span{lo:BytePos(a),hi:BytePos(b),expn_info:None} } - #[test] fn path_exprs_1 () { + #[test] fn path_exprs_1() { assert_eq!(string_to_expr(@"a"), - @ast::expr{id:1, - node:ast::expr_path(ast::Path {span:sp(0,1), - global:false, - idents:~[str_to_ident("a")], - rp:None, - types:~[]}), - span:sp(0,1)}) + @ast::expr{ + id: 1, + node: ast::expr_path(ast::Path { + span: sp(0, 1), + global: false, + segments: ~[ + ast::PathSegment { + identifier: str_to_ident("a"), + lifetime: None, + types: ~[], + } + ], + }), + span: sp(0, 1) + }) } #[test] fn path_exprs_2 () { assert_eq!(string_to_expr(@"::a::b"), - @ast::expr{id:1, - node:ast::expr_path( - ast::Path {span:sp(0,6), - global:true, - idents:strs_to_idents(~["a","b"]), - rp:None, - types:~[]}), - span:sp(0,6)}) + @ast::expr { + id:1, + node: ast::expr_path(ast::Path { + span: sp(0, 6), + global: true, + segments: ~[ + ast::PathSegment { + identifier: str_to_ident("a"), + lifetime: None, + types: ~[], + }, + ast::PathSegment { + identifier: str_to_ident("b"), + lifetime: None, + types: ~[], + } + ] + }, + span: sp(0, 6)) + }) } #[should_fail] @@ -420,32 +440,43 @@ mod test { #[test] fn ret_expr() { assert_eq!(string_to_expr(@"return d"), - @ast::expr{id:2, - node:ast::expr_ret( - Some(@ast::expr{id:1, - node:ast::expr_path( - ast::Path{span:sp(7,8), - global:false, - idents:~[str_to_ident("d")], - rp:None, - types:~[] - }), - span:sp(7,8)})), - span:sp(0,8)}) + @ast::expr{ + id:2, + node:ast::expr_ret(Some(@ast::expr{ + id:1, + node:ast::expr_path(ast::Path{ + span: sp(7, 8), + global: false, + segments: ~[ + ast::PathSegment { + identifier: str_to_ident("d"), + lifetime: None, + types: opt_vec::Empty, + } + ], + }), + span:sp(7,8) + })), + span:sp(0,8) + }) } #[test] fn parse_stmt_1 () { assert_eq!(string_to_stmt(@"b;"), @spanned{ - node: ast::stmt_expr(@ast::expr{ + node: ast::stmt_expr(@ast::expr { id: 1, - node: ast::expr_path( - ast::Path{ - span:sp(0,1), - global:false, - idents:~[str_to_ident("b")], - rp:None, - types: ~[]}), + node: ast::expr_path(ast::Path { + span:sp(0,1), + global:false, + segments: ~[ + ast::PathSegment { + identifier: str_to_ident("b"), + lifetime: None, + types: opt_vec::Empty, + } + ], + }), span: sp(0,1)}, 2), // fixme span: sp(0,1)}) @@ -460,15 +491,20 @@ mod test { let parser = string_to_parser(@"b"); assert_eq!(parser.parse_pat(), @ast::pat{id:1, // fixme - node: ast::pat_ident(ast::bind_infer, - ast::Path{ - span:sp(0,1), - global:false, - idents:~[str_to_ident("b")], - rp: None, - types: ~[]}, - None // no idea - ), + node: ast::pat_ident( + ast::bind_infer, + ast::Path { + span:sp(0,1), + global:false, + segments: ~[ + ast::PathSegment { + identifier: str_to_ident("b"), + lifetime: None, + types: opt_vec::Empty, + } + ], + }, + None /* no idea */), span: sp(0,1)}); parser_done(parser); } @@ -483,21 +519,33 @@ mod test { span:sp(4,4), // this is bizarre... // check this in the original parser? global:false, - idents:~[str_to_ident("int")], - rp: None, - types: ~[]}, - None, 2), + segments: ~[ + ast::PathSegment { + identifier: + str_to_ident("int"), + lifetime: None, + types: opt_vec::Empty, + } + ], + }, None, 2), span:sp(4,7)}, pat: @ast::pat{id:1, - node: ast::pat_ident(ast::bind_infer, - ast::Path{ - span:sp(0,1), - global:false, - idents:~[str_to_ident("b")], - rp: None, - types: ~[]}, - None // no idea - ), + node: ast::pat_ident( + ast::bind_infer, + ast::Path { + span:sp(0,1), + global:false, + segments: ~[ + ast::PathSegment { + identifier: + str_to_ident("b"), + lifetime: None, + types: opt_vec::Empty, + } + ], + }, + None // no idea + ), span: sp(0,1)}, id: 4 // fixme }) @@ -519,23 +567,37 @@ mod test { node: ast::ty_path(ast::Path{ span:sp(10,13), global:false, - idents:~[str_to_ident("int")], - rp: None, - types: ~[]}, - None, 2), - span:sp(10,13)}, - pat: @ast::pat{id:1, // fixme - node: ast::pat_ident( - ast::bind_infer, - ast::Path{ - span:sp(6,7), - global:false, - idents:~[str_to_ident("b")], - rp: None, - types: ~[]}, - None // no idea - ), - span: sp(6,7)}, + segments: ~[ + ast::PathSegment { + identifier: + str_to_ident("int"), + lifetime: None, + types: opt_vec::Empty, + } + ], + }, None, 2), + span:sp(10,13) + }, + pat: @ast::pat { + id:1, // fixme + node: ast::pat_ident( + ast::bind_infer, + ast::Path { + span:sp(6,7), + global:false, + segments: ~[ + ast::PathSegment { + identifier: + str_to_ident("b"), + lifetime: None, + types: opt_vec::Empty, + } + ], + }, + None // no idea + ), + span: sp(6,7) + }, id: 4 // fixme }], output: ast::Ty{id:5, // fixme @@ -558,9 +620,18 @@ mod test { ast::Path{ span:sp(17,18), global:false, - idents:~[str_to_ident("b")], - rp:None, - types: ~[]}), + segments: ~[ + ast::PathSegment { + identifier: + str_to_ident( + "b"), + lifetime: + None, + types: + opt_vec::Empty + } + ], + }), span: sp(17,18)}, 7), // fixme span: sp(17,18)}], diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9c8ca651f80e5..9a821d1ed28eb 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -97,6 +97,37 @@ enum restriction { type arg_or_capture_item = Either; type item_info = (ident, item_, Option<~[Attribute]>); +/// How to parse a path. There are four different kinds of paths, all of which +/// are parsed somewhat differently. +#[deriving(Eq)] +pub enum PathParsingMode { + /// A path with no type parameters; e.g. `foo::bar::Baz` + NoTypesAllowed, + /// A path with a lifetime and type parameters, with no double colons + /// before the type parameters; e.g. `foo::bar<'self>::Baz` + LifetimeAndTypesWithoutColons, + /// A path with a lifetime and type parameters with double colons before + /// the type parameters; e.g. `foo::bar::<'self>::Baz::` + LifetimeAndTypesWithColons, + /// A path with a lifetime and type parameters with bounds before the last + /// set of type parameters only; e.g. `foo::bar<'self>::Baz:X+Y` This + /// form does not use extra double colons. + LifetimeAndTypesAndBounds, +} + +/// A pair of a path segment and group of type parameter bounds. (See `ast.rs` +/// for the definition of a path segment.) +struct PathSegmentAndBoundSet { + segment: ast::PathSegment, + bound_set: Option>, +} + +/// A path paired with optional type bounds. +struct PathAndBounds { + path: ast::Path, + bounds: Option>, +} + pub enum item_or_view_item { // Indicates a failure to parse any kind of item. The attributes are // returned. @@ -1108,7 +1139,10 @@ impl Parser { } else if *self.token == token::MOD_SEP || is_ident_or_path(self.token) { // NAMED TYPE - let (path, bounds) = self.parse_type_path(); + let PathAndBounds { + path, + bounds + } = self.parse_path(LifetimeAndTypesAndBounds); ty_path(path, bounds, self.get_id()) } else { self.fatal(fmt!("expected type, found token %?", @@ -1330,139 +1364,155 @@ impl Parser { } } - // parse a path into a vector of idents, whether the path starts - // with ::, and a span. - pub fn parse_path(&self) -> (~[ast::ident],bool,span) { + /// Parses a path and optional type parameter bounds, depending on the + /// mode. The `mode` parameter determines whether lifetimes, types, and/or + /// bounds are permitted and whether `::` must precede type parameter + /// groups. + pub fn parse_path(&self, mode: PathParsingMode) -> PathAndBounds { + // Check for a whole path... + let found = match *self.token { + INTERPOLATED(token::nt_path(_)) => Some(self.bump_and_get()), + _ => None, + }; + match found { + Some(INTERPOLATED(token::nt_path(path))) => { + return PathAndBounds { + path: path, + bounds: None, + } + } + _ => {} + } + let lo = self.span.lo; let is_global = self.eat(&token::MOD_SEP); - let (ids,span{lo:_,hi,expn_info}) = self.parse_path_non_global(); - (ids,is_global,span{lo:lo,hi:hi,expn_info:expn_info}) - } - // parse a path beginning with an identifier into a vector of idents and a span - pub fn parse_path_non_global(&self) -> (~[ast::ident],span) { - let lo = self.span.lo; - let mut ids = ~[]; - // must be at least one to begin: - ids.push(self.parse_ident()); + // Parse any number of segments and bound sets. A segment is an + // identifier followed by an optional lifetime and a set of types. + // A bound set is a set of type parameter bounds. + let mut segments = ~[]; loop { + // First, parse an identifier. match *self.token { - token::MOD_SEP => { - let is_ident = do self.look_ahead(1) |t| { - match *t { - token::IDENT(*) => true, - _ => false, - } - }; - if is_ident { - self.bump(); - ids.push(self.parse_ident()); - } else { - break - } - } - _ => break + token::IDENT(*) => {} + _ => break, } - } - (ids, mk_sp(lo, self.last_span.hi)) - } + let identifier = self.parse_ident(); - // parse a path that doesn't have type parameters attached - pub fn parse_path_without_tps(&self) -> ast::Path { - maybe_whole!(deref self, nt_path); - let (ids,is_global,sp) = self.parse_path(); - ast::Path { span: sp, - global: is_global, - idents: ids, - rp: None, - types: ~[] } - } + // Next, parse a colon and bounded type parameters, if applicable. + let bound_set = if mode == LifetimeAndTypesAndBounds { + self.parse_optional_ty_param_bounds() + } else { + None + }; - pub fn parse_bounded_path_with_tps(&self, colons: bool, - before_tps: Option<&fn()>) -> ast::Path { - debug!("parse_path_with_tps(colons=%b)", colons); + // Parse the '::' before type parameters if it's required. If + // it is required and wasn't present, then we're done. + if mode == LifetimeAndTypesWithColons && + !self.eat(&token::MOD_SEP) { + segments.push(PathSegmentAndBoundSet { + segment: ast::PathSegment { + identifier: identifier, + lifetime: None, + types: opt_vec::Empty, + }, + bound_set: bound_set + }); + break + } - maybe_whole!(deref self, nt_path); - let lo = self.span.lo; - let path = self.parse_path_without_tps(); - if colons && !self.eat(&token::MOD_SEP) { - return path; - } - - // If the path might have bounds on it, they should be parsed before - // the parameters, e.g. module::TraitName:B1+B2 - before_tps.map_move(|callback| callback()); - - // Parse the (obsolete) trailing region parameter, if any, which will - // be written "foo/&x" - let rp_slash = { - if *self.token == token::BINOP(token::SLASH) - && self.look_ahead(1, |t| *t == token::BINOP(token::AND)) - { - self.bump(); self.bump(); - self.obsolete(*self.last_span, ObsoleteLifetimeNotation); - match *self.token { - token::IDENT(sid, _) => { - let span = self.span; - self.bump(); - Some(ast::Lifetime { - id: self.get_id(), - span: *span, - ident: sid - }) + // Parse the `<` before the lifetime and types, if applicable. + let (any_lifetime_or_types, optional_lifetime, types) = + if mode != NoTypesAllowed && self.eat(&token::LT) { + // Parse an optional lifetime. + let optional_lifetime = match *self.token { + token::LIFETIME(*) => Some(self.parse_lifetime()), + _ => None, + }; + + // Parse type parameters. + let mut types = opt_vec::Empty; + let mut need_comma = optional_lifetime.is_some(); + loop { + // We're done if we see a `>`. + match *self.token { + token::GT | token::BINOP(token::SHR) => { + self.expect_gt(); + break + } + _ => {} // Go on. } - _ => { - self.fatal(fmt!("Expected a lifetime name")); + + if need_comma { + self.expect(&token::COMMA) + } else { + need_comma = true } + + types.push(self.parse_ty(false)) } + + (true, optional_lifetime, types) } else { - None - } - }; + (false, None, opt_vec::Empty) + }; - // Parse any lifetime or type parameters which may appear: - let (lifetimes, tps) = self.parse_generic_values(); - let hi = self.span.lo; + // Assemble and push the result. + segments.push(PathSegmentAndBoundSet { + segment: ast::PathSegment { + identifier: identifier, + lifetime: optional_lifetime, + types: types, + }, + bound_set: bound_set + }); - let rp = match (&rp_slash, &lifetimes) { - (&Some(_), _) => rp_slash, - (&None, v) => { - if v.len() == 0 { - None - } else if v.len() == 1 { - Some(*v.get(0)) - } else { - self.fatal(fmt!("Expected at most one \ - lifetime name (for now)")); + // We're done if we don't see a '::', unless the mode required + // a double colon to get here in the first place. + if !(mode == LifetimeAndTypesWithColons && + !any_lifetime_or_types) { + if !self.eat(&token::MOD_SEP) { + break } } - }; - - ast::Path { - span: mk_sp(lo, hi), - rp: rp, - types: tps, - .. path.clone() } - } - // parse a path optionally with type parameters. If 'colons' - // is true, then type parameters must be preceded by colons, - // as in a::t:: - pub fn parse_path_with_tps(&self, colons: bool) -> ast::Path { - self.parse_bounded_path_with_tps(colons, None) - } + // Assemble the span. + let span = mk_sp(lo, self.last_span.hi); - // Like the above, but can also parse kind bounds in the case of a - // path to be used as a type that might be a trait. - pub fn parse_type_path(&self) -> (ast::Path, Option>) { + // Assemble the path segments. + let mut path_segments = ~[]; let mut bounds = None; - let path = self.parse_bounded_path_with_tps(false, Some(|| { - // Note: this closure might not even get called in the case of a - // macro-generated path. But that's the macro parser's job. - bounds = self.parse_optional_ty_param_bounds(); - })); - (path, bounds) + let last_segment_index = segments.len() - 1; + for (i, segment_and_bounds) in segments.consume_iter().enumerate() { + let PathSegmentAndBoundSet { + segment: segment, + bound_set: bound_set + } = segment_and_bounds; + path_segments.push(segment); + + if bound_set.is_some() { + if i != last_segment_index { + self.span_err(span, + "type parameter bounds are allowed only \ + before the last segment in a path") + } + + bounds = bound_set + } + } + + // Assemble the result. + let path_and_bounds = PathAndBounds { + path: ast::Path { + span: span, + global: is_global, + segments: path_segments, + }, + bounds: bounds, + }; + + path_and_bounds } /// parses 0 or 1 lifetime @@ -1790,7 +1840,7 @@ impl Parser { } else if *self.token == token::MOD_SEP || is_ident(&*self.token) && !self.is_keyword(keywords::True) && !self.is_keyword(keywords::False) { - let pth = self.parse_path_with_tps(true); + let pth = self.parse_path(LifetimeAndTypesWithColons).path; // `!`, as an operator, is prefix, so we know this isn't that if *self.token == token::NOT { @@ -2881,7 +2931,8 @@ impl Parser { let val = self.parse_literal_maybe_minus(); if self.eat(&token::DOTDOT) { let end = if is_ident_or_path(tok) { - let path = self.parse_path_with_tps(true); + let path = self.parse_path(LifetimeAndTypesWithColons) + .path; let hi = self.span.hi; self.mk_expr(lo, hi, expr_path(path)) } else { @@ -2910,7 +2961,7 @@ impl Parser { let end = self.parse_expr_res(RESTRICT_NO_BAR_OP); pat = pat_range(start, end); } else if is_plain_ident(&*self.token) && !can_be_enum_or_struct { - let name = self.parse_path_without_tps(); + let name = self.parse_path(NoTypesAllowed).path; let sub; if self.eat(&token::AT) { // parse foo @ pat @@ -2922,7 +2973,8 @@ impl Parser { pat = pat_ident(bind_infer, name, sub); } else { // parse an enum pat - let enum_path = self.parse_path_with_tps(true); + let enum_path = self.parse_path(LifetimeAndTypesWithColons) + .path; match *self.token { token::LBRACE => { self.bump(); @@ -2958,7 +3010,7 @@ impl Parser { } }, _ => { - if enum_path.idents.len()==1u { + if enum_path.segments.len() == 1 { // it could still be either an enum // or an identifier pattern, resolve // will sort it out: @@ -2993,7 +3045,7 @@ impl Parser { "expected identifier, found path"); } // why a path here, and not just an identifier? - let name = self.parse_path_without_tps(); + let name = self.parse_path(NoTypesAllowed).path; let sub = if self.eat(&token::AT) { Some(self.parse_pat()) } else { @@ -3110,7 +3162,7 @@ impl Parser { // Potential trouble: if we allow macros with paths instead of // idents, we'd need to look ahead past the whole path here... - let pth = self.parse_path_without_tps(); + let pth = self.parse_path(NoTypesAllowed).path; self.bump(); let id = if *self.token == token::LPAREN { @@ -3786,7 +3838,7 @@ impl Parser { // parse a::B<~str,int> fn parse_trait_ref(&self) -> trait_ref { ast::trait_ref { - path: self.parse_path_with_tps(false), + path: self.parse_path(LifetimeAndTypesWithoutColons).path, ref_id: self.get_id(), } } @@ -4706,7 +4758,7 @@ impl Parser { } // item macro. - let pth = self.parse_path_without_tps(); + let pth = self.parse_path(NoTypesAllowed).path; self.expect(&token::NOT); // a 'special' identifier (like what `macro_rules!` uses) @@ -4790,11 +4842,17 @@ impl Parser { let id = self.parse_ident(); path.push(id); } - let path = ast::Path { span: mk_sp(lo, self.span.hi), - global: false, - idents: path, - rp: None, - types: ~[] }; + let path = ast::Path { + span: mk_sp(lo, self.span.hi), + global: false, + segments: path.consume_iter().transform(|identifier| { + ast::PathSegment { + identifier: identifier, + lifetime: None, + types: opt_vec::Empty, + } + }).collect() + }; return @spanned(lo, self.span.hi, view_path_simple(first_ident, path, @@ -4820,11 +4878,17 @@ impl Parser { seq_sep_trailing_allowed(token::COMMA), |p| p.parse_path_list_ident() ); - let path = ast::Path { span: mk_sp(lo, self.span.hi), - global: false, - idents: path, - rp: None, - types: ~[] }; + let path = ast::Path { + span: mk_sp(lo, self.span.hi), + global: false, + segments: path.consume_iter().transform(|identifier| { + ast::PathSegment { + identifier: identifier, + lifetime: None, + types: opt_vec::Empty, + } + }).collect() + }; return @spanned(lo, self.span.hi, view_path_list(path, idents, self.get_id())); } @@ -4832,11 +4896,17 @@ impl Parser { // foo::bar::* token::BINOP(token::STAR) => { self.bump(); - let path = ast::Path { span: mk_sp(lo, self.span.hi), - global: false, - idents: path, - rp: None, - types: ~[] }; + let path = ast::Path { + span: mk_sp(lo, self.span.hi), + global: false, + segments: path.consume_iter().transform(|identifier| { + ast::PathSegment { + identifier: identifier, + lifetime: None, + types: opt_vec::Empty, + } + }).collect() + }; return @spanned(lo, self.span.hi, view_path_glob(path, self.get_id())); } @@ -4848,11 +4918,17 @@ impl Parser { _ => () } let last = path[path.len() - 1u]; - let path = ast::Path { span: mk_sp(lo, self.span.hi), - global: false, - idents: path, - rp: None, - types: ~[] }; + let path = ast::Path { + span: mk_sp(lo, self.span.hi), + global: false, + segments: path.consume_iter().transform(|identifier| { + ast::PathSegment { + identifier: identifier, + lifetime: None, + types: opt_vec::Empty, + } + }).collect() + }; return @spanned(lo, self.last_span.hi, view_path_simple(last, path, self.get_id())); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 037e306ba00a0..f7f2f27ab0ed6 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1502,34 +1502,52 @@ pub fn print_for_decl(s: @ps, loc: &ast::Local, coll: &ast::expr) { print_expr(s, coll); } -fn print_path_(s: @ps, path: &ast::Path, colons_before_params: bool, +fn print_path_(s: @ps, + path: &ast::Path, + colons_before_params: bool, opt_bounds: &Option>) { maybe_print_comment(s, path.span.lo); - if path.global { word(s.s, "::"); } - let mut first = true; - for id in path.idents.iter() { - if first { first = false; } else { word(s.s, "::"); } - print_ident(s, *id); + if path.global { + word(s.s, "::"); } - do opt_bounds.map |bounds| { - print_bounds(s, bounds, true); - }; - if path.rp.is_some() || !path.types.is_empty() { - if colons_before_params { word(s.s, "::"); } - if path.rp.is_some() || !path.types.is_empty() { + let mut first = true; + for (i, segment) in path.segments.iter().enumerate() { + if first { + first = false + } else { + word(s.s, "::") + } + + print_ident(s, segment.identifier); + + if segment.lifetime.is_some() || !segment.types.is_empty() { + // If this is the last segment, print the bounds. + if i == path.segments.len() - 1 { + match *opt_bounds { + None => {} + Some(ref bounds) => print_bounds(s, bounds, true), + } + } + + if colons_before_params { + word(s.s, "::") + } word(s.s, "<"); - for r in path.rp.iter() { - print_lifetime(s, r); - if !path.types.is_empty() { - word_space(s, ","); + for lifetime in segment.lifetime.iter() { + print_lifetime(s, lifetime); + if !segment.types.is_empty() { + word_space(s, ",") } } - commasep(s, inconsistent, path.types, print_type); + commasep(s, + inconsistent, + segment.types.map_to_vec(|t| (*t).clone()), + print_type); - word(s.s, ">"); + word(s.s, ">") } } } @@ -1820,7 +1838,7 @@ pub fn print_meta_item(s: @ps, item: &ast::MetaItem) { pub fn print_view_path(s: @ps, vp: &ast::view_path) { match vp.node { ast::view_path_simple(ident, ref path, _) => { - if path.idents[path.idents.len()-1u] != ident { + if path.segments.last().identifier != ident { print_ident(s, ident); space(s.s); word_space(s, "="); @@ -1900,8 +1918,9 @@ pub fn print_arg(s: @ps, input: &ast::arg) { _ => { match input.pat.node { ast::pat_ident(_, ref path, _) if - path.idents.len() == 1 && - path.idents[0] == parse::token::special_idents::invalid => { + path.segments.len() == 1 && + path.segments[0].identifier == + parse::token::special_idents::invalid => { // Do nothing. } _ => { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 8178e7f3760b7..ef44a368ab517 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -319,8 +319,10 @@ pub fn walk_ty>(visitor: &mut V, typ: &Ty, env: E) { } pub fn walk_path>(visitor: &mut V, path: &Path, env: E) { - for typ in path.types.iter() { - visitor.visit_ty(typ, env.clone()) + for segment in path.segments.iter() { + for typ in path.types.iter() { + visitor.visit_ty(typ, env.clone()) + } } } diff --git a/src/test/run-pass/mid-path-type-params.rs b/src/test/run-pass/mid-path-type-params.rs new file mode 100644 index 0000000000000..8f01bd5e5eacf --- /dev/null +++ b/src/test/run-pass/mid-path-type-params.rs @@ -0,0 +1,16 @@ +struct S { + contents: T, +} + +impl S { + fn new(x: T, _: U) -> S { + S { + contents: x, + } + } +} + +fn main() { + let _ = S::::new::(1, 1.0); +} + From fe37d810f1b853b3362b85c704f6f6a47df1790d Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 8 Aug 2013 11:38:10 -0700 Subject: [PATCH 03/16] librustc: Ensure that type parameters are in the right positions in paths. This removes the stacking of type parameters that occurs when invoking trait methods, and fixes all places in the standard library that were relying on it. It is somewhat awkward in places; I think we'll probably want something like the `Foo::::new()` syntax. --- src/libextra/dlist.rs | 18 +- src/libextra/num/bigint.rs | 61 +++-- src/libextra/num/rational.rs | 29 ++- src/libextra/priority_queue.rs | 19 +- src/libextra/ringbuf.rs | 2 +- src/libextra/treemap.rs | 5 +- src/librustc/front/test.rs | 4 +- src/librustc/metadata/decoder.rs | 20 +- src/librustc/metadata/tydecode.rs | 2 +- src/librustc/middle/astencode.rs | 11 +- .../middle/borrowck/gather_loans/mod.rs | 4 +- src/librustc/middle/privacy.rs | 9 +- src/librustc/middle/region.rs | 2 +- src/librustc/middle/resolve.rs | 62 +++-- src/librustc/middle/trans/callee.rs | 7 +- src/librustc/middle/trans/expr.rs | 8 +- src/librustc/middle/typeck/astconv.rs | 6 +- src/librustc/middle/typeck/check/_match.rs | 14 +- src/librustc/middle/typeck/check/method.rs | 2 +- src/librustc/middle/typeck/check/mod.rs | 224 ++++++++++++++++-- src/libstd/at_vec.rs | 2 +- src/libstd/cell.rs | 2 +- src/libstd/fmt/mod.rs | 15 +- src/libstd/hashmap.rs | 6 +- src/libstd/iterator.rs | 10 +- src/libstd/logging.rs | 3 +- src/libstd/num/f32.rs | 179 +++++++++----- src/libstd/num/f64.rs | 186 +++++++++------ src/libstd/num/float.rs | 224 ++++++++++++------ src/libstd/num/int_macros.rs | 9 +- src/libstd/num/num.rs | 24 +- src/libstd/num/uint_macros.rs | 9 +- src/libstd/rt/borrowck.rs | 2 +- src/libstd/rt/comm.rs | 10 +- src/libstd/rt/io/net/ip.rs | 51 ++-- src/libstd/rt/io/net/tcp.rs | 4 +- src/libstd/rt/io/net/udp.rs | 5 +- src/libstd/rt/io/timer.rs | 4 +- src/libstd/rt/local.rs | 30 ++- src/libstd/rt/local_heap.rs | 7 +- src/libstd/rt/mod.rs | 8 +- src/libstd/rt/sched.rs | 23 +- src/libstd/rt/select.rs | 1 + src/libstd/rt/task.rs | 12 +- src/libstd/rt/tube.rs | 12 +- src/libstd/rt/uv/uvio.rs | 84 +++---- src/libstd/select.rs | 2 +- src/libstd/sys.rs | 4 +- src/libstd/task/local_data_priv.rs | 2 +- src/libstd/task/mod.rs | 12 +- src/libstd/task/spawn.rs | 10 +- src/libstd/tuple.rs | 2 +- src/libstd/unstable/atomics.rs | 3 +- src/libstd/unstable/lang.rs | 5 +- src/libstd/unstable/sync.rs | 2 +- src/libsyntax/ast.rs | 12 +- src/libsyntax/ext/build.rs | 31 ++- src/libsyntax/ext/deriving/rand.rs | 27 ++- src/libsyntax/parse/mod.rs | 4 +- src/libsyntax/parse/parser.rs | 12 +- src/libsyntax/visit.rs | 2 +- .../compile-fail/bad-mid-path-type-params.rs | 37 +++ src/test/compile-fail/issue-4096.rs | 22 -- src/test/compile-fail/prim-with-args.rs | 24 +- src/test/compile-fail/regions-bounds.rs | 4 - .../compile-fail/static-method-privacy.rs | 2 +- src/test/run-pass/borrowck-pat-enum.rs | 2 + src/test/run-pass/deriving-zero.rs | 3 +- src/test/run-pass/float-nan.rs | 7 +- src/test/run-pass/mid-path-type-params.rs | 17 ++ src/test/run-pass/trait-default-method-xc.rs | 2 +- .../trait-static-method-overwriting.rs | 6 +- 72 files changed, 1143 insertions(+), 544 deletions(-) create mode 100644 src/test/compile-fail/bad-mid-path-type-params.rs delete mode 100644 src/test/compile-fail/issue-4096.rs diff --git a/src/libextra/dlist.rs b/src/libextra/dlist.rs index 076e86dd5b040..8e64107363785 100644 --- a/src/libextra/dlist.rs +++ b/src/libextra/dlist.rs @@ -661,7 +661,7 @@ mod tests { #[test] fn test_basic() { - let mut m = DList::new::<~int>(); + let mut m: DList<~int> = DList::new(); assert_eq!(m.pop_front(), None); assert_eq!(m.pop_back(), None); assert_eq!(m.pop_front(), None); @@ -768,7 +768,7 @@ mod tests { #[test] fn test_rotate() { - let mut n = DList::new::(); + let mut n: DList = DList::new(); n.rotate_backward(); check_links(&n); assert_eq!(n.len(), 0); n.rotate_forward(); check_links(&n); @@ -1033,7 +1033,7 @@ mod tests { #[cfg(test)] fn fuzz_test(sz: int) { - let mut m = DList::new::(); + let mut m: DList = DList::new(); let mut v = ~[]; for i in range(0, sz) { check_links(&m); @@ -1078,7 +1078,7 @@ mod tests { #[bench] fn bench_push_front(b: &mut test::BenchHarness) { - let mut m = DList::new::(); + let mut m: DList = DList::new(); do b.iter { m.push_front(0); } @@ -1086,7 +1086,7 @@ mod tests { #[bench] fn bench_push_back(b: &mut test::BenchHarness) { - let mut m = DList::new::(); + let mut m: DList = DList::new(); do b.iter { m.push_back(0); } @@ -1094,7 +1094,7 @@ mod tests { #[bench] fn bench_push_back_pop_back(b: &mut test::BenchHarness) { - let mut m = DList::new::(); + let mut m: DList = DList::new(); do b.iter { m.push_back(0); m.pop_back(); @@ -1103,7 +1103,7 @@ mod tests { #[bench] fn bench_push_front_pop_front(b: &mut test::BenchHarness) { - let mut m = DList::new::(); + let mut m: DList = DList::new(); do b.iter { m.push_front(0); m.pop_front(); @@ -1112,7 +1112,7 @@ mod tests { #[bench] fn bench_rotate_forward(b: &mut test::BenchHarness) { - let mut m = DList::new::(); + let mut m: DList = DList::new(); m.push_front(0); m.push_front(1); do b.iter { @@ -1122,7 +1122,7 @@ mod tests { #[bench] fn bench_rotate_backward(b: &mut test::BenchHarness) { - let mut m = DList::new::(); + let mut m: DList = DList::new(); m.push_front(0); m.push_front(1); do b.iter { diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index 354696ef42060..7e74fff82f7a3 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -380,7 +380,7 @@ impl Integer for BigUint { fn div_mod_floor_inner(a: BigUint, b: BigUint) -> (BigUint, BigUint) { let mut m = a; - let mut d = Zero::zero::(); + let mut d: BigUint = Zero::zero(); let mut n = 1; while m >= b { let (d0, d_unit, b_unit) = div_estimate(&m, &b, n); @@ -432,8 +432,9 @@ impl Integer for BigUint { if shift == 0 { return (BigUint::new(d), One::one(), (*b).clone()); } + let one: BigUint = One::one(); return (BigUint::from_slice(d).shl_unit(shift), - One::one::().shl_unit(shift), + one.shl_unit(shift), b.shl_unit(shift)); } } @@ -1510,11 +1511,18 @@ mod biguint_tests { #[test] fn test_is_even() { - assert!(FromStr::from_str::("1").unwrap().is_odd()); - assert!(FromStr::from_str::("2").unwrap().is_even()); - assert!(FromStr::from_str::("1000").unwrap().is_even()); - assert!(FromStr::from_str::("1000000000000000000000").unwrap().is_even()); - assert!(FromStr::from_str::("1000000000000000000001").unwrap().is_odd()); + let one: Option = FromStr::from_str("1"); + let two: Option = FromStr::from_str("2"); + let thousand: Option = FromStr::from_str("1000"); + let big: Option = + FromStr::from_str("1000000000000000000000"); + let bigger: Option = + FromStr::from_str("1000000000000000000001"); + assert!(one.unwrap().is_odd()); + assert!(two.unwrap().is_even()); + assert!(thousand.unwrap().is_even()); + assert!(big.unwrap().is_even()); + assert!(bigger.unwrap().is_odd()); assert!((BigUint::from_uint(1) << 64).is_even()); assert!(((BigUint::from_uint(1) << 64) + BigUint::from_uint(1)).is_odd()); } @@ -1599,15 +1607,19 @@ mod biguint_tests { } } - assert_eq!(FromStrRadix::from_str_radix::("Z", 10), None); - assert_eq!(FromStrRadix::from_str_radix::("_", 2), None); - assert_eq!(FromStrRadix::from_str_radix::("-1", 10), None); + let zed: Option = FromStrRadix::from_str_radix("Z", 10); + assert_eq!(zed, None); + let blank: Option = FromStrRadix::from_str_radix("_", 2); + assert_eq!(blank, None); + let minus_one: Option = FromStrRadix::from_str_radix("-1", + 10); + assert_eq!(minus_one, None); } #[test] fn test_factor() { fn factor(n: uint) -> BigUint { - let mut f= One::one::(); + let mut f: BigUint = One::one(); for i in range(2, n + 1) { // FIXME(#6102): Assignment operator for BigInt causes ICE // f *= BigUint::from_uint(i); @@ -2005,17 +2017,24 @@ mod bigint_tests { #[test] fn test_abs_sub() { - assert_eq!((-One::one::()).abs_sub(&One::one()), Zero::zero()); - assert_eq!(One::one::().abs_sub(&One::one()), Zero::zero()); - assert_eq!(One::one::().abs_sub(&Zero::zero()), One::one()); - assert_eq!(One::one::().abs_sub(&-One::one::()), - IntConvertible::from_int(2)); + let zero: BigInt = Zero::zero(); + let one: BigInt = One::one(); + assert_eq!((-one).abs_sub(&one), zero); + let one: BigInt = One::one(); + let zero: BigInt = Zero::zero(); + assert_eq!(one.abs_sub(&one), zero); + let one: BigInt = One::one(); + let zero: BigInt = Zero::zero(); + assert_eq!(one.abs_sub(&zero), one); + let one: BigInt = One::one(); + assert_eq!(one.abs_sub(&-one), IntConvertible::from_int(2)); } #[test] fn test_to_str_radix() { fn check(n: int, ans: &str) { - assert!(ans == IntConvertible::from_int::(n).to_str_radix(10)); + let n: BigInt = IntConvertible::from_int(n); + assert!(ans == n.to_str_radix(10)); } check(10, "10"); check(1, "1"); @@ -2028,7 +2047,10 @@ mod bigint_tests { #[test] fn test_from_str_radix() { fn check(s: &str, ans: Option) { - let ans = ans.map_move(|n| IntConvertible::from_int::(n)); + let ans = ans.map_move(|n| { + let x: BigInt = IntConvertible::from_int(n); + x + }); assert_eq!(FromStrRadix::from_str_radix(s, 10), ans); } check("10", Some(10)); @@ -2046,6 +2068,7 @@ mod bigint_tests { BigInt::new(Minus, ~[1, 1, 1])); assert!(-BigInt::new(Minus, ~[1, 1, 1]) == BigInt::new(Plus, ~[1, 1, 1])); - assert_eq!(-Zero::zero::(), Zero::zero::()); + let zero: BigInt = Zero::zero(); + assert_eq!(-zero, zero); } } diff --git a/src/libextra/num/rational.rs b/src/libextra/num/rational.rs index 60dd36a3b886e..41e9a488bf8ae 100644 --- a/src/libextra/num/rational.rs +++ b/src/libextra/num/rational.rs @@ -269,9 +269,13 @@ impl /// Parses `numer/denom`. fn from_str(s: &str) -> Option> { let split: ~[&str] = s.splitn_iter('/', 1).collect(); - if split.len() < 2 { return None; } - do FromStr::from_str::(split[0]).chain |a| { - do FromStr::from_str::(split[1]).chain |b| { + if split.len() < 2 { + return None + } + let a_option: Option = FromStr::from_str(split[0]); + do a_option.chain |a| { + let b_option: Option = FromStr::from_str(split[1]); + do b_option.chain |b| { Some(Ratio::new(a.clone(), b.clone())) } } @@ -282,10 +286,15 @@ impl /// Parses `numer/denom` where the numbers are in base `radix`. fn from_str_radix(s: &str, radix: uint) -> Option> { let split: ~[&str] = s.splitn_iter('/', 1).collect(); - if split.len() < 2 { None } - else { - do FromStrRadix::from_str_radix::(split[0], radix).chain |a| { - do FromStrRadix::from_str_radix::(split[1], radix).chain |b| { + if split.len() < 2 { + None + } else { + let a_option: Option = FromStrRadix::from_str_radix(split[0], + radix); + do a_option.chain |a| { + let b_option: Option = + FromStrRadix::from_str_radix(split[1], radix); + do b_option.chain |b| { Some(Ratio::new(a.clone(), b.clone())) } } @@ -496,7 +505,8 @@ mod test { #[test] fn test_from_str_fail() { fn test(s: &str) { - assert_eq!(FromStr::from_str::(s), None); + let rational: Option = FromStr::from_str(s); + assert_eq!(rational, None); } let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1"]; @@ -536,7 +546,8 @@ mod test { #[test] fn test_from_str_radix_fail() { fn test(s: &str) { - assert_eq!(FromStrRadix::from_str_radix::(s, 3), None); + let radix: Option = FromStrRadix::from_str_radix(s, 3); + assert_eq!(radix, None); } let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1", "3/2"]; diff --git a/src/libextra/priority_queue.rs b/src/libextra/priority_queue.rs index 4f0fed5fccf47..09b351433a26d 100644 --- a/src/libextra/priority_queue.rs +++ b/src/libextra/priority_queue.rs @@ -339,29 +339,38 @@ mod tests { #[test] #[should_fail] #[ignore(cfg(windows))] - fn test_empty_pop() { let mut heap = PriorityQueue::new::(); heap.pop(); } + fn test_empty_pop() { + let mut heap: PriorityQueue = PriorityQueue::new(); + heap.pop(); + } #[test] fn test_empty_maybe_pop() { - let mut heap = PriorityQueue::new::(); + let mut heap: PriorityQueue = PriorityQueue::new(); assert!(heap.maybe_pop().is_none()); } #[test] #[should_fail] #[ignore(cfg(windows))] - fn test_empty_top() { let empty = PriorityQueue::new::(); empty.top(); } + fn test_empty_top() { + let empty: PriorityQueue = PriorityQueue::new(); + empty.top(); + } #[test] fn test_empty_maybe_top() { - let empty = PriorityQueue::new::(); + let empty: PriorityQueue = PriorityQueue::new(); assert!(empty.maybe_top().is_none()); } #[test] #[should_fail] #[ignore(cfg(windows))] - fn test_empty_replace() { let mut heap = PriorityQueue::new(); heap.replace(5); } + fn test_empty_replace() { + let mut heap: PriorityQueue = PriorityQueue::new(); + heap.replace(5); + } #[test] fn test_from_iter() { diff --git a/src/libextra/ringbuf.rs b/src/libextra/ringbuf.rs index a38cb580c5057..4f2755374af02 100644 --- a/src/libextra/ringbuf.rs +++ b/src/libextra/ringbuf.rs @@ -483,7 +483,7 @@ mod tests { #[bench] fn bench_new(b: &mut test::BenchHarness) { do b.iter { - let _ = RingBuf::new::(); + let _: RingBuf = RingBuf::new(); } } diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs index 118754ec02830..307de43a067f0 100644 --- a/src/libextra/treemap.rs +++ b/src/libextra/treemap.rs @@ -879,7 +879,8 @@ mod test_treemap { #[test] fn find_empty() { - let m = TreeMap::new::(); assert!(m.find(&5) == None); + let m: TreeMap = TreeMap::new(); + assert!(m.find(&5) == None); } #[test] @@ -1006,7 +1007,7 @@ mod test_treemap { #[test] fn test_rand_int() { - let mut map = TreeMap::new::(); + let mut map: TreeMap = TreeMap::new(); let mut ctrl = ~[]; check_equal(ctrl, &map); diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 347ea5d740520..92e9e17cde7d9 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -344,7 +344,7 @@ fn path_node(ids: ~[ast::ident]) -> ast::Path { ast::Path { span: dummy_sp(), global: false, - segments: ids.consume_iter().transform(|identifier| ast::PathSegment { + segments: ids.move_iter().map(|identifier| ast::PathSegment { identifier: identifier, lifetime: None, types: opt_vec::Empty, @@ -356,7 +356,7 @@ fn path_node_global(ids: ~[ast::ident]) -> ast::Path { ast::Path { span: dummy_sp(), global: true, - segments: ids.consume_iter().transform(|identifier| ast::PathSegment { + segments: ids.move_iter().map(|identifier| ast::PathSegment { identifier: identifier, lifetime: None, types: opt_vec::Empty, diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index ffb09e1cb8f74..34c100a95f2f3 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -335,15 +335,19 @@ fn item_to_def_like(item: ebml::Doc, did: ast::def_id, cnum: ast::CrateNum) let purity = if fam == UnsafeStaticMethod { ast::unsafe_fn } else { ast::impure_fn }; // def_static_method carries an optional field of its enclosing - // *trait*, but not an inclosing Impl (if this is an inherent - // static method). So we need to detect whether this is in - // a trait or not, which we do through the mildly hacky - // way of checking whether there is a trait_method_sort. - let trait_did_opt = if reader::maybe_get_doc( + // trait or enclosing impl (if this is an inherent static method). + // So we need to detect whether this is in a trait or not, which + // we do through the mildly hacky way of checking whether there is + // a trait_method_sort. + let provenance = if reader::maybe_get_doc( item, tag_item_trait_method_sort).is_some() { - Some(item_reqd_and_translated_parent_item(cnum, item)) - } else { None }; - dl_def(ast::def_static_method(did, trait_did_opt, purity)) + ast::FromTrait(item_reqd_and_translated_parent_item(cnum, + item)) + } else { + ast::FromImpl(item_reqd_and_translated_parent_item(cnum, + item)) + }; + dl_def(ast::def_static_method(did, provenance, purity)) } Type | ForeignType => dl_def(ast::def_ty(did)), Mod => dl_def(ast::def_mod(did)), diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 3606ecd8d24c1..f5bad88b1ca66 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -141,7 +141,7 @@ fn parse_path(st: &mut PState) -> @ast::Path { return @ast::Path { span: dummy_sp(), global: false, - segments: idents.consume_iter().transform(|identifier| { + segments: idents.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, lifetime: None, diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index d6342c582f052..7cf4d05f095bc 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -374,9 +374,16 @@ impl tr for ast::def { fn tr(&self, xcx: @ExtendedDecodeContext) -> ast::def { match *self { ast::def_fn(did, p) => ast::def_fn(did.tr(xcx), p), - ast::def_static_method(did, did2_opt, p) => { + ast::def_static_method(did, wrapped_did2, p) => { ast::def_static_method(did.tr(xcx), - did2_opt.map(|did2| did2.tr(xcx)), + match wrapped_did2 { + ast::FromTrait(did2) => { + ast::FromTrait(did2.tr(xcx)) + } + ast::FromImpl(did2) => { + ast::FromImpl(did2.tr(xcx)) + } + }, p) } ast::def_method(did0, did1) => { diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index 8c5da2f3d0f84..dbe5214e0eb50 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -392,10 +392,12 @@ impl GatherLoanCtxt { } ty::AutoBorrowObj(r, m) => { let cmt_deref = mcx.cat_deref_fn_or_obj(expr, cmt, 0); + let loan_mutability = + LoanMutability::from_ast_mutability(m); self.guarantee_valid(expr.id, expr.span, cmt_deref, - m, + loan_mutability, r) } ty::AutoUnsafe(_) => {} diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 813792e36ad0e..b9dad6b45c502 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// A pass that checks to make sure private fields and methods aren't used -// outside their scopes. - +//! A pass that checks to make sure private fields and methods aren't used +//! outside their scopes. use metadata::csearch; use middle::ty::{ty_struct, ty_enum}; @@ -37,8 +36,8 @@ use syntax::oldvisit; use syntax::parse::token; pub fn check_crate<'mm>(tcx: ty::ctxt, - method_map: &'mm method_map, - crate: &ast::Crate) { + method_map: &'mm method_map, + crate: &ast::Crate) { let privileged_items = @mut ~[]; // Adds an item to its scope. diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 3c6b619e8b8ce..6fcc2a2d460c7 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -829,7 +829,7 @@ fn determine_rp_in_ty(ty: &ast::Ty, ast::ty_path(ref path, _, _) => { // type parameters are---for now, anyway---always invariant do cx.with_ambient_variance(rv_invariant) { - for tp in path.segments.iter().flat_map_(|s| s.types.iter()) { + for tp in path.segments.iter().flat_map(|s| s.types.iter()) { (visitor.visit_ty)(tp, (cx, visitor)); } } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 880ad3389b721..150d56ad89250 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -58,6 +58,12 @@ pub type BindingMap = HashMap; // Trait method resolution pub type TraitMap = HashMap; +// A summary of the generics on a trait. +struct TraitGenerics { + has_lifetime: bool, + type_parameter_count: uint, +} + // This is the replacement export map. It maps a module to all of the exports // within. pub type ExportMap2 = @mut HashMap; @@ -1274,9 +1280,12 @@ impl Resolver { method.span); let def = match method.explicit_self.node { sty_static => { - // Static methods become `def_fn`s. - def_fn(local_def(method.id), - method.purity) + // Static methods become + // `def_static_method`s. + def_static_method(local_def(method.id), + FromImpl(local_def( + item.id)), + method.purity) } _ => { // Non-static methods become @@ -1326,7 +1335,7 @@ impl Resolver { sty_static => { // Static methods become `def_static_method`s. def_static_method(local_def(ty_m.id), - Some(local_def(item.id)), + FromTrait(local_def(item.id)), ty_m.purity) } _ => { @@ -2069,7 +2078,7 @@ impl Resolver { fn path_idents_to_str(@mut self, path: &Path) -> ~str { let identifiers: ~[ast::ident] = path.segments .iter() - .transform(|seg| seg.identifier) + .map(|seg| seg.identifier) .collect(); self.idents_to_str(identifiers) } @@ -4131,6 +4140,22 @@ impl Resolver { Some(&primitive_type) => { result_def = Some(def_prim_ty(primitive_type)); + + if path.segments + .iter() + .any(|s| s.lifetime.is_some()) { + self.session.span_err(path.span, + "lifetime parameters \ + are not allowed on \ + this type") + } else if path.segments + .iter() + .any(|s| s.types.len() > 0) { + self.session.span_err(path.span, + "type parameters are \ + not allowed on this \ + type") + } } None => { // Continue. @@ -4140,12 +4165,17 @@ impl Resolver { match result_def { None => { - match self.resolve_path(ty.id, path, TypeNS, true, visitor) { + match self.resolve_path(ty.id, + path, + TypeNS, + true, + visitor) { Some(def) => { debug!("(resolving type) resolved `%s` to \ type %?", - self.session.str_of( - path.segments.last().identifier), + self.session.str_of(path.segments + .last() + .identifier), def); result_def = Some(def); } @@ -4154,9 +4184,7 @@ impl Resolver { } } } - Some(_) => { - // Continue. - } + Some(_) => {} // Continue. } match result_def { @@ -4334,7 +4362,7 @@ impl Resolver { // Check the types in the path pattern. for ty in path.segments .iter() - .flat_map_(|seg| seg.types.iter()) { + .flat_map(|seg| seg.types.iter()) { self.resolve_type(ty, visitor); } } @@ -4369,7 +4397,7 @@ impl Resolver { // Check the types in the path pattern. for ty in path.segments .iter() - .flat_map_(|s| s.types.iter()) { + .flat_map(|s| s.types.iter()) { self.resolve_type(ty, visitor); } } @@ -4402,7 +4430,7 @@ impl Resolver { // Check the types in the path pattern. for ty in path.segments .iter() - .flat_map_(|s| s.types.iter()) { + .flat_map(|s| s.types.iter()) { self.resolve_type(ty, visitor); } } @@ -4499,7 +4527,7 @@ impl Resolver { visitor: ResolveVisitor) -> Option { // First, resolve the types. - for ty in path.segments.iter().flat_map_(|s| s.types.iter()) { + for ty in path.segments.iter().flat_map(|s| s.types.iter()) { self.resolve_type(ty, visitor); } @@ -4523,11 +4551,13 @@ impl Resolver { match (def, unqualified_def) { (Some(d), Some(ud)) if d == ud => { self.session.add_lint(unnecessary_qualification, - id, path.span, + id, + path.span, ~"unnecessary qualification"); } _ => () } + return def; } diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 4caaf38487351..09ed98140f7d6 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -114,10 +114,13 @@ pub fn trans(bcx: @mut Block, expr: @ast::expr) -> Callee { fn trans_def(bcx: @mut Block, def: ast::def, ref_expr: @ast::expr) -> Callee { match def { - ast::def_fn(did, _) | ast::def_static_method(did, None, _) => { + ast::def_fn(did, _) | + ast::def_static_method(did, ast::FromImpl(_), _) => { fn_callee(bcx, trans_fn_ref(bcx, did, ref_expr.id)) } - ast::def_static_method(impl_did, Some(trait_did), _) => { + ast::def_static_method(impl_did, + ast::FromTrait(trait_did), + _) => { fn_callee(bcx, meth::trans_static_method_callee(bcx, impl_did, trait_did, ref_expr.id)) diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 04fd477a31738..fca04cfa6fe63 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -821,12 +821,14 @@ fn trans_def_datum_unadjusted(bcx: @mut Block, let _icx = push_ctxt("trans_def_datum_unadjusted"); match def { - ast::def_fn(did, _) | ast::def_static_method(did, None, _) => { + ast::def_fn(did, _) | + ast::def_static_method(did, ast::FromImpl(_), _) => { let fn_data = callee::trans_fn_ref(bcx, did, ref_expr.id); return fn_data_to_datum(bcx, ref_expr, did, fn_data); } - ast::def_static_method(impl_did, Some(trait_did), _) => { - let fn_data = meth::trans_static_method_callee(bcx, impl_did, + ast::def_static_method(impl_did, ast::FromTrait(trait_did), _) => { + let fn_data = meth::trans_static_method_callee(bcx, + impl_did, trait_did, ref_expr.id); return fn_data_to_datum(bcx, ref_expr, impl_did, fn_data); diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 8b93155b94d70..735e9a8a37f4d 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -178,7 +178,7 @@ fn ast_path_substs( // Convert the type parameters supplied by the user. let supplied_type_parameter_count = - path.segments.iter().flat_map_(|s| s.types.iter()).len_(); + path.segments.iter().flat_map(|s| s.types.iter()).len(); if decl_generics.type_param_defs.len() != supplied_type_parameter_count { this.tcx().sess.span_fatal( path.span, @@ -188,8 +188,8 @@ fn ast_path_substs( } let tps = path.segments .iter() - .flat_map_(|s| s.types.iter()) - .transform(|a_t| ast_ty_to_ty(this, rscope, a_t)) + .flat_map(|s| s.types.iter()) + .map(|a_t| ast_ty_to_ty(this, rscope, a_t)) .collect(); substs { diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index b7114e602830f..628ceccd61e7e 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -128,7 +128,12 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path, Some((enm, var)) => { // Assign the pattern the type of the *enum*, not the variant. let enum_tpt = ty::lookup_item_type(tcx, enm); - instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id); + instantiate_path(pcx.fcx, + path, + enum_tpt, + v_def, + pat.span, + pat.id); // check that the type of the value being matched is a subtype // of the type of the pattern: @@ -185,7 +190,12 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path, } else { ctor_tpt }; - instantiate_path(pcx.fcx, path, struct_tpt, pat.span, pat.id); + instantiate_path(pcx.fcx, + path, + struct_tpt, + s_def, + pat.span, + pat.id); // Check that the type of the value being matched is a subtype of // the type of the pattern. diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index f0179388a67c6..84f238496c2ff 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -697,7 +697,7 @@ impl<'self> LookupContext<'self> { // Coerce ~/@/&Trait instances to &Trait. self.search_for_some_kind_of_autorefd_method( - AutoBorrowObj, autoderefs, [m_const, m_imm, m_mutbl], + AutoBorrowObj, autoderefs, [m_imm, m_mutbl], |trt_mut, reg| { ty::mk_trait(tcx, trt_did, trt_substs.clone(), RegionTraitStore(reg), trt_mut, b) diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 00dc6ab9c580c..1063a5386b11f 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -1135,8 +1135,160 @@ pub enum DerefArgs { DoDerefArgs } -pub fn break_here() { - debug!("break here!"); +// Given the provenance of a static method, returns the generics of the static +// method's container. +fn generics_of_static_method_container(type_context: ty::ctxt, + provenance: ast::MethodProvenance) + -> ty::Generics { + match provenance { + ast::FromTrait(trait_def_id) => { + ty::lookup_trait_def(type_context, trait_def_id).generics + } + ast::FromImpl(impl_def_id) => { + ty::lookup_item_type(type_context, impl_def_id).generics + } + } +} + +// Verifies that type parameters supplied in paths are in the right +// locations. +fn check_type_parameter_positions_in_path(function_context: @mut FnCtxt, + path: &ast::Path, + def: ast::def) { + // We only care about checking the case in which the path has two or + // more segments. + if path.segments.len() < 2 { + return + } + + // Verify that no lifetimes or type parameters are present anywhere + // except the final two elements of the path. + for i in range(0, path.segments.len() - 2) { + match path.segments[i].lifetime { + None => {} + Some(lifetime) => { + function_context.tcx() + .sess + .span_err(lifetime.span, + "lifetime parameters may not \ + appear here") + } + } + + for typ in path.segments[i].types.iter() { + function_context.tcx() + .sess + .span_err(typ.span, + "type parameters may not appear here") + } + } + + // If there are no parameters at all, there is nothing more to do; the + // rest of typechecking will (attempt to) infer everything. + if path.segments + .iter() + .all(|s| s.lifetime.is_none() && s.types.is_empty()) { + return + } + + match def { + // If this is a static method of a trait or implementation, then + // ensure that the segment of the path which names the trait or + // implementation (the penultimate segment) is annotated with the + // right number of type parameters. + ast::def_static_method(_, provenance, _) => { + let generics = + generics_of_static_method_container(function_context.ccx.tcx, + provenance); + let name = match provenance { + ast::FromTrait(_) => "trait", + ast::FromImpl(_) => "impl", + }; + + let trait_segment = &path.segments[path.segments.len() - 2]; + + // Make sure lifetime parameterization agrees with the trait or + // implementation type. + match (generics.region_param, trait_segment.lifetime) { + (Some(_), None) => { + function_context.tcx() + .sess + .span_err(path.span, + fmt!("this %s has a lifetime \ + parameter but no \ + lifetime was specified", + name)) + } + (None, Some(_)) => { + function_context.tcx() + .sess + .span_err(path.span, + fmt!("this %s has no lifetime \ + parameter but a lifetime \ + was specified", + name)) + } + (Some(_), Some(_)) | (None, None) => {} + } + + // Make sure the number of type parameters supplied on the trait + // or implementation segment equals the number of type parameters + // on the trait or implementation definition. + let trait_type_parameter_count = generics.type_param_defs.len(); + let supplied_type_parameter_count = trait_segment.types.len(); + if trait_type_parameter_count != supplied_type_parameter_count { + let trait_count_suffix = if trait_type_parameter_count == 1 { + "" + } else { + "s" + }; + let supplied_count_suffix = + if supplied_type_parameter_count == 1 { + "" + } else { + "s" + }; + function_context.tcx() + .sess + .span_err(path.span, + fmt!("the %s referenced by this \ + path has %u type \ + parameter%s, but %u type \ + parameter%s were supplied", + name, + trait_type_parameter_count, + trait_count_suffix, + supplied_type_parameter_count, + supplied_count_suffix)) + } + } + _ => { + // Verify that no lifetimes or type parameters are present on + // the penultimate segment of the path. + let segment = &path.segments[path.segments.len() - 2]; + match segment.lifetime { + None => {} + Some(lifetime) => { + function_context.tcx() + .sess + .span_err(lifetime.span, + "lifetime parameters may not + appear here") + } + } + for typ in segment.types.iter() { + function_context.tcx() + .sess + .span_err(typ.span, + "type parameters may not appear \ + here"); + function_context.tcx() + .sess + .span_note(typ.span, + fmt!("this is a %?", def)); + } + } + } } /// Invariant: @@ -2336,8 +2488,9 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, ast::expr_path(ref pth) => { let defn = lookup_def(fcx, pth.span, id); + check_type_parameter_positions_in_path(fcx, pth, defn); let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn); - instantiate_path(fcx, pth, tpt, expr.span, expr.id); + instantiate_path(fcx, pth, tpt, defn, expr.span, expr.id); } ast::expr_self => { let definition = lookup_def(fcx, expr.span, id); @@ -3161,11 +3314,12 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt, pub fn instantiate_path(fcx: @mut FnCtxt, pth: &ast::Path, tpt: ty_param_bounds_and_ty, + def: ast::def, span: span, node_id: ast::NodeId) { debug!(">>> instantiate_path"); - let ty_param_count = tpt.generics.type_param_defs.len(); + let mut ty_param_count = tpt.generics.type_param_defs.len(); let mut ty_substs_len = 0; for segment in pth.segments.iter() { ty_substs_len += segment.types.len() @@ -3199,6 +3353,21 @@ pub fn instantiate_path(fcx: @mut FnCtxt, } }; + // Special case: If there is a self parameter, omit it from the list of + // type parameters. + // + // Here we calculate the "user type parameter count", which is the number + // of type parameters actually manifest in the AST. This will differ from + // the internal type parameter count when there are self types involved. + let (user_type_parameter_count, self_parameter_index) = match def { + ast::def_static_method(_, provenance @ ast::FromTrait(_), _) => { + let generics = generics_of_static_method_container(fcx.ccx.tcx, + provenance); + (ty_param_count - 1, Some(generics.type_param_defs.len())) + } + _ => (ty_param_count, None), + }; + // determine values for type parameters, using the values given by // the user (if any) and otherwise using fresh type variables let tps = if ty_substs_len == 0 { @@ -3207,33 +3376,44 @@ pub fn instantiate_path(fcx: @mut FnCtxt, fcx.ccx.tcx.sess.span_err (span, "this item does not take type parameters"); fcx.infcx().next_ty_vars(ty_param_count) - } else if ty_substs_len > ty_param_count { + } else if ty_substs_len > user_type_parameter_count { fcx.ccx.tcx.sess.span_err (span, fmt!("too many type parameters provided: expected %u, found %u", - ty_param_count, ty_substs_len)); + user_type_parameter_count, ty_substs_len)); fcx.infcx().next_ty_vars(ty_param_count) - } else if ty_substs_len < ty_param_count { - let is_static_method = match fcx.ccx.tcx.def_map.find(&node_id) { - Some(&ast::def_static_method(*)) => true, - _ => false - }; + } else if ty_substs_len < user_type_parameter_count { fcx.ccx.tcx.sess.span_err (span, fmt!("not enough type parameters provided: expected %u, found %u", - ty_param_count, ty_substs_len)); - if is_static_method { - fcx.ccx.tcx.sess.span_note - (span, "Static methods have an extra implicit type parameter -- \ - did you omit the type parameter for the `Self` type?"); - } + user_type_parameter_count, ty_substs_len)); fcx.infcx().next_ty_vars(ty_param_count) } else { - pth.segments - .iter() - .flat_map_(|s| s.types.iter()) - .transform(|aty| fcx.to_ty(aty)) - .collect() + // Build up the list of type parameters, inserting the self parameter + // at the appropriate position. + let mut result = ~[]; + let mut pushed = false; + for (i, ast_type) in pth.segments + .iter() + .flat_map(|segment| segment.types.iter()) + .enumerate() { + match self_parameter_index { + Some(index) if index == i => { + result.push(fcx.infcx().next_ty_vars(1)[0]); + pushed = true; + } + _ => {} + } + result.push(fcx.to_ty(ast_type)) + } + + // If the self parameter goes at the end, insert it there. + if !pushed && self_parameter_index.is_some() { + result.push(fcx.infcx().next_ty_vars(1)[0]) + } + + assert_eq!(result.len(), ty_param_count) + result }; let substs = substs { diff --git a/src/libstd/at_vec.rs b/src/libstd/at_vec.rs index 31de7bf82f827..6c574aceee0ba 100644 --- a/src/libstd/at_vec.rs +++ b/src/libstd/at_vec.rs @@ -278,7 +278,7 @@ pub mod raw { use rt::local::Local; use rt::task::Task; - do Local::borrow:: |task| { + do Local::borrow |task: &mut Task| { task.heap.realloc(ptr as *libc::c_void, size) as *() } } diff --git a/src/libstd/cell.rs b/src/libstd/cell.rs index 372effad61d3c..918731073ba8c 100644 --- a/src/libstd/cell.rs +++ b/src/libstd/cell.rs @@ -95,7 +95,7 @@ fn test_basic() { #[should_fail] #[ignore(cfg(windows))] fn test_take_empty() { - let value_cell = Cell::new_empty::<~int>(); + let value_cell: Cell<~int> = Cell::new_empty(); value_cell.take(); } diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs index 70ec5d9319984..6d30bf87b7121 100644 --- a/src/libstd/fmt/mod.rs +++ b/src/libstd/fmt/mod.rs @@ -844,10 +844,17 @@ impl Poly for T { } } -// n.b. use 'const' to get an implementation for both '*mut' and '*' at the same -// time. -impl Pointer for *const T { - fn fmt(t: &*const T, f: &mut Formatter) { +impl Pointer for *T { + fn fmt(t: &*T, f: &mut Formatter) { + f.flags |= 1 << (parse::FlagAlternate as uint); + do ::uint::to_str_bytes(*t as uint, 16) |buf| { + f.pad_integral(buf, "0x", true); + } + } +} + +impl Pointer for *mut T { + fn fmt(t: &*mut T, f: &mut Formatter) { f.flags |= 1 << (parse::FlagAlternate as uint); do ::uint::to_str_bytes(*t as uint, 16) |buf| { f.pad_integral(buf, "0x", true); diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index 50e59cf438d0c..bcd658ece6653 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -869,21 +869,21 @@ mod test_map { #[test] fn test_find_or_insert() { - let mut m = HashMap::new::(); + let mut m: HashMap = HashMap::new(); assert_eq!(*m.find_or_insert(1, 2), 2); assert_eq!(*m.find_or_insert(1, 3), 2); } #[test] fn test_find_or_insert_with() { - let mut m = HashMap::new::(); + let mut m: HashMap = HashMap::new(); assert_eq!(*m.find_or_insert_with(1, |_| 2), 2); assert_eq!(*m.find_or_insert_with(1, |_| 3), 2); } #[test] fn test_insert_or_update_with() { - let mut m = HashMap::new::(); + let mut m: HashMap = HashMap::new(); assert_eq!(*m.insert_or_update_with(1, 2, |_,x| *x+=1), 2); assert_eq!(*m.insert_or_update_with(1, 2, |_,x| *x+=1), 3); } diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 34bbe9292a5cb..e8558e6b1f01d 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -637,7 +637,10 @@ pub trait AdditiveIterator { impl + Zero, T: Iterator> AdditiveIterator for T { #[inline] - fn sum(&mut self) -> A { self.fold(Zero::zero::(), |s, x| s + x) } + fn sum(&mut self) -> A { + let zero: A = Zero::zero(); + self.fold(zero, |s, x| s + x) + } } /// A trait for iterators over elements whose elements can be multiplied @@ -662,7 +665,10 @@ pub trait MultiplicativeIterator { impl + One, T: Iterator> MultiplicativeIterator for T { #[inline] - fn product(&mut self) -> A { self.fold(One::one::(), |p, x| p * x) } + fn product(&mut self) -> A { + let one: A = One::one(); + self.fold(one, |p, x| p * x) + } } /// A trait for iterators over elements which can be compared to one another. diff --git a/src/libstd/logging.rs b/src/libstd/logging.rs index 7de55f48317a5..215067ea72919 100644 --- a/src/libstd/logging.rs +++ b/src/libstd/logging.rs @@ -59,7 +59,8 @@ fn newsched_log_str(msg: ~str) { use rt::local::Local; unsafe { - match Local::try_unsafe_borrow::() { + let optional_task: Option<*mut Task> = Local::try_unsafe_borrow(); + match optional_task { Some(local) => { // Use the available logger (*local).logger.log(Left(msg)); diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index faf9b2e2390dc..9d7a5ca15d01c 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -182,7 +182,7 @@ impl ApproxEq for f32 { #[inline] fn approx_eq(&self, other: &f32) -> bool { - self.approx_eq_eps(other, &ApproxEq::approx_epsilon::()) + self.approx_eq_eps(other, &1.0e-6) } #[inline] @@ -561,11 +561,14 @@ impl Real for f32 { /// Converts to degrees, assuming the number is in radians #[inline] - fn to_degrees(&self) -> f32 { *self * (180.0 / Real::pi::()) } + fn to_degrees(&self) -> f32 { *self * (180.0f32 / Real::pi()) } /// Converts to radians, assuming the number is in degrees #[inline] - fn to_radians(&self) -> f32 { *self * (Real::pi::() / 180.0) } + fn to_radians(&self) -> f32 { + let value: f32 = Real::pi(); + *self * (value / 180.0f32) + } } impl Bounded for f32 { @@ -578,10 +581,10 @@ impl Bounded for f32 { impl Primitive for f32 { #[inline] - fn bits() -> uint { 32 } + fn bits(_: Option) -> uint { 32 } #[inline] - fn bytes() -> uint { Primitive::bits::() / 8 } + fn bytes(_: Option) -> uint { Primitive::bits(Some(0f32)) / 8 } } impl Float for f32 { @@ -638,25 +641,25 @@ impl Float for f32 { } #[inline] - fn mantissa_digits() -> uint { 24 } + fn mantissa_digits(_: Option) -> uint { 24 } #[inline] - fn digits() -> uint { 6 } + fn digits(_: Option) -> uint { 6 } #[inline] fn epsilon() -> f32 { 1.19209290e-07 } #[inline] - fn min_exp() -> int { -125 } + fn min_exp(_: Option) -> int { -125 } #[inline] - fn max_exp() -> int { 128 } + fn max_exp(_: Option) -> int { 128 } #[inline] - fn min_10_exp() -> int { -37 } + fn min_10_exp(_: Option) -> int { -37 } #[inline] - fn max_10_exp() -> int { 38 } + fn max_10_exp(_: Option) -> int { 38 } /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp` #[inline] @@ -956,9 +959,11 @@ mod tests { assert_eq!(1f32.clamp(&2f32, &4f32), 2f32); assert_eq!(8f32.clamp(&2f32, &4f32), 4f32); assert_eq!(3f32.clamp(&2f32, &4f32), 3f32); - assert!(3f32.clamp(&Float::NaN::(), &4f32).is_NaN()); - assert!(3f32.clamp(&2f32, &Float::NaN::()).is_NaN()); - assert!(Float::NaN::().clamp(&2f32, &4f32).is_NaN()); + + let nan: f32 = Float::NaN(); + assert!(3f32.clamp(&nan, &4f32).is_NaN()); + assert!(3f32.clamp(&2f32, &nan).is_NaN()); + assert!(nan.clamp(&2f32, &4f32).is_NaN()); } #[test] @@ -1035,9 +1040,13 @@ mod tests { fn test_asinh() { assert_eq!(0.0f32.asinh(), 0.0f32); assert_eq!((-0.0f32).asinh(), -0.0f32); - assert_eq!(Float::infinity::().asinh(), Float::infinity::()); - assert_eq!(Float::neg_infinity::().asinh(), Float::neg_infinity::()); - assert!(Float::NaN::().asinh().is_NaN()); + + let inf: f32 = Float::infinity(); + let neg_inf: f32 = Float::neg_infinity(); + let nan: f32 = Float::NaN(); + assert_eq!(inf.asinh(), inf); + assert_eq!(neg_inf.asinh(), neg_inf); + assert!(nan.asinh().is_NaN()); assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32); assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32); } @@ -1046,9 +1055,13 @@ mod tests { fn test_acosh() { assert_eq!(1.0f32.acosh(), 0.0f32); assert!(0.999f32.acosh().is_NaN()); - assert_eq!(Float::infinity::().acosh(), Float::infinity::()); - assert!(Float::neg_infinity::().acosh().is_NaN()); - assert!(Float::NaN::().acosh().is_NaN()); + + let inf: f32 = Float::infinity(); + let neg_inf: f32 = Float::neg_infinity(); + let nan: f32 = Float::NaN(); + assert_eq!(inf.acosh(), inf); + assert!(neg_inf.acosh().is_NaN()); + assert!(nan.acosh().is_NaN()); assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32); assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32); } @@ -1057,34 +1070,61 @@ mod tests { fn test_atanh() { assert_eq!(0.0f32.atanh(), 0.0f32); assert_eq!((-0.0f32).atanh(), -0.0f32); - assert_eq!(1.0f32.atanh(), Float::infinity::()); - assert_eq!((-1.0f32).atanh(), Float::neg_infinity::()); + + let inf32: f32 = Float::infinity(); + let neg_inf32: f32 = Float::neg_infinity(); + assert_eq!(1.0f32.atanh(), inf32); + assert_eq!((-1.0f32).atanh(), neg_inf32); + assert!(2f64.atanh().atanh().is_NaN()); assert!((-2f64).atanh().atanh().is_NaN()); - assert!(Float::infinity::().atanh().is_NaN()); - assert!(Float::neg_infinity::().atanh().is_NaN()); - assert!(Float::NaN::().atanh().is_NaN()); + + let inf64: f32 = Float::infinity(); + let neg_inf64: f32 = Float::neg_infinity(); + let nan32: f32 = Float::NaN(); + assert!(inf64.atanh().is_NaN()); + assert!(neg_inf64.atanh().is_NaN()); + assert!(nan32.atanh().is_NaN()); + assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32); assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32); } #[test] fn test_real_consts() { - assert_approx_eq!(Real::two_pi::(), 2f32 * Real::pi::()); - assert_approx_eq!(Real::frac_pi_2::(), Real::pi::() / 2f32); - assert_approx_eq!(Real::frac_pi_3::(), Real::pi::() / 3f32); - assert_approx_eq!(Real::frac_pi_4::(), Real::pi::() / 4f32); - assert_approx_eq!(Real::frac_pi_6::(), Real::pi::() / 6f32); - assert_approx_eq!(Real::frac_pi_8::(), Real::pi::() / 8f32); - assert_approx_eq!(Real::frac_1_pi::(), 1f32 / Real::pi::()); - assert_approx_eq!(Real::frac_2_pi::(), 2f32 / Real::pi::()); - assert_approx_eq!(Real::frac_2_sqrtpi::(), 2f32 / Real::pi::().sqrt()); - assert_approx_eq!(Real::sqrt2::(), 2f32.sqrt()); - assert_approx_eq!(Real::frac_1_sqrt2::(), 1f32 / 2f32.sqrt()); - assert_approx_eq!(Real::log2_e::(), Real::e::().log2()); - assert_approx_eq!(Real::log10_e::(), Real::e::().log10()); - assert_approx_eq!(Real::ln_2::(), 2f32.ln()); - assert_approx_eq!(Real::ln_10::(), 10f32.ln()); + let pi: f32 = Real::pi(); + let two_pi: f32 = Real::two_pi(); + let frac_pi_2: f32 = Real::frac_pi_2(); + let frac_pi_3: f32 = Real::frac_pi_3(); + let frac_pi_4: f32 = Real::frac_pi_4(); + let frac_pi_6: f32 = Real::frac_pi_6(); + let frac_pi_8: f32 = Real::frac_pi_8(); + let frac_1_pi: f32 = Real::frac_1_pi(); + let frac_2_pi: f32 = Real::frac_2_pi(); + let frac_2_sqrtpi: f32 = Real::frac_2_sqrtpi(); + let sqrt2: f32 = Real::sqrt2(); + let frac_1_sqrt2: f32 = Real::frac_1_sqrt2(); + let e: f32 = Real::e(); + let log2_e: f32 = Real::log2_e(); + let log10_e: f32 = Real::log10_e(); + let ln_2: f32 = Real::ln_2(); + let ln_10: f32 = Real::ln_10(); + + assert_approx_eq!(two_pi, 2f32 * pi); + assert_approx_eq!(frac_pi_2, pi / 2f32); + assert_approx_eq!(frac_pi_3, pi / 3f32); + assert_approx_eq!(frac_pi_4, pi / 4f32); + assert_approx_eq!(frac_pi_6, pi / 6f32); + assert_approx_eq!(frac_pi_8, pi / 8f32); + assert_approx_eq!(frac_1_pi, 1f32 / pi); + assert_approx_eq!(frac_2_pi, 2f32 / pi); + assert_approx_eq!(frac_2_sqrtpi, 2f32 / pi.sqrt()); + assert_approx_eq!(sqrt2, 2f32.sqrt()); + assert_approx_eq!(frac_1_sqrt2, 1f32 / 2f32.sqrt()); + assert_approx_eq!(log2_e, e.log2()); + assert_approx_eq!(log10_e, e.log10()); + assert_approx_eq!(ln_2, 2f32.ln()); + assert_approx_eq!(ln_10, 10f32.ln()); } #[test] @@ -1160,17 +1200,23 @@ mod tests { #[test] fn test_primitive() { - assert_eq!(Primitive::bits::(), sys::size_of::() * 8); - assert_eq!(Primitive::bytes::(), sys::size_of::()); + let none: Option = None; + assert_eq!(Primitive::bits(none), sys::size_of::() * 8); + assert_eq!(Primitive::bytes(none), sys::size_of::()); } #[test] fn test_is_normal() { - assert!(!Float::NaN::().is_normal()); - assert!(!Float::infinity::().is_normal()); - assert!(!Float::neg_infinity::().is_normal()); - assert!(!Zero::zero::().is_normal()); - assert!(!Float::neg_zero::().is_normal()); + let nan: f32 = Float::NaN(); + let inf: f32 = Float::infinity(); + let neg_inf: f32 = Float::neg_infinity(); + let zero: f32 = Zero::zero(); + let neg_zero: f32 = Float::neg_zero(); + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); assert!(1f32.is_normal()); assert!(1e-37f32.is_normal()); assert!(!1e-38f32.is_normal()); @@ -1178,11 +1224,16 @@ mod tests { #[test] fn test_classify() { - assert_eq!(Float::NaN::().classify(), FPNaN); - assert_eq!(Float::infinity::().classify(), FPInfinite); - assert_eq!(Float::neg_infinity::().classify(), FPInfinite); - assert_eq!(Zero::zero::().classify(), FPZero); - assert_eq!(Float::neg_zero::().classify(), FPZero); + let nan: f32 = Float::NaN(); + let inf: f32 = Float::infinity(); + let neg_inf: f32 = Float::neg_infinity(); + let zero: f32 = Zero::zero(); + let neg_zero: f32 = Float::neg_zero(); + assert_eq!(nan.classify(), FPNaN); + assert_eq!(inf.classify(), FPInfinite); + assert_eq!(neg_inf.classify(), FPInfinite); + assert_eq!(zero.classify(), FPZero); + assert_eq!(neg_zero.classify(), FPZero); assert_eq!(1f32.classify(), FPNormal); assert_eq!(1e-37f32.classify(), FPNormal); assert_eq!(1e-38f32.classify(), FPSubnormal); @@ -1199,11 +1250,13 @@ mod tests { assert_eq!(Float::ldexp(0f32, -123), 0f32); assert_eq!(Float::ldexp(-0f32, -123), -0f32); - assert_eq!(Float::ldexp(Float::infinity::(), -123), - Float::infinity::()); - assert_eq!(Float::ldexp(Float::neg_infinity::(), -123), - Float::neg_infinity::()); - assert!(Float::ldexp(Float::NaN::(), -123).is_NaN()); + + let inf: f32 = Float::infinity(); + let neg_inf: f32 = Float::neg_infinity(); + let nan: f32 = Float::NaN(); + assert_eq!(Float::ldexp(inf, -123), inf); + assert_eq!(Float::ldexp(neg_inf, -123), neg_inf); + assert!(Float::ldexp(nan, -123).is_NaN()); } #[test] @@ -1221,10 +1274,12 @@ mod tests { assert_eq!(0f32.frexp(), (0f32, 0)); assert_eq!((-0f32).frexp(), (-0f32, 0)); - assert_eq!(match Float::infinity::().frexp() { (x, _) => x }, - Float::infinity::()) - assert_eq!(match Float::neg_infinity::().frexp() { (x, _) => x }, - Float::neg_infinity::()) - assert!(match Float::NaN::().frexp() { (x, _) => x.is_NaN() }) + + let inf: f32 = Float::infinity(); + let neg_inf: f32 = Float::neg_infinity(); + let nan: f32 = Float::NaN(); + assert_eq!(match inf.frexp() { (x, _) => x }, inf) + assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf) + assert!(match nan.frexp() { (x, _) => x.is_NaN() }) } } diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 60527905779f0..34c8de780459c 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -205,7 +205,7 @@ impl ApproxEq for f64 { #[inline] fn approx_eq(&self, other: &f64) -> bool { - self.approx_eq_eps(other, &ApproxEq::approx_epsilon::()) + self.approx_eq_eps(other, &1.0e-6) } #[inline] @@ -578,11 +578,14 @@ impl Real for f64 { /// Converts to degrees, assuming the number is in radians #[inline] - fn to_degrees(&self) -> f64 { *self * (180.0 / Real::pi::()) } + fn to_degrees(&self) -> f64 { *self * (180.0f64 / Real::pi()) } /// Converts to radians, assuming the number is in degrees #[inline] - fn to_radians(&self) -> f64 { *self * (Real::pi::() / 180.0) } + fn to_radians(&self) -> f64 { + let value: f64 = Real::pi(); + *self * (value / 180.0) + } } impl RealExt for f64 { @@ -625,10 +628,10 @@ impl Bounded for f64 { impl Primitive for f64 { #[inline] - fn bits() -> uint { 64 } + fn bits(_: Option) -> uint { 64 } #[inline] - fn bytes() -> uint { Primitive::bits::() / 8 } + fn bytes(_: Option) -> uint { Primitive::bits(Some(0f64)) / 8 } } impl Float for f64 { @@ -685,25 +688,25 @@ impl Float for f64 { } #[inline] - fn mantissa_digits() -> uint { 53 } + fn mantissa_digits(_: Option) -> uint { 53 } #[inline] - fn digits() -> uint { 15 } + fn digits(_: Option) -> uint { 15 } #[inline] fn epsilon() -> f64 { 2.2204460492503131e-16 } #[inline] - fn min_exp() -> int { -1021 } + fn min_exp(_: Option) -> int { -1021 } #[inline] - fn max_exp() -> int { 1024 } + fn max_exp(_: Option) -> int { 1024 } #[inline] - fn min_10_exp() -> int { -307 } + fn min_10_exp(_: Option) -> int { -307 } #[inline] - fn max_10_exp() -> int { 308 } + fn max_10_exp(_: Option) -> int { 308 } /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp` #[inline] @@ -990,16 +993,20 @@ mod tests { fn test_min() { assert_eq!(1f64.min(&2f64), 1f64); assert_eq!(2f64.min(&1f64), 1f64); - assert!(1f64.min(&Float::NaN::()).is_NaN()); - assert!(Float::NaN::().min(&1f64).is_NaN()); + + let nan: f64 = Float::NaN(); + assert!(1f64.min(&nan).is_NaN()); + assert!(nan.min(&1f64).is_NaN()); } #[test] fn test_max() { assert_eq!(1f64.max(&2f64), 2f64); assert_eq!(2f64.max(&1f64), 2f64); - assert!(1f64.max(&Float::NaN::()).is_NaN()); - assert!(Float::NaN::().max(&1f64).is_NaN()); + + let nan: f64 = Float::NaN(); + assert!(1f64.max(&nan).is_NaN()); + assert!(nan.max(&1f64).is_NaN()); } #[test] @@ -1007,9 +1014,11 @@ mod tests { assert_eq!(1f64.clamp(&2f64, &4f64), 2f64); assert_eq!(8f64.clamp(&2f64, &4f64), 4f64); assert_eq!(3f64.clamp(&2f64, &4f64), 3f64); - assert!(3f64.clamp(&Float::NaN::(), &4f64).is_NaN()); - assert!(3f64.clamp(&2f64, &Float::NaN::()).is_NaN()); - assert!(Float::NaN::().clamp(&2f64, &4f64).is_NaN()); + + let nan: f64 = Float::NaN(); + assert!(3f64.clamp(&nan, &4f64).is_NaN()); + assert!(3f64.clamp(&2f64, &nan).is_NaN()); + assert!(nan.clamp(&2f64, &4f64).is_NaN()); } #[test] @@ -1086,9 +1095,13 @@ mod tests { fn test_asinh() { assert_eq!(0.0f64.asinh(), 0.0f64); assert_eq!((-0.0f64).asinh(), -0.0f64); - assert_eq!(Float::infinity::().asinh(), Float::infinity::()); - assert_eq!(Float::neg_infinity::().asinh(), Float::neg_infinity::()); - assert!(Float::NaN::().asinh().is_NaN()); + + let inf: f64 = Float::infinity(); + let neg_inf: f64 = Float::neg_infinity(); + let nan: f64 = Float::NaN(); + assert_eq!(inf.asinh(), inf); + assert_eq!(neg_inf.asinh(), neg_inf); + assert!(nan.asinh().is_NaN()); assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64); assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64); } @@ -1097,9 +1110,13 @@ mod tests { fn test_acosh() { assert_eq!(1.0f64.acosh(), 0.0f64); assert!(0.999f64.acosh().is_NaN()); - assert_eq!(Float::infinity::().acosh(), Float::infinity::()); - assert!(Float::neg_infinity::().acosh().is_NaN()); - assert!(Float::NaN::().acosh().is_NaN()); + + let inf: f64 = Float::infinity(); + let neg_inf: f64 = Float::neg_infinity(); + let nan: f64 = Float::NaN(); + assert_eq!(inf.acosh(), inf); + assert!(neg_inf.acosh().is_NaN()); + assert!(nan.acosh().is_NaN()); assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64); assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64); } @@ -1108,34 +1125,56 @@ mod tests { fn test_atanh() { assert_eq!(0.0f64.atanh(), 0.0f64); assert_eq!((-0.0f64).atanh(), -0.0f64); - assert_eq!(1.0f64.atanh(), Float::infinity::()); - assert_eq!((-1.0f64).atanh(), Float::neg_infinity::()); + + let inf: f64 = Float::infinity(); + let neg_inf: f64 = Float::neg_infinity(); + let nan: f64 = Float::NaN(); + assert_eq!(1.0f64.atanh(), inf); + assert_eq!((-1.0f64).atanh(), neg_inf); assert!(2f64.atanh().atanh().is_NaN()); assert!((-2f64).atanh().atanh().is_NaN()); - assert!(Float::infinity::().atanh().is_NaN()); - assert!(Float::neg_infinity::().atanh().is_NaN()); - assert!(Float::NaN::().atanh().is_NaN()); + assert!(inf.atanh().is_NaN()); + assert!(neg_inf.atanh().is_NaN()); + assert!(nan.atanh().is_NaN()); assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64); assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64); } #[test] fn test_real_consts() { - assert_approx_eq!(Real::two_pi::(), 2.0 * Real::pi::()); - assert_approx_eq!(Real::frac_pi_2::(), Real::pi::() / 2f64); - assert_approx_eq!(Real::frac_pi_3::(), Real::pi::() / 3f64); - assert_approx_eq!(Real::frac_pi_4::(), Real::pi::() / 4f64); - assert_approx_eq!(Real::frac_pi_6::(), Real::pi::() / 6f64); - assert_approx_eq!(Real::frac_pi_8::(), Real::pi::() / 8f64); - assert_approx_eq!(Real::frac_1_pi::(), 1f64 / Real::pi::()); - assert_approx_eq!(Real::frac_2_pi::(), 2f64 / Real::pi::()); - assert_approx_eq!(Real::frac_2_sqrtpi::(), 2f64 / Real::pi::().sqrt()); - assert_approx_eq!(Real::sqrt2::(), 2f64.sqrt()); - assert_approx_eq!(Real::frac_1_sqrt2::(), 1f64 / 2f64.sqrt()); - assert_approx_eq!(Real::log2_e::(), Real::e::().log2()); - assert_approx_eq!(Real::log10_e::(), Real::e::().log10()); - assert_approx_eq!(Real::ln_2::(), 2f64.ln()); - assert_approx_eq!(Real::ln_10::(), 10f64.ln()); + let pi: f64 = Real::pi(); + let two_pi: f64 = Real::two_pi(); + let frac_pi_2: f64 = Real::frac_pi_2(); + let frac_pi_3: f64 = Real::frac_pi_3(); + let frac_pi_4: f64 = Real::frac_pi_4(); + let frac_pi_6: f64 = Real::frac_pi_6(); + let frac_pi_8: f64 = Real::frac_pi_8(); + let frac_1_pi: f64 = Real::frac_1_pi(); + let frac_2_pi: f64 = Real::frac_2_pi(); + let frac_2_sqrtpi: f64 = Real::frac_2_sqrtpi(); + let sqrt2: f64 = Real::sqrt2(); + let frac_1_sqrt2: f64 = Real::frac_1_sqrt2(); + let e: f64 = Real::e(); + let log2_e: f64 = Real::log2_e(); + let log10_e: f64 = Real::log10_e(); + let ln_2: f64 = Real::ln_2(); + let ln_10: f64 = Real::ln_10(); + + assert_approx_eq!(two_pi, 2.0 * pi); + assert_approx_eq!(frac_pi_2, pi / 2f64); + assert_approx_eq!(frac_pi_3, pi / 3f64); + assert_approx_eq!(frac_pi_4, pi / 4f64); + assert_approx_eq!(frac_pi_6, pi / 6f64); + assert_approx_eq!(frac_pi_8, pi / 8f64); + assert_approx_eq!(frac_1_pi, 1f64 / pi); + assert_approx_eq!(frac_2_pi, 2f64 / pi); + assert_approx_eq!(frac_2_sqrtpi, 2f64 / pi.sqrt()); + assert_approx_eq!(sqrt2, 2f64.sqrt()); + assert_approx_eq!(frac_1_sqrt2, 1f64 / 2f64.sqrt()); + assert_approx_eq!(log2_e, e.log2()); + assert_approx_eq!(log10_e, e.log10()); + assert_approx_eq!(ln_2, 2f64.ln()); + assert_approx_eq!(ln_10, 10f64.ln()); } #[test] @@ -1211,17 +1250,23 @@ mod tests { #[test] fn test_primitive() { - assert_eq!(Primitive::bits::(), sys::size_of::() * 8); - assert_eq!(Primitive::bytes::(), sys::size_of::()); + let none: Option = None; + assert_eq!(Primitive::bits(none), sys::size_of::() * 8); + assert_eq!(Primitive::bytes(none), sys::size_of::()); } #[test] fn test_is_normal() { - assert!(!Float::NaN::().is_normal()); - assert!(!Float::infinity::().is_normal()); - assert!(!Float::neg_infinity::().is_normal()); - assert!(!Zero::zero::().is_normal()); - assert!(!Float::neg_zero::().is_normal()); + let nan: f64 = Float::NaN(); + let inf: f64 = Float::infinity(); + let neg_inf: f64 = Float::neg_infinity(); + let zero: f64 = Zero::zero(); + let neg_zero: f64 = Float::neg_zero(); + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); assert!(1f64.is_normal()); assert!(1e-307f64.is_normal()); assert!(!1e-308f64.is_normal()); @@ -1229,11 +1274,16 @@ mod tests { #[test] fn test_classify() { - assert_eq!(Float::NaN::().classify(), FPNaN); - assert_eq!(Float::infinity::().classify(), FPInfinite); - assert_eq!(Float::neg_infinity::().classify(), FPInfinite); - assert_eq!(Zero::zero::().classify(), FPZero); - assert_eq!(Float::neg_zero::().classify(), FPZero); + let nan: f64 = Float::NaN(); + let inf: f64 = Float::infinity(); + let neg_inf: f64 = Float::neg_infinity(); + let zero: f64 = Zero::zero(); + let neg_zero: f64 = Float::neg_zero(); + assert_eq!(nan.classify(), FPNaN); + assert_eq!(inf.classify(), FPInfinite); + assert_eq!(neg_inf.classify(), FPInfinite); + assert_eq!(zero.classify(), FPZero); + assert_eq!(neg_zero.classify(), FPZero); assert_eq!(1e-307f64.classify(), FPNormal); assert_eq!(1e-308f64.classify(), FPSubnormal); } @@ -1249,11 +1299,13 @@ mod tests { assert_eq!(Float::ldexp(0f64, -123), 0f64); assert_eq!(Float::ldexp(-0f64, -123), -0f64); - assert_eq!(Float::ldexp(Float::infinity::(), -123), - Float::infinity::()); - assert_eq!(Float::ldexp(Float::neg_infinity::(), -123), - Float::neg_infinity::()); - assert!(Float::ldexp(Float::NaN::(), -123).is_NaN()); + + let inf: f64 = Float::infinity(); + let neg_inf: f64 = Float::neg_infinity(); + let nan: f64 = Float::NaN(); + assert_eq!(Float::ldexp(inf, -123), inf); + assert_eq!(Float::ldexp(neg_inf, -123), neg_inf); + assert!(Float::ldexp(nan, -123).is_NaN()); } #[test] @@ -1271,10 +1323,12 @@ mod tests { assert_eq!(0f64.frexp(), (0f64, 0)); assert_eq!((-0f64).frexp(), (-0f64, 0)); - assert_eq!(match Float::infinity::().frexp() { (x, _) => x }, - Float::infinity::()) - assert_eq!(match Float::neg_infinity::().frexp() { (x, _) => x }, - Float::neg_infinity::()) - assert!(match Float::NaN::().frexp() { (x, _) => x.is_NaN() }) + + let inf: f64 = Float::infinity(); + let neg_inf: f64 = Float::neg_infinity(); + let nan: f64 = Float::NaN(); + assert_eq!(match inf.frexp() { (x, _) => x }, inf) + assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf) + assert!(match nan.frexp() { (x, _) => x.is_NaN() }) } } diff --git a/src/libstd/num/float.rs b/src/libstd/num/float.rs index 486d35620899a..360a37ccbd1a9 100644 --- a/src/libstd/num/float.rs +++ b/src/libstd/num/float.rs @@ -349,7 +349,7 @@ impl ApproxEq for float { #[inline] fn approx_eq(&self, other: &float) -> bool { - self.approx_eq_eps(other, &ApproxEq::approx_epsilon::()) + self.approx_eq_eps(other, &1.0e-6) } #[inline] @@ -790,32 +790,56 @@ impl Signed for float { impl Bounded for float { #[inline] - fn min_value() -> float { Bounded::min_value::() as float } + fn min_value() -> float { + let x: f64 = Bounded::min_value(); + x as float + } #[inline] - fn max_value() -> float { Bounded::max_value::() as float } + fn max_value() -> float { + let x: f64 = Bounded::max_value(); + x as float + } } impl Primitive for float { #[inline] - fn bits() -> uint { Primitive::bits::() } + fn bits(_: Option) -> uint { + let bits: uint = Primitive::bits(Some(0f64)); + bits + } #[inline] - fn bytes() -> uint { Primitive::bytes::() } + fn bytes(_: Option) -> uint { + let bytes: uint = Primitive::bytes(Some(0f64)); + bytes + } } impl Float for float { #[inline] - fn NaN() -> float { Float::NaN::() as float } + fn NaN() -> float { + let value: f64 = Float::NaN(); + value as float + } #[inline] - fn infinity() -> float { Float::infinity::() as float } + fn infinity() -> float { + let value: f64 = Float::infinity(); + value as float + } #[inline] - fn neg_infinity() -> float { Float::neg_infinity::() as float } + fn neg_infinity() -> float { + let value: f64 = Float::neg_infinity(); + value as float + } #[inline] - fn neg_zero() -> float { Float::neg_zero::() as float } + fn neg_zero() -> float { + let value: f64 = Float::neg_zero(); + value as float + } /// Returns `true` if the number is NaN #[inline] @@ -839,30 +863,46 @@ impl Float for float { fn classify(&self) -> FPCategory { (*self as f64).classify() } #[inline] - fn mantissa_digits() -> uint { Float::mantissa_digits::() } + fn mantissa_digits(_: Option) -> uint { + Float::mantissa_digits(Some(0f64)) + } #[inline] - fn digits() -> uint { Float::digits::() } + fn digits(_: Option) -> uint { + Float::digits(Some(0f64)) + } #[inline] - fn epsilon() -> float { Float::epsilon::() as float } + fn epsilon() -> float { + let value: f64 = Float::epsilon(); + value as float + } #[inline] - fn min_exp() -> int { Float::min_exp::() } + fn min_exp(_: Option) -> int { + Float::min_exp(Some(0f64)) + } #[inline] - fn max_exp() -> int { Float::max_exp::() } + fn max_exp(_: Option) -> int { + Float::max_exp(Some(0f64)) + } #[inline] - fn min_10_exp() -> int { Float::min_10_exp::() } + fn min_10_exp(_: Option) -> int { + Float::min_10_exp(Some(0f64)) + } #[inline] - fn max_10_exp() -> int { Float::max_10_exp::() } + fn max_10_exp(_: Option) -> int { + Float::max_10_exp(Some(0f64)) + } /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp` #[inline] fn ldexp(x: float, exp: int) -> float { - Float::ldexp(x as f64, exp) as float + let value: f64 = Float::ldexp(x as f64, exp); + value as float } /// @@ -944,9 +984,10 @@ mod tests { assert_eq!(1f.clamp(&2f, &4f), 2f); assert_eq!(8f.clamp(&2f, &4f), 4f); assert_eq!(3f.clamp(&2f, &4f), 3f); - assert!(3f.clamp(&Float::NaN::(), &4f).is_NaN()); - assert!(3f.clamp(&2f, &Float::NaN::()).is_NaN()); - assert!(Float::NaN::().clamp(&2f, &4f).is_NaN()); + let nan: float = Float::NaN(); + assert!(3f.clamp(&nan, &4f).is_NaN()); + assert!(3f.clamp(&2f, &nan).is_NaN()); + assert!(nan.clamp(&2f, &4f).is_NaN()); } #[test] @@ -1023,9 +1064,13 @@ mod tests { fn test_asinh() { assert_eq!(0.0f.asinh(), 0.0f); assert_eq!((-0.0f).asinh(), -0.0f); - assert_eq!(Float::infinity::().asinh(), Float::infinity::()); - assert_eq!(Float::neg_infinity::().asinh(), Float::neg_infinity::()); - assert!(Float::NaN::().asinh().is_NaN()); + + let inf: float = Float::infinity(); + let neg_inf: float = Float::neg_infinity(); + let nan: float = Float::NaN(); + assert_eq!(inf.asinh(), inf); + assert_eq!(neg_inf.asinh(), neg_inf); + assert!(nan.asinh().is_NaN()); assert_approx_eq!(2.0f.asinh(), 1.443635475178810342493276740273105f); assert_approx_eq!((-2.0f).asinh(), -1.443635475178810342493276740273105f); } @@ -1034,9 +1079,13 @@ mod tests { fn test_acosh() { assert_eq!(1.0f.acosh(), 0.0f); assert!(0.999f.acosh().is_NaN()); - assert_eq!(Float::infinity::().acosh(), Float::infinity::()); - assert!(Float::neg_infinity::().acosh().is_NaN()); - assert!(Float::NaN::().acosh().is_NaN()); + + let inf: float = Float::infinity(); + let neg_inf: float = Float::neg_infinity(); + let nan: float = Float::NaN(); + assert_eq!(inf.acosh(), inf); + assert!(neg_inf.acosh().is_NaN()); + assert!(nan.acosh().is_NaN()); assert_approx_eq!(2.0f.acosh(), 1.31695789692481670862504634730796844f); assert_approx_eq!(3.0f.acosh(), 1.76274717403908605046521864995958461f); } @@ -1045,34 +1094,58 @@ mod tests { fn test_atanh() { assert_eq!(0.0f.atanh(), 0.0f); assert_eq!((-0.0f).atanh(), -0.0f); - assert_eq!(1.0f.atanh(), Float::infinity::()); - assert_eq!((-1.0f).atanh(), Float::neg_infinity::()); + + let inf: float = Float::infinity(); + let neg_inf: float = Float::neg_infinity(); + let inf64: f64 = Float::infinity(); + let neg_inf64: f64 = Float::neg_infinity(); + let nan: float = Float::NaN(); + assert_eq!(1.0f.atanh(), inf); + assert_eq!((-1.0f).atanh(), neg_inf); assert!(2f64.atanh().atanh().is_NaN()); assert!((-2f64).atanh().atanh().is_NaN()); - assert!(Float::infinity::().atanh().is_NaN()); - assert!(Float::neg_infinity::().atanh().is_NaN()); - assert!(Float::NaN::().atanh().is_NaN()); + assert!(inf64.atanh().is_NaN()); + assert!(neg_inf64.atanh().is_NaN()); + assert!(nan.atanh().is_NaN()); assert_approx_eq!(0.5f.atanh(), 0.54930614433405484569762261846126285f); assert_approx_eq!((-0.5f).atanh(), -0.54930614433405484569762261846126285f); } #[test] fn test_real_consts() { - assert_approx_eq!(Real::two_pi::(), 2f * Real::pi::()); - assert_approx_eq!(Real::frac_pi_2::(), Real::pi::() / 2f); - assert_approx_eq!(Real::frac_pi_3::(), Real::pi::() / 3f); - assert_approx_eq!(Real::frac_pi_4::(), Real::pi::() / 4f); - assert_approx_eq!(Real::frac_pi_6::(), Real::pi::() / 6f); - assert_approx_eq!(Real::frac_pi_8::(), Real::pi::() / 8f); - assert_approx_eq!(Real::frac_1_pi::(), 1f / Real::pi::()); - assert_approx_eq!(Real::frac_2_pi::(), 2f / Real::pi::()); - assert_approx_eq!(Real::frac_2_sqrtpi::(), 2f / Real::pi::().sqrt()); - assert_approx_eq!(Real::sqrt2::(), 2f.sqrt()); - assert_approx_eq!(Real::frac_1_sqrt2::(), 1f / 2f.sqrt()); - assert_approx_eq!(Real::log2_e::(), Real::e::().log2()); - assert_approx_eq!(Real::log10_e::(), Real::e::().log10()); - assert_approx_eq!(Real::ln_2::(), 2f.ln()); - assert_approx_eq!(Real::ln_10::(), 10f.ln()); + let pi: float = Real::pi(); + let two_pi: float = Real::two_pi(); + let frac_pi_2: float = Real::frac_pi_2(); + let frac_pi_3: float = Real::frac_pi_3(); + let frac_pi_4: float = Real::frac_pi_4(); + let frac_pi_6: float = Real::frac_pi_6(); + let frac_pi_8: float = Real::frac_pi_8(); + let frac_1_pi: float = Real::frac_1_pi(); + let frac_2_pi: float = Real::frac_2_pi(); + let frac_2_sqrtpi: float = Real::frac_2_sqrtpi(); + let sqrt2: float = Real::sqrt2(); + let frac_1_sqrt2: float = Real::frac_1_sqrt2(); + let e: float = Real::e(); + let log2_e: float = Real::log2_e(); + let log10_e: float = Real::log10_e(); + let ln_2: float = Real::ln_2(); + let ln_10: float = Real::ln_10(); + + assert_approx_eq!(two_pi, 2f * pi); + assert_approx_eq!(frac_pi_2, pi / 2f); + assert_approx_eq!(frac_pi_3, pi / 3f); + assert_approx_eq!(frac_pi_4, pi / 4f); + assert_approx_eq!(frac_pi_6, pi / 6f); + assert_approx_eq!(frac_pi_8, pi / 8f); + assert_approx_eq!(frac_1_pi, 1f / pi); + assert_approx_eq!(frac_2_pi, 2f / pi); + assert_approx_eq!(frac_2_sqrtpi, 2f / pi.sqrt()); + assert_approx_eq!(sqrt2, 2f.sqrt()); + assert_approx_eq!(frac_1_sqrt2, 1f / 2f.sqrt()); + assert_approx_eq!(log2_e, e.log2()); + assert_approx_eq!(log10_e, e.log10()); + assert_approx_eq!(ln_2, 2f.ln()); + assert_approx_eq!(ln_10, 10f.ln()); } #[test] @@ -1148,17 +1221,23 @@ mod tests { #[test] fn test_primitive() { - assert_eq!(Primitive::bits::(), sys::size_of::() * 8); - assert_eq!(Primitive::bytes::(), sys::size_of::()); + let none: Option = None; + assert_eq!(Primitive::bits(none), sys::size_of::() * 8); + assert_eq!(Primitive::bytes(none), sys::size_of::()); } #[test] fn test_is_normal() { - assert!(!Float::NaN::().is_normal()); - assert!(!Float::infinity::().is_normal()); - assert!(!Float::neg_infinity::().is_normal()); - assert!(!Zero::zero::().is_normal()); - assert!(!Float::neg_zero::().is_normal()); + let nan: float = Float::NaN(); + let inf: float = Float::infinity(); + let neg_inf: float = Float::neg_infinity(); + let zero: float = Zero::zero(); + let neg_zero: float = Float::neg_zero(); + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); assert!(1f.is_normal()); assert!(1e-307f.is_normal()); assert!(!1e-308f.is_normal()); @@ -1166,11 +1245,16 @@ mod tests { #[test] fn test_classify() { - assert_eq!(Float::NaN::().classify(), FPNaN); - assert_eq!(Float::infinity::().classify(), FPInfinite); - assert_eq!(Float::neg_infinity::().classify(), FPInfinite); - assert_eq!(Zero::zero::().classify(), FPZero); - assert_eq!(Float::neg_zero::().classify(), FPZero); + let nan: float = Float::NaN(); + let inf: float = Float::infinity(); + let neg_inf: float = Float::neg_infinity(); + let zero: float = Zero::zero(); + let neg_zero: float = Float::neg_zero(); + assert_eq!(nan.classify(), FPNaN); + assert_eq!(inf.classify(), FPInfinite); + assert_eq!(neg_inf.classify(), FPInfinite); + assert_eq!(zero.classify(), FPZero); + assert_eq!(neg_zero.classify(), FPZero); assert_eq!(1f.classify(), FPNormal); assert_eq!(1e-307f.classify(), FPNormal); assert_eq!(1e-308f.classify(), FPSubnormal); @@ -1187,11 +1271,13 @@ mod tests { assert_eq!(Float::ldexp(0f, -123), 0f); assert_eq!(Float::ldexp(-0f, -123), -0f); - assert_eq!(Float::ldexp(Float::infinity::(), -123), - Float::infinity::()); - assert_eq!(Float::ldexp(Float::neg_infinity::(), -123), - Float::neg_infinity::()); - assert!(Float::ldexp(Float::NaN::(), -123).is_NaN()); + + let inf: float = Float::infinity(); + let neg_inf: float = Float::neg_infinity(); + let nan: float = Float::NaN(); + assert_eq!(Float::ldexp(inf, -123), inf); + assert_eq!(Float::ldexp(neg_inf, -123), neg_inf); + assert!(Float::ldexp(nan, -123).is_NaN()); } #[test] @@ -1209,11 +1295,13 @@ mod tests { assert_eq!(0f.frexp(), (0f, 0)); assert_eq!((-0f).frexp(), (-0f, 0)); - assert_eq!(match Float::infinity::().frexp() { (x, _) => x }, - Float::infinity::()) - assert_eq!(match Float::neg_infinity::().frexp() { (x, _) => x }, - Float::neg_infinity::()) - assert!(match Float::NaN::().frexp() { (x, _) => x.is_NaN() }) + + let inf: float = Float::infinity(); + let neg_inf: float = Float::neg_infinity(); + let nan: float = Float::NaN(); + assert_eq!(match inf.frexp() { (x, _) => x }, inf); + assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf); + assert!(match nan.frexp() { (x, _) => x.is_NaN() }) } #[test] diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index 41da9a6ccbe48..55a2bcb9f69c3 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -455,10 +455,10 @@ impl Int for $T {} impl Primitive for $T { #[inline] - fn bits() -> uint { bits } + fn bits(_: Option<$T>) -> uint { bits } #[inline] - fn bytes() -> uint { bits / 8 } + fn bytes(_: Option<$T>) -> uint { bits / 8 } } // String conversion functions and impl str -> num @@ -752,8 +752,9 @@ mod tests { #[test] fn test_primitive() { - assert_eq!(Primitive::bits::<$T>(), sys::size_of::<$T>() * 8); - assert_eq!(Primitive::bytes::<$T>(), sys::size_of::<$T>()); + let none: Option<$T> = None; + assert_eq!(Primitive::bits(none), sys::size_of::<$T>() * 8); + assert_eq!(Primitive::bytes(none), sys::size_of::<$T>()); } #[test] diff --git a/src/libstd/num/num.rs b/src/libstd/num/num.rs index 04a1cc11b2673..1ad0048e0371b 100644 --- a/src/libstd/num/num.rs +++ b/src/libstd/num/num.rs @@ -272,8 +272,8 @@ pub trait Primitive: Num + Div + Rem { // FIXME (#5527): These should be associated constants - fn bits() -> uint; - fn bytes() -> uint; + fn bits(unused_self: Option) -> uint; + fn bytes(unused_self: Option) -> uint; } /// A collection of traits relevant to primitive signed and unsigned integers @@ -314,13 +314,13 @@ pub trait Float: Real fn is_normal(&self) -> bool; fn classify(&self) -> FPCategory; - fn mantissa_digits() -> uint; - fn digits() -> uint; + fn mantissa_digits(unused_self: Option) -> uint; + fn digits(unused_self: Option) -> uint; fn epsilon() -> Self; - fn min_exp() -> int; - fn max_exp() -> int; - fn min_10_exp() -> int; - fn max_10_exp() -> int; + fn min_exp(unused_self: Option) -> int; + fn max_exp(unused_self: Option) -> int; + fn min_10_exp(unused_self: Option) -> int; + fn max_10_exp(unused_self: Option) -> int; fn ldexp(x: Self, exp: int) -> Self; fn frexp(&self) -> (Self, int); @@ -484,9 +484,9 @@ impl Saturating for T { match self.checked_add(&v) { Some(x) => x, None => if v >= Zero::zero() { - Bounded::max_value::() + Bounded::max_value() } else { - Bounded::min_value::() + Bounded::min_value() } } } @@ -496,9 +496,9 @@ impl Saturating for T { match self.checked_sub(&v) { Some(x) => x, None => if v >= Zero::zero() { - Bounded::min_value::() + Bounded::min_value() } else { - Bounded::max_value::() + Bounded::max_value() } } } diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index 86b5b4ddfc09f..aa4bca2462ef6 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -403,10 +403,10 @@ impl ToStrRadix for $T { impl Primitive for $T { #[inline] - fn bits() -> uint { bits } + fn bits(_: Option<$T>) -> uint { bits } #[inline] - fn bytes() -> uint { bits / 8 } + fn bytes(_: Option<$T>) -> uint { bits / 8 } } impl BitCount for $T { @@ -519,8 +519,9 @@ mod tests { #[test] fn test_primitive() { - assert_eq!(Primitive::bits::<$T>(), sys::size_of::<$T>() * 8); - assert_eq!(Primitive::bytes::<$T>(), sys::size_of::<$T>()); + let none: Option<$T> = None; + assert_eq!(Primitive::bits(none), sys::size_of::<$T>() * 8); + assert_eq!(Primitive::bytes(none), sys::size_of::<$T>()); } #[test] diff --git a/src/libstd/rt/borrowck.rs b/src/libstd/rt/borrowck.rs index 5e481fac307a3..a7e466e3d846e 100644 --- a/src/libstd/rt/borrowck.rs +++ b/src/libstd/rt/borrowck.rs @@ -12,7 +12,7 @@ use c_str::ToCStr; use cast::transmute; use io::{Writer, WriterUtil}; use io; -use libc::{c_char, c_void, size_t, STDERR_FILENO}; +use libc::{c_char, size_t, STDERR_FILENO}; use option::{Option, None, Some}; use ptr::RawPtr; use str::{OwnedStr, StrSlice}; diff --git a/src/libstd/rt/comm.rs b/src/libstd/rt/comm.rs index 42d59ccdf958e..2a814b804687d 100644 --- a/src/libstd/rt/comm.rs +++ b/src/libstd/rt/comm.rs @@ -144,13 +144,13 @@ impl ChanOne { match oldstate { STATE_BOTH => { // Port is not waiting yet. Nothing to do - do Local::borrow:: |sched| { + do Local::borrow |sched: &mut Scheduler| { rtdebug!("non-rendezvous send"); sched.metrics.non_rendezvous_sends += 1; } } STATE_ONE => { - do Local::borrow:: |sched| { + do Local::borrow |sched: &mut Scheduler| { rtdebug!("rendezvous send"); sched.metrics.rendezvous_sends += 1; } @@ -167,7 +167,7 @@ impl ChanOne { }; } else { let recvr = Cell::new(recvr); - do Local::borrow:: |sched| { + do Local::borrow |sched: &mut Scheduler| { sched.enqueue_blocked_task(recvr.take()); } } @@ -207,7 +207,7 @@ impl PortOne { if !this.optimistic_check() { // No data available yet. // Switch to the scheduler to put the ~Task into the Packet state. - let sched = Local::take::(); + let sched: ~Scheduler = Local::take(); do sched.deschedule_running_task_and_then |sched, task| { this.block_on(sched, task); } @@ -229,7 +229,7 @@ impl SelectInner for PortOne { // The optimistic check is never necessary for correctness. For testing // purposes, making it randomly return false simulates a racing sender. use rand::{Rand}; - let actually_check = do Local::borrow:: |sched| { + let actually_check = do Local::borrow |sched: &mut Scheduler| { Rand::rand(&mut sched.rng) }; if actually_check { diff --git a/src/libstd/rt/io/net/ip.rs b/src/libstd/rt/io/net/ip.rs index 77176088801de..7b2d38caaaf05 100644 --- a/src/libstd/rt/io/net/ip.rs +++ b/src/libstd/rt/io/net/ip.rs @@ -359,7 +359,7 @@ impl FromStr for SocketAddr { mod test { use super::*; use from_str::FromStr; - use option::{Some, None}; + use option::{Option, Some, None}; #[test] fn test_from_str_ipv4() { @@ -368,13 +368,17 @@ mod test { assert_eq!(Some(Ipv4Addr(0, 0, 0, 0)), FromStr::from_str("0.0.0.0")); // out of range - assert_eq!(None, FromStr::from_str::("256.0.0.1")); + let none: Option = FromStr::from_str("256.0.0.1"); + assert_eq!(None, none); // too short - assert_eq!(None, FromStr::from_str::("255.0.0")); + let none: Option = FromStr::from_str("255.0.0"); + assert_eq!(None, none); // too long - assert_eq!(None, FromStr::from_str::("255.0.0.1.2")); + let none: Option = FromStr::from_str("255.0.0.1.2"); + assert_eq!(None, none); // no number between dots - assert_eq!(None, FromStr::from_str::("255.0..1")); + let none: Option = FromStr::from_str("255.0..1"); + assert_eq!(None, none); } #[test] @@ -389,15 +393,20 @@ mod test { FromStr::from_str("2a02:6b8::11:11")); // too long group - assert_eq!(None, FromStr::from_str::("::00000")); + let none: Option = FromStr::from_str("::00000"); + assert_eq!(None, none); // too short - assert_eq!(None, FromStr::from_str::("1:2:3:4:5:6:7")); + let none: Option = FromStr::from_str("1:2:3:4:5:6:7"); + assert_eq!(None, none); // too long - assert_eq!(None, FromStr::from_str::("1:2:3:4:5:6:7:8:9")); + let none: Option = FromStr::from_str("1:2:3:4:5:6:7:8:9"); + assert_eq!(None, none); // triple colon - assert_eq!(None, FromStr::from_str::("1:2:::6:7:8")); + let none: Option = FromStr::from_str("1:2:::6:7:8"); + assert_eq!(None, none); // two double colons - assert_eq!(None, FromStr::from_str::("1:2::6::8")); + let none: Option = FromStr::from_str("1:2::6::8"); + assert_eq!(None, none); } #[test] @@ -412,11 +421,15 @@ mod test { FromStr::from_str("2001:db8:122:c000:2:2100:192.0.2.33")); // colon after v4 - assert_eq!(None, FromStr::from_str::("::127.0.0.1:")); + let none: Option = FromStr::from_str("::127.0.0.1:"); + assert_eq!(None, none); // not enought groups - assert_eq!(None, FromStr::from_str::("1.2.3.4.5:127.0.0.1")); + let none: Option = FromStr::from_str("1.2.3.4.5:127.0.0.1"); + assert_eq!(None, none); // too many groups - assert_eq!(None, FromStr::from_str::("1.2.3.4.5:6:7:127.0.0.1")); + let none: Option = + FromStr::from_str("1.2.3.4.5:6:7:127.0.0.1"); + assert_eq!(None, none); } #[test] @@ -429,13 +442,17 @@ mod test { FromStr::from_str("[::127.0.0.1]:22")); // without port - assert_eq!(None, FromStr::from_str::("127.0.0.1")); + let none: Option = FromStr::from_str("127.0.0.1"); + assert_eq!(None, none); // without port - assert_eq!(None, FromStr::from_str::("127.0.0.1:")); + let none: Option = FromStr::from_str("127.0.0.1:"); + assert_eq!(None, none); // wrong brackets around v4 - assert_eq!(None, FromStr::from_str::("[127.0.0.1]:22")); + let none: Option = FromStr::from_str("[127.0.0.1]:22"); + assert_eq!(None, none); // port out of range - assert_eq!(None, FromStr::from_str::("127.0.0.1:123456")); + let none: Option = FromStr::from_str("127.0.0.1:123456"); + assert_eq!(None, none); } #[test] diff --git a/src/libstd/rt/io/net/tcp.rs b/src/libstd/rt/io/net/tcp.rs index 27222542e087d..52c350951014e 100644 --- a/src/libstd/rt/io/net/tcp.rs +++ b/src/libstd/rt/io/net/tcp.rs @@ -29,7 +29,7 @@ impl TcpStream { pub fn connect(addr: SocketAddr) -> Option { let stream = unsafe { rtdebug!("borrowing io to connect"); - let io = Local::unsafe_borrow::(); + let io: *mut IoFactoryObject = Local::unsafe_borrow(); rtdebug!("about to connect"); (*io).tcp_connect(addr) }; @@ -102,7 +102,7 @@ pub struct TcpListener(~RtioTcpListenerObject); impl TcpListener { pub fn bind(addr: SocketAddr) -> Option { let listener = unsafe { - let io = Local::unsafe_borrow::(); + let io: *mut IoFactoryObject = Local::unsafe_borrow(); (*io).tcp_bind(addr) }; match listener { diff --git a/src/libstd/rt/io/net/udp.rs b/src/libstd/rt/io/net/udp.rs index 644abcbe145ec..132ca064515c1 100644 --- a/src/libstd/rt/io/net/udp.rs +++ b/src/libstd/rt/io/net/udp.rs @@ -20,7 +20,10 @@ pub struct UdpSocket(~RtioUdpSocketObject); impl UdpSocket { pub fn bind(addr: SocketAddr) -> Option { - let socket = unsafe { (*Local::unsafe_borrow::()).udp_bind(addr) }; + let socket = unsafe { + let factory: *mut IoFactoryObject = Local::unsafe_borrow(); + (*factory).udp_bind(addr) + }; match socket { Ok(s) => Some(UdpSocket(s)), Err(ioerr) => { diff --git a/src/libstd/rt/io/timer.rs b/src/libstd/rt/io/timer.rs index c7820ebf6238b..36a3e8bb08030 100644 --- a/src/libstd/rt/io/timer.rs +++ b/src/libstd/rt/io/timer.rs @@ -25,7 +25,7 @@ impl Timer { pub fn new() -> Option { let timer = unsafe { rtdebug!("Timer::init: borrowing io to init timer"); - let io = Local::unsafe_borrow::(); + let io: *mut IoFactoryObject = Local::unsafe_borrow(); rtdebug!("about to init timer"); (*io).timer_init() }; @@ -61,4 +61,4 @@ mod test { } } } -} \ No newline at end of file +} diff --git a/src/libstd/rt/local.rs b/src/libstd/rt/local.rs index 1faad913b5025..5b26b073f747a 100644 --- a/src/libstd/rt/local.rs +++ b/src/libstd/rt/local.rs @@ -19,7 +19,7 @@ use cell::Cell; pub trait Local { fn put(value: ~Self); fn take() -> ~Self; - fn exists() -> bool; + fn exists(unused_value: Option) -> bool; fn borrow(f: &fn(&mut Self) -> T) -> T; unsafe fn unsafe_borrow() -> *mut Self; unsafe fn try_unsafe_borrow() -> Option<*mut Self>; @@ -28,7 +28,7 @@ pub trait Local { impl Local for Task { fn put(value: ~Task) { unsafe { local_ptr::put(value) } } fn take() -> ~Task { unsafe { local_ptr::take() } } - fn exists() -> bool { local_ptr::exists() } + fn exists(_: Option) -> bool { local_ptr::exists() } fn borrow(f: &fn(&mut Task) -> T) -> T { let mut res: Option = None; let res_ptr: *mut Option = &mut res; @@ -52,21 +52,21 @@ impl Local for Task { impl Local for Scheduler { fn put(value: ~Scheduler) { let value = Cell::new(value); - do Local::borrow:: |task| { + do Local::borrow |task: &mut Task| { let task = task; task.sched = Some(value.take()); }; } fn take() -> ~Scheduler { - do Local::borrow:: |task| { + do Local::borrow |task: &mut Task| { let sched = task.sched.take_unwrap(); let task = task; task.sched = None; sched } } - fn exists() -> bool { - do Local::borrow:: |task| { + fn exists(_: Option) -> bool { + do Local::borrow |task: &mut Task| { match task.sched { Some(ref _task) => true, None => false @@ -74,7 +74,7 @@ impl Local for Scheduler { } } fn borrow(f: &fn(&mut Scheduler) -> T) -> T { - do Local::borrow:: |task| { + do Local::borrow |task: &mut Task| { match task.sched { Some(~ref mut task) => { f(task) @@ -86,7 +86,8 @@ impl Local for Scheduler { } } unsafe fn unsafe_borrow() -> *mut Scheduler { - match (*Local::unsafe_borrow::()).sched { + let task: *mut Task = Local::unsafe_borrow(); + match (*task).sched { Some(~ref mut sched) => { let s: *mut Scheduler = &mut *sched; return s; @@ -97,7 +98,8 @@ impl Local for Scheduler { } } unsafe fn try_unsafe_borrow() -> Option<*mut Scheduler> { - if Local::exists::() { + let no_scheduler: Option = None; + if Local::exists(no_scheduler) { Some(Local::unsafe_borrow()) } else { None @@ -109,14 +111,16 @@ impl Local for Scheduler { impl Local for IoFactoryObject { fn put(_value: ~IoFactoryObject) { rtabort!("unimpl") } fn take() -> ~IoFactoryObject { rtabort!("unimpl") } - fn exists() -> bool { rtabort!("unimpl") } + fn exists(_: Option) -> bool { rtabort!("unimpl") } fn borrow(_f: &fn(&mut IoFactoryObject) -> T) -> T { rtabort!("unimpl") } unsafe fn unsafe_borrow() -> *mut IoFactoryObject { - let sched = Local::unsafe_borrow::(); + let sched: *mut Scheduler = Local::unsafe_borrow(); let io: *mut IoFactoryObject = (*sched).event_loop.io().unwrap(); return io; } - unsafe fn try_unsafe_borrow() -> Option<*mut IoFactoryObject> { rtabort!("unimpl") } + unsafe fn try_unsafe_borrow() -> Option<*mut IoFactoryObject> { + rtabort!("unimpl") + } } @@ -182,7 +186,7 @@ mod test { let task = ~Task::new_root(&mut sched.stack_pool, None, || {}); Local::put(task); - let res = do Local::borrow:: |_task| { + let res = do Local::borrow |_task: &mut Task| { true }; assert!(res) diff --git a/src/libstd/rt/local_heap.rs b/src/libstd/rt/local_heap.rs index 8715e768e3276..3054e7d698273 100644 --- a/src/libstd/rt/local_heap.rs +++ b/src/libstd/rt/local_heap.rs @@ -13,7 +13,7 @@ use libc; use libc::{c_void, uintptr_t, size_t}; use ops::Drop; -use option::{Some, None}; +use option::{Option, None, Some}; use rt::local::Local; use rt::task::Task; use unstable::raw; @@ -86,7 +86,8 @@ impl Drop for LocalHeap { // A little compatibility function pub unsafe fn local_free(ptr: *libc::c_char) { // XXX: Unsafe borrow for speed. Lame. - match Local::try_unsafe_borrow::() { + let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow(); + match task_ptr { Some(task) => { (*task).heap.free(ptr as *libc::c_void); } @@ -95,7 +96,7 @@ pub unsafe fn local_free(ptr: *libc::c_char) { } pub fn live_allocs() -> *raw::Box<()> { - let region = do Local::borrow:: |task| { + let region = do Local::borrow |task: &mut Task| { task.heap.boxed_region }; diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 65214d0cea78a..822e0f799496a 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -64,7 +64,7 @@ use cell::Cell; use clone::Clone; use container::Container; use iterator::{Iterator, range}; -use option::{Some, None}; +use option::{Option, None, Some}; use ptr::RawPtr; use rt::local::Local; use rt::sched::{Scheduler, Shutdown}; @@ -402,7 +402,8 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { pub fn in_sched_context() -> bool { unsafe { - match Local::try_unsafe_borrow::() { + let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow(); + match task_ptr { Some(task) => { match (*task).task_type { SchedTask => true, @@ -416,7 +417,8 @@ pub fn in_sched_context() -> bool { pub fn in_green_task_context() -> bool { unsafe { - match Local::try_unsafe_borrow::() { + let task: Option<*mut Task> = Local::try_unsafe_borrow(); + match task { Some(task) => { match (*task).task_type { GreenTask(_) => true, diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index 92657167c5fdd..fe644a76466b6 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -170,7 +170,7 @@ impl Scheduler { // successfully run the input task. Start by running the // scheduler. Grab it out of TLS - performing the scheduler // action will have given it away. - let sched = Local::take::(); + let sched: ~Scheduler = Local::take(); rtdebug!("starting scheduler %u", sched.sched_id()); @@ -181,7 +181,7 @@ impl Scheduler { // cleaning up the memory it uses. As we didn't actually call // task.run() on the scheduler task we never get through all // the cleanup code it runs. - let mut stask = Local::take::(); + let mut stask: ~Task = Local::take(); rtdebug!("stopping scheduler %u", stask.sched.get_ref().sched_id()); @@ -213,7 +213,7 @@ impl Scheduler { // Our scheduler must be in the task before the event loop // is started. let self_sched = Cell::new(self_sched); - do Local::borrow:: |stask| { + do Local::borrow |stask: &mut Task| { stask.sched = Some(self_sched.take()); }; @@ -235,7 +235,7 @@ impl Scheduler { // already have a scheduler stored in our local task, so we // start off by taking it. This is the only path through the // scheduler where we get the scheduler this way. - let sched = Local::take::(); + let sched: ~Scheduler = Local::take(); // Our first task is to read mail to see if we have important // messages. @@ -307,7 +307,6 @@ impl Scheduler { /// event loop to run it later. Always use this instead of pushing /// to the work queue directly. pub fn enqueue_task(&mut self, task: ~Task) { - let this = self; // We push the task onto our local queue clone. @@ -591,7 +590,7 @@ impl Scheduler { // Task context case - use TLS. pub fn run_task(task: ~Task) { - let sched = Local::take::(); + let sched: ~Scheduler = Local::take(); let opt = do sched.schedule_task(task) |sched, next_task| { do sched.switch_running_tasks_and_then(next_task) |sched, last_task| { sched.enqueue_blocked_task(last_task); @@ -614,7 +613,7 @@ impl Scheduler { let mut this = self; // The current task is grabbed from TLS, not taken as an input. - let current_task: ~Task = Local::take::(); + let current_task: ~Task = Local::take(); // Check that the task is not in an atomically() section (e.g., // holding a pthread mutex, which could deadlock the scheduler). @@ -676,11 +675,11 @@ impl Scheduler { // run the cleanup job, as expected by the previously called // swap_contexts function. unsafe { - let sched = Local::unsafe_borrow::(); + let sched: *mut Scheduler = Local::unsafe_borrow(); (*sched).run_cleanup_job(); // Must happen after running the cleanup job (of course). - let task = Local::unsafe_borrow::(); + let task: *mut Task = Local::unsafe_borrow(); (*task).death.check_killed((*task).unwinder.unwinding); } } @@ -742,7 +741,7 @@ impl Scheduler { // We aren't performing a scheduler operation, so we want to // put the Scheduler back when we finish. let next_task = Cell::new(next_task); - do Local::borrow:: |sched| { + do Local::borrow |sched: &mut Scheduler| { sched.enqueue_task(next_task.take()); }; } @@ -1055,12 +1054,12 @@ mod test { // exit before emptying the work queue do run_in_newsched_task { do spawntask { - let sched = Local::take::(); + let sched: ~Scheduler = Local::take(); do sched.deschedule_running_task_and_then |sched, task| { let task = Cell::new(task); do sched.event_loop.callback_ms(10) { rtdebug!("in callback"); - let mut sched = Local::take::(); + let mut sched: ~Scheduler = Local::take(); sched.enqueue_blocked_task(task.take()); Local::put(sched); } diff --git a/src/libstd/rt/select.rs b/src/libstd/rt/select.rs index 19a4948af3c5a..6cde0a1f2169f 100644 --- a/src/libstd/rt/select.rs +++ b/src/libstd/rt/select.rs @@ -26,3 +26,4 @@ pub trait SelectInner { pub trait SelectPortInner { fn recv_ready(self) -> Option; } + diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index 708166518bb89..437aa0ca01574 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -89,7 +89,7 @@ impl Task { pub fn build_homed_child(stack_size: Option, f: ~fn(), home: SchedHome) -> ~Task { let f = Cell::new(f); let home = Cell::new(home); - do Local::borrow:: |running_task| { + do Local::borrow |running_task: &mut Task| { let mut sched = running_task.sched.take_unwrap(); let new_task = ~running_task.new_child_homed(&mut sched.stack_pool, stack_size, @@ -107,7 +107,7 @@ impl Task { pub fn build_homed_root(stack_size: Option, f: ~fn(), home: SchedHome) -> ~Task { let f = Cell::new(f); let home = Cell::new(home); - do Local::borrow:: |running_task| { + do Local::borrow |running_task: &mut Task| { let mut sched = running_task.sched.take_unwrap(); let new_task = ~Task::new_root_homed(&mut sched.stack_pool, stack_size, @@ -295,7 +295,7 @@ impl Task { // Grab both the scheduler and the task from TLS and check if the // task is executing on an appropriate scheduler. pub fn on_appropriate_sched() -> bool { - do Local::borrow:: |task| { + do Local::borrow |task: &mut Task| { let sched_id = task.sched.get_ref().sched_id(); let sched_run_anything = task.sched.get_ref().run_anything; match task.task_type { @@ -359,7 +359,7 @@ impl Coroutine { unsafe { // Again - might work while safe, or it might not. - do Local::borrow:: |sched| { + do Local::borrow |sched: &mut Scheduler| { (sched).run_cleanup_job(); } @@ -368,7 +368,7 @@ impl Coroutine { // simply unsafe_borrow it to get this reference. We // need to still have the task in TLS though, so we // need to unsafe_borrow. - let task = Local::unsafe_borrow::(); + let task: *mut Task = Local::unsafe_borrow(); do (*task).run { // N.B. Removing `start` from the start wrapper @@ -387,7 +387,7 @@ impl Coroutine { } // We remove the sched from the Task in TLS right now. - let sched = Local::take::(); + let sched: ~Scheduler = Local::take(); // ... allowing us to give it away when performing a // scheduling operation. sched.terminate_current_task() diff --git a/src/libstd/rt/tube.rs b/src/libstd/rt/tube.rs index 247893f75de00..b8e535e4c7dfd 100644 --- a/src/libstd/rt/tube.rs +++ b/src/libstd/rt/tube.rs @@ -51,7 +51,7 @@ impl Tube { // There's a waiting task. Wake it up rtdebug!("waking blocked tube"); let task = (*state).blocked_task.take_unwrap(); - let sched = Local::take::(); + let sched: ~Scheduler = Local::take(); sched.resume_blocked_task_immediately(task); } } @@ -67,7 +67,7 @@ impl Tube { rtdebug!("blocking on tube recv"); assert!(self.p.refcount() > 1); // There better be somebody to wake us up assert!((*state).blocked_task.is_none()); - let sched = Local::take::(); + let sched: ~Scheduler = Local::take(); do sched.deschedule_running_task_and_then |_, task| { (*state).blocked_task = Some(task); } @@ -102,7 +102,7 @@ mod test { let mut tube: Tube = Tube::new(); let tube_clone = tube.clone(); let tube_clone_cell = Cell::new(tube_clone); - let sched = Local::take::(); + let sched: ~Scheduler = Local::take(); do sched.deschedule_running_task_and_then |sched, task| { let mut tube_clone = tube_clone_cell.take(); tube_clone.send(1); @@ -119,7 +119,7 @@ mod test { let mut tube: Tube = Tube::new(); let tube_clone = tube.clone(); let tube_clone = Cell::new(tube_clone); - let sched = Local::take::(); + let sched: ~Scheduler = Local::take(); do sched.deschedule_running_task_and_then |sched, task| { let tube_clone = Cell::new(tube_clone.take()); do sched.event_loop.callback { @@ -143,7 +143,7 @@ mod test { let mut tube: Tube = Tube::new(); let tube_clone = tube.clone(); let tube_clone = Cell::new(tube_clone); - let sched = Local::take::(); + let sched: ~Scheduler = Local::take(); do sched.deschedule_running_task_and_then |sched, task| { callback_send(tube_clone.take(), 0); @@ -151,7 +151,7 @@ mod test { if i == 100 { return; } let tube = Cell::new(Cell::new(tube)); - do Local::borrow:: |sched| { + do Local::borrow |sched: &mut Scheduler| { let tube = tube.take(); do sched.event_loop.callback { let mut tube = tube.take(); diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index a26b8a3ad594d..54542a34ff55a 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -214,7 +214,7 @@ mod test_remote { let mut tube = Tube::new(); let tube_clone = tube.clone(); let remote_cell = Cell::new_empty(); - do Local::borrow::() |sched| { + do Local::borrow |sched: &mut Scheduler| { let tube_clone = tube_clone.clone(); let tube_clone_cell = Cell::new(tube_clone); let remote = do sched.event_loop.remote_callback { @@ -250,7 +250,7 @@ impl IoFactory for UvIoFactory { let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); // Block this task and take ownership, switch to scheduler context do scheduler.deschedule_running_task_and_then |_, task| { @@ -272,7 +272,7 @@ impl IoFactory for UvIoFactory { unsafe { (*result_cell_ptr).put_back(res); } // Context switch - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); scheduler.resume_blocked_task_immediately(task_cell.take()); } else { rtdebug!("status is some"); @@ -280,7 +280,7 @@ impl IoFactory for UvIoFactory { do stream_watcher.close { let res = Err(uv_error_to_io_error(status.unwrap())); unsafe { (*result_cell_ptr).put_back(res); } - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); scheduler.resume_blocked_task_immediately(task_cell.take()); } }; @@ -296,11 +296,11 @@ impl IoFactory for UvIoFactory { match watcher.bind(addr) { Ok(_) => Ok(~UvTcpListener::new(watcher)), Err(uverr) => { - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); do watcher.as_stream().close { - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); scheduler.resume_blocked_task_immediately(task_cell.take()); } } @@ -314,11 +314,11 @@ impl IoFactory for UvIoFactory { match watcher.bind(addr) { Ok(_) => Ok(~UvUdpSocket(watcher)), Err(uverr) => { - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); do watcher.close { - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); scheduler.resume_blocked_task_immediately(task_cell.take()); } } @@ -353,11 +353,11 @@ impl UvTcpListener { impl Drop for UvTcpListener { fn drop(&self) { let watcher = self.watcher(); - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); do watcher.as_stream().close { - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); scheduler.resume_blocked_task_immediately(task_cell.take()); } } @@ -433,11 +433,11 @@ pub struct UvTcpStream(TcpWatcher); impl Drop for UvTcpStream { fn drop(&self) { rtdebug!("closing tcp stream"); - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); do self.as_stream().close { - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); scheduler.resume_blocked_task_immediately(task_cell.take()); } } @@ -455,7 +455,7 @@ impl RtioTcpStream for UvTcpStream { let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); let buf_ptr: *&mut [u8] = &buf; do scheduler.deschedule_running_task_and_then |_sched, task| { rtdebug!("read: entered scheduler context"); @@ -483,7 +483,7 @@ impl RtioTcpStream for UvTcpStream { unsafe { (*result_cell_ptr).put_back(result); } - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); scheduler.resume_blocked_task_immediately(task_cell.take()); } } @@ -495,7 +495,7 @@ impl RtioTcpStream for UvTcpStream { fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); let buf_ptr: *&[u8] = &buf; do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); @@ -510,7 +510,7 @@ impl RtioTcpStream for UvTcpStream { unsafe { (*result_cell_ptr).put_back(result); } - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); scheduler.resume_blocked_task_immediately(task_cell.take()); } } @@ -574,11 +574,11 @@ pub struct UvUdpSocket(UdpWatcher); impl Drop for UvUdpSocket { fn drop(&self) { rtdebug!("closing udp socket"); - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); do self.close { - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); scheduler.resume_blocked_task_immediately(task_cell.take()); } } @@ -596,7 +596,7 @@ impl RtioUdpSocket for UvUdpSocket { let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); let buf_ptr: *&mut [u8] = &buf; do scheduler.deschedule_running_task_and_then |_sched, task| { rtdebug!("recvfrom: entered scheduler context"); @@ -617,7 +617,7 @@ impl RtioUdpSocket for UvUdpSocket { unsafe { (*result_cell_ptr).put_back(result); } - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); scheduler.resume_blocked_task_immediately(task_cell.take()); } } @@ -629,7 +629,7 @@ impl RtioUdpSocket for UvUdpSocket { fn sendto(&mut self, buf: &[u8], dst: SocketAddr) -> Result<(), IoError> { let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); let buf_ptr: *&[u8] = &buf; do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); @@ -643,7 +643,7 @@ impl RtioUdpSocket for UvUdpSocket { unsafe { (*result_cell_ptr).put_back(result); } - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); scheduler.resume_blocked_task_immediately(task_cell.take()); } } @@ -758,11 +758,11 @@ impl UvTimer { impl Drop for UvTimer { fn drop(&self) { rtdebug!("closing UvTimer"); - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); do self.close { - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); scheduler.resume_blocked_task_immediately(task_cell.take()); } } @@ -771,14 +771,14 @@ impl Drop for UvTimer { impl RtioTimer for UvTimer { fn sleep(&self, msecs: u64) { - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); do scheduler.deschedule_running_task_and_then |_sched, task| { rtdebug!("sleep: entered scheduler context"); let task_cell = Cell::new(task); let mut watcher = **self; do watcher.start(msecs, 0) |_, status| { assert!(status.is_none()); - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); scheduler.resume_blocked_task_immediately(task_cell.take()); } } @@ -791,7 +791,7 @@ impl RtioTimer for UvTimer { fn test_simple_io_no_connect() { do run_in_newsched_task { unsafe { - let io = Local::unsafe_borrow::(); + let io: *mut IoFactoryObject = Local::unsafe_borrow(); let addr = next_test_ip4(); let maybe_chan = (*io).tcp_connect(addr); assert!(maybe_chan.is_err()); @@ -803,7 +803,7 @@ fn test_simple_io_no_connect() { fn test_simple_udp_io_bind_only() { do run_in_newsched_task { unsafe { - let io = Local::unsafe_borrow::(); + let io: *mut IoFactoryObject = Local::unsafe_borrow(); let addr = next_test_ip4(); let maybe_socket = (*io).udp_bind(addr); assert!(maybe_socket.is_ok()); @@ -819,7 +819,7 @@ fn test_simple_tcp_server_and_client() { // Start the server first so it's listening when we connect do spawntask { unsafe { - let io = Local::unsafe_borrow::(); + let io: *mut IoFactoryObject = Local::unsafe_borrow(); let mut listener = (*io).tcp_bind(addr).unwrap(); let mut stream = listener.accept().unwrap(); let mut buf = [0, .. 2048]; @@ -834,7 +834,7 @@ fn test_simple_tcp_server_and_client() { do spawntask { unsafe { - let io = Local::unsafe_borrow::(); + let io: *mut IoFactoryObject = Local::unsafe_borrow(); let mut stream = (*io).tcp_connect(addr).unwrap(); stream.write([0, 1, 2, 3, 4, 5, 6, 7]); } @@ -850,7 +850,7 @@ fn test_simple_udp_server_and_client() { do spawntask { unsafe { - let io = Local::unsafe_borrow::(); + let io: *mut IoFactoryObject = Local::unsafe_borrow(); let mut server_socket = (*io).udp_bind(server_addr).unwrap(); let mut buf = [0, .. 2048]; let (nread,src) = server_socket.recvfrom(buf).unwrap(); @@ -865,7 +865,7 @@ fn test_simple_udp_server_and_client() { do spawntask { unsafe { - let io = Local::unsafe_borrow::(); + let io: *mut IoFactoryObject = Local::unsafe_borrow(); let mut client_socket = (*io).udp_bind(client_addr).unwrap(); client_socket.sendto([0, 1, 2, 3, 4, 5, 6, 7], server_addr); } @@ -879,7 +879,7 @@ fn test_read_and_block() { let addr = next_test_ip4(); do spawntask { - let io = unsafe { Local::unsafe_borrow::() }; + let io: *mut IoFactoryObject = unsafe { Local::unsafe_borrow() }; let mut listener = unsafe { (*io).tcp_bind(addr).unwrap() }; let mut stream = listener.accept().unwrap(); let mut buf = [0, .. 2048]; @@ -897,7 +897,7 @@ fn test_read_and_block() { } reads += 1; - let scheduler = Local::take::(); + let scheduler: ~Scheduler = Local::take(); // Yield to the other task in hopes that it // will trigger a read callback while we are // not ready for it @@ -913,7 +913,7 @@ fn test_read_and_block() { do spawntask { unsafe { - let io = Local::unsafe_borrow::(); + let io: *mut IoFactoryObject = Local::unsafe_borrow(); let mut stream = (*io).tcp_connect(addr).unwrap(); stream.write([0, 1, 2, 3, 4, 5, 6, 7]); stream.write([0, 1, 2, 3, 4, 5, 6, 7]); @@ -933,7 +933,7 @@ fn test_read_read_read() { do spawntask { unsafe { - let io = Local::unsafe_borrow::(); + let io: *mut IoFactoryObject = Local::unsafe_borrow(); let mut listener = (*io).tcp_bind(addr).unwrap(); let mut stream = listener.accept().unwrap(); let buf = [1, .. 2048]; @@ -947,7 +947,7 @@ fn test_read_read_read() { do spawntask { unsafe { - let io = Local::unsafe_borrow::(); + let io: *mut IoFactoryObject = Local::unsafe_borrow(); let mut stream = (*io).tcp_connect(addr).unwrap(); let mut buf = [0, .. 2048]; let mut total_bytes_read = 0; @@ -973,7 +973,7 @@ fn test_udp_twice() { do spawntask { unsafe { - let io = Local::unsafe_borrow::(); + let io: *mut IoFactoryObject = Local::unsafe_borrow(); let mut client = (*io).udp_bind(client_addr).unwrap(); assert!(client.sendto([1], server_addr).is_ok()); assert!(client.sendto([2], server_addr).is_ok()); @@ -982,7 +982,7 @@ fn test_udp_twice() { do spawntask { unsafe { - let io = Local::unsafe_borrow::(); + let io: *mut IoFactoryObject = Local::unsafe_borrow(); let mut server = (*io).udp_bind(server_addr).unwrap(); let mut buf1 = [0]; let mut buf2 = [0]; @@ -1010,7 +1010,7 @@ fn test_udp_many_read() { do spawntask { unsafe { - let io = Local::unsafe_borrow::(); + let io: *mut IoFactoryObject = Local::unsafe_borrow(); let mut server_out = (*io).udp_bind(server_out_addr).unwrap(); let mut server_in = (*io).udp_bind(server_in_addr).unwrap(); let msg = [1, .. 2048]; @@ -1033,7 +1033,7 @@ fn test_udp_many_read() { do spawntask { unsafe { - let io = Local::unsafe_borrow::(); + let io: *mut IoFactoryObject = Local::unsafe_borrow(); let mut client_out = (*io).udp_bind(client_out_addr).unwrap(); let mut client_in = (*io).udp_bind(client_in_addr).unwrap(); let mut total_bytes_recv = 0; @@ -1060,7 +1060,7 @@ fn test_udp_many_read() { fn test_timer_sleep_simple_impl() { unsafe { - let io = Local::unsafe_borrow::(); + let io: *mut IoFactoryObject = Local::unsafe_borrow(); let timer = (*io).timer_init(); match timer { Ok(t) => t.sleep(1), diff --git a/src/libstd/select.rs b/src/libstd/select.rs index a92339e256244..579d19e6725d1 100644 --- a/src/libstd/select.rs +++ b/src/libstd/select.rs @@ -57,7 +57,7 @@ pub fn select(ports: &mut [A]) -> uint { let p = Cell::new(p); let c = Cell::new(c); - let sched = Local::take::(); + let sched: ~Scheduler = Local::take(); do sched.deschedule_running_task_and_then |sched, task| { let task_handles = task.make_selectable(ports.len()); diff --git a/src/libstd/sys.rs b/src/libstd/sys.rs index bfb9bee78028c..cb0753fb2e5de 100644 --- a/src/libstd/sys.rs +++ b/src/libstd/sys.rs @@ -143,7 +143,7 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { if in_green_task_context() { // XXX: Logging doesn't work here - the check to call the log // function never passes - so calling the log function directly. - do Local::borrow:: |task| { + do Local::borrow |task: &mut Task| { let msg = match task.name { Some(ref name) => fmt!("task '%s' failed at '%s', %s:%i", @@ -160,7 +160,7 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { msg, file, line as int); } - let task = Local::unsafe_borrow::(); + let task: *mut Task = Local::unsafe_borrow(); if (*task).unwinder.unwinding { rtabort!("unwinding again"); } diff --git a/src/libstd/task/local_data_priv.rs b/src/libstd/task/local_data_priv.rs index 3a11dee313816..ab59c70032523 100644 --- a/src/libstd/task/local_data_priv.rs +++ b/src/libstd/task/local_data_priv.rs @@ -28,7 +28,7 @@ impl Handle { pub fn new() -> Handle { use rt::local::Local; unsafe { - let task = Local::unsafe_borrow::(); + let task: *mut Task = Local::unsafe_borrow(); NewHandle(&mut (*task).storage) } } diff --git a/src/libstd/task/mod.rs b/src/libstd/task/mod.rs index c38e6f233130b..7d9208cfd93c3 100644 --- a/src/libstd/task/mod.rs +++ b/src/libstd/task/mod.rs @@ -526,7 +526,7 @@ pub fn with_task_name(blk: &fn(Option<&str>) -> U) -> U { use rt::task::Task; if in_green_task_context() { - do Local::borrow:: |task| { + do Local::borrow |task: &mut Task| { match task.name { Some(ref name) => blk(Some(name.as_slice())), None => blk(None) @@ -545,7 +545,7 @@ pub fn yield() { // XXX: What does yield really mean in newsched? // FIXME(#7544): Optimize this, since we know we won't block. - let sched = Local::take::(); + let sched: ~Scheduler = Local::take(); do sched.deschedule_running_task_and_then |sched, task| { sched.enqueue_blocked_task(task); } @@ -556,7 +556,7 @@ pub fn failing() -> bool { use rt::task::Task; - do Local::borrow:: |local| { + do Local::borrow |local: &mut Task| { local.unwinder.unwinding } } @@ -582,7 +582,7 @@ pub fn unkillable(f: &fn() -> U) -> U { unsafe { if in_green_task_context() { // The inhibits/allows might fail and need to borrow the task. - let t = Local::unsafe_borrow::(); + let t: *mut Task = Local::unsafe_borrow(); do (|| { (*t).death.inhibit_kill((*t).unwinder.unwinding); f() @@ -602,7 +602,7 @@ pub unsafe fn rekillable(f: &fn() -> U) -> U { use rt::task::Task; if in_green_task_context() { - let t = Local::unsafe_borrow::(); + let t: *mut Task = Local::unsafe_borrow(); do (|| { (*t).death.allow_kill((*t).unwinder.unwinding); f() @@ -989,7 +989,7 @@ fn test_try_fail() { #[cfg(test)] fn get_sched_id() -> int { - do Local::borrow::<::rt::sched::Scheduler, int> |sched| { + do Local::borrow |sched: &mut ::rt::sched::Scheduler| { sched.sched_id() as int } } diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index e0efc14a8871f..216a9e9e4264d 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -450,7 +450,7 @@ impl RuntimeGlue { let mut handle = handle; do handle.kill().map_move |killed_task| { let killed_task = Cell::new(killed_task); - do Local::borrow:: |sched| { + do Local::borrow |sched: &mut Scheduler| { sched.enqueue_task(killed_task.take()); } }; @@ -461,7 +461,7 @@ impl RuntimeGlue { unsafe { // Can't use safe borrow, because the taskgroup destructor needs to // access the scheduler again to send kill signals to other tasks. - let me = Local::unsafe_borrow::(); + let me: *mut Task = Local::unsafe_borrow(); blk((*me).death.kill_handle.get_ref(), (*me).unwinder.unwinding) } } else { @@ -474,7 +474,7 @@ impl RuntimeGlue { unsafe { // Can't use safe borrow, because creating new hashmaps for the // tasksets requires an rng, which needs to borrow the sched. - let me = Local::unsafe_borrow::(); + let me: *mut Task = Local::unsafe_borrow(); blk(match (*me).taskgroup { None => { // First task in its (unlinked/unsupervised) taskgroup. @@ -587,7 +587,7 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) { // If child data is 'None', the enlist is vacuously successful. let enlist_success = do child_data.take().map_move_default(true) |child_data| { let child_data = Cell::new(child_data); // :( - do Local::borrow:: |me| { + do Local::borrow |me: &mut Task| { let (child_tg, ancestors) = child_data.take(); let mut ancestors = ancestors; let handle = me.death.kill_handle.get_ref(); @@ -621,7 +621,7 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) { } else { unsafe { // Creating a 1:1 task:thread ... - let sched = Local::unsafe_borrow::(); + let sched: *mut Scheduler = Local::unsafe_borrow(); let sched_handle = (*sched).make_handle(); // Since this is a 1:1 scheduler we create a queue not in diff --git a/src/libstd/tuple.rs b/src/libstd/tuple.rs index 12073a1f4f095..5d9ca6202e262 100644 --- a/src/libstd/tuple.rs +++ b/src/libstd/tuple.rs @@ -176,7 +176,7 @@ macro_rules! tuple_impls { impl<$($T:Zero),+> Zero for ($($T,)+) { #[inline] fn zero() -> ($($T,)+) { - ($(Zero::zero::<$T>(),)+) + ($({ let x: $T = Zero::zero(); x},)+) } #[inline] fn is_zero(&self) -> bool { diff --git a/src/libstd/unstable/atomics.rs b/src/libstd/unstable/atomics.rs index 2cfe63d99266f..5744bf0fb0c86 100644 --- a/src/libstd/unstable/atomics.rs +++ b/src/libstd/unstable/atomics.rs @@ -538,7 +538,8 @@ mod test { #[test] fn option_empty() { - assert!(AtomicOption::empty::<()>().is_empty(SeqCst)); + let mut option: AtomicOption<()> = AtomicOption::empty(); + assert!(option.is_empty(SeqCst)); } #[test] diff --git a/src/libstd/unstable/lang.rs b/src/libstd/unstable/lang.rs index 91b4283ba12dd..b32f66e48010f 100644 --- a/src/libstd/unstable/lang.rs +++ b/src/libstd/unstable/lang.rs @@ -13,7 +13,7 @@ use c_str::ToCStr; use cast::transmute; use libc::{c_char, c_void, size_t, uintptr_t}; -use option::{Some, None}; +use option::{Option, None, Some}; use sys; use rt::task::Task; use rt::local::Local; @@ -37,7 +37,8 @@ pub fn fail_bounds_check(file: *c_char, line: size_t, #[lang="malloc"] pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { // XXX: Unsafe borrow for speed. Lame. - match Local::try_unsafe_borrow::() { + let task: Option<*mut Task> = Local::try_unsafe_borrow(); + match task { Some(task) => { (*task).heap.alloc(td as *c_void, size as uint) as *c_char } diff --git a/src/libstd/unstable/sync.rs b/src/libstd/unstable/sync.rs index adbf9fc757819..743083348f0f3 100644 --- a/src/libstd/unstable/sync.rs +++ b/src/libstd/unstable/sync.rs @@ -286,7 +286,7 @@ pub unsafe fn atomically(f: &fn() -> U) -> U { use rt::in_green_task_context; if in_green_task_context() { - let t = Local::unsafe_borrow::(); + let t: *mut Task = Local::unsafe_borrow(); do (|| { (*t).death.inhibit_yield(); f() diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f44e031b84545..1b39c64be7139 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -174,12 +174,16 @@ impl Generics { } } +#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)] +pub enum MethodProvenance { + FromTrait(def_id), + FromImpl(def_id), +} + #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)] pub enum def { def_fn(def_id, purity), - def_static_method(/* method */ def_id, - /* trait */ Option, - purity), + def_static_method(/* method */ def_id, MethodProvenance, purity), def_self(NodeId, bool /* is_implicit */), def_self_ty(/* trait id */ NodeId), def_mod(def_id), @@ -716,7 +720,7 @@ impl ToStr for float_ty { } // NB Eq method appears below. -#[deriving(Clone, Eq, Encodable, Decodable,IterBytes)] +#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)] pub struct Ty { id: NodeId, node: ty_, diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 5a2fa4d58b4dd..91f6b64076f6d 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -74,6 +74,13 @@ pub trait AstBuilder { // statements fn stmt_expr(&self, expr: @ast::expr) -> @ast::stmt; fn stmt_let(&self, sp: span, mutbl: bool, ident: ast::ident, ex: @ast::expr) -> @ast::stmt; + fn stmt_let_typed(&self, + sp: span, + mutbl: bool, + ident: ast::ident, + typ: ast::Ty, + ex: @ast::expr) + -> @ast::stmt; // blocks fn block(&self, span: span, stmts: ~[@ast::stmt], expr: Option<@ast::expr>) -> ast::Block; @@ -241,8 +248,8 @@ impl AstBuilder for @ExtCtxt { types: ~[ast::Ty]) -> ast::Path { let last_identifier = idents.pop(); - let mut segments: ~[ast::PathSegment] = idents.consume_iter() - .transform(|ident| { + let mut segments: ~[ast::PathSegment] = idents.move_iter() + .map(|ident| { ast::PathSegment { identifier: ident, lifetime: None, @@ -400,6 +407,26 @@ impl AstBuilder for @ExtCtxt { @respan(sp, ast::stmt_decl(@decl, self.next_id())) } + fn stmt_let_typed(&self, + sp: span, + mutbl: bool, + ident: ast::ident, + typ: ast::Ty, + ex: @ast::expr) + -> @ast::stmt { + let pat = self.pat_ident(sp, ident); + let local = @ast::Local { + is_mutbl: mutbl, + ty: typ, + pat: pat, + init: Some(ex), + id: self.next_id(), + span: sp, + }; + let decl = respan(sp, ast::decl_local(local)); + @respan(sp, ast::stmt_decl(@decl, self.next_id())) + } + fn block(&self, span: span, stmts: ~[@ast::stmt], expr: Option<@expr>) -> ast::Block { self.block_all(span, ~[], stmts, expr) } diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index e55a96f77ff9b..9f86fe7d7f2c2 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -76,24 +76,34 @@ fn rand_substructure(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr { let variant_count = cx.expr_uint(span, variants.len()); - // need to specify the uint-ness of the random number - let uint_ty = cx.ty_ident(span, cx.ident_of("uint")); let r_ty = cx.ty_ident(span, cx.ident_of("R")); let rand_name = cx.path_all(span, true, rand_ident.clone(), None, - ~[ uint_ty, r_ty ]); + ~[]); let rand_name = cx.expr_path(rand_name); - // ::std::rand::Rand::rand::(rng) + // ::std::rand::Rand::rand(rng) let rv_call = cx.expr_call(span, rand_name, ~[ rng[0].duplicate(cx) ]); + // need to specify the uint-ness of the random number + let uint_ty = cx.ty_ident(span, cx.ident_of("uint")); + let value_ident = cx.ident_of("__value"); + let let_statement = cx.stmt_let_typed(span, + false, + value_ident, + uint_ty, + rv_call); + // rand() % variants.len() - let rand_variant = cx.expr_binary(span, ast::rem, - rv_call, variant_count); + let value_ref = cx.expr_ident(span, value_ident); + let rand_variant = cx.expr_binary(span, + ast::rem, + value_ref, + variant_count); let mut arms = do variants.iter().enumerate().map |(i, id_sum)| { let i_expr = cx.expr_uint(span, i); @@ -111,7 +121,10 @@ fn rand_substructure(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr { // _ => {} at the end. Should never occur arms.push(cx.arm_unreachable(span)); - cx.expr_match(span, rand_variant, arms) + let match_expr = cx.expr_match(span, rand_variant, arms); + + let block = cx.block(span, ~[ let_statement ], Some(match_expr)); + cx.expr_block(block) } _ => cx.bug("Non-static method in `deriving(Rand)`") }; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 73e17f551c9f7..1a7fc558dcd29 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -399,8 +399,8 @@ mod test { types: ~[], } ] - }, - span: sp(0, 6)) + }), + span: sp(0, 6) }) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9a821d1ed28eb..9aca142838dc6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1375,7 +1375,7 @@ impl Parser { _ => None, }; match found { - Some(INTERPOLATED(token::nt_path(path))) => { + Some(INTERPOLATED(token::nt_path(~path))) => { return PathAndBounds { path: path, bounds: None, @@ -1484,7 +1484,7 @@ impl Parser { let mut path_segments = ~[]; let mut bounds = None; let last_segment_index = segments.len() - 1; - for (i, segment_and_bounds) in segments.consume_iter().enumerate() { + for (i, segment_and_bounds) in segments.move_iter().enumerate() { let PathSegmentAndBoundSet { segment: segment, bound_set: bound_set @@ -4845,7 +4845,7 @@ impl Parser { let path = ast::Path { span: mk_sp(lo, self.span.hi), global: false, - segments: path.consume_iter().transform(|identifier| { + segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, lifetime: None, @@ -4881,7 +4881,7 @@ impl Parser { let path = ast::Path { span: mk_sp(lo, self.span.hi), global: false, - segments: path.consume_iter().transform(|identifier| { + segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, lifetime: None, @@ -4899,7 +4899,7 @@ impl Parser { let path = ast::Path { span: mk_sp(lo, self.span.hi), global: false, - segments: path.consume_iter().transform(|identifier| { + segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, lifetime: None, @@ -4921,7 +4921,7 @@ impl Parser { let path = ast::Path { span: mk_sp(lo, self.span.hi), global: false, - segments: path.consume_iter().transform(|identifier| { + segments: path.move_iter().map(|identifier| { ast::PathSegment { identifier: identifier, lifetime: None, diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index ef44a368ab517..e5b7823ae44ec 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -320,7 +320,7 @@ pub fn walk_ty>(visitor: &mut V, typ: &Ty, env: E) { pub fn walk_path>(visitor: &mut V, path: &Path, env: E) { for segment in path.segments.iter() { - for typ in path.types.iter() { + for typ in segment.types.iter() { visitor.visit_ty(typ, env.clone()) } } diff --git a/src/test/compile-fail/bad-mid-path-type-params.rs b/src/test/compile-fail/bad-mid-path-type-params.rs new file mode 100644 index 0000000000000..e4833345d311c --- /dev/null +++ b/src/test/compile-fail/bad-mid-path-type-params.rs @@ -0,0 +1,37 @@ +#[no_std]; + +struct S { + contents: T, +} + +impl S { + fn new(x: T, _: U) -> S { + S { + contents: x, + } + } +} + +trait Trait { + fn new(x: T, y: U) -> Self; +} + +struct S2 { + contents: int, +} + +impl Trait for S2 { + fn new(x: int, _: U) -> S2 { + S2 { + contents: x, + } + } +} + +fn main() { + let _ = S::new::(1, 1.0); //~ ERROR the impl referenced by this path has 1 type parameter, but 0 type parameters were supplied + let _ = S::<'self,int>::new::(1, 1.0); //~ ERROR this impl has no lifetime parameter + let _: S2 = Trait::new::(1, 1.0); //~ ERROR the trait referenced by this path has 1 type parameter, but 0 type parameters were supplied + let _: S2 = Trait::<'self,int>::new::(1, 1.0); //~ ERROR this trait has no lifetime parameter +} + diff --git a/src/test/compile-fail/issue-4096.rs b/src/test/compile-fail/issue-4096.rs deleted file mode 100644 index 3f1172b6de8f6..0000000000000 --- a/src/test/compile-fail/issue-4096.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2013 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub trait Nummy { - fn from_inty() -> Self; -} - -impl Nummy for float { - fn from_inty() -> float { 0.0 } -} - -fn main() { - let _1:float = Nummy::from_inty::(); //~ ERROR not enough type - //~^ NOTE Static methods have an extra implicit type parameter -} diff --git a/src/test/compile-fail/prim-with-args.rs b/src/test/compile-fail/prim-with-args.rs index 40d5a44124177..e60fbf4fc49a8 100644 --- a/src/test/compile-fail/prim-with-args.rs +++ b/src/test/compile-fail/prim-with-args.rs @@ -23,17 +23,17 @@ let x: u64; //~ ERROR type parameters are not allowed on this type let x: float; //~ ERROR type parameters are not allowed on this type let x: char; //~ ERROR type parameters are not allowed on this type -let x: int<'static>; //~ ERROR region parameters are not allowed on this type -let x: i8<'static>; //~ ERROR region parameters are not allowed on this type -let x: i16<'static>; //~ ERROR region parameters are not allowed on this type -let x: i32<'static>; //~ ERROR region parameters are not allowed on this type -let x: i64<'static>; //~ ERROR region parameters are not allowed on this type -let x: uint<'static>; //~ ERROR region parameters are not allowed on this type -let x: u8<'static>; //~ ERROR region parameters are not allowed on this type -let x: u16<'static>; //~ ERROR region parameters are not allowed on this type -let x: u32<'static>; //~ ERROR region parameters are not allowed on this type -let x: u64<'static>; //~ ERROR region parameters are not allowed on this type -let x: float<'static>; //~ ERROR region parameters are not allowed on this type -let x: char<'static>; //~ ERROR region parameters are not allowed on this type +let x: int<'static>; //~ ERROR lifetime parameters are not allowed on this type +let x: i8<'static>; //~ ERROR lifetime parameters are not allowed on this type +let x: i16<'static>; //~ ERROR lifetime parameters are not allowed on this type +let x: i32<'static>; //~ ERROR lifetime parameters are not allowed on this type +let x: i64<'static>; //~ ERROR lifetime parameters are not allowed on this type +let x: uint<'static>; //~ ERROR lifetime parameters are not allowed on this type +let x: u8<'static>; //~ ERROR lifetime parameters are not allowed on this type +let x: u16<'static>; //~ ERROR lifetime parameters are not allowed on this type +let x: u32<'static>; //~ ERROR lifetime parameters are not allowed on this type +let x: u64<'static>; //~ ERROR lifetime parameters are not allowed on this type +let x: float<'static>; //~ ERROR lifetime parameters are not allowed on this type +let x: char<'static>; //~ ERROR lifetime parameters are not allowed on this type } diff --git a/src/test/compile-fail/regions-bounds.rs b/src/test/compile-fail/regions-bounds.rs index ab2ac6cc0e5b9..ab365c1bf6fb3 100644 --- a/src/test/compile-fail/regions-bounds.rs +++ b/src/test/compile-fail/regions-bounds.rs @@ -25,8 +25,4 @@ fn a_fn3<'a,'b>(e: a_class<'a>) -> a_class<'b> { //~^ ERROR cannot infer an appropriate lifetime } -fn a_fn4<'a,'b>() { - let _: int<'a> = 1; //~ ERROR region parameters are not allowed on this type -} - fn main() { } diff --git a/src/test/compile-fail/static-method-privacy.rs b/src/test/compile-fail/static-method-privacy.rs index 0fd82b5ace3a7..b637037f60e8f 100644 --- a/src/test/compile-fail/static-method-privacy.rs +++ b/src/test/compile-fail/static-method-privacy.rs @@ -6,5 +6,5 @@ mod a { } fn main() { - let _ = a::S::new(); //~ ERROR function `new` is private + let _ = a::S::new(); //~ ERROR method `new` is private } diff --git a/src/test/run-pass/borrowck-pat-enum.rs b/src/test/run-pass/borrowck-pat-enum.rs index 6c00bea28b6e3..f320de39c8c3b 100644 --- a/src/test/run-pass/borrowck-pat-enum.rs +++ b/src/test/run-pass/borrowck-pat-enum.rs @@ -1,3 +1,5 @@ +// xfail-pretty + // Copyright 2012 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. diff --git a/src/test/run-pass/deriving-zero.rs b/src/test/run-pass/deriving-zero.rs index 54895d1796f40..1dfb03f3c783b 100644 --- a/src/test/run-pass/deriving-zero.rs +++ b/src/test/run-pass/deriving-zero.rs @@ -38,5 +38,6 @@ struct Lots { } fn main() { - assert!(Zero::zero::().is_zero()); + let lots: Lots = Zero::zero(); + assert!(lots.is_zero()); } diff --git a/src/test/run-pass/float-nan.rs b/src/test/run-pass/float-nan.rs index 29a180db1855d..d59b8c77d0067 100644 --- a/src/test/run-pass/float-nan.rs +++ b/src/test/run-pass/float-nan.rs @@ -13,11 +13,12 @@ extern mod extra; use std::num::Float; pub fn main() { - let nan = Float::NaN::(); + let nan: float = Float::NaN(); assert!((nan).is_NaN()); - let inf = Float::infinity::(); - assert_eq!(-inf, Float::neg_infinity::()); + let inf: float = Float::infinity(); + let neg_inf: float = Float::neg_infinity(); + assert_eq!(-inf, neg_inf); assert!( nan != nan); assert!( nan != -nan); diff --git a/src/test/run-pass/mid-path-type-params.rs b/src/test/run-pass/mid-path-type-params.rs index 8f01bd5e5eacf..1bc37a035e046 100644 --- a/src/test/run-pass/mid-path-type-params.rs +++ b/src/test/run-pass/mid-path-type-params.rs @@ -10,7 +10,24 @@ impl S { } } +trait Trait { + fn new(x: T, y: U) -> Self; +} + +struct S2 { + contents: int, +} + +impl Trait for S2 { + fn new(x: int, _: U) -> S2 { + S2 { + contents: x, + } + } +} + fn main() { let _ = S::::new::(1, 1.0); + let _: S2 = Trait::::new::(1, 1.0); } diff --git a/src/test/run-pass/trait-default-method-xc.rs b/src/test/run-pass/trait-default-method-xc.rs index 38b386838a1b4..9b7ff287e3c03 100644 --- a/src/test/run-pass/trait-default-method-xc.rs +++ b/src/test/run-pass/trait-default-method-xc.rs @@ -59,7 +59,7 @@ fn main () { assert_eq!(0i.thing(3.14, 1), (3.14, 1)); assert_eq!(B::staticthing(&0i, 3.14, 1), (3.14, 1)); - assert_eq!(B::staticthing::(&0i, 3.14, 1), (3.14, 1)); + assert_eq!(B::::staticthing::(&0i, 3.14, 1), (3.14, 1)); assert_eq!(g(0i, 3.14, 1), (3.14, 1)); assert_eq!(g(false, 3.14, 1), (3.14, 1)); diff --git a/src/test/run-pass/trait-static-method-overwriting.rs b/src/test/run-pass/trait-static-method-overwriting.rs index 1f5c33e2bc097..b79c97c6fbbb8 100644 --- a/src/test/run-pass/trait-static-method-overwriting.rs +++ b/src/test/run-pass/trait-static-method-overwriting.rs @@ -14,7 +14,7 @@ mod base { use std::io; pub trait HasNew { - fn new() -> T; + fn new() -> Self; } pub struct Foo { @@ -41,6 +41,6 @@ mod base { } pub fn main() { - let f: base::Foo = base::HasNew::new::(); - let b: base::Bar = base::HasNew::new::(); + let f: base::Foo = base::HasNew::::new(); + let b: base::Bar = base::HasNew::::new(); } From 5267100f1ff71860e980c15ffa55e052c018fd59 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 16 Aug 2013 13:55:34 -0700 Subject: [PATCH 04/16] librustc: Port region resolution to the new visitor --- src/librustc/middle/region.rs | 576 +++++++++++++++++----------------- 1 file changed, 280 insertions(+), 296 deletions(-) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 6fcc2a2d460c7..01b1b4c3e4e99 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -34,7 +34,10 @@ use syntax::codemap::span; use syntax::print::pprust; use syntax::parse::token; use syntax::parse::token::special_idents; -use syntax::{ast, oldvisit}; +use syntax::ast; +use syntax::oldvisit; +use syntax::visit::Visitor; +use syntax::visit; /** The region maps encode information about region relationships. @@ -323,147 +326,142 @@ fn parent_to_expr(cx: Context, child_id: ast::NodeId, sp: span) { } } -fn resolve_block(blk: &ast::Block, - (cx, visitor): (Context, oldvisit::vt)) { - // Record the parent of this block. - parent_to_expr(cx, blk.id, blk.span); - - // Descend. - let new_cx = Context {var_parent: Some(blk.id), - parent: Some(blk.id), - ..cx}; - oldvisit::visit_block(blk, (new_cx, visitor)); +struct RegionVisitor { + contents: (), } -fn resolve_arm(arm: &ast::arm, - (cx, visitor): (Context, oldvisit::vt)) { - oldvisit::visit_arm(arm, (cx, visitor)); -} +impl Visitor for RegionVisitor { + fn visit_block(&mut self, blk: &ast::Block, cx: Context) { + // Record the parent of this block. + parent_to_expr(cx, blk.id, blk.span); -fn resolve_pat(pat: @ast::pat, - (cx, visitor): (Context, oldvisit::vt)) { - assert_eq!(cx.var_parent, cx.parent); - parent_to_expr(cx, pat.id, pat.span); - oldvisit::visit_pat(pat, (cx, visitor)); -} - -fn resolve_stmt(stmt: @ast::stmt, - (cx, visitor): (Context, oldvisit::vt)) { - match stmt.node { - ast::stmt_decl(*) => { - oldvisit::visit_stmt(stmt, (cx, visitor)); - } - ast::stmt_expr(_, stmt_id) | - ast::stmt_semi(_, stmt_id) => { - parent_to_expr(cx, stmt_id, stmt.span); - let expr_cx = Context {parent: Some(stmt_id), ..cx}; - oldvisit::visit_stmt(stmt, (expr_cx, visitor)); - } - ast::stmt_mac(*) => cx.sess.bug("unexpanded macro") + // Descend. + let new_cx = Context {var_parent: Some(blk.id), + parent: Some(blk.id), + ..cx}; + visit::walk_block(self, blk, new_cx); } -} -fn resolve_expr(expr: @ast::expr, - (cx, visitor): (Context, oldvisit::vt)) { - parent_to_expr(cx, expr.id, expr.span); - - let mut new_cx = cx; - new_cx.parent = Some(expr.id); - match expr.node { - ast::expr_assign_op(*) | ast::expr_index(*) | ast::expr_binary(*) | - ast::expr_unary(*) | ast::expr_call(*) | ast::expr_method_call(*) => { - // FIXME(#6268) Nested method calls - // - // The lifetimes for a call or method call look as follows: - // - // call.id - // - arg0.id - // - ... - // - argN.id - // - call.callee_id - // - // The idea is that call.callee_id represents *the time when - // the invoked function is actually running* and call.id - // represents *the time to prepare the arguments and make the - // call*. See the section "Borrows in Calls" borrowck/doc.rs - // for an extended explanantion of why this distinction is - // important. - // - // parent_to_expr(new_cx, expr.callee_id); - } + fn visit_pat(&mut self, pat: @ast::pat, cx: Context) { + assert_eq!(cx.var_parent, cx.parent); + parent_to_expr(cx, pat.id, pat.span); + visit::walk_pat(self, pat, cx); + } - ast::expr_match(*) => { - new_cx.var_parent = Some(expr.id); + fn visit_stmt(&mut self, stmt: @ast::stmt, cx: Context) { + match stmt.node { + ast::stmt_decl(*) => { + visit::walk_stmt(self, stmt, cx); + } + ast::stmt_expr(_, stmt_id) | + ast::stmt_semi(_, stmt_id) => { + parent_to_expr(cx, stmt_id, stmt.span); + let expr_cx = Context {parent: Some(stmt_id), ..cx}; + visit::walk_stmt(self, stmt, expr_cx); + } + ast::stmt_mac(*) => cx.sess.bug("unexpanded macro") } + } - _ => {} - }; - - - oldvisit::visit_expr(expr, (new_cx, visitor)); -} + fn visit_expr(&mut self, expr: @ast::expr, cx: Context) { + parent_to_expr(cx, expr.id, expr.span); + + let mut new_cx = cx; + new_cx.parent = Some(expr.id); + match expr.node { + ast::expr_assign_op(*) | ast::expr_index(*) | ast::expr_binary(*) | + ast::expr_unary(*) | ast::expr_call(*) + | ast::expr_method_call(*) => { + // FIXME(#6268) Nested method calls + // + // The lifetimes for a call or method call look as follows: + // + // call.id + // - arg0.id + // - ... + // - argN.id + // - call.callee_id + // + // The idea is that call.callee_id represents *the time when + // the invoked function is actually running* and call.id + // represents *the time to prepare the arguments and make the + // call*. See the section "Borrows in Calls" borrowck/doc.rs + // for an extended explanantion of why this distinction is + // important. + // + // parent_to_expr(new_cx, expr.callee_id); + } -fn resolve_local(local: @ast::Local, - (cx, visitor): (Context, oldvisit::vt)) { - assert_eq!(cx.var_parent, cx.parent); - parent_to_expr(cx, local.id, local.span); - oldvisit::visit_local(local, (cx, visitor)); -} + ast::expr_match(*) => { + new_cx.var_parent = Some(expr.id); + } -fn resolve_item(item: @ast::item, - (cx, visitor): (Context, oldvisit::vt)) { - // Items create a new outer block scope as far as we're concerned. - let new_cx = Context {var_parent: None, parent: None, ..cx}; - oldvisit::visit_item(item, (new_cx, visitor)); -} + _ => {} + }; -fn resolve_fn(fk: &oldvisit::fn_kind, - decl: &ast::fn_decl, - body: &ast::Block, - sp: span, - id: ast::NodeId, - (cx, visitor): (Context, - oldvisit::vt)) { - debug!("region::resolve_fn(id=%?, \ - span=%?, \ - body.id=%?, \ - cx.parent=%?)", - id, - cx.sess.codemap.span_to_str(sp), - body.id, - cx.parent); - - // The arguments and `self` are parented to the body of the fn. - let decl_cx = Context {parent: Some(body.id), - var_parent: Some(body.id), - ..cx}; - match *fk { - oldvisit::fk_method(_, _, method) => { - cx.region_maps.record_parent(method.self_id, body.id); + visit::walk_expr(self, expr, new_cx); + } + + fn visit_local(&mut self, local: @ast::Local, cx: Context) { + assert_eq!(cx.var_parent, cx.parent); + parent_to_expr(cx, local.id, local.span); + visit::walk_local(self, local, cx); + } + + fn visit_item(&mut self, item: @ast::item, cx: Context) { + // Items create a new outer block scope as far as we're concerned. + let new_cx = Context {var_parent: None, parent: None, ..cx}; + visit::walk_item(self, item, new_cx); + } + + fn visit_fn(&mut self, + fk: &visit::fn_kind, + decl: &ast::fn_decl, + body: &ast::Block, + sp: span, + id: ast::NodeId, + cx: Context) { + debug!("region::resolve_fn(id=%?, \ + span=%?, \ + body.id=%?, \ + cx.parent=%?)", + id, + cx.sess.codemap.span_to_str(sp), + body.id, + cx.parent); + + // The arguments and `self` are parented to the body of the fn. + let decl_cx = Context {parent: Some(body.id), + var_parent: Some(body.id), + ..cx}; + match *fk { + visit::fk_method(_, _, method) => { + cx.region_maps.record_parent(method.self_id, body.id); + } + _ => {} } - _ => {} - } - oldvisit::visit_fn_decl(decl, (decl_cx, visitor)); + visit::walk_fn_decl(self, decl, decl_cx); + + // The body of the fn itself is either a root scope (top-level fn) + // or it continues with the inherited scope (closures). + let body_cx = match *fk { + visit::fk_item_fn(*) | + visit::fk_method(*) => { + Context {parent: None, var_parent: None, ..cx} + } + visit::fk_anon(*) | + visit::fk_fn_block(*) => { + cx + } + }; - // The body of the fn itself is either a root scope (top-level fn) - // or it continues with the inherited scope (closures). - let body_cx = match *fk { - oldvisit::fk_item_fn(*) | - oldvisit::fk_method(*) => { - Context {parent: None, var_parent: None, ..cx} - } - oldvisit::fk_anon(*) | - oldvisit::fk_fn_block(*) => { - cx - } - }; - (visitor.visit_block)(body, (body_cx, visitor)); + self.visit_block(body, body_cx); + } } pub fn resolve_crate(sess: Session, def_map: resolve::DefMap, - crate: &ast::Crate) -> @mut RegionMaps -{ + crate: &ast::Crate) -> @mut RegionMaps { let region_maps = @mut RegionMaps { scope_map: HashMap::new(), free_region_map: HashMap::new(), @@ -474,18 +472,10 @@ pub fn resolve_crate(sess: Session, region_maps: region_maps, parent: None, var_parent: None}; - let visitor = oldvisit::mk_vt(@oldvisit::Visitor { - visit_block: resolve_block, - visit_item: resolve_item, - visit_fn: resolve_fn, - visit_arm: resolve_arm, - visit_pat: resolve_pat, - visit_stmt: resolve_stmt, - visit_expr: resolve_expr, - visit_local: resolve_local, - .. *oldvisit::default_visitor() - }); - oldvisit::visit_crate(crate, (cx, visitor)); + let mut visitor = RegionVisitor { + contents: () + }; + visit::walk_crate(&mut visitor, crate, cx); return region_maps; } @@ -673,10 +663,10 @@ impl DetermineRpCtxt { } } - pub fn with(@mut self, + pub fn with(&mut self, item_id: ast::NodeId, anon_implies_rp: bool, - f: &fn()) { + f: &fn(&mut DetermineRpCtxt)) { let old_item_id = self.item_id; let old_anon_implies_rp = self.anon_implies_rp; self.item_id = item_id; @@ -685,203 +675,205 @@ impl DetermineRpCtxt { item_id, anon_implies_rp); let _i = ::util::common::indenter(); - f(); + f(self); self.item_id = old_item_id; self.anon_implies_rp = old_anon_implies_rp; } - pub fn with_ambient_variance(@mut self, + pub fn with_ambient_variance(&mut self, variance: region_variance, - f: &fn()) { + f: &fn(&mut DetermineRpCtxt)) { let old_ambient_variance = self.ambient_variance; self.ambient_variance = self.add_variance(variance); - f(); + f(self); self.ambient_variance = old_ambient_variance; } } -fn determine_rp_in_item(item: @ast::item, - (cx, visitor): (@mut DetermineRpCtxt, - oldvisit::vt<@mut DetermineRpCtxt>)) { - do cx.with(item.id, true) { - oldvisit::visit_item(item, (cx, visitor)); +impl DetermineRpCtxt { + fn visit_mt(&mut self, mt: &ast::mt, _: ()) { + // mutability is invariant + if mt.mutbl == ast::m_mutbl { + do self.with_ambient_variance(rv_invariant) |this| { + this.visit_ty(mt.ty, ()); + } + } else { + self.visit_ty(mt.ty, ()); + } } } -fn determine_rp_in_fn(fk: &oldvisit::fn_kind, - decl: &ast::fn_decl, - body: &ast::Block, - _: span, - _: ast::NodeId, - (cx, visitor): (@mut DetermineRpCtxt, - oldvisit::vt<@mut DetermineRpCtxt>)) { - do cx.with(cx.item_id, false) { - do cx.with_ambient_variance(rv_contravariant) { - for a in decl.inputs.iter() { - (visitor.visit_ty)(&a.ty, (cx, visitor)); +impl Visitor<()> for DetermineRpCtxt { + fn visit_item(&mut self, item: @ast::item, _: ()) { + do self.with(item.id, true) |this| { + visit::walk_item(this, item, ()); + } + } + + fn visit_fn(&mut self, + fk: &visit::fn_kind, + decl: &ast::fn_decl, + body: &ast::Block, + _: span, + _: ast::NodeId, + _: ()) { + do self.with(self.item_id, false) |this| { + do this.with_ambient_variance(rv_contravariant) |this| { + for a in decl.inputs.iter() { + this.visit_ty(&a.ty, ()); + } } + this.visit_ty(&decl.output, ()); + let generics = visit::generics_of_fn(fk); + this.visit_generics(&generics, ()); + this.visit_block(body, ()); } - (visitor.visit_ty)(&decl.output, (cx, visitor)); - let generics = oldvisit::generics_of_fn(fk); - (visitor.visit_generics)(&generics, (cx, visitor)); - (visitor.visit_block)(body, (cx, visitor)); } -} -fn determine_rp_in_ty_method(ty_m: &ast::TypeMethod, - (cx, visitor): - (@mut DetermineRpCtxt, - oldvisit::vt<@mut DetermineRpCtxt>)) { - do cx.with(cx.item_id, false) { - oldvisit::visit_ty_method(ty_m, (cx, visitor)); + fn visit_ty_method(&mut self, + ty_m: &ast::TypeMethod, + _: ()) { + do self.with(self.item_id, false) |this| { + visit::walk_ty_method(this, ty_m, ()); + } } -} -fn determine_rp_in_ty(ty: &ast::Ty, - (cx, visitor): (@mut DetermineRpCtxt, - oldvisit::vt<@mut DetermineRpCtxt>)) { - // we are only interested in types that will require an item to - // be region-parameterized. if cx.item_id is zero, then this type - // is not a member of a type defn nor is it a constitutent of an - // impl etc. So we can ignore it and its components. - if cx.item_id == 0 { return; } - - // if this type directly references a region pointer like &'r ty, - // add to the worklist/set. Note that &'r ty is contravariant with - // respect to &r, because &'r ty can be used whereever a *smaller* - // region is expected (and hence is a supertype of those - // locations) - let sess = cx.sess; - match ty.node { - ast::ty_rptr(ref r, _) => { - debug!("referenced rptr type %s", - pprust::ty_to_str(ty, sess.intr())); - - if cx.region_is_relevant(r) { - let rv = cx.add_variance(rv_contravariant); - cx.add_rp(cx.item_id, rv) - } + fn visit_ty(&mut self, ty: &ast::Ty, _: ()) { + // we are only interested in types that will require an item to + // be region-parameterized. if cx.item_id is zero, then this type + // is not a member of a type defn nor is it a constitutent of an + // impl etc. So we can ignore it and its components. + if self.item_id == 0 { + return; } - ast::ty_closure(ref f) => { - debug!("referenced fn type: %s", - pprust::ty_to_str(ty, sess.intr())); - match f.region { - Some(_) => { - if cx.region_is_relevant(&f.region) { - let rv = cx.add_variance(rv_contravariant); - cx.add_rp(cx.item_id, rv) - } + // if this type directly references a region pointer like &'r ty, + // add to the worklist/set. Note that &'r ty is contravariant with + // respect to &r, because &'r ty can be used whereever a *smaller* + // region is expected (and hence is a supertype of those + // locations) + let sess = self.sess; + match ty.node { + ast::ty_rptr(ref r, _) => { + debug!("referenced rptr type %s", + pprust::ty_to_str(ty, sess.intr())); + + if self.region_is_relevant(r) { + let rv = self.add_variance(rv_contravariant); + self.add_rp(self.item_id, rv) } - None => { - if f.sigil == ast::BorrowedSigil && cx.anon_implies_rp { - let rv = cx.add_variance(rv_contravariant); - cx.add_rp(cx.item_id, rv) + } + + ast::ty_closure(ref f) => { + debug!("referenced fn type: %s", + pprust::ty_to_str(ty, sess.intr())); + match f.region { + Some(_) => { + if self.region_is_relevant(&f.region) { + let rv = self.add_variance(rv_contravariant); + self.add_rp(self.item_id, rv) + } + } + None => { + if f.sigil == ast::BorrowedSigil && + self.anon_implies_rp { + let rv = self.add_variance(rv_contravariant); + self.add_rp(self.item_id, rv) + } } } } + + _ => {} } - _ => {} - } - - // if this references another named type, add the dependency - // to the dep_map. If the type is not defined in this crate, - // then check whether it is region-parameterized and consider - // that as a direct dependency. - match ty.node { - ast::ty_path(ref path, _, id) => { - match cx.def_map.find(&id) { - Some(&ast::def_ty(did)) | - Some(&ast::def_trait(did)) | - Some(&ast::def_struct(did)) => { - if did.crate == ast::LOCAL_CRATE { - if cx.region_is_relevant(&path.segments.last().lifetime) { - cx.add_dep(did.node); - } - } else { - let cstore = sess.cstore; - match csearch::get_region_param(cstore, did) { - None => {} - Some(variance) => { - debug!("reference to external, rp'd type %s", - pprust::ty_to_str(ty, sess.intr())); - if cx.region_is_relevant(&path.segments.last().lifetime) { - let rv = cx.add_variance(variance); - cx.add_rp(cx.item_id, rv) + // if this references another named type, add the dependency + // to the dep_map. If the type is not defined in this crate, + // then check whether it is region-parameterized and consider + // that as a direct dependency. + match ty.node { + ast::ty_path(ref path, _, id) => { + match self.def_map.find(&id) { + Some(&ast::def_ty(did)) | + Some(&ast::def_trait(did)) | + Some(&ast::def_struct(did)) => { + if did.crate == ast::LOCAL_CRATE { + if self.region_is_relevant(&path.segments + .last() + .lifetime) { + self.add_dep(did.node); + } + } else { + let cstore = sess.cstore; + match csearch::get_region_param(cstore, did) { + None => {} + Some(variance) => { + debug!("reference to external, rp'd type %s", + pprust::ty_to_str(ty, sess.intr())); + if self.region_is_relevant(&path.segments + .last() + .lifetime) { + let rv = self.add_variance(variance); + self.add_rp(self.item_id, rv) + } + } } - } } + } + _ => {} } } _ => {} } - } - _ => {} - } - match ty.node { - ast::ty_box(ref mt) | ast::ty_uniq(ref mt) | ast::ty_vec(ref mt) | - ast::ty_rptr(_, ref mt) | ast::ty_ptr(ref mt) => { - visit_mt(mt, (cx, visitor)); - } + match ty.node { + ast::ty_box(ref mt) | ast::ty_uniq(ref mt) | ast::ty_vec(ref mt) | + ast::ty_rptr(_, ref mt) | ast::ty_ptr(ref mt) => { + self.visit_mt(mt, ()); + } - ast::ty_path(ref path, _, _) => { - // type parameters are---for now, anyway---always invariant - do cx.with_ambient_variance(rv_invariant) { - for tp in path.segments.iter().flat_map(|s| s.types.iter()) { - (visitor.visit_ty)(tp, (cx, visitor)); + ast::ty_path(ref path, _, _) => { + // type parameters are---for now, anyway---always invariant + do self.with_ambient_variance(rv_invariant) |this| { + for tp in path.segments.iter().flat_map(|s| s.types.iter()) { + this.visit_ty(tp, ()); + } } - } - } - - ast::ty_closure(@ast::TyClosure {decl: ref decl, _}) | - ast::ty_bare_fn(@ast::TyBareFn {decl: ref decl, _}) => { - // fn() binds the & region, so do not consider &T types that - // appear *inside* a fn() type to affect the enclosing item: - do cx.with(cx.item_id, false) { - // parameters are contravariant - do cx.with_ambient_variance(rv_contravariant) { - for a in decl.inputs.iter() { - (visitor.visit_ty)(&a.ty, (cx, visitor)); + } + + ast::ty_closure(@ast::TyClosure {decl: ref decl, _}) | + ast::ty_bare_fn(@ast::TyBareFn {decl: ref decl, _}) => { + // fn() binds the & region, so do not consider &T types that + // appear *inside* a fn() type to affect the enclosing item: + do self.with(self.item_id, false) |this| { + // parameters are contravariant + do this.with_ambient_variance(rv_contravariant) |this| { + for a in decl.inputs.iter() { + this.visit_ty(&a.ty, ()); + } } + this.visit_ty(&decl.output, ()); } - (visitor.visit_ty)(&decl.output, (cx, visitor)); + } + + _ => { + visit::walk_ty(self, ty, ()); + } } - } - _ => { - oldvisit::visit_ty(ty, (cx, visitor)); - } } - fn visit_mt(mt: &ast::mt, - (cx, visitor): (@mut DetermineRpCtxt, - oldvisit::vt<@mut DetermineRpCtxt>)) { - // mutability is invariant - if mt.mutbl == ast::m_mutbl { - do cx.with_ambient_variance(rv_invariant) { - (visitor.visit_ty)(mt.ty, (cx, visitor)); - } - } else { - (visitor.visit_ty)(mt.ty, (cx, visitor)); - } + fn visit_struct_field(&mut self, cm: @ast::struct_field, _: ()) { + visit::walk_struct_field(self, cm, ()); } } -fn determine_rp_in_struct_field( - cm: @ast::struct_field, - (cx, visitor): (@mut DetermineRpCtxt, - oldvisit::vt<@mut DetermineRpCtxt>)) { - oldvisit::visit_struct_field(cm, (cx, visitor)); -} - pub fn determine_rp_in_crate(sess: Session, ast_map: ast_map::map, def_map: resolve::DefMap, crate: &ast::Crate) - -> region_paramd_items { - let cx = @mut DetermineRpCtxt { + -> region_paramd_items { + let mut cx = DetermineRpCtxt { sess: sess, ast_map: ast_map, def_map: def_map, @@ -894,15 +886,7 @@ pub fn determine_rp_in_crate(sess: Session, }; // Gather up the base set, worklist and dep_map - let visitor = oldvisit::mk_vt(@oldvisit::Visitor { - visit_fn: determine_rp_in_fn, - visit_item: determine_rp_in_item, - visit_ty: determine_rp_in_ty, - visit_ty_method: determine_rp_in_ty_method, - visit_struct_field: determine_rp_in_struct_field, - .. *oldvisit::default_visitor() - }); - oldvisit::visit_crate(crate, (cx, visitor)); + visit::walk_crate(&mut cx, crate, ()); // Propagate indirect dependencies // @@ -914,7 +898,7 @@ pub fn determine_rp_in_crate(sess: Session, // with the ambient variance where the reference occurred and then // update the region-parameterization of D to reflect the result. { - let cx = &mut *cx; + let cx = &mut cx; while cx.worklist.len() != 0 { let c_id = cx.worklist.pop(); let c_variance = cx.region_paramd_items.get_copy(&c_id); From a953a4c4002a637fc37dcc26d3daeb2b1db0c9dc Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 16 Aug 2013 14:31:20 -0700 Subject: [PATCH 05/16] librustc: Remove the old visitor from the crate reader. --- src/librustc/metadata/creader.rs | 190 ++++++++++++++++--------------- src/libsyntax/visit.rs | 49 ++++---- 2 files changed, 127 insertions(+), 112 deletions(-) diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index c8c4a396c87af..30d1de0f2c810 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -25,7 +25,8 @@ use syntax::codemap::{span, dummy_sp}; use syntax::diagnostic::span_handler; use syntax::parse::token; use syntax::parse::token::ident_interner; -use syntax::oldvisit; +use syntax::visit::SimpleVisitor; +use syntax::visit; // Traverses an AST, reading all the information about use'd crates and extern // libraries necessary for later resolving, typechecking, linking, etc. @@ -46,13 +47,11 @@ pub fn read_crates(diag: @mut span_handler, next_crate_num: 1, intr: intr }; - let v = - oldvisit::mk_simple_visitor(@oldvisit::SimpleVisitor { - visit_view_item: |a| visit_view_item(e, a), - visit_item: |a| visit_item(e, a), - .. *oldvisit::default_simple_visitor()}); - visit_crate(e, crate); - oldvisit::visit_crate(crate, ((), v)); + e.visit_crate(crate); + let mut visitor = visit::SimpleVisitorVisitor { + simple_visitor: e as @mut SimpleVisitor, + }; + visit::walk_crate(&mut visitor, crate, ()); dump_crates(*e.crate_cache); warn_if_multiple_versions(e, diag, *e.crate_cache); } @@ -115,103 +114,110 @@ struct Env { intr: @ident_interner } -fn visit_crate(e: &Env, c: &ast::Crate) { - let cstore = e.cstore; +impl Env { + fn visit_crate(&self, c: &ast::Crate) { + let cstore = self.cstore; - for a in c.attrs.iter().filter(|m| "link_args" == m.name()) { - match a.value_str() { - Some(ref linkarg) => { - cstore::add_used_link_args(cstore, *linkarg); - } - None => {/* fallthrough */ } + for a in c.attrs.iter().filter(|m| "link_args" == m.name()) { + match a.value_str() { + Some(ref linkarg) => { + cstore::add_used_link_args(cstore, *linkarg); + } + None => {/* fallthrough */ } + } } } } -fn visit_view_item(e: @mut Env, i: &ast::view_item) { - match i.node { - ast::view_item_extern_mod(ident, path_opt, ref meta_items, id) => { - let ident = token::ident_to_str(&ident); - let meta_items = match path_opt { - None => meta_items.clone(), - Some(p) => { - let p_path = Path(p); - match p_path.filestem() { - Some(s) => - vec::append( - ~[attr::mk_name_value_item_str(@"package_id", p), - attr::mk_name_value_item_str(@"name", s.to_managed())], - *meta_items), - None => e.diag.span_bug(i.span, "Bad package path in `extern mod` item") - } - } - }; - debug!("resolving extern mod stmt. ident: %?, meta: %?", - ident, meta_items); - let cnum = resolve_crate(e, - ident, - meta_items, - @"", - i.span); - cstore::add_extern_mod_stmt_cnum(e.cstore, id, cnum); + +impl SimpleVisitor for Env { + fn visit_view_item(&mut self, i: &ast::view_item) { + match i.node { + ast::view_item_extern_mod(ident, path_opt, ref meta_items, id) => { + let ident = token::ident_to_str(&ident); + let meta_items = match path_opt { + None => meta_items.clone(), + Some(p) => { + let p_path = Path(p); + match p_path.filestem() { + Some(s) => + vec::append( + ~[attr::mk_name_value_item_str(@"package_id", p), + attr::mk_name_value_item_str(@"name", s.to_managed())], + *meta_items), + None => self.diag.span_bug(i.span, "Bad package path in `extern mod` item") + } + } + }; + debug!("resolving extern mod stmt. ident: %?, meta: %?", + ident, meta_items); + let cnum = resolve_crate(self, + ident, + meta_items, + @"", + i.span); + cstore::add_extern_mod_stmt_cnum(self.cstore, id, cnum); + } + _ => () } - _ => () - } -} + } -fn visit_item(e: &Env, i: @ast::item) { - match i.node { - ast::item_foreign_mod(ref fm) => { - if fm.abis.is_rust() || fm.abis.is_intrinsic() { - return; - } + fn visit_item(&mut self, i: @ast::item) { + match i.node { + ast::item_foreign_mod(ref fm) => { + if fm.abis.is_rust() || fm.abis.is_intrinsic() { + return; + } - let cstore = e.cstore; - let mut already_added = false; - let link_args = i.attrs.iter() - .filter_map(|at| if "link_args" == at.name() {Some(at)} else {None}) - .collect::<~[&ast::Attribute]>(); - - match fm.sort { - ast::named => { - let link_name = i.attrs.iter() - .find(|at| "link_name" == at.name()) - .chain(|at| at.value_str()); - - let foreign_name = match link_name { - Some(nn) => { - if nn.is_empty() { - e.diag.span_fatal( - i.span, - "empty #[link_name] not allowed; use \ - #[nolink]."); + let cstore = self.cstore; + let mut already_added = false; + let link_args = i.attrs.iter() + .filter_map(|at| if "link_args" == at.name() {Some(at)} else {None}) + .collect::<~[&ast::Attribute]>(); + + match fm.sort { + ast::named => { + let link_name = i.attrs.iter() + .find(|at| "link_name" == at.name()) + .chain(|at| at.value_str()); + + let foreign_name = match link_name { + Some(nn) => { + if nn.is_empty() { + self.diag.span_fatal( + i.span, + "empty #[link_name] not allowed; use \ + #[nolink]."); + } + nn } - nn - } - None => token::ident_to_str(&i.ident) - }; - if !attr::contains_name(i.attrs, "nolink") { - already_added = - !cstore::add_used_library(cstore, foreign_name); - } - if !link_args.is_empty() && already_added { - e.diag.span_fatal(i.span, ~"library '" + foreign_name + - "' already added: can't specify link_args."); + None => token::ident_to_str(&i.ident) + }; + if !attr::contains_name(i.attrs, "nolink") { + already_added = + !cstore::add_used_library(cstore, foreign_name); + } + if !link_args.is_empty() && already_added { + self.diag.span_fatal(i.span, ~"library '" + + foreign_name + + "' already added: can't specify \ + link_args."); + } } + ast::anonymous => { /* do nothing */ } } - ast::anonymous => { /* do nothing */ } - } - for m in link_args.iter() { - match m.value_str() { - Some(linkarg) => { - cstore::add_used_link_args(cstore, linkarg); + for m in link_args.iter() { + match m.value_str() { + Some(linkarg) => { + cstore::add_used_link_args(cstore, linkarg); + } + None => { /* fallthrough */ } } - None => { /* fallthrough */ } } + } + _ => { } } - } - _ => { } } } @@ -240,7 +246,7 @@ fn existing_match(e: &Env, metas: &[@ast::MetaItem], hash: &str) return None; } -fn resolve_crate(e: @mut Env, +fn resolve_crate(e: &mut Env, ident: @str, metas: ~[@ast::MetaItem], hash: @str, @@ -308,7 +314,7 @@ fn resolve_crate(e: @mut Env, } // Go through the crate metadata and load any crates that it references -fn resolve_crate_deps(e: @mut Env, cdata: @~[u8]) -> cstore::cnum_map { +fn resolve_crate_deps(e: &mut Env, cdata: @~[u8]) -> cstore::cnum_map { debug!("resolving deps of external crate"); // The map from crate numbers in the crate we're resolving to local crate // numbers diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index e5b7823ae44ec..2a0630d332ca7 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -673,26 +673,35 @@ pub fn walk_arm>(visitor: &mut V, arm: &arm, env: E) { // calls the given functions on the nodes. pub trait SimpleVisitor { - fn visit_mod(&mut self, &_mod, span, NodeId); - fn visit_view_item(&mut self, &view_item); - fn visit_foreign_item(&mut self, @foreign_item); - fn visit_item(&mut self, @item); - fn visit_local(&mut self, @Local); - fn visit_block(&mut self, &Block); - fn visit_stmt(&mut self, @stmt); - fn visit_arm(&mut self, &arm); - fn visit_pat(&mut self, @pat); - fn visit_decl(&mut self, @decl); - fn visit_expr(&mut self, @expr); - fn visit_expr_post(&mut self, @expr); - fn visit_ty(&mut self, &Ty); - fn visit_generics(&mut self, &Generics); - fn visit_fn(&mut self, &fn_kind, &fn_decl, &Block, span, NodeId); - fn visit_ty_method(&mut self, &TypeMethod); - fn visit_trait_method(&mut self, &trait_method); - fn visit_struct_def(&mut self, @struct_def, ident, &Generics, NodeId); - fn visit_struct_field(&mut self, @struct_field); - fn visit_struct_method(&mut self, @method); + fn visit_mod(&mut self, _m: &_mod, _s: span, _n: NodeId) {} + fn visit_view_item(&mut self, _vi: &view_item) {} + fn visit_foreign_item(&mut self, _fi: @foreign_item) {} + fn visit_item(&mut self, _i: @item) {} + fn visit_local(&mut self, _l: @Local) {} + fn visit_block(&mut self, _b: &Block) {} + fn visit_stmt(&mut self, _s: @stmt) {} + fn visit_arm(&mut self, _a: &arm) {} + fn visit_pat(&mut self, _p: @pat) {} + fn visit_decl(&mut self, _d: @decl) {} + fn visit_expr(&mut self, _e: @expr) {} + fn visit_expr_post(&mut self, _e: @expr) {} + fn visit_ty(&mut self, _t: &Ty) {} + fn visit_generics(&mut self, _g: &Generics) {} + fn visit_fn(&mut self, + _fk: &fn_kind, + _fd: &fn_decl, + _b: &Block, + _s: span, + _n: NodeId) {} + fn visit_ty_method(&mut self, _t: &TypeMethod) {} + fn visit_trait_method(&mut self, _t: &trait_method) {} + fn visit_struct_def(&mut self, + _s: @struct_def, + _i: ident, + _g: &Generics, + _n: NodeId) {} + fn visit_struct_field(&mut self, _s: @struct_field) {} + fn visit_struct_method(&mut self, _m: @method) {} } pub struct SimpleVisitorVisitor { From 9e4ba0758e18c25e81d65acb08b92b9a052b8b9f Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 16 Aug 2013 15:06:00 -0700 Subject: [PATCH 06/16] librustc: Convert check loans to use the new visitor --- src/librustc/middle/borrowck/check_loans.rs | 280 +++++++++----------- 1 file changed, 129 insertions(+), 151 deletions(-) diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 975d13a1e63e2..ca49354f1d89d 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -27,7 +27,8 @@ use syntax::ast::m_mutbl; use syntax::ast; use syntax::ast_util; use syntax::codemap::span; -use syntax::oldvisit; +use syntax::visit::Visitor; +use syntax::visit; use util::ppaux::Repr; #[deriving(Clone)] @@ -39,6 +40,93 @@ struct CheckLoanCtxt<'self> { reported: @mut HashSet, } +impl<'self> Visitor<()> for CheckLoanCtxt<'self> { + fn visit_expr(&mut self, expr: @ast::expr, _: ()) { + visit::walk_expr(self, expr, ()); + + debug!("check_loans_in_expr(expr=%s)", expr.repr(self.tcx())); + + self.check_for_conflicting_loans(expr.id); + self.check_move_out_from_expr(expr); + + match expr.node { + ast::expr_self | + ast::expr_path(*) => { + if !self.move_data.is_assignee(expr.id) { + let cmt = self.bccx.cat_expr_unadjusted(expr); + debug!("path cmt=%s", cmt.repr(self.tcx())); + let r = opt_loan_path(cmt); + for &lp in r.iter() { + self.check_if_path_is_moved(expr.id, expr.span, MovedInUse, lp); + } + } + } + ast::expr_assign(dest, _) | + ast::expr_assign_op(_, _, dest, _) => { + self.check_assignment(dest); + } + ast::expr_call(f, ref args, _) => { + self.check_call(expr, Some(f), f.id, f.span, *args); + } + ast::expr_method_call(callee_id, _, _, _, ref args, _) => { + self.check_call(expr, None, callee_id, expr.span, *args); + } + ast::expr_index(callee_id, _, rval) | + ast::expr_binary(callee_id, _, _, rval) + if self.bccx.method_map.contains_key(&expr.id) => { + self.check_call(expr, + None, + callee_id, + expr.span, + [rval]); + } + ast::expr_unary(callee_id, _, _) | ast::expr_index(callee_id, _, _) + if self.bccx.method_map.contains_key(&expr.id) => { + self.check_call(expr, + None, + callee_id, + expr.span, + []); + } + _ => { } + } + } + + fn visit_pat(&mut self, pat: @ast::pat, _: ()) { + self.check_for_conflicting_loans(pat.id); + self.check_move_out_from_id(pat.id, pat.span); + visit::walk_pat(self, pat, ()); + } + + fn visit_fn(&mut self, + fk: &visit::fn_kind, + decl: &ast::fn_decl, + body: &ast::Block, + sp: span, + id: ast::NodeId, + _: ()) { + match *fk { + visit::fk_item_fn(*) | + visit::fk_method(*) => { + // Don't process nested items. + return; + } + + visit::fk_anon(*) | + visit::fk_fn_block(*) => { + self.check_captured_variables(id, sp); + } + } + + visit::walk_fn(self, fk, decl, body, sp, id, ()); + } + + fn visit_block(&mut self, blk: &ast::Block, _: ()) { + visit::walk_block(self, blk, ()); + self.check_for_conflicting_loans(blk.id); + } +} + pub fn check_loans(bccx: @BorrowckCtxt, dfcx_loans: &LoanDataFlow, move_data: move_data::FlowedMoveData, @@ -46,23 +134,14 @@ pub fn check_loans(bccx: @BorrowckCtxt, body: &ast::Block) { debug!("check_loans(body id=%?)", body.id); - let clcx = CheckLoanCtxt { + let mut clcx = CheckLoanCtxt { bccx: bccx, dfcx_loans: dfcx_loans, move_data: @move_data, all_loans: all_loans, reported: @mut HashSet::new(), }; - - let vt = oldvisit::mk_vt(@oldvisit::Visitor { - visit_expr: check_loans_in_expr, - visit_local: check_loans_in_local, - visit_block: check_loans_in_block, - visit_pat: check_loans_in_pat, - visit_fn: check_loans_in_fn, - .. *oldvisit::default_visitor() - }); - (vt.visit_block)(body, (clcx, vt)); + clcx.visit_block(body, ()); } enum MoveError { @@ -71,6 +150,44 @@ enum MoveError { } impl<'self> CheckLoanCtxt<'self> { + fn check_by_move_capture(&self, + closure_id: ast::NodeId, + cap_var: &moves::CaptureVar, + move_path: @LoanPath) { + let move_err = self.analyze_move_out_from(closure_id, move_path); + match move_err { + MoveOk => {} + MoveWhileBorrowed(loan_path, loan_span) => { + self.bccx.span_err( + cap_var.span, + fmt!("cannot move `%s` into closure \ + because it is borrowed", + self.bccx.loan_path_to_str(move_path))); + self.bccx.span_note( + loan_span, + fmt!("borrow of `%s` occurs here", + self.bccx.loan_path_to_str(loan_path))); + } + } + } + + fn check_captured_variables(&self, closure_id: ast::NodeId, span: span) { + let cap_vars = self.bccx.capture_map.get(&closure_id); + for cap_var in cap_vars.iter() { + let var_id = ast_util::def_id_of_def(cap_var.def).node; + let var_path = @LpVar(var_id); + self.check_if_path_is_moved(closure_id, span, + MovedInCapture, var_path); + match cap_var.mode { + moves::CapRef | moves::CapCopy => {} + moves::CapMove => { + self.check_by_move_capture(closure_id, cap_var, var_path); + } + } + } + return; + } + pub fn tcx(&self) -> ty::ctxt { self.bccx.tcx } pub fn each_issued_loan(&self, @@ -628,142 +745,3 @@ impl<'self> CheckLoanCtxt<'self> { } } -fn check_loans_in_fn<'a>(fk: &oldvisit::fn_kind, - decl: &ast::fn_decl, - body: &ast::Block, - sp: span, - id: ast::NodeId, - (this, visitor): (CheckLoanCtxt<'a>, - oldvisit::vt>)) { - match *fk { - oldvisit::fk_item_fn(*) | - oldvisit::fk_method(*) => { - // Don't process nested items. - return; - } - - oldvisit::fk_anon(*) | - oldvisit::fk_fn_block(*) => { - check_captured_variables(this, id, sp); - } - } - - oldvisit::visit_fn(fk, decl, body, sp, id, (this, visitor)); - - fn check_captured_variables(this: CheckLoanCtxt, - closure_id: ast::NodeId, - span: span) { - let cap_vars = this.bccx.capture_map.get(&closure_id); - for cap_var in cap_vars.iter() { - let var_id = ast_util::def_id_of_def(cap_var.def).node; - let var_path = @LpVar(var_id); - this.check_if_path_is_moved(closure_id, span, - MovedInCapture, var_path); - match cap_var.mode { - moves::CapRef | moves::CapCopy => {} - moves::CapMove => { - check_by_move_capture(this, closure_id, cap_var, var_path); - } - } - } - return; - - fn check_by_move_capture(this: CheckLoanCtxt, - closure_id: ast::NodeId, - cap_var: &moves::CaptureVar, - move_path: @LoanPath) { - let move_err = this.analyze_move_out_from(closure_id, move_path); - match move_err { - MoveOk => {} - MoveWhileBorrowed(loan_path, loan_span) => { - this.bccx.span_err( - cap_var.span, - fmt!("cannot move `%s` into closure \ - because it is borrowed", - this.bccx.loan_path_to_str(move_path))); - this.bccx.span_note( - loan_span, - fmt!("borrow of `%s` occurs here", - this.bccx.loan_path_to_str(loan_path))); - } - } - } - } -} - -fn check_loans_in_local<'a>(local: @ast::Local, - (this, vt): (CheckLoanCtxt<'a>, - oldvisit::vt>)) { - oldvisit::visit_local(local, (this, vt)); -} - -fn check_loans_in_expr<'a>(expr: @ast::expr, - (this, vt): (CheckLoanCtxt<'a>, - oldvisit::vt>)) { - oldvisit::visit_expr(expr, (this, vt)); - - debug!("check_loans_in_expr(expr=%s)", - expr.repr(this.tcx())); - - this.check_for_conflicting_loans(expr.id); - this.check_move_out_from_expr(expr); - - match expr.node { - ast::expr_self | - ast::expr_path(*) => { - if !this.move_data.is_assignee(expr.id) { - let cmt = this.bccx.cat_expr_unadjusted(expr); - debug!("path cmt=%s", cmt.repr(this.tcx())); - let r = opt_loan_path(cmt); - for &lp in r.iter() { - this.check_if_path_is_moved(expr.id, expr.span, MovedInUse, lp); - } - } - } - ast::expr_assign(dest, _) | - ast::expr_assign_op(_, _, dest, _) => { - this.check_assignment(dest); - } - ast::expr_call(f, ref args, _) => { - this.check_call(expr, Some(f), f.id, f.span, *args); - } - ast::expr_method_call(callee_id, _, _, _, ref args, _) => { - this.check_call(expr, None, callee_id, expr.span, *args); - } - ast::expr_index(callee_id, _, rval) | - ast::expr_binary(callee_id, _, _, rval) - if this.bccx.method_map.contains_key(&expr.id) => { - this.check_call(expr, - None, - callee_id, - expr.span, - [rval]); - } - ast::expr_unary(callee_id, _, _) | ast::expr_index(callee_id, _, _) - if this.bccx.method_map.contains_key(&expr.id) => { - this.check_call(expr, - None, - callee_id, - expr.span, - []); - } - _ => { } - } -} - -fn check_loans_in_pat<'a>(pat: @ast::pat, - (this, vt): (CheckLoanCtxt<'a>, - oldvisit::vt>)) -{ - this.check_for_conflicting_loans(pat.id); - this.check_move_out_from_id(pat.id, pat.span); - oldvisit::visit_pat(pat, (this, vt)); -} - -fn check_loans_in_block<'a>(blk: &ast::Block, - (this, vt): (CheckLoanCtxt<'a>, - oldvisit::vt>)) -{ - oldvisit::visit_block(blk, (this, vt)); - this.check_for_conflicting_loans(blk.id); -} From 5eb22747a7f7ed6e10baa01cc2ab822839a66972 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 16 Aug 2013 15:36:57 -0700 Subject: [PATCH 07/16] librustc: Port loop checking to the new scheduler --- src/librustc/middle/check_loop.rs | 104 +++++++++++++++++------------- 1 file changed, 58 insertions(+), 46 deletions(-) diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs index cbd1d3cd9ad81..bddf3b0038f86 100644 --- a/src/librustc/middle/check_loop.rs +++ b/src/librustc/middle/check_loop.rs @@ -12,7 +12,8 @@ use middle::ty; use syntax::ast::*; -use syntax::oldvisit; +use syntax::visit::Visitor; +use syntax::visit; #[deriving(Clone)] pub struct Context { @@ -20,50 +21,61 @@ pub struct Context { can_ret: bool } -pub fn check_crate(tcx: ty::ctxt, crate: &Crate) { - oldvisit::visit_crate(crate, - (Context { in_loop: false, can_ret: true }, - oldvisit::mk_vt(@oldvisit::Visitor { - visit_item: |i, (_cx, v)| { - oldvisit::visit_item(i, (Context { - in_loop: false, - can_ret: true - }, v)); - }, - visit_expr: |e: @expr, (cx, v): (Context, oldvisit::vt)| { - match e.node { - expr_while(e, ref b) => { - (v.visit_expr)(e, (cx, v)); - (v.visit_block)(b, (Context { in_loop: true,.. cx }, v)); - } - expr_loop(ref b, _) => { - (v.visit_block)(b, (Context { in_loop: true,.. cx }, v)); - } - expr_fn_block(_, ref b) => { - (v.visit_block)(b, (Context { - in_loop: false, - can_ret: false - }, v)); - } - expr_break(_) => { - if !cx.in_loop { - tcx.sess.span_err(e.span, "`break` outside of loop"); - } - } - expr_again(_) => { - if !cx.in_loop { - tcx.sess.span_err(e.span, "`loop` outside of loop"); - } - } - expr_ret(oe) => { - if !cx.can_ret { - tcx.sess.span_err(e.span, "`return` in block function"); - } - oldvisit::visit_expr_opt(oe, (cx, v)); - } - _ => oldvisit::visit_expr(e, (cx, v)) +struct LoopCheckingVisitor { + tcx: ty::ctxt, +} + +impl Visitor for LoopCheckingVisitor { + fn visit_item(&mut self, i: @item, _: Context) { + visit::walk_item(self, i, Context { + in_loop: false, + can_ret: true, + }); + } + + fn visit_expr(&mut self, e: @expr, cx: Context) { + match e.node { + expr_while(e, ref b) => { + self.visit_expr(e, cx); + self.visit_block(b, Context { in_loop: true,.. cx }); + } + expr_loop(ref b, _) => { + self.visit_block(b, Context { in_loop: true,.. cx }); + } + expr_fn_block(_, ref b) => { + self.visit_block(b, Context { + in_loop: false, + can_ret: false, + }); + } + expr_break(_) => { + if !cx.in_loop { + self.tcx.sess.span_err(e.span, "`break` outside of loop"); + } + } + expr_again(_) => { + if !cx.in_loop { + self.tcx.sess.span_err(e.span, "`loop` outside of loop"); } - }, - .. *oldvisit::default_visitor() - }))); + } + expr_ret(oe) => { + if !cx.can_ret { + self.tcx.sess.span_err(e.span, "`return` in block function"); + } + visit::walk_expr_opt(self, oe, cx); + } + _ => visit::walk_expr(self, e, cx) + } + } +} + +pub fn check_crate(tcx: ty::ctxt, crate: &Crate) { + let cx = Context { + in_loop: false, + can_ret: true, + }; + let mut visitor = LoopCheckingVisitor { + tcx: tcx, + }; + visit::walk_crate(&mut visitor, crate, cx); } From 60ddfe64f7d75289b779f1b92da5c0eddd5eb27c Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 16 Aug 2013 16:07:25 -0700 Subject: [PATCH 08/16] librustc: Partially port constant checking to the new visitor --- src/librustc/middle/check_const.rs | 330 +++++++++++++++-------------- 1 file changed, 175 insertions(+), 155 deletions(-) diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index ae3cb86ae5959..9d1fc5e68a14b 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -18,183 +18,203 @@ use util::ppaux; use syntax::ast::*; use syntax::codemap; use syntax::{oldvisit, ast_util, ast_map}; +use syntax::visit::Visitor; +use syntax::visit; -pub fn check_crate(sess: Session, - crate: &Crate, - ast_map: ast_map::map, - def_map: resolve::DefMap, - method_map: typeck::method_map, - tcx: ty::ctxt) { - oldvisit::visit_crate(crate, (false, oldvisit::mk_vt(@oldvisit::Visitor { - visit_item: |a,b| check_item(sess, ast_map, def_map, a, b), - visit_pat: check_pat, - visit_expr: |a,b| - check_expr(sess, def_map, method_map, tcx, a, b), - .. *oldvisit::default_visitor() - }))); - sess.abort_if_errors(); +struct ConstCheckingVisitor { + sess: Session, + ast_map: ast_map::map, + def_map: resolve::DefMap, + method_map: typeck::method_map, + tcx: ty::ctxt, } -pub fn check_item(sess: Session, - ast_map: ast_map::map, - def_map: resolve::DefMap, - it: @item, - (_is_const, v): (bool, - oldvisit::vt)) { - match it.node { - item_static(_, _, ex) => { - (v.visit_expr)(ex, (true, v)); - check_item_recursion(sess, ast_map, def_map, it); - } - item_enum(ref enum_definition, _) => { - for var in (*enum_definition).variants.iter() { - for ex in var.node.disr_expr.iter() { - (v.visit_expr)(*ex, (true, v)); +impl Visitor for ConstCheckingVisitor { + fn visit_item(&mut self, it: @item, _: bool) { + match it.node { + item_static(_, _, ex) => { + self.visit_expr(ex, true); + check_item_recursion(self.sess, self.ast_map, self.def_map, it); + } + item_enum(ref enum_definition, _) => { + for var in (*enum_definition).variants.iter() { + for ex in var.node.disr_expr.iter() { + self.visit_expr(*ex, true); + } } + } + _ => visit::walk_item(self, it, false) } - } - _ => oldvisit::visit_item(it, (false, v)) } -} -pub fn check_pat(p: @pat, (_is_const, v): (bool, oldvisit::vt)) { - fn is_str(e: @expr) -> bool { - match e.node { - expr_vstore( - @expr { node: expr_lit(@codemap::spanned { - node: lit_str(_), - _}), - _ }, - expr_vstore_uniq - ) => true, - _ => false + fn visit_pat(&mut self, p: @pat, _: bool) { + fn is_str(e: @expr) -> bool { + match e.node { + expr_vstore( + @expr { node: expr_lit(@codemap::spanned { + node: lit_str(_), + _}), + _ }, + expr_vstore_uniq + ) => true, + _ => false + } } - } - match p.node { - // Let through plain ~-string literals here - pat_lit(a) => if !is_str(a) { (v.visit_expr)(a, (true, v)); }, - pat_range(a, b) => { - if !is_str(a) { (v.visit_expr)(a, (true, v)); } - if !is_str(b) { (v.visit_expr)(b, (true, v)); } - } - _ => oldvisit::visit_pat(p, (false, v)) - } -} - -pub fn check_expr(sess: Session, - def_map: resolve::DefMap, - method_map: typeck::method_map, - tcx: ty::ctxt, - e: @expr, - (is_const, v): (bool, - oldvisit::vt)) { - if is_const { - match e.node { - expr_unary(_, deref, _) => { } - expr_unary(_, box(_), _) | expr_unary(_, uniq, _) => { - sess.span_err(e.span, - "disallowed operator in constant expression"); - return; - } - expr_lit(@codemap::spanned {node: lit_str(_), _}) => { } - expr_binary(*) | expr_unary(*) => { - if method_map.contains_key(&e.id) { - sess.span_err(e.span, "user-defined operators are not \ - allowed in constant expressions"); + match p.node { + // Let through plain ~-string literals here + pat_lit(a) => { + if !is_str(a) { + self.visit_expr(a, true); } } - expr_lit(_) => (), - expr_cast(_, _) => { - let ety = ty::expr_ty(tcx, e); - if !ty::type_is_numeric(ety) && !ty::type_is_unsafe_ptr(ety) { - sess.span_err(e.span, ~"can not cast to `" + - ppaux::ty_to_str(tcx, ety) + - "` in a constant expression"); - } + pat_range(a, b) => { + if !is_str(a) { self.visit_expr(a, true); } + if !is_str(b) { self.visit_expr(b, true); } } - expr_path(ref pth) => { - // NB: In the future you might wish to relax this slightly - // to handle on-demand instantiation of functions via - // foo:: in a const. Currently that is only done on - // a path in trans::callee that only works in block contexts. - if !pth.segments.iter().all(|segment| segment.types.is_empty()) { - sess.span_err( - e.span, "paths in constants may only refer to \ - items without type parameters"); - } - match def_map.find(&e.id) { - Some(&def_static(*)) | - Some(&def_fn(_, _)) | - Some(&def_variant(_, _)) | - Some(&def_struct(_)) => { } - - Some(&def) => { - debug!("(checking const) found bad def: %?", def); - sess.span_err( - e.span, - "paths in constants may only refer to \ - constants or functions"); + _ => visit::walk_pat(self, p, false) + } + } + + fn visit_expr(&mut self, e: @expr, is_const: bool) { + if is_const { + match e.node { + expr_unary(_, deref, _) => { } + expr_unary(_, box(_), _) | expr_unary(_, uniq, _) => { + self.sess.span_err(e.span, + "disallowed operator in constant \ + expression"); + return; + } + expr_lit(@codemap::spanned {node: lit_str(_), _}) => { } + expr_binary(*) | expr_unary(*) => { + if self.method_map.contains_key(&e.id) { + self.sess.span_err(e.span, + "user-defined operators are not \ + allowed in constant expressions"); + } } - None => { - sess.span_bug(e.span, "unbound path in const?!"); + expr_lit(_) => (), + expr_cast(_, _) => { + let ety = ty::expr_ty(self.tcx, e); + if !ty::type_is_numeric(ety) && !ty::type_is_unsafe_ptr(ety) { + self.sess.span_err(e.span, + ~"can not cast to `" + + ppaux::ty_to_str(self.tcx, ety) + + "` in a constant expression"); + } } - } - } - expr_call(callee, _, NoSugar) => { - match def_map.find(&callee.id) { - Some(&def_struct(*)) => {} // OK. - Some(&def_variant(*)) => {} // OK. - _ => { - sess.span_err( + expr_path(ref pth) => { + // NB: In the future you might wish to relax this slightly + // to handle on-demand instantiation of functions via + // foo:: in a const. Currently that is only done on + // a path in trans::callee that only works in block contexts. + if !pth.segments.iter().all(|s| s.types.is_empty()) { + self.sess.span_err( + e.span, "paths in constants may only refer to \ + items without type parameters"); + } + match self.def_map.find(&e.id) { + Some(&def_static(*)) | + Some(&def_fn(_, _)) | + Some(&def_variant(_, _)) | + Some(&def_struct(_)) => { } + + Some(&def) => { + debug!("(checking const) found bad def: %?", def); + self.sess.span_err( e.span, - "function calls in constants are limited to \ - struct and enum constructors"); + "paths in constants may only refer to \ + constants or functions"); + } + None => { + self.sess.span_bug(e.span, "unbound path in const?!"); + } } + } + expr_call(callee, _, NoSugar) => { + match self.def_map.find(&callee.id) { + Some(&def_struct(*)) => {} // OK. + Some(&def_variant(*)) => {} // OK. + _ => { + self.sess.span_err( + e.span, + "function calls in constants are limited to \ + struct and enum constructors"); + } + } + } + expr_paren(e) => self.visit_expr(e, is_const), + expr_vstore(_, expr_vstore_slice) | + expr_vec(_, m_imm) | + expr_addr_of(m_imm, _) | + expr_field(*) | + expr_index(*) | + expr_tup(*) | + expr_repeat(*) | + expr_struct(*) => { } + expr_addr_of(*) => { + self.sess.span_err( + e.span, + "borrowed pointers in constants may only refer to \ + immutable values"); + } + _ => { + self.sess.span_err(e.span, + "constant contains unimplemented \ + expression type"); + return; + } } - } - expr_paren(e) => { check_expr(sess, def_map, method_map, - tcx, e, (is_const, v)); } - expr_vstore(_, expr_vstore_slice) | - expr_vec(_, m_imm) | - expr_addr_of(m_imm, _) | - expr_field(*) | - expr_index(*) | - expr_tup(*) | - expr_repeat(*) | - expr_struct(*) => { } - expr_addr_of(*) => { - sess.span_err( - e.span, - "borrowed pointers in constants may only refer to \ - immutable values"); - } - _ => { - sess.span_err(e.span, - "constant contains unimplemented expression type"); - return; - } } - } - match e.node { - expr_lit(@codemap::spanned {node: lit_int(v, t), _}) => { - if t != ty_char { - if (v as u64) > ast_util::int_ty_max( - if t == ty_i { sess.targ_cfg.int_type } else { t }) { - sess.span_err(e.span, "literal out of range for its type"); + match e.node { + expr_lit(@codemap::spanned {node: lit_int(v, t), _}) => { + if t != ty_char { + if (v as u64) > ast_util::int_ty_max( + if t == ty_i { + self.sess.targ_cfg.int_type + } else { + t + }) { + self.sess.span_err(e.span, + "literal out of range for its type"); + } } + } + expr_lit(@codemap::spanned {node: lit_uint(v, t), _}) => { + if v > ast_util::uint_ty_max(if t == ty_u { + self.sess.targ_cfg.uint_type + } else { + t + }) { + self.sess.span_err(e.span, + "literal out of range for its type"); + } + } + _ => () } - } - expr_lit(@codemap::spanned {node: lit_uint(v, t), _}) => { - if v > ast_util::uint_ty_max( - if t == ty_u { sess.targ_cfg.uint_type } else { t }) { - sess.span_err(e.span, "literal out of range for its type"); - } - } - _ => () + visit::walk_expr(self, e, is_const); } - oldvisit::visit_expr(e, (is_const, v)); + +} + +pub fn check_crate(sess: Session, + crate: &Crate, + ast_map: ast_map::map, + def_map: resolve::DefMap, + method_map: typeck::method_map, + tcx: ty::ctxt) { + let mut visitor = ConstCheckingVisitor { + sess: sess, + ast_map: ast_map, + def_map: def_map, + method_map: method_map, + tcx: tcx, + }; + visit::walk_crate(&mut visitor, crate, false); + sess.abort_if_errors(); } + #[deriving(Clone)] struct env { root_it: @item, From 44b765eaf6583d4cc9816ede6b7a87a68377b423 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 16 Aug 2013 16:29:47 -0700 Subject: [PATCH 09/16] librustc: Finish porting constant checking to the new visitor --- src/librustc/middle/check_const.rs | 57 +++++++++++++++++------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 9d1fc5e68a14b..6694b0b21244f 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -16,8 +16,9 @@ use middle::typeck; use util::ppaux; use syntax::ast::*; +use syntax::ast_map; +use syntax::ast_util; use syntax::codemap; -use syntax::{oldvisit, ast_util, ast_map}; use syntax::visit::Visitor; use syntax::visit; @@ -226,41 +227,29 @@ struct env { // Make sure a const item doesn't recursively refer to itself // FIXME: Should use the dependency graph when it's available (#1356) -pub fn check_item_recursion(sess: Session, - ast_map: ast_map::map, - def_map: resolve::DefMap, - it: @item) { - let env = env { - root_it: it, - sess: sess, - ast_map: ast_map, - def_map: def_map, - idstack: @mut ~[] - }; - - let visitor = oldvisit::mk_vt(@oldvisit::Visitor { - visit_item: visit_item, - visit_expr: visit_expr, - .. *oldvisit::default_visitor() - }); - (visitor.visit_item)(it, (env, visitor)); +struct ItemRecursionCheckingVisitor { + sess: Session, + ast_map: ast_map::map, + def_map: resolve::DefMap, +} - fn visit_item(it: @item, (env, v): (env, oldvisit::vt)) { +impl Visitor for ItemRecursionCheckingVisitor { + fn visit_item(&mut self, it: @item, env: env) { if env.idstack.iter().any(|x| x == &(it.id)) { env.sess.span_fatal(env.root_it.span, "recursive constant"); } env.idstack.push(it.id); - oldvisit::visit_item(it, (env, v)); + visit::walk_item(self, it, env); env.idstack.pop(); } - fn visit_expr(e: @expr, (env, v): (env, oldvisit::vt)) { + fn visit_expr(&mut self, e: @expr, env: env) { match e.node { expr_path(*) => match env.def_map.find(&e.id) { Some(&def_static(def_id, _)) if ast_util::is_local(def_id) => match env.ast_map.get_copy(&def_id.node) { ast_map::node_item(it, _) => { - (v.visit_item)(it, (env, v)); + self.visit_item(it, env); } _ => fail!("const not bound to an item") }, @@ -268,6 +257,26 @@ pub fn check_item_recursion(sess: Session, }, _ => () } - oldvisit::visit_expr(e, (env, v)); + visit::walk_expr(self, e, env); } } + +fn check_item_recursion(sess: Session, + ast_map: ast_map::map, + def_map: resolve::DefMap, + it: @item) { + let env = env { + root_it: it, + sess: sess, + ast_map: ast_map, + def_map: def_map, + idstack: @mut ~[] + }; + let mut visitor = ItemRecursionCheckingVisitor { + sess: sess, + ast_map: ast_map, + def_map: def_map, + }; + visitor.visit_item(it, env); +} + From 406dbdbc23198390f2ccb398271d9fa8c4989055 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 16 Aug 2013 16:47:06 -0700 Subject: [PATCH 10/16] librustc: Port match checking to the new visitor --- src/librustc/middle/check_match.rs | 173 ++++++++++++++--------------- 1 file changed, 84 insertions(+), 89 deletions(-) diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 9719460bbd33e..5988d4ac6ccad 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -25,7 +25,8 @@ use extra::sort; use syntax::ast::*; use syntax::ast_util::{unguarded_pat, walk_pat}; use syntax::codemap::{span, dummy_sp, spanned}; -use syntax::oldvisit; +use syntax::visit::Visitor; +use syntax::visit; pub struct MatchCheckCtxt { tcx: ty::ctxt, @@ -33,72 +34,96 @@ pub struct MatchCheckCtxt { moves_map: moves::MovesMap } -pub fn check_crate(tcx: ty::ctxt, - method_map: method_map, - moves_map: moves::MovesMap, - crate: &Crate) { - let cx = @MatchCheckCtxt {tcx: tcx, - method_map: method_map, - moves_map: moves_map}; - oldvisit::visit_crate(crate, ((), oldvisit::mk_vt(@oldvisit::Visitor { - visit_expr: |a,b| check_expr(cx, a, b), - visit_local: |a,b| check_local(cx, a, b), - visit_fn: |kind, decl, body, sp, id, (e, v)| - check_fn(cx, kind, decl, body, sp, id, (e, v)), - .. *oldvisit::default_visitor::<()>() - }))); - tcx.sess.abort_if_errors(); -} +impl Visitor<()> for MatchCheckCtxt { + fn visit_expr(&mut self, ex: @expr, _: ()) { + visit::walk_expr(self, ex, ()); + match ex.node { + expr_match(scrut, ref arms) => { + // First, check legality of move bindings. + for arm in arms.iter() { + check_legality_of_move_bindings(self, + arm.guard.is_some(), + arm.pats); + } -pub fn check_expr(cx: @MatchCheckCtxt, - ex: @expr, - (s, v): ((), oldvisit::vt<()>)) { - oldvisit::visit_expr(ex, (s, v)); - match ex.node { - expr_match(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); - } + check_arms(self, *arms); + /* Check for exhaustiveness */ + // Check for empty enum, because is_useful only works on inhabited + // types. + let pat_ty = node_id_to_type(self.tcx, scrut.id); + if (*arms).is_empty() { + if !type_is_empty(self.tcx, pat_ty) { + // We know the type is inhabited, so this must be wrong + self.tcx.sess.span_err(ex.span, + fmt!("non-exhaustive patterns: \ + type %s is non-empty", + ty_to_str(self.tcx, pat_ty))); + } + // If the type *is* empty, it's vacuously exhaustive + return; + } + match ty::get(pat_ty).sty { + ty_enum(did, _) => { + if (*enum_variants(self.tcx, did)).is_empty() && + (*arms).is_empty() { - check_arms(cx, *arms); - /* 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, fmt!("non-exhaustive patterns: \ - type %s is non-empty", - ty_to_str(cx.tcx, pat_ty))); + return; + } + } + _ => { /* We assume only enum types can be uninhabited */ } } - // If the type *is* empty, it's vacuously exhaustive - return; - } - match ty::get(pat_ty).sty { - ty_enum(did, _) => { - if (*enum_variants(cx.tcx, did)).is_empty() && - (*arms).is_empty() { + let arms = arms.iter().filter_map(unguarded_pat).collect::<~[~[@pat]]>().concat_vec(); + if arms.is_empty() { + self.tcx.sess.span_err(ex.span, "non-exhaustive patterns"); + } else { + check_exhaustive(self, ex.span, arms); + } + } + _ => () + } + } - return; + fn visit_local(&mut self, loc: @Local, _: ()) { + visit::walk_local(self, loc, ()); + if is_refutable(self, loc.pat) { + self.tcx.sess.span_err(loc.pat.span, + "refutable pattern in local binding"); + } + + // Check legality of move bindings. + check_legality_of_move_bindings(self, false, [ loc.pat ]); + } + + fn visit_fn(&mut self, + kind: &visit::fn_kind, + decl: &fn_decl, + body: &Block, + sp: span, + id: NodeId, + _: ()) { + visit::walk_fn(self, kind, decl, body, sp, id, ()); + for input in decl.inputs.iter() { + if is_refutable(self, input.pat) { + self.tcx.sess.span_err(input.pat.span, + "refutable pattern in function argument"); } - } - _ => { /* We assume only enum types can be uninhabited */ } - } - let arms = arms.iter().filter_map(unguarded_pat).collect::<~[~[@pat]]>().concat_vec(); - if arms.is_empty() { - cx.tcx.sess.span_err(ex.span, "non-exhaustive patterns"); - } else { - check_exhaustive(cx, ex.span, arms); - } - } - _ => () + } } } +pub fn check_crate(tcx: ty::ctxt, + method_map: method_map, + moves_map: moves::MovesMap, + crate: &Crate) { + let mut cx = MatchCheckCtxt { + tcx: tcx, + method_map: method_map, + moves_map: moves_map + }; + visit::walk_crate(&mut cx, crate, ()); + tcx.sess.abort_if_errors(); +} + // Check for unreachable patterns pub fn check_arms(cx: &MatchCheckCtxt, arms: &[arm]) { let mut seen = ~[]; @@ -787,36 +812,6 @@ pub fn default(cx: &MatchCheckCtxt, r: &[@pat]) -> Option<~[@pat]> { else { None } } -pub fn check_local(cx: &MatchCheckCtxt, - loc: @Local, - (s, v): ((), oldvisit::vt<()>)) { - oldvisit::visit_local(loc, (s, v)); - if is_refutable(cx, loc.pat) { - cx.tcx.sess.span_err(loc.pat.span, - "refutable pattern in local binding"); - } - - // Check legality of move bindings. - check_legality_of_move_bindings(cx, false, [ loc.pat ]); -} - -pub fn check_fn(cx: &MatchCheckCtxt, - kind: &oldvisit::fn_kind, - decl: &fn_decl, - body: &Block, - sp: span, - id: NodeId, - (s, v): ((), - oldvisit::vt<()>)) { - oldvisit::visit_fn(kind, decl, body, sp, id, (s, v)); - for input in decl.inputs.iter() { - if is_refutable(cx, input.pat) { - cx.tcx.sess.span_err(input.pat.span, - "refutable pattern in function argument"); - } - } -} - pub fn is_refutable(cx: &MatchCheckCtxt, pat: &pat) -> bool { match cx.tcx.def_map.find(&pat.id) { Some(&def_variant(enum_id, _)) => { From 2eabce750f6608f1c32d71e54a6c30c1691f1c43 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 16 Aug 2013 17:02:01 -0700 Subject: [PATCH 11/16] librustc: Port the constant evaluator to the new visitor. --- src/librustc/middle/const_eval.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 68e3dfd63be9f..c5f3dc6ea0341 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -14,8 +14,10 @@ use middle::astencode; use middle::ty; use middle; -use syntax::{ast, ast_map, ast_util, oldvisit}; +use syntax::{ast, ast_map, ast_util}; use syntax::ast::*; +use syntax::visit::{SimpleVisitor, SimpleVisitorVisitor}; +use syntax::visit; use std::float; use std::hashmap::{HashMap, HashSet}; @@ -267,13 +269,25 @@ pub fn lookup_constness(tcx: ty::ctxt, e: &expr) -> constness { } } +struct ConstantClassifyingVisitor { + tcx: ty::ctxt, +} + +impl SimpleVisitor for ConstantClassifyingVisitor { + fn visit_expr_post(&mut self, e: @expr) { + let _ = classify(e, self.tcx); + } +} + pub fn process_crate(crate: &ast::Crate, tcx: ty::ctxt) { - let v = oldvisit::mk_simple_visitor(@oldvisit::SimpleVisitor { - visit_expr_post: |e| { classify(e, tcx); }, - .. *oldvisit::default_simple_visitor() - }); - oldvisit::visit_crate(crate, ((), v)); + let visitor = @mut ConstantClassifyingVisitor { + tcx: tcx, + }; + let mut simple_visitor = SimpleVisitorVisitor { + simple_visitor: visitor as @mut SimpleVisitor, + }; + visit::walk_crate(&mut simple_visitor, crate, ()); tcx.sess.abort_if_errors(); } From 608ae1176b3cdbc0377ecaf010e949547dfa4bb7 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 16 Aug 2013 17:23:15 -0700 Subject: [PATCH 12/16] librustc: Make effect checking use the new visitor --- src/librustc/middle/effect.rs | 225 +++++++++++++++++----------------- 1 file changed, 115 insertions(+), 110 deletions(-) diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 651ce292d284d..c159a35bc5451 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -20,8 +20,8 @@ use syntax::ast::{deref, expr_call, expr_inline_asm, expr_method_call}; use syntax::ast::{expr_unary, unsafe_fn, expr_path}; use syntax::ast; use syntax::codemap::span; -use syntax::oldvisit::{fk_item_fn, fk_method}; -use syntax::oldvisit; +use syntax::visit::{fk_item_fn, fk_method, Visitor}; +use syntax::visit; #[deriving(Eq)] enum UnsafeContext { @@ -31,134 +31,139 @@ enum UnsafeContext { } struct Context { + /// The type context. + type_context: ty::ctxt, /// The method map. method_map: method_map, /// Whether we're in an unsafe context. unsafe_context: UnsafeContext, } -fn type_is_unsafe_function(ty: ty::t) -> bool { - match ty::get(ty).sty { - ty_bare_fn(ref f) => f.purity == unsafe_fn, - ty_closure(ref f) => f.purity == unsafe_fn, - _ => false, - } -} - -pub fn check_crate(tcx: ty::ctxt, - method_map: method_map, - crate: &ast::Crate) { - let context = @mut Context { - method_map: method_map, - unsafe_context: SafeContext, - }; - - let require_unsafe: @fn(span: span, - description: &str) = |span, description| { - match context.unsafe_context { - SafeContext => { - // Report an error. - tcx.sess.span_err(span, - fmt!("%s requires unsafe function or block", - description)) - } - UnsafeBlock(block_id) => { - // OK, but record this. - debug!("effect: recording unsafe block as used: %?", block_id); - let _ = tcx.used_unsafe.insert(block_id); - } - UnsafeFn => {} +impl Visitor<()> for Context { + fn visit_fn(&mut self, + fn_kind: &visit::fn_kind, + fn_decl: &ast::fn_decl, + block: &ast::Block, + span: span, + node_id: ast::NodeId, + _: ()) { + let (is_item_fn, is_unsafe_fn) = match *fn_kind { + fk_item_fn(_, _, purity, _) => (true, purity == unsafe_fn), + fk_method(_, _, method) => (true, method.purity == unsafe_fn), + _ => (false, false), + }; + + let old_unsafe_context = self.unsafe_context; + if is_unsafe_fn { + self.unsafe_context = UnsafeFn + } else if is_item_fn { + self.unsafe_context = SafeContext } - }; - let visitor = oldvisit::mk_vt(@oldvisit::Visitor { - visit_fn: |fn_kind, fn_decl, block, span, node_id, (_, visitor)| { - let (is_item_fn, is_unsafe_fn) = match *fn_kind { - fk_item_fn(_, _, purity, _) => (true, purity == unsafe_fn), - fk_method(_, _, method) => (true, method.purity == unsafe_fn), - _ => (false, false), - }; - - let old_unsafe_context = context.unsafe_context; - if is_unsafe_fn { - context.unsafe_context = UnsafeFn - } else if is_item_fn { - context.unsafe_context = SafeContext - } + visit::walk_fn(self, fn_kind, fn_decl, block, span, node_id, ()); - oldvisit::visit_fn(fn_kind, - fn_decl, - block, - span, - node_id, - ((), - visitor)); - - context.unsafe_context = old_unsafe_context - }, - - visit_block: |block, (_, visitor)| { - let old_unsafe_context = context.unsafe_context; - if block.rules == ast::UnsafeBlock && - context.unsafe_context == SafeContext { - context.unsafe_context = UnsafeBlock(block.id) - } + self.unsafe_context = old_unsafe_context + } - oldvisit::visit_block(block, ((), visitor)); + fn visit_block(&mut self, block: &ast::Block, _: ()) { + let old_unsafe_context = self.unsafe_context; + if block.rules == ast::UnsafeBlock && + self.unsafe_context == SafeContext { + self.unsafe_context = UnsafeBlock(block.id) + } - context.unsafe_context = old_unsafe_context - }, + visit::walk_block(self, block, ()); - visit_expr: |expr, (_, visitor)| { - match expr.node { - expr_method_call(callee_id, _, _, _, _, _) => { - let base_type = ty::node_id_to_type(tcx, callee_id); - debug!("effect: method call case, base type is %s", - ppaux::ty_to_str(tcx, base_type)); - if type_is_unsafe_function(base_type) { - require_unsafe(expr.span, - "invocation of unsafe method") - } + self.unsafe_context = old_unsafe_context + } + + fn visit_expr(&mut self, expr: @ast::expr, _: ()) { + match expr.node { + expr_method_call(callee_id, _, _, _, _, _) => { + let base_type = ty::node_id_to_type(self.type_context, + callee_id); + debug!("effect: method call case, base type is %s", + ppaux::ty_to_str(self.type_context, base_type)); + if type_is_unsafe_function(base_type) { + self.require_unsafe(expr.span, + "invocation of unsafe method") } - expr_call(base, _, _) => { - let base_type = ty::node_id_to_type(tcx, base.id); - debug!("effect: call case, base type is %s", - ppaux::ty_to_str(tcx, base_type)); - if type_is_unsafe_function(base_type) { - require_unsafe(expr.span, "call to unsafe function") - } + } + expr_call(base, _, _) => { + let base_type = ty::node_id_to_type(self.type_context, + base.id); + debug!("effect: call case, base type is %s", + ppaux::ty_to_str(self.type_context, base_type)); + if type_is_unsafe_function(base_type) { + self.require_unsafe(expr.span, "call to unsafe function") } - expr_unary(_, deref, base) => { - let base_type = ty::node_id_to_type(tcx, base.id); - debug!("effect: unary case, base type is %s", - ppaux::ty_to_str(tcx, base_type)); - match ty::get(base_type).sty { - ty_ptr(_) => { - require_unsafe(expr.span, - "dereference of unsafe pointer") - } - _ => {} + } + expr_unary(_, deref, base) => { + let base_type = ty::node_id_to_type(self.type_context, + base.id); + debug!("effect: unary case, base type is %s", + ppaux::ty_to_str(self.type_context, base_type)); + match ty::get(base_type).sty { + ty_ptr(_) => { + self.require_unsafe(expr.span, + "dereference of unsafe pointer") } + _ => {} } - expr_inline_asm(*) => { - require_unsafe(expr.span, "use of inline assembly") - } - expr_path(*) => { - match ty::resolve_expr(tcx, expr) { - ast::def_static(_, true) => { - require_unsafe(expr.span, "use of mutable static") - } - _ => {} + } + expr_inline_asm(*) => { + self.require_unsafe(expr.span, "use of inline assembly") + } + expr_path(*) => { + match ty::resolve_expr(self.type_context, expr) { + ast::def_static(_, true) => { + self.require_unsafe(expr.span, + "use of mutable static") } + _ => {} } - _ => {} } + _ => {} + } - oldvisit::visit_expr(expr, ((), visitor)) - }, + visit::walk_expr(self, expr, ()); + } +} + +impl Context { + fn require_unsafe(&mut self, span: span, description: &str) { + match self.unsafe_context { + SafeContext => { + // Report an error. + self.type_context.sess.span_err(span, + fmt!("%s requires unsafe function or block", + description)) + } + UnsafeBlock(block_id) => { + // OK, but record this. + debug!("effect: recording unsafe block as used: %?", block_id); + let _ = self.type_context.used_unsafe.insert(block_id); + } + UnsafeFn => {} + } + } +} - .. *oldvisit::default_visitor() - }); +fn type_is_unsafe_function(ty: ty::t) -> bool { + match ty::get(ty).sty { + ty_bare_fn(ref f) => f.purity == unsafe_fn, + ty_closure(ref f) => f.purity == unsafe_fn, + _ => false, + } +} - oldvisit::visit_crate(crate, ((), visitor)) +pub fn check_crate(tcx: ty::ctxt, + method_map: method_map, + crate: &ast::Crate) { + let mut context = Context { + type_context: tcx, + method_map: method_map, + unsafe_context: SafeContext, + }; + visit::walk_crate(&mut context, crate, ()); } From e70e48ddc63db082b66f06d1210ca9f5c9e99efa Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 16 Aug 2013 17:49:16 -0700 Subject: [PATCH 13/16] librustc: Port entry point finding to the new visitor --- src/librustc/middle/entry.rs | 95 +++++++++++++++++------------------- 1 file changed, 45 insertions(+), 50 deletions(-) diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index 34aeaf8a6cebe..b2d5d3a695ec4 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -15,9 +15,9 @@ use syntax::ast::{Crate, NodeId, item, item_fn}; use syntax::ast_map; use syntax::attr; use syntax::codemap::span; -use syntax::oldvisit::{default_visitor, mk_vt, vt, Visitor, visit_crate}; -use syntax::oldvisit::{visit_item}; use syntax::parse::token::special_idents; +use syntax::visit::Visitor; +use syntax::visit; use std::util; struct EntryContext { @@ -39,8 +39,6 @@ struct EntryContext { non_main_fns: ~[(NodeId, span)], } -type EntryVisitor = vt<@mut EntryContext>; - pub fn find_entry_point(session: Session, crate: &Crate, ast_map: ast_map::map) { // FIXME #4404 android JNI hacks @@ -56,7 +54,7 @@ pub fn find_entry_point(session: Session, crate: &Crate, ast_map: ast_map::map) return } - let ctxt = @mut EntryContext { + let mut ctxt = EntryContext { session: session, ast_map: ast_map, main_fn: None, @@ -64,67 +62,64 @@ pub fn find_entry_point(session: Session, crate: &Crate, ast_map: ast_map::map) start_fn: None, non_main_fns: ~[], }; - - visit_crate(crate, (ctxt, mk_vt(@Visitor { - visit_item: |item, (ctxt, visitor)| find_item(item, ctxt, visitor), - .. *default_visitor() - }))); - - configure_main(ctxt); + visit::walk_crate(&mut ctxt, crate, ()); + configure_main(&mut ctxt); } -fn find_item(item: @item, ctxt: @mut EntryContext, visitor: EntryVisitor) { - match item.node { - item_fn(*) => { - if item.ident == special_idents::main { - match ctxt.ast_map.find(&item.id) { - Some(&ast_map::node_item(_, path)) => { - if path.len() == 0 { - // This is a top-level function so can be 'main' - if ctxt.main_fn.is_none() { - ctxt.main_fn = Some((item.id, item.span)); +impl Visitor<()> for EntryContext { + fn visit_item(&mut self, item: @item, _: ()) { + match item.node { + item_fn(*) => { + if item.ident == special_idents::main { + match self.ast_map.find(&item.id) { + Some(&ast_map::node_item(_, path)) => { + if path.len() == 0 { + // This is a top-level function so can be + // 'main' + if self.main_fn.is_none() { + self.main_fn = Some((item.id, item.span)); + } else { + self.session.span_err( + item.span, + "multiple 'main' functions"); + } } else { - ctxt.session.span_err( - item.span, - "multiple 'main' functions"); + // This isn't main + self.non_main_fns.push((item.id, item.span)); } - } else { - // This isn't main - ctxt.non_main_fns.push((item.id, item.span)); } + _ => util::unreachable() } - _ => util::unreachable() } - } - if attr::contains_name(item.attrs, "main") { - if ctxt.attr_main_fn.is_none() { - ctxt.attr_main_fn = Some((item.id, item.span)); - } else { - ctxt.session.span_err( - item.span, - "multiple 'main' functions"); + if attr::contains_name(item.attrs, "main") { + if self.attr_main_fn.is_none() { + self.attr_main_fn = Some((item.id, item.span)); + } else { + self.session.span_err( + item.span, + "multiple 'main' functions"); + } } - } - if attr::contains_name(item.attrs, "start") { - if ctxt.start_fn.is_none() { - ctxt.start_fn = Some((item.id, item.span)); - } else { - ctxt.session.span_err( - item.span, - "multiple 'start' functions"); + if attr::contains_name(item.attrs, "start") { + if self.start_fn.is_none() { + self.start_fn = Some((item.id, item.span)); + } else { + self.session.span_err( + item.span, + "multiple 'start' functions"); + } } } + _ => () } - _ => () - } - visit_item(item, (ctxt, visitor)); + visit::walk_item(self, item, ()); + } } -fn configure_main(ctxt: @mut EntryContext) { - let this = &mut *ctxt; +fn configure_main(this: &mut EntryContext) { if this.start_fn.is_some() { *this.session.entry_fn = this.start_fn; *this.session.entry_type = Some(session::EntryStart); From 11d5f00e6b69d78441ed6b985568abd81c519b2f Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 16 Aug 2013 18:14:26 -0700 Subject: [PATCH 14/16] librustc: Port free variable finding to the new visitor --- src/librustc/middle/freevars.rs | 137 ++++++++++++++++++-------------- 1 file changed, 79 insertions(+), 58 deletions(-) diff --git a/src/librustc/middle/freevars.rs b/src/librustc/middle/freevars.rs index 5f7ef8d31f703..8a61f8bd3bd5c 100644 --- a/src/librustc/middle/freevars.rs +++ b/src/librustc/middle/freevars.rs @@ -17,7 +17,9 @@ use middle::ty; use std::hashmap::HashMap; use syntax::codemap::span; -use syntax::{ast, ast_util, oldvisit}; +use syntax::{ast, ast_util}; +use syntax::visit::{SimpleVisitor, SimpleVisitorVisitor, Visitor}; +use syntax::visit; // A vector of defs representing the free variables referred to in a function. // (The def_upvar will already have been stripped). @@ -29,6 +31,53 @@ pub struct freevar_entry { pub type freevar_info = @~[@freevar_entry]; pub type freevar_map = @mut HashMap; +struct FreeVarCollectingVisitor { + seen: @mut HashMap, + refs: @mut ~[@freevar_entry], + def_map: resolve::DefMap, +} + +impl Visitor for FreeVarCollectingVisitor { + fn visit_item(&mut self, _: @ast::item, _: int) { + // Ignore! + } + + fn visit_expr(&mut self, expr: @ast::expr, depth: int) { + match expr.node { + ast::expr_fn_block(*) => { + visit::walk_expr(self, expr, depth + 1) + } + ast::expr_path(*) | ast::expr_self => { + let mut i = 0; + match self.def_map.find(&expr.id) { + None => fail!("path not found"), + Some(&df) => { + let mut def = df; + while i < depth { + match def { + ast::def_upvar(_, inner, _, _) => { def = *inner; } + _ => break + } + i += 1; + } + if i == depth { // Made it to end of loop + let dnum = ast_util::def_id_of_def(def).node; + if !self.seen.contains_key(&dnum) { + self.refs.push(@freevar_entry { + def: def, + span: expr.span, + }); + self.seen.insert(dnum, ()); + } + } + } + } + } + _ => visit::walk_expr(self, expr, depth) + } + } +} + // Searches through part of the AST for all references to locals or // upvars in this frame and returns the list of definition IDs thus found. // Since we want to be able to collect upvars in some arbitrary piece @@ -38,50 +87,30 @@ fn collect_freevars(def_map: resolve::DefMap, blk: &ast::Block) -> freevar_info { let seen = @mut HashMap::new(); let refs = @mut ~[]; + let mut visitor = FreeVarCollectingVisitor { + seen: seen, + refs: refs, + def_map: def_map, + }; + visitor.visit_block(blk, 1); + return @(*refs).clone(); +} - fn ignore_item(_i: @ast::item, (_depth, _v): (int, oldvisit::vt)) { } - - let walk_expr: @fn(expr: @ast::expr, (int, oldvisit::vt)) = - |expr, (depth, v)| { - match expr.node { - ast::expr_fn_block(*) => { - oldvisit::visit_expr(expr, (depth + 1, v)) - } - ast::expr_path(*) | ast::expr_self => { - let mut i = 0; - match def_map.find(&expr.id) { - None => fail!("path not found"), - Some(&df) => { - let mut def = df; - while i < depth { - match def { - ast::def_upvar(_, inner, _, _) => { def = *inner; } - _ => break - } - i += 1; - } - if i == depth { // Made it to end of loop - let dnum = ast_util::def_id_of_def(def).node; - if !seen.contains_key(&dnum) { - refs.push(@freevar_entry { - def: def, - span: expr.span, - }); - seen.insert(dnum, ()); - } - } - } - } - } - _ => oldvisit::visit_expr(expr, (depth, v)) - } - }; +struct FreeVarAnnotatingVisitor { + def_map: resolve::DefMap, + freevars: freevar_map, +} - let v = oldvisit::mk_vt(@oldvisit::Visitor {visit_item: ignore_item, - visit_expr: walk_expr, - .. *oldvisit::default_visitor()}); - (v.visit_block)(blk, (1, v)); - return @(*refs).clone(); +impl SimpleVisitor for FreeVarAnnotatingVisitor { + fn visit_fn(&mut self, + _: &visit::fn_kind, + _: &ast::fn_decl, + blk: &ast::Block, + _: span, + nid: ast::NodeId) { + let vars = collect_freevars(self.def_map, blk); + self.freevars.insert(nid, vars); + } } // Build a map from every function and for-each body to a set of the @@ -92,22 +121,14 @@ fn collect_freevars(def_map: resolve::DefMap, blk: &ast::Block) pub fn annotate_freevars(def_map: resolve::DefMap, crate: &ast::Crate) -> freevar_map { let freevars = @mut HashMap::new(); - - let walk_fn: @fn(&oldvisit::fn_kind, - &ast::fn_decl, - &ast::Block, - span, - ast::NodeId) = |_, _, blk, _, nid| { - let vars = collect_freevars(def_map, blk); - freevars.insert(nid, vars); + let visitor = @mut FreeVarAnnotatingVisitor { + def_map: def_map, + freevars: freevars, }; - - let visitor = - oldvisit::mk_simple_visitor(@oldvisit::SimpleVisitor { - visit_fn: walk_fn, - .. *oldvisit::default_simple_visitor()}); - oldvisit::visit_crate(crate, ((), visitor)); - + let mut simple_visitor = SimpleVisitorVisitor { + simple_visitor: visitor as @mut SimpleVisitor, + }; + visit::walk_crate(&mut simple_visitor, crate, ()); return freevars; } From 6e1f30f4cb5dd90b0791947cc8e4ee1fe2db85ca Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Sat, 17 Aug 2013 00:24:48 -0700 Subject: [PATCH 15/16] librustc: Long lines --- src/librustc/metadata/creader.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index 30d1de0f2c810..f74fecb522390 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -145,7 +145,10 @@ impl SimpleVisitor for Env { ~[attr::mk_name_value_item_str(@"package_id", p), attr::mk_name_value_item_str(@"name", s.to_managed())], *meta_items), - None => self.diag.span_bug(i.span, "Bad package path in `extern mod` item") + None => { + self.diag.span_bug(i.span, + "bad package path in `extern mod` item") + } } } }; From 050dc6191f001152b4eddc5b29592829a32e321d Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Sat, 17 Aug 2013 11:14:44 -0700 Subject: [PATCH 16/16] test: xfail a test that relies on old path behavior. --- src/test/run-pass/issue-6898.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/run-pass/issue-6898.rs b/src/test/run-pass/issue-6898.rs index 2d612bb742eb3..8e9502d6d49e6 100644 --- a/src/test/run-pass/issue-6898.rs +++ b/src/test/run-pass/issue-6898.rs @@ -1,3 +1,5 @@ +// xfail-test + // Copyright 2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT.