A collection of refactorings that I found it hard/tiresome to divide:

- Make `extern fn()` assignable to any closure type, rather than
  a subtype.
- Remove unused int_ty_set and float_ty_set
- Refactor variable unification and make it more DRY
- Do fn sub/lub/glb on the level of fn_sig
- Rename infer::to_str::ToStr to infer::to_str::InferStr
- Capitalize names of various types
- Correct hashing of FnMeta
- Convert various records-of-fns into structs-of-fns.  This is both
  eliminating use of deprecated features and more forwards compatible
  with fn reform.

r=pcwalton
This commit is contained in:
Niko Matsakis 2013-01-08 14:00:45 -08:00
parent 11a307294a
commit 2b92962aa2
87 changed files with 1642 additions and 1661 deletions

View File

@ -211,7 +211,7 @@ fn is_test(config: config, testfile: &Path) -> bool {
fn make_test(config: config, testfile: &Path) ->
test::TestDesc {
{
test::TestDesc {
name: make_test_name(config, testfile),
testfn: make_test_closure(config, testfile),
ignore: header::is_test_ignored(config, testfile),

View File

@ -403,7 +403,7 @@ fn load_crate(filename: &Path) -> Option<Crate> {
let e = @{
mut deps: ~[]
};
let v = visit::mk_simple_visitor(@{
let v = visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_view_item: |a| goto_view_item(sess, e, a),
visit_item: |a| goto_item(e, a),
.. *visit::default_simple_visitor()

View File

@ -99,5 +99,5 @@ extern mod rustrt {
#[abi = "rust-intrinsic"]
extern mod rusti {
#[legacy_exports];
fn frame_address(f: fn(++x: *u8));
fn frame_address(f: &once fn(++x: *u8));
}

View File

@ -167,7 +167,7 @@ type stolen_stuff = {exprs: ~[ast::expr], tys: ~[ast::Ty]};
fn steal(crate: ast::crate, tm: test_mode) -> stolen_stuff {
let exprs = @mut ~[];
let tys = @mut ~[];
let v = visit::mk_simple_visitor(@{
let v = visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_expr: |a| stash_expr_if(safe_to_steal_expr, exprs, a, tm),
visit_ty: |a| stash_ty_if(safe_to_steal_ty, tys, a, tm),
.. *visit::default_simple_visitor()
@ -216,7 +216,7 @@ fn replace_expr_in_crate(crate: ast::crate, i: uint,
fold::noop_fold_expr(original, fld)
}
}
let afp = @{
let afp = @fold::AstFoldFns {
fold_expr: fold::wrap(|a,b| {
fold_expr_rep(j, i, newexpr.node, a, b, tm)
}),
@ -241,7 +241,7 @@ fn replace_ty_in_crate(crate: ast::crate, i: uint, newty: ast::Ty,
newty_
} else { fold::noop_fold_ty(original, fld) }
}
let afp = @{
let afp = @fold::AstFoldFns {
fold_ty: fold::wrap(|a,b| fold_ty_rep(j, i, newty.node, a, b, tm) ),
.. *fold::default_ast_fold()
};
@ -486,7 +486,8 @@ fn has_raw_pointers(c: ast::crate) -> bool {
}
}
let v =
visit::mk_simple_visitor(@{visit_ty: |a| visit_ty(has_rp, a),
visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_ty: |a| visit_ty(has_rp, a),
.. *visit::default_simple_visitor()});
visit::visit_crate(c, (), v);
return *has_rp;

View File

@ -395,13 +395,16 @@ fn pretty_print_input(sess: Session, +cfg: ast::crate_cfg, input: input,
let ann = match ppm {
ppm_typed => {
{pre: ann_paren_for_expr,
pprust::pp_ann {pre: ann_paren_for_expr,
post: |a| ann_typed_post(tcx.get(), a) }
}
ppm_identified | ppm_expanded_identified => {
{pre: ann_paren_for_expr, post: ann_identified_post}
pprust::pp_ann {pre: ann_paren_for_expr,
post: ann_identified_post}
}
ppm_expanded | ppm_normal => {
pprust::no_ann()
}
ppm_expanded | ppm_normal => pprust::no_ann()
};
let is_expanded = upto != cu_parse;
let src = sess.codemap.get_filemap(source_name(input)).src;

View File

@ -38,8 +38,8 @@ fn strip_items(crate: @ast::crate, in_cfg: in_cfg_pred)
let ctxt = @{in_cfg: in_cfg};
let precursor =
@{fold_mod: |a,b| fold_mod(ctxt, a, b),
let precursor = @fold::AstFoldFns {
fold_mod: |a,b| fold_mod(ctxt, a, b),
fold_block: fold::wrap(|a,b| fold_block(ctxt, a, b) ),
fold_foreign_mod: |a,b| fold_foreign_mod(ctxt, a, b),
fold_item_underscore: |a,b| {

View File

@ -42,7 +42,7 @@ fn inject_libcore_ref(sess: Session,
ast::spanned { node: x, span: dummy_sp() }
}
let precursor = @{
let precursor = @fold::AstFoldFns {
fold_crate: |crate, span, fld| {
let n1 = sess.next_node_id();
let vi1 = @{node: ast::view_item_use(sess.ident_of(~"core"),

View File

@ -65,8 +65,8 @@ fn generate_test_harness(sess: session::Session,
mut path: ~[],
testfns: DVec()};
let precursor =
@{fold_crate: fold::wrap(|a,b| fold_crate(cx, a, b) ),
let precursor = @fold::AstFoldFns {
fold_crate: fold::wrap(|a,b| fold_crate(cx, a, b) ),
fold_item: |a,b| fold_item(cx, a, b),
fold_mod: |a,b| fold_mod(cx, a, b),.. *fold::default_ast_fold()};
@ -424,8 +424,14 @@ fn mk_test_desc_rec(cx: test_ctxt, test: test) -> @ast::expr {
ident: cx.sess.ident_of(~"should_fail"),
expr: @fail_expr});
let test_desc_path =
mk_path(cx, ~[cx.sess.ident_of(~"test"),
cx.sess.ident_of(~"TestDesc")]);
let desc_rec_: ast::expr_ =
ast::expr_rec(~[name_field, fn_field, ignore_field, fail_field],
ast::expr_struct(
test_desc_path,
~[name_field, fn_field, ignore_field, fail_field],
option::None);
let desc_rec: ast::expr =
{id: cx.sess.next_node_id(), callee_id: cx.sess.next_node_id(),

View File

@ -52,10 +52,10 @@ fn read_crates(diag: span_handler,
mut next_crate_num: 1,
intr: intr};
let v =
visit::mk_simple_visitor(@{visit_view_item:
|a| visit_view_item(e, a),
visit_item: |a| visit_item(e, a)
,.. *visit::default_simple_visitor()});
visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_view_item: |a| visit_view_item(e, a),
visit_item: |a| visit_item(e, a),
.. *visit::default_simple_visitor()});
visit::visit_crate(crate, (), v);
dump_crates(e.crate_cache);
warn_if_multiple_versions(e, diag, e.crate_cache.get());

View File

@ -180,7 +180,8 @@ fn def_to_str(did: def_id) -> ~str { fmt!("%d:%d", did.crate, did.node) }
fn encode_ty_type_param_bounds(ebml_w: writer::Encoder, ecx: @encode_ctxt,
params: @~[ty::param_bounds]) {
let ty_str_ctxt = @{diag: ecx.diag,
let ty_str_ctxt = @tyencode::ctxt {
diag: ecx.diag,
ds: def_to_str,
tcx: ecx.tcx,
reachable: |a| reachable(ecx, a),
@ -207,8 +208,8 @@ fn encode_variant_id(ebml_w: writer::Encoder, vid: def_id) {
}
fn write_type(ecx: @encode_ctxt, ebml_w: writer::Encoder, typ: ty::t) {
let ty_str_ctxt =
@{diag: ecx.diag,
let ty_str_ctxt = @tyencode::ctxt {
diag: ecx.diag,
ds: def_to_str,
tcx: ecx.tcx,
reachable: |a| reachable(ecx, a),
@ -218,8 +219,8 @@ fn write_type(ecx: @encode_ctxt, ebml_w: writer::Encoder, typ: ty::t) {
fn write_vstore(ecx: @encode_ctxt, ebml_w: writer::Encoder,
vstore: ty::vstore) {
let ty_str_ctxt =
@{diag: ecx.diag,
let ty_str_ctxt = @tyencode::ctxt {
diag: ecx.diag,
ds: def_to_str,
tcx: ecx.tcx,
reachable: |a| reachable(ecx, a),
@ -887,7 +888,7 @@ fn encode_info_for_items(ecx: @encode_ctxt, ebml_w: writer::Encoder,
encode_info_for_mod(ecx, ebml_w, crate.node.module,
crate_node_id, ~[],
syntax::parse::token::special_idents::invalid);
visit::visit_crate(*crate, (), visit::mk_vt(@{
visit::visit_crate(*crate, (), visit::mk_vt(@visit::Visitor {
visit_expr: |_e, _cx, _v| { },
visit_item: |i, cx, v, copy ebml_w| {
visit::visit_item(i, cx, v);
@ -1267,7 +1268,8 @@ fn encode_metadata(parms: encode_parms, crate: @crate) -> ~[u8] {
// Get the encoded string for a type
fn encoded_ty(tcx: ty::ctxt, t: ty::t) -> ~str {
let cx = @{diag: tcx.diag,
let cx = @tyencode::ctxt {
diag: tcx.diag,
ds: def_to_str,
tcx: tcx,
reachable: |_id| false,

View File

@ -14,7 +14,7 @@
use core::prelude::*;
use middle::ty;
use middle::ty::vid;
use middle::ty::Vid;
use core::io::WriterUtil;
use core::io;
@ -24,6 +24,7 @@ use std::map::HashMap;
use syntax::ast::*;
use syntax::diagnostic::span_handler;
use syntax::print::pprust::*;
use middle::ty::Vid;
export ctxt;
export ty_abbrev;
@ -35,7 +36,7 @@ export enc_mode;
export enc_arg;
export enc_vstore;
type ctxt = {
struct ctxt {
diag: span_handler,
// Def -> str Callback:
ds: fn@(def_id) -> ~str,
@ -43,7 +44,7 @@ type ctxt = {
tcx: ty::ctxt,
reachable: fn@(node_id) -> bool,
abbrevs: abbrev_ctxt
};
}
// Compact string representation for ty.t values. API ty_str & parse_from_str.
// Extra parameters are for converting to/from def_ids in the string rep.

View File

@ -271,7 +271,7 @@ fn simplify_ast(ii: ast::inlined_item) -> ast::inlined_item {
fold::noop_fold_block(blk_sans_items, fld)
}
let fld = fold::make_fold(@{
let fld = fold::make_fold(@fold::AstFoldFns {
fold_block: fold::wrap(drop_nested_items),
.. *fold::default_ast_fold()
});
@ -304,7 +304,7 @@ fn decode_ast(par_doc: ebml::Doc) -> ast::inlined_item {
fn renumber_ast(xcx: extended_decode_ctxt, ii: ast::inlined_item)
-> ast::inlined_item {
let fld = fold::make_fold(@{
let fld = fold::make_fold(@fold::AstFoldFns{
new_id: |a| xcx.tr_id(a),
new_span: |a| xcx.tr_span(a),
.. *fold::default_ast_fold()
@ -643,7 +643,7 @@ trait get_ty_str_ctxt {
impl @e::encode_ctxt: get_ty_str_ctxt {
fn ty_str_ctxt() -> @tyencode::ctxt {
@{diag: self.tcx.sess.diagnostic(),
@tyencode::ctxt {diag: self.tcx.sess.diagnostic(),
ds: e::def_to_str,
tcx: self.tcx,
reachable: |a| encoder::reachable(self, a),

View File

@ -92,7 +92,7 @@ fn check_loans(bccx: borrowck_ctxt,
reported: HashMap(),
mut declared_purity: ast::impure_fn,
mut fn_args: @~[]});
let vt = visit::mk_vt(@{visit_expr: check_loans_in_expr,
let vt = visit::mk_vt(@visit::Visitor {visit_expr: check_loans_in_expr,
visit_local: check_loans_in_local,
visit_block: check_loans_in_block,
visit_fn: check_loans_in_fn,
@ -247,13 +247,13 @@ impl check_loan_ctxt {
let callee_ty = ty::node_id_to_type(tcx, callee_id);
match ty::get(callee_ty).sty {
ty::ty_fn(ref fn_ty) => {
match (*fn_ty).meta.purity {
match fn_ty.meta.purity {
ast::pure_fn => return, // case (c) above
ast::impure_fn | ast::unsafe_fn | ast::extern_fn => {
self.report_purity_error(
pc, callee_span,
fmt!("access to %s function",
pprust::purity_to_str((*fn_ty).meta.purity)));
fn_ty.meta.purity.to_str()));
}
}
}

View File

@ -82,7 +82,7 @@ fn gather_loans(bccx: borrowck_ctxt, crate: @ast::crate) -> req_maps {
mut item_ub: 0,
mut root_ub: 0,
mut ignore_adjustments: LinearMap()});
let v = visit::mk_vt(@{visit_expr: req_loans_in_expr,
let v = visit::mk_vt(@visit::Visitor {visit_expr: req_loans_in_expr,
visit_fn: req_loans_in_fn,
.. *visit::default_visitor()});
visit::visit_crate(*crate, glcx, v);

View File

@ -231,7 +231,6 @@ use core::prelude::*;
use middle::liveness;
use middle::mem_categorization::*;
use middle::region;
use middle::ty::to_str;
use middle::ty;
use util::common::indenter;
use util::ppaux::{expr_repr, note_and_explain_region};

View File

@ -25,7 +25,7 @@ use syntax::{visit, ast_util, ast_map};
fn check_crate(sess: Session, crate: @crate, ast_map: ast_map::map,
def_map: resolve::DefMap,
method_map: typeck::method_map, tcx: ty::ctxt) {
visit::visit_crate(*crate, false, visit::mk_vt(@{
visit::visit_crate(*crate, false, visit::mk_vt(@visit::Visitor {
visit_item: |a,b,c| check_item(sess, ast_map, def_map, a, b, c),
visit_pat: check_pat,
visit_expr: |a,b,c|
@ -211,7 +211,7 @@ fn check_item_recursion(sess: Session, ast_map: ast_map::map,
idstack: @DVec()
};
let visitor = visit::mk_vt(@{
let visitor = visit::mk_vt(@visit::Visitor {
visit_item: visit_item,
visit_expr: visit_expr,
.. *visit::default_visitor()

View File

@ -19,7 +19,7 @@ type ctx = {in_loop: bool, can_ret: bool};
fn check_crate(tcx: ty::ctxt, crate: @crate) {
visit::visit_crate(*crate,
{in_loop: false, can_ret: true},
visit::mk_vt(@{
visit::mk_vt(@visit::Visitor {
visit_item: |i, _cx, v| {
visit::visit_item(i, {in_loop: false, can_ret: true}, v);
},

View File

@ -38,7 +38,7 @@ struct MatchCheckCtxt {
fn check_crate(tcx: ty::ctxt, method_map: method_map, crate: @crate) {
let cx = @MatchCheckCtxt { tcx: tcx, method_map: method_map };
visit::visit_crate(*crate, (), visit::mk_vt(@{
visit::visit_crate(*crate, (), visit::mk_vt(@visit::Visitor {
visit_expr: |a,b,c| check_expr(cx, a, b, c),
visit_local: |a,b,c| check_local(cx, a, b, c),
visit_fn: |kind, decl, body, sp, id, e, v|
@ -797,7 +797,7 @@ fn check_legality_of_move_bindings(cx: @MatchCheckCtxt,
// Now check to ensure that any move binding is not behind an @ or &.
// This is always illegal.
let vt = visit::mk_vt(@{
let vt = visit::mk_vt(@visit::Visitor {
visit_pat: |pat, behind_bad_pointer, v| {
let error_out = || {
cx.tcx.sess.span_err(pat.span, ~"by-move pattern \

View File

@ -207,7 +207,7 @@ fn lookup_constness(tcx: ty::ctxt, e: @expr) -> constness {
fn process_crate(crate: @ast::crate,
def_map: resolve::DefMap,
tcx: ty::ctxt) {
let v = visit::mk_simple_visitor(@{
let v = visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_expr_post: |e| { classify(e, def_map, tcx); },
.. *visit::default_simple_visitor()
});

View File

@ -90,7 +90,8 @@ fn collect_freevars(def_map: resolve::DefMap, blk: ast::blk)
}
};
let v = visit::mk_vt(@{visit_item: ignore_item, visit_expr: walk_expr,
let v = visit::mk_vt(@visit::Visitor {visit_item: ignore_item,
visit_expr: walk_expr,
.. *visit::default_visitor()});
(v.visit_block)(blk, 1, v);
return @/*bad*/copy *refs;
@ -112,7 +113,8 @@ fn annotate_freevars(def_map: resolve::DefMap, crate: @ast::crate) ->
};
let visitor =
visit::mk_simple_visitor(@{visit_fn: walk_fn,
visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_fn: walk_fn,
.. *visit::default_simple_visitor()});
visit::visit_crate(*crate, (), visitor);

View File

@ -97,7 +97,7 @@ fn check_crate(tcx: ty::ctxt,
method_map: method_map,
last_use_map: last_use_map,
current_item: -1};
let visit = visit::mk_vt(@{
let visit = visit::mk_vt(@visit::Visitor {
visit_arm: check_arm,
visit_expr: check_expr,
visit_stmt: check_stmt,

View File

@ -29,7 +29,7 @@ use metadata::decoder::{dl_def, dl_field, dl_impl};
use syntax::ast::{crate, def_fn, def_id, def_ty, lit_str, meta_item};
use syntax::ast::{meta_list, meta_name_value, meta_word};
use syntax::ast_util::{local_def};
use syntax::visit::{default_simple_visitor, mk_simple_visitor};
use syntax::visit::{default_simple_visitor, mk_simple_visitor, SimpleVisitor};
use syntax::visit::{visit_crate, visit_item};
use core::ptr;
@ -333,7 +333,7 @@ impl LanguageItemCollector {
fn collect_local_language_items() {
let this = unsafe { ptr::addr_of(&self) };
visit_crate(*self.crate, (), mk_simple_visitor(@{
visit_crate(*self.crate, (), mk_simple_visitor(@SimpleVisitor {
visit_item: |item| {
for item.attrs.each |attribute| {
unsafe {

View File

@ -430,7 +430,7 @@ fn build_settings_crate(sess: session::Session, crate: @ast::crate) {
let cx = ctxt_({is_default: true,.. *cx});
let visit = visit::mk_vt(@{
let visit = visit::mk_vt(@visit::Visitor {
visit_item: build_settings_item,
.. *visit::default_visitor()
});
@ -458,21 +458,24 @@ fn check_item(i: @ast::item, cx: ty::ctxt) {
// not traverse into subitems, since that is handled by the outer
// lint visitor.
fn item_stopping_visitor<E>(v: visit::vt<E>) -> visit::vt<E> {
visit::mk_vt(@{visit_item: |_i, _e, _v| { },.. **v})
visit::mk_vt(@visit::Visitor {visit_item: |_i, _e, _v| { },.. **v})
}
fn check_item_while_true(cx: ty::ctxt, it: @ast::item) {
let visit = item_stopping_visitor(visit::mk_simple_visitor(@{
visit_expr: fn@(e: @ast::expr) {
let visit = item_stopping_visitor(
visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_expr: |e: @ast::expr| {
match e.node {
ast::expr_while(cond, _) => {
match cond.node {
ast::expr_lit(@ast::spanned { node: ast::lit_bool(true),
_}) => {
ast::expr_lit(@ast::spanned {
node: ast::lit_bool(true), _}) =>
{
cx.sess.span_lint(
while_true, e.id, it.id,
e.span,
~"denote infinite loops with loop { ... }");
~"denote infinite loops \
with loop { ... }");
}
_ => ()
}
@ -596,7 +599,8 @@ fn check_item_type_limits(cx: ty::ctxt, it: @ast::item) {
}
};
let visit = item_stopping_visitor(visit::mk_simple_visitor(@{
let visit = item_stopping_visitor(
visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_expr: visit_expr,
.. *visit::default_simple_visitor()
}));
@ -660,8 +664,9 @@ fn check_item_deprecated_self(cx: ty::ctxt, item: @ast::item) {
}
fn check_item_structural_records(cx: ty::ctxt, it: @ast::item) {
let visit = item_stopping_visitor(visit::mk_simple_visitor(@{
visit_expr: fn@(e: @ast::expr) {
let visit = item_stopping_visitor(
visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_expr: |e: @ast::expr| {
match e.node {
ast::expr_rec(*) =>
cx.sess.span_lint(
@ -779,8 +784,9 @@ fn check_item_heap(cx: ty::ctxt, it: @ast::item) {
_ => ()
}
let visit = item_stopping_visitor(visit::mk_simple_visitor(@{
visit_expr: fn@(e: @ast::expr) {
let visit = item_stopping_visitor(
visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_expr: |e: @ast::expr| {
let ty = ty::expr_ty(cx, e);
check_type(cx, e.id, it.id, e.span, ty);
},
@ -790,8 +796,9 @@ fn check_item_heap(cx: ty::ctxt, it: @ast::item) {
}
fn check_item_path_statement(cx: ty::ctxt, it: @ast::item) {
let visit = item_stopping_visitor(visit::mk_simple_visitor(@{
visit_stmt: fn@(s: @ast::stmt) {
let visit = item_stopping_visitor(
visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_stmt: |s: @ast::stmt| {
match s.node {
ast::stmt_semi(@{id: id,
callee_id: _,
@ -975,7 +982,7 @@ fn check_item_deprecated_modes(tcx: ty::ctxt, it: @ast::item) {
fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
let v = visit::mk_simple_visitor(@{
let v = visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_item: |it|
check_item(it, tcx),
visit_fn: |fk, decl, body, span, id|

View File

@ -207,7 +207,7 @@ fn live_node_kind_to_str(lnk: LiveNodeKind, cx: ty::ctxt) -> ~str {
fn check_crate(tcx: ty::ctxt,
method_map: typeck::method_map,
crate: @crate) -> last_use_map {
let visitor = visit::mk_vt(@{
let visitor = visit::mk_vt(@visit::Visitor {
visit_fn: visit_fn,
visit_local: visit_local,
visit_expr: visit_expr,
@ -489,7 +489,7 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
let entry_ln = (*lsets).compute(decl, body);
// check for various error conditions
let check_vt = visit::mk_vt(@{
let check_vt = visit::mk_vt(@visit::Visitor {
visit_fn: check_fn,
visit_local: check_local,
visit_expr: check_expr,

View File

@ -234,7 +234,7 @@ fn compute_modes_for_pat(pat: @pat,
}
pub fn compute_modes(tcx: ctxt, method_map: method_map, crate: @crate) {
let visitor = visit::mk_vt(@{
let visitor = visit::mk_vt(@visit::Visitor {
visit_expr: compute_modes_for_expr,
visit_pat: compute_modes_for_pat,
.. *visit::default_visitor()

View File

@ -190,7 +190,7 @@ fn check_crate(tcx: ty::ctxt, method_map: &method_map, crate: @ast::crate) {
}
};
let visitor = visit::mk_vt(@{
let visitor = visit::mk_vt(@visit::Visitor {
visit_mod: |the_module, span, node_id, method_map, visitor| {
let n_added = add_privileged_items(the_module.items);

View File

@ -352,7 +352,7 @@ fn resolve_crate(sess: Session, def_map: resolve::DefMap,
region_map: HashMap(),
root_exprs: HashMap(),
parent: None};
let visitor = visit::mk_vt(@{
let visitor = visit::mk_vt(@visit::Visitor {
visit_block: resolve_block,
visit_item: resolve_item,
visit_fn: resolve_fn,
@ -782,7 +782,7 @@ fn determine_rp_in_crate(sess: Session,
mut ambient_variance: rv_covariant});
// Gather up the base set, worklist and dep_map
let visitor = visit::mk_vt(@{
let visitor = visit::mk_vt(@visit::Visitor {
visit_fn: determine_rp_in_fn,
visit_item: determine_rp_in_item,
visit_ty: determine_rp_in_ty,

View File

@ -64,7 +64,7 @@ use syntax::parse::token::ident_interner;
use syntax::parse::token::special_idents;
use syntax::print::pprust::{pat_to_str, path_to_str};
use syntax::codemap::span;
use syntax::visit::{default_visitor, fk_method, mk_vt, visit_block};
use syntax::visit::{default_visitor, fk_method, mk_vt, Visitor, visit_block};
use syntax::visit::{visit_crate, visit_expr, visit_expr_opt, visit_fn};
use syntax::visit::{visit_foreign_item, visit_item, visit_method_helper};
use syntax::visit::{visit_mod, visit_ty, vt};
@ -947,7 +947,7 @@ impl Resolver {
fn build_reduced_graph(this: @Resolver) {
let initial_parent =
ModuleReducedGraphParent((*self.graph_root).get_module());
visit_crate(*self.crate, initial_parent, mk_vt(@{
visit_crate(*self.crate, initial_parent, mk_vt(@Visitor {
visit_item: |item, context, visitor|
(*this).build_reduced_graph_for_item(item, context, visitor),
@ -3719,7 +3719,7 @@ impl Resolver {
fn resolve_crate(@self) {
debug!("(resolving crate) starting");
visit_crate(*self.crate, (), mk_vt(@{
visit_crate(*self.crate, (), mk_vt(@Visitor {
visit_item: |item, _context, visitor|
self.resolve_item(item, visitor),
visit_arm: |arm, _context, visitor|

View File

@ -2372,7 +2372,9 @@ fn trans_constant(ccx: @crate_ctxt, it: @ast::item) {
}
fn trans_constants(ccx: @crate_ctxt, crate: @ast::crate) {
visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{
visit::visit_crate(
*crate, (),
visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_item: |a| trans_constant(ccx, a),
..*visit::default_simple_visitor()
}));

View File

@ -390,7 +390,7 @@ fn trans_rtcall_or_lang_call_with_type_params(bcx: block,
fn body_contains_ret(body: ast::blk) -> bool {
let cx = {mut found: false};
visit::visit_block(body, cx, visit::mk_vt(@{
visit::visit_block(body, cx, visit::mk_vt(@visit::Visitor {
visit_item: |_i, _cx, _v| { },
visit_expr: |e: @ast::expr, cx: {mut found: bool}, v| {
if !cx.found {

View File

@ -142,7 +142,8 @@ fn traverse_public_item(cx: ctx, item: @item) {
}
fn mk_ty_visitor() -> visit::vt<ctx> {
visit::mk_vt(@{visit_ty: traverse_ty, ..*visit::default_visitor()})
visit::mk_vt(@visit::Visitor {visit_ty: traverse_ty,
..*visit::default_visitor()})
}
fn traverse_ty(ty: @Ty, cx: ctx, v: visit::vt<ctx>) {
@ -209,7 +210,7 @@ fn traverse_inline_body(cx: ctx, body: blk) {
fn traverse_item(i: @item, cx: ctx, _v: visit::vt<ctx>) {
traverse_public_item(cx, i);
}
visit::visit_block(body, cx, visit::mk_vt(@{
visit::visit_block(body, cx, visit::mk_vt(@visit::Visitor {
visit_expr: traverse_expr,
visit_item: traverse_item,
..*visit::default_visitor()
@ -217,12 +218,14 @@ fn traverse_inline_body(cx: ctx, body: blk) {
}
fn traverse_all_resources_and_impls(cx: ctx, crate_mod: _mod) {
visit::visit_mod(crate_mod, ast_util::dummy_sp(), 0, cx, visit::mk_vt(@{
visit::visit_mod(
crate_mod, ast_util::dummy_sp(), 0, cx,
visit::mk_vt(@visit::Visitor {
visit_expr: |_e, _cx, _v| { },
visit_item: |i, cx, v| {
visit::visit_item(i, cx, v);
match i.node {
item_struct(struct_def, _) if struct_def.dtor.is_some() => {
item_struct(sdef, _) if sdef.dtor.is_some() => {
traverse_public_item(cx, i);
}
item_impl(*) => {

View File

@ -340,7 +340,7 @@ fn mark_for_expr(cx: ctx, e: @expr) {
}
fn handle_body(cx: ctx, body: blk) {
let v = visit::mk_vt(@{
let v = visit::mk_vt(@visit::Visitor {
visit_expr: |e, cx, v| {
visit::visit_expr(e, cx, v);
mark_for_expr(cx, e);

View File

@ -47,7 +47,7 @@ use syntax::ast::*;
use syntax::ast_util::{is_local, local_def};
use syntax::ast_util;
use syntax::codemap::span;
use syntax::print::pprust::*;
use syntax::print::pprust;
use syntax::{ast, ast_map};
use syntax;
@ -55,7 +55,7 @@ export ProvidedMethodSource;
export ProvidedMethodInfo;
export ProvidedMethodsMap;
export InstantiatedTraitRef;
export TyVid, IntVid, FloatVid, FnVid, RegionVid, vid;
export TyVid, IntVid, FloatVid, FnVid, RegionVid, Vid;
export br_hashmap;
export is_instantiable;
export node_id_to_type;
@ -118,7 +118,8 @@ export ty_opaque_closure_ptr, mk_opaque_closure_ptr;
export ty_opaque_box, mk_opaque_box;
export ty_float, mk_float, mk_mach_float, type_is_fp;
export ty_fn, FnTy, FnTyBase, FnMeta, FnSig, mk_fn;
export ty_fn_proto, ty_fn_purity, ty_fn_ret, tys_in_fn_ty;
export ty_fn_proto, ty_fn_purity, ty_fn_ret, tys_in_fn_sig;
export replace_fn_return_type;
export ty_int, mk_int, mk_mach_int, mk_char;
export mk_i8, mk_u8, mk_i16, mk_u16, mk_i32, mk_u32, mk_i64, mk_u64;
export mk_f32, mk_f64;
@ -139,7 +140,8 @@ export ty_tup, mk_tup;
export ty_type, mk_type;
export ty_uint, mk_uint, mk_mach_uint;
export ty_uniq, mk_uniq, mk_imm_uniq, type_is_unique_box;
export ty_infer, mk_infer, type_is_ty_var, mk_var, mk_int_var, mk_float_var;
export ty_infer, mk_infer, type_is_ty_var, mk_var, mk_int_var;
export mk_float_var;
export InferTy, TyVar, IntVar, FloatVar;
export ValueMode, ReadValue, CopyValue, MoveValue;
export ty_self, mk_self, type_has_self;
@ -222,7 +224,6 @@ export terr_regions_insufficiently_polymorphic;
export terr_regions_overly_polymorphic;
export terr_proto_mismatch;
export terr_fn, terr_trait;
export purity_to_str;
export onceness_to_str;
export param_tys_in_type;
export eval_repeat_count;
@ -519,6 +520,7 @@ pure fn type_id(t: t) -> uint { get(t).id }
* times.
* - `region` is the region bound on the function's upvars (often &static).
* - `bounds` is the parameter bounds on the function's upvars. */
#[deriving_eq]
struct FnMeta {
purity: ast::purity,
proto: ast::Proto,
@ -533,6 +535,7 @@ struct FnMeta {
*
* - `inputs` is the list of arguments and their modes.
* - `output` is the return type. */
#[deriving_eq]
struct FnSig {
inputs: ~[arg],
output: t
@ -543,9 +546,16 @@ struct FnSig {
* type signature. This particular type is parameterized
* by the meta information because, in some cases, the
* meta information is inferred. */
#[deriving_eq]
struct FnTyBase<M: cmp::Eq> {
meta: M,
sig: FnSig
meta: M, // Either FnMeta or FnVid
sig: FnSig // Types of arguments/return type
}
impl<M: to_bytes::IterBytes> FnTyBase<M> : to_bytes::IterBytes {
pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
to_bytes::iter_bytes_2(&self.meta, &self.sig, lsb0, f)
}
}
type FnTy = FnTyBase<FnMeta>;
@ -673,7 +683,7 @@ enum sty {
ty_param(param_ty), // type parameter
ty_self, // special, implicit `self` type parameter
ty_infer(InferTy), // soething used only during inference/typeck
ty_infer(InferTy), // something used only during inference/typeck
ty_err, // Also only used during inference/typeck, to represent
// the type of an erroneous expression (helps cut down
// on non-useful type error messages)
@ -742,6 +752,7 @@ enum FnVid = uint;
#[auto_decode]
enum RegionVid = uint;
#[deriving_eq]
enum InferTy {
TyVar(TyVid),
IntVar(IntVid),
@ -753,7 +764,7 @@ impl InferTy : to_bytes::IterBytes {
match *self {
TyVar(ref tv) => to_bytes::iter_bytes_2(&0u8, tv, lsb0, f),
IntVar(ref iv) => to_bytes::iter_bytes_2(&1u8, iv, lsb0, f),
FloatVar(ref fv) => to_bytes::iter_bytes_2(&2u8, fv, lsb0, f)
FloatVar(ref fv) => to_bytes::iter_bytes_2(&2u8, fv, lsb0, f),
}
}
}
@ -804,64 +815,67 @@ impl param_bound : to_bytes::IterBytes {
}
}
trait vid {
trait Vid {
pure fn to_uint() -> uint;
pure fn to_str() -> ~str;
}
impl TyVid: vid {
impl TyVid: Vid {
pure fn to_uint() -> uint { *self }
}
impl TyVid: ToStr {
pure fn to_str() -> ~str { fmt!("<V%u>", self.to_uint()) }
}
impl IntVid: vid {
impl IntVid: Vid {
pure fn to_uint() -> uint { *self }
}
impl IntVid: ToStr {
pure fn to_str() -> ~str { fmt!("<VI%u>", self.to_uint()) }
}
impl FloatVid: vid {
impl FloatVid: Vid {
pure fn to_uint() -> uint { *self }
}
impl FloatVid: ToStr {
pure fn to_str() -> ~str { fmt!("<VF%u>", self.to_uint()) }
}
impl FnVid: vid {
impl FnVid: Vid {
pure fn to_uint() -> uint { *self }
}
impl FnVid: ToStr {
pure fn to_str() -> ~str { fmt!("<F%u>", self.to_uint()) }
}
impl RegionVid: vid {
impl RegionVid: Vid {
pure fn to_uint() -> uint { *self }
}
impl RegionVid: ToStr {
pure fn to_str() -> ~str { fmt!("%?", self) }
}
impl InferTy {
pure fn to_hash() -> uint {
match self {
TyVar(v) => v.to_uint() << 1,
IntVar(v) => (v.to_uint() << 1) + 1,
FloatVar(v) => (v.to_uint() << 1) + 2
impl FnSig : ToStr {
pure fn to_str() -> ~str {
// grr, without tcx not much we can do.
return ~"(...)";
}
}
impl InferTy: ToStr {
pure fn to_str() -> ~str {
match self {
TyVar(v) => v.to_str(),
IntVar(v) => v.to_str(),
FloatVar(v) => v.to_str()
TyVar(ref v) => v.to_str(),
IntVar(ref v) => v.to_str(),
FloatVar(ref v) => v.to_str()
}
}
}
trait purity_to_str {
pure fn to_str() -> ~str;
}
impl purity: purity_to_str {
pure fn to_str() -> ~str {
purity_to_str(self)
}
}
impl RegionVid : to_bytes::IterBytes {
pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
(**self).iter_bytes(lsb0, f)
@ -1197,7 +1211,7 @@ fn mk_int_var(cx: ctxt, v: IntVid) -> t { mk_infer(cx, IntVar(v)) }
fn mk_float_var(cx: ctxt, v: FloatVid) -> t { mk_infer(cx, FloatVar(v)) }
fn mk_infer(cx: ctxt, it: InferTy) -> t { mk_t(cx, ty_infer(it)) }
fn mk_infer(cx: ctxt, +it: InferTy) -> t { mk_t(cx, ty_infer(it)) }
fn mk_self(cx: ctxt) -> t { mk_t(cx, ty_self) }
@ -1369,15 +1383,8 @@ fn fold_sty(sty: &sty, fldop: fn(t) -> t) -> sty {
ty_tup(new_ts)
}
ty_fn(ref f) => {
let new_args = f.sig.inputs.map(|a| {
let new_ty = fldop(a.ty);
{mode: a.mode, ty: new_ty}
});
let new_output = fldop(f.sig.output);
ty_fn(FnTyBase {
meta: f.meta,
sig: FnSig {inputs: new_args, output: new_output}
})
let sig = fold_sig(&f.sig, fldop);
ty_fn(FnTyBase {meta: f.meta, sig: sig})
}
ty_rptr(r, tm) => {
ty_rptr(r, {ty: fldop(tm.ty), mutbl: tm.mutbl})
@ -1424,8 +1431,8 @@ fn fold_regions_and_ty(
fn fold_substs(
substs: &substs,
fldr: fn(r: Region) -> Region,
fldt: fn(t: t) -> t) -> substs {
fldt: fn(t: t) -> t) -> substs
{
{self_r: substs.self_r.map(|r| fldr(*r)),
self_ty: substs.self_ty.map(|t| fldt(*t)),
tps: substs.tps.map(|t| fldt(*t))}
@ -1457,18 +1464,9 @@ fn fold_regions_and_ty(
ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt), vst)
}
ty_fn(ref f) => {
let new_region = fldr(f.meta.region);
let new_args = vec::map(f.sig.inputs, |a| {
let new_ty = fldfnt(a.ty);
{mode: a.mode, ty: new_ty}
});
let new_output = fldfnt(f.sig.output);
ty::mk_fn(cx, FnTyBase {
meta: FnMeta {region: new_region,
ty::mk_fn(cx, FnTyBase {meta: FnMeta {region: fldr(f.meta.region),
..f.meta},
sig: FnSig {inputs: new_args,
output: new_output}
})
sig: fold_sig(&f.sig, fldfnt)})
}
ref sty => {
fold_sty_to_ty(cx, sty, |t| fldt(t))
@ -1509,6 +1507,7 @@ fn fold_regions(
{
fn do_fold(cx: ctxt, ty: t, in_fn: bool,
fldr: fn(Region, bool) -> Region) -> t {
debug!("do_fold(ty=%s, in_fn=%b)", ty_to_str(cx, ty), in_fn);
if !type_has_regions(ty) { return ty; }
fold_regions_and_ty(
cx, ty,
@ -2834,8 +2833,9 @@ impl arg : to_bytes::IterBytes {
impl FnMeta : to_bytes::IterBytes {
pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
to_bytes::iter_bytes_4(&self.purity,
to_bytes::iter_bytes_5(&self.purity,
&self.proto,
&self.onceness,
&self.region,
&self.bounds,
lsb0, f);
@ -2887,10 +2887,7 @@ impl sty : to_bytes::IterBytes {
to_bytes::iter_bytes_2(&11u8, fs, lsb0, f),
ty_fn(ref ft) =>
to_bytes::iter_bytes_3(&12u8,
&ft.meta,
&ft.sig,
lsb0, f),
to_bytes::iter_bytes_2(&12u8, ft, lsb0, f),
ty_self => 13u8.iter_bytes(lsb0, f),
@ -2997,9 +2994,30 @@ fn ty_region(ty: t) -> Region {
}
}
fn replace_fn_return_type(tcx: ctxt, fn_type: t, ret_type: t) -> t {
/*!
*
* Returns a new function type based on `fn_type` but returning a value of
* type `ret_type` instead. */
match ty::get(fn_type).sty {
ty::ty_fn(ref fty) => {
ty::mk_fn(tcx, FnTyBase {
meta: fty.meta,
sig: FnSig {output: ret_type, ..copy fty.sig}
})
}
_ => {
tcx.sess.bug(fmt!(
"replace_fn_ret() invoked with non-fn-type: %s",
ty_to_str(tcx, fn_type)));
}
}
}
// Returns a vec of all the input and output types of fty.
fn tys_in_fn_ty(fty: &FnTy) -> ~[t] {
vec::append_one(fty.sig.inputs.map(|a| a.ty), fty.sig.output)
fn tys_in_fn_sig(sig: &FnSig) -> ~[t] {
vec::append_one(sig.inputs.map(|a| a.ty), sig.output)
}
// Just checks whether it's a fn that returns bool,
@ -3444,18 +3462,16 @@ fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str {
terr_mismatch => ~"types differ",
terr_purity_mismatch(values) => {
fmt!("expected %s fn but found %s fn",
purity_to_str(values.expected),
purity_to_str(values.found))
values.expected.to_str(), values.found.to_str())
}
terr_onceness_mismatch(values) => {
fmt!("expected %s fn but found %s fn",
onceness_to_str(values.expected),
onceness_to_str(values.found))
values.expected.to_str(), values.found.to_str())
}
terr_proto_mismatch(values) => {
fmt!("expected %s closure, found %s closure",
proto_ty_to_str(cx, values.expected),
proto_ty_to_str(cx, values.found))
proto_ty_to_str(cx, values.expected, false),
proto_ty_to_str(cx, values.found, false))
}
terr_mutability => ~"values differ in mutability",
terr_box_mutability => ~"boxed values differ in mutability",
@ -3489,7 +3505,8 @@ fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str {
terr_arg_count => ~"incorrect number of function parameters",
terr_mode_mismatch(values) => {
fmt!("expected argument mode %s, but found %s",
mode_to_str(values.expected), mode_to_str(values.found))
pprust::mode_to_str(values.expected),
pprust::mode_to_str(values.found))
}
terr_regions_does_not_outlive(*) => {
fmt!("lifetime mismatch")
@ -4398,30 +4415,6 @@ impl vstore : cmp::Eq {
pure fn ne(&self, other: &vstore) -> bool { !(*self).eq(other) }
}
impl FnMeta : cmp::Eq {
pure fn eq(&self, other: &FnMeta) -> bool {
(*self).purity == (*other).purity &&
(*self).proto == (*other).proto &&
(*self).bounds == (*other).bounds
}
pure fn ne(&self, other: &FnMeta) -> bool { !(*self).eq(other) }
}
impl FnSig : cmp::Eq {
pure fn eq(&self, other: &FnSig) -> bool {
(*self).inputs == (*other).inputs &&
(*self).output == (*other).output
}
pure fn ne(&self, other: &FnSig) -> bool { !(*self).eq(other) }
}
impl<M: cmp::Eq> FnTyBase<M> : cmp::Eq {
pure fn eq(&self, other: &FnTyBase<M>) -> bool {
(*self).meta == (*other).meta && (*self).sig == (*other).sig
}
pure fn ne(&self, other: &FnTyBase<M>) -> bool { !(*self).eq(other) }
}
impl TyVid : cmp::Eq {
pure fn eq(&self, other: &TyVid) -> bool { *(*self) == *(*other) }
pure fn ne(&self, other: &TyVid) -> bool { *(*self) != *(*other) }
@ -4532,13 +4525,6 @@ impl substs : cmp::Eq {
pure fn ne(&self, other: &substs) -> bool { !(*self).eq(other) }
}
impl InferTy : cmp::Eq {
pure fn eq(&self, other: &InferTy) -> bool {
(*self).to_hash() == (*other).to_hash()
}
pure fn ne(&self, other: &InferTy) -> bool { !(*self).eq(other) }
}
impl sty : cmp::Eq {
pure fn eq(&self, other: &sty) -> bool {
match (/*bad*/copy *self) {
@ -4651,9 +4637,9 @@ impl sty : cmp::Eq {
_ => false
}
}
ty_infer(e0a) => {
ty_infer(ref e0a) => {
match (*other) {
ty_infer(e0b) => e0a == e0b,
ty_infer(ref e0b) => *e0a == *e0b,
_ => false
}
}

View File

@ -1137,7 +1137,7 @@ impl LookupContext {
ty::item_path_str(self.tcx(), did)));
}
fn infcx(&self) -> infer::infer_ctxt {
fn infcx(&self) -> @infer::InferCtxt {
self.fcx.inh.infcx
}

View File

@ -82,8 +82,9 @@ use middle::capture;
use middle::const_eval;
use middle::pat_util::pat_id_map;
use middle::pat_util;
use middle::ty::{TyVid, vid, FnTyBase, FnMeta, FnSig, VariantInfo_, field};
use middle::ty::{TyVid, Vid, FnTyBase, FnMeta, FnSig, VariantInfo_, field};
use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty};
use middle::ty::{re_bound, br_cap_avoid};
use middle::ty;
use middle::typeck::astconv::{ast_conv, ast_path_to_ty};
use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty};
@ -91,6 +92,7 @@ use middle::typeck::astconv;
use middle::typeck::check::_match::pat_ctxt;
use middle::typeck::check::method::TransformTypeNormally;
use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_ty;
use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
use middle::typeck::check::vtable::{LocationInfo, VtableContext};
use middle::typeck::crate_ctxt;
use middle::typeck::infer::{resolve_type, force_tvar};
@ -187,7 +189,7 @@ type self_info = {
/// `bar()` will each have their own `fn_ctxt`, but they will
/// share the inherited fields.
struct inherited {
infcx: infer::infer_ctxt,
infcx: @infer::InferCtxt,
locals: HashMap<ast::node_id, TyVid>,
node_types: HashMap<ast::node_id, ty::t>,
node_type_substs: HashMap<ast::node_id, ty::substs>,
@ -265,7 +267,7 @@ fn blank_fn_ctxt(ccx: @crate_ctxt, rty: ty::t,
}
fn check_item_types(ccx: @crate_ctxt, crate: @ast::crate) {
let visit = visit::mk_simple_visitor(@{
let visit = visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_item: |a| check_item(ccx, a),
.. *visit::default_simple_visitor()
});
@ -273,7 +275,7 @@ fn check_item_types(ccx: @crate_ctxt, crate: @ast::crate) {
}
fn check_bare_fn(ccx: @crate_ctxt,
decl: ast::fn_decl,
decl: &ast::fn_decl,
body: ast::blk,
id: ast::node_id,
self_info: Option<self_info>) {
@ -290,7 +292,7 @@ fn check_bare_fn(ccx: @crate_ctxt,
fn check_fn(ccx: @crate_ctxt,
self_info: Option<self_info>,
fn_ty: &ty::FnTy,
decl: ast::fn_decl,
decl: &ast::fn_decl,
body: ast::blk,
fn_kind: FnKind,
old_fcx: Option<@fn_ctxt>) {
@ -305,15 +307,15 @@ fn check_fn(ccx: @crate_ctxt,
// types with free ones. The free region references will be bound
// the node_id of the body block.
let {isr: isr, self_info: self_info, fn_ty: fn_ty} = {
let {isr, self_info, fn_sig} = {
let old_isr = option::map_default(&old_fcx, @Nil,
|fcx| fcx.in_scope_regions);
replace_bound_regions_in_fn_ty(tcx, old_isr, self_info, fn_ty,
replace_bound_regions_in_fn_sig(tcx, old_isr, self_info, &fn_ty.sig,
|br| ty::re_free(body.node.id, br))
};
let arg_tys = fn_ty.sig.inputs.map(|a| a.ty);
let ret_ty = fn_ty.sig.output;
let arg_tys = fn_sig.inputs.map(|a| a.ty);
let ret_ty = fn_sig.output;
debug!("check_fn(arg_tys=%?, ret_ty=%?, self_info.self_ty=%?)",
arg_tys.map(|a| ppaux::ty_to_str(tcx, *a)),
@ -406,12 +408,12 @@ fn check_fn(ccx: @crate_ctxt,
// resolved when the enclosing scope finishes up.
if old_fcx.is_none() {
vtable::resolve_in_block(fcx, body);
regionck::regionck_fn(fcx, decl, body);
regionck::regionck_fn(fcx, body);
writeback::resolve_type_vars_in_fn(fcx, decl, body, self_info);
}
fn gather_locals(fcx: @fn_ctxt,
decl: ast::fn_decl,
decl: &ast::fn_decl,
body: ast::blk,
arg_tys: ~[ty::t],
self_info: Option<self_info>) {
@ -503,7 +505,8 @@ fn check_fn(ccx: @crate_ctxt,
}
fn visit_item(_i: @ast::item, &&_e: (), _v: visit::vt<()>) { }
let visit = visit::mk_vt(@{visit_local: visit_local,
let visit = visit::mk_vt(
@visit::Visitor {visit_local: visit_local,
visit_pat: visit_pat,
visit_fn: visit_fn,
visit_item: visit_item,
@ -520,7 +523,7 @@ fn check_method(ccx: @crate_ctxt, method: @ast::method,
self_id: method.self_id,
def_id: self_impl_def_id,
explicit_self: method.self_ty };
check_bare_fn(ccx, method.decl, method.body, method.id, Some(self_info));
check_bare_fn(ccx, &method.decl, method.body, method.id, Some(self_info));
}
fn check_no_duplicate_fields(tcx: ty::ctxt, fields:
@ -559,7 +562,8 @@ fn check_struct(ccx: @crate_ctxt, struct_def: @ast::struct_def,
spanned { node: ast::sty_by_ref,
span: ast_util::dummy_sp() } };
// typecheck the dtor
check_bare_fn(ccx, ast_util::dtor_dec(),
let dtor_dec = ast_util::dtor_dec();
check_bare_fn(ccx, &dtor_dec,
dtor.node.body, dtor.node.id,
Some(class_t));
};
@ -583,7 +587,7 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
it.id);
}
ast::item_fn(ref decl, _, _, ref body) => {
check_bare_fn(ccx, *decl, (*body), it.id, None);
check_bare_fn(ccx, decl, (*body), it.id, None);
}
ast::item_impl(_, _, ty, ms) => {
let rp = ccx.tcx.region_paramd_items.find(it.id);
@ -657,7 +661,7 @@ impl @fn_ctxt: ast_conv {
}
impl @fn_ctxt {
fn infcx() -> infer::infer_ctxt { self.inh.infcx }
fn infcx() -> @infer::InferCtxt { self.inh.infcx }
fn search_in_scope_regions(br: ty::bound_region)
-> Result<ty::Region, ~str>
{
@ -1519,7 +1523,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
fn check_expr_fn(fcx: @fn_ctxt,
expr: @ast::expr,
ast_proto_opt: Option<ast::Proto>,
decl: ast::fn_decl,
decl: &ast::fn_decl,
body: ast::blk,
fn_kind: FnKind,
expected: Option<ty::t>) {
@ -1569,7 +1573,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
fcx, fcx,
proto, purity, expected_onceness,
/*bounds:*/ @~[], /*opt_region:*/ None,
decl, expected_tys, expr.span);
*decl, expected_tys, expr.span);
// XXX: Bad copy.
let fty = ty::mk_fn(tcx, copy fn_ty);
@ -2157,12 +2161,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
}
ast::expr_fn(proto, ref decl, ref body, cap_clause) => {
check_expr_fn(fcx, expr, Some(proto),
*decl, (*body), Vanilla, expected);
decl, (*body), Vanilla, expected);
capture::check_capture_clause(tcx, expr.id, cap_clause);
}
ast::expr_fn_block(ref decl, ref body, cap_clause) => {
check_expr_fn(fcx, expr, None,
*decl, (*body), Vanilla, expected);
decl, (*body), Vanilla, expected);
capture::check_capture_clause(tcx, expr.id, cap_clause);
}
ast::expr_loop_body(b) => {
@ -2218,7 +2222,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
match b.node {
ast::expr_fn_block(ref decl, ref body, cap_clause) => {
check_expr_fn(fcx, b, None,
*decl, (*body), ForLoop, Some(inner_ty));
decl, *body, ForLoop, Some(inner_ty));
demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
capture::check_capture_clause(tcx, b.id, cap_clause);
}
@ -2227,20 +2231,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
}
let block_ty = structurally_resolved_type(
fcx, expr.span, fcx.node_ty(b.id));
match ty::get(block_ty).sty {
ty::ty_fn(ref fty) => {
if !err_happened {
fcx.write_ty(expr.id, ty::mk_fn(tcx, FnTyBase {
meta: (*fty).meta,
sig: FnSig {output: ty::mk_bool(tcx),
../*bad*/copy (*fty).sig}
}));
}
else {
if err_happened {
fcx.write_ty(expr.id, ty::mk_err(fcx.tcx()));
}
}
_ => fail ~"expected fn type"
} else {
let loop_body_ty = ty::replace_fn_return_type(tcx, block_ty,
ty::mk_bool(tcx));
fcx.write_ty(expr.id, loop_body_ty);
}
}
ast::expr_do_body(b) => {
@ -2267,21 +2263,14 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
match b.node {
ast::expr_fn_block(ref decl, ref body, cap_clause) => {
check_expr_fn(fcx, b, None,
*decl, (*body), DoBlock, Some(inner_ty));
decl, *body, DoBlock, Some(inner_ty));
demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
capture::check_capture_clause(tcx, b.id, cap_clause);
}
// argh
_ => fail ~"expected fn ty"
}
let block_ty = structurally_resolved_type(
fcx, expr.span, fcx.node_ty(b.id));
match ty::get(block_ty).sty {
ty::ty_fn(ref fty) => {
fcx.write_ty(expr.id, ty::mk_fn(tcx, (/*bad*/copy *fty)));
}
_ => fail ~"expected fn ty"
}
fcx.write_ty(expr.id, fcx.node_ty(b.id));
}
ast::expr_block(ref b) => {
// If this is an unchecked block, turn off purity-checking

View File

@ -114,7 +114,6 @@ fn regionck_expr(fcx: @fn_ctxt, e: @ast::expr) {
}
fn regionck_fn(fcx: @fn_ctxt,
_decl: ast::fn_decl,
blk: ast::blk) {
let rcx = rcx_({fcx:fcx, mut errors_reported: 0});
let v = regionck_visitor();
@ -123,7 +122,7 @@ fn regionck_fn(fcx: @fn_ctxt,
}
fn regionck_visitor() -> rvt {
visit::mk_vt(@{visit_item: visit_item,
visit::mk_vt(@visit::Visitor {visit_item: visit_item,
visit_stmt: visit_stmt,
visit_expr: visit_expr,
visit_block: visit_block,

View File

@ -12,6 +12,7 @@
use core::prelude::*;
use middle::ty::{FnTyBase};
use middle::ty;
use middle::typeck::check::self_info;
use middle::typeck::isr_alist;
@ -25,22 +26,37 @@ use syntax::print::pprust::{expr_to_str};
// Helper functions related to manipulating region types.
fn replace_bound_regions_in_fn_ty(
pub fn replace_bound_regions_in_fn_ty(
tcx: ty::ctxt,
isr: isr_alist,
self_info: Option<self_info>,
fn_ty: &ty::FnTy,
mapf: fn(ty::bound_region) -> ty::Region) ->
{isr: isr_alist, self_info: Option<self_info>, fn_ty: ty::FnTy} {
{isr: isr_alist, self_info: Option<self_info>, fn_ty: ty::FnTy}
{
let {isr, self_info, fn_sig} =
replace_bound_regions_in_fn_sig(
tcx, isr, self_info, &fn_ty.sig, mapf);
{isr: isr,
self_info: self_info,
fn_ty: FnTyBase {meta: fn_ty.meta,
sig: fn_sig}}
}
pub fn replace_bound_regions_in_fn_sig(
tcx: ty::ctxt,
isr: isr_alist,
self_info: Option<self_info>,
fn_sig: &ty::FnSig,
mapf: fn(ty::bound_region) -> ty::Region) ->
{isr: isr_alist, self_info: Option<self_info>, fn_sig: ty::FnSig}
{
// Take self_info apart; the self_ty part is the only one we want
// to update here.
let (self_ty, rebuild_self_info) = match self_info {
Some(copy s) => (Some(s.self_ty), |t| Some({self_ty: t,.. s})),
None => (None, |_t| None)
};
let self_ty = self_info.map(|s| s.self_ty);
let rebuild_self_info = |t| self_info.map(|s| {self_ty: t, ..*s});
let mut all_tys = ty::tys_in_fn_ty(fn_ty);
let mut all_tys = ty::tys_in_fn_sig(fn_sig);
match self_info {
Some({explicit_self: ast::spanned { node: ast::sty_region(m),
@ -56,10 +72,10 @@ fn replace_bound_regions_in_fn_ty(
for self_ty.each |t| { all_tys.push(*t) }
debug!("replace_bound_regions_in_fn_ty(self_info.self_ty=%?, fn_ty=%s, \
debug!("replace_bound_regions_in_fn_sig(self_info.self_ty=%?, fn_sig=%s, \
all_tys=%?)",
self_ty.map(|t| ppaux::ty_to_str(tcx, *t)),
ppaux::ty_to_str(tcx, ty::mk_fn(tcx, *fn_ty)),
ppaux::fn_sig_to_str(tcx, fn_sig),
all_tys.map(|t| ppaux::ty_to_str(tcx, *t)));
let _i = indenter();
@ -67,17 +83,15 @@ fn replace_bound_regions_in_fn_ty(
debug!("br=%?", br);
mapf(br)
};
let ty_fn = ty::ty_fn(/*bad*/copy *fn_ty);
let t_fn = ty::fold_sty_to_ty(tcx, &ty_fn, |t| {
let new_fn_sig = ty::fold_sig(fn_sig, |t| {
replace_bound_regions(tcx, isr, t)
});
let t_self = self_ty.map(|t| replace_bound_regions(tcx, isr, *t));
debug!("result of replace_bound_regions_in_fn_ty: self_info.self_ty=%?, \
fn_ty=%s",
debug!("result of replace_bound_regions_in_fn_sig: self_info.self_ty=%?, \
fn_sig=%s",
t_self.map(|t| ppaux::ty_to_str(tcx, *t)),
ppaux::ty_to_str(tcx, t_fn));
ppaux::fn_sig_to_str(tcx, &new_fn_sig));
// Glue updated self_ty back together with its original def_id.
let new_self_info: Option<self_info> = match t_self {
@ -87,9 +101,7 @@ fn replace_bound_regions_in_fn_ty(
return {isr: isr,
self_info: new_self_info,
fn_ty: match ty::get(t_fn).sty { ty::ty_fn(ref o) => /*bad*/copy *o,
_ => tcx.sess.bug(~"replace_bound_regions_in_fn_ty: impossible")}};
fn_sig: new_fn_sig};
// Takes `isr`, a (possibly empty) mapping from in-scope region
// names ("isr"s) to their corresponding regions; `tys`, a list of
@ -158,7 +170,7 @@ fn replace_bound_regions_in_fn_ty(
ty: ty::t) -> ty::t {
do ty::fold_regions(tcx, ty) |r, in_fn| {
match r {
let r1 = match r {
// As long as we are not within a fn() type, `&T` is
// mapped to the free region anon_r. But within a fn
// type, it remains bound.
@ -187,7 +199,8 @@ fn replace_bound_regions_in_fn_ty(
ty::re_scope(_) |
ty::re_free(_, _) |
ty::re_infer(_) => r
}
};
r1
}
}
}

View File

@ -14,7 +14,7 @@ use middle::resolve;
use middle::ty;
use middle::typeck::check::{fn_ctxt, impl_self_ty};
use middle::typeck::check::{structurally_resolved_type};
use middle::typeck::infer::{fixup_err_to_str, infer_ctxt};
use middle::typeck::infer::{fixup_err_to_str, InferCtxt};
use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type};
use middle::typeck::infer;
use middle::typeck::{crate_ctxt, vtable_origin, vtable_param, vtable_res};
@ -63,7 +63,7 @@ struct LocationInfo {
/// callback function to call in case of type error.
struct VtableContext {
ccx: @crate_ctxt,
infcx: infer::infer_ctxt
infcx: @infer::InferCtxt
}
impl VtableContext {
@ -685,8 +685,8 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) {
ex.span,
fmt!("failed to find an implementation of trait \
%s for %s",
ppaux::ty_to_str(fcx.tcx(), target_ty),
ppaux::ty_to_str(fcx.tcx(), ty)));
fcx.infcx().ty_to_str(target_ty),
fcx.infcx().ty_to_str(ty)));
}
}
Some(vtable) => {
@ -714,7 +714,7 @@ fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
// Detect points where a trait-bounded type parameter is
// instantiated, resolve the impls for the parameters.
fn resolve_in_block(fcx: @fn_ctxt, bl: ast::blk) {
visit::visit_block(bl, fcx, visit::mk_vt(@{
visit::visit_block(bl, fcx, visit::mk_vt(@visit::Visitor {
visit_expr: resolve_expr,
visit_item: fn@(_i: @ast::item, &&_e: @fn_ctxt,
_v: visit::vt<@fn_ctxt>) {},

View File

@ -161,9 +161,8 @@ fn visit_expr(e: @ast::expr, wbcx: wb_ctxt, v: wb_vt) {
resolve_type_vars_for_node(wbcx, e.span, e.id);
resolve_method_map_entry(wbcx.fcx, e.span, e.id);
resolve_method_map_entry(wbcx.fcx, e.span, e.callee_id);
match /*bad*/copy e.node {
ast::expr_fn(_, decl, _, _) |
ast::expr_fn_block(decl, _, _) => {
match e.node {
ast::expr_fn_block(ref decl, _, _) => {
for vec::each(decl.inputs) |input| {
let r_ty = resolve_type_vars_for_node(wbcx, e.span, input.id);
@ -237,7 +236,7 @@ fn visit_item(_item: @ast::item, _wbcx: wb_ctxt, _v: wb_vt) {
}
fn mk_visitor() -> visit::vt<wb_ctxt> {
visit::mk_vt(@{visit_item: visit_item,
visit::mk_vt(@visit::Visitor {visit_item: visit_item,
visit_stmt: visit_stmt,
visit_expr: visit_expr,
visit_block: visit_block,
@ -254,7 +253,7 @@ fn resolve_type_vars_in_expr(fcx: @fn_ctxt, e: @ast::expr) -> bool {
}
fn resolve_type_vars_in_fn(fcx: @fn_ctxt,
decl: ast::fn_decl,
decl: &ast::fn_decl,
blk: ast::blk,
self_info: Option<self_info>) -> bool {
let wbcx = {fcx: fcx, mut success: true};

View File

@ -34,7 +34,7 @@ use middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec, type_kind_ext};
use middle::ty::{type_is_ty_var};
use middle::ty;
use middle::typeck::crate_ctxt;
use middle::typeck::infer::{infer_ctxt, can_mk_subty};
use middle::typeck::infer::{InferCtxt, can_mk_subty};
use middle::typeck::infer::{new_infer_ctxt, resolve_ivar};
use middle::typeck::infer::{resolve_nested_tvar, resolve_type};
use syntax::ast::{crate, def_id, def_mod, def_ty};
@ -51,6 +51,7 @@ use syntax::codemap::span;
use syntax::parse;
use syntax::visit::{default_simple_visitor, default_visitor};
use syntax::visit::{mk_simple_visitor, mk_vt, visit_crate, visit_item};
use syntax::visit::{Visitor, SimpleVisitor};
use syntax::visit::{visit_mod};
use util::ppaux::ty_to_str;
@ -69,7 +70,7 @@ struct UniversalQuantificationResult {
bounds: @~[param_bounds]
}
fn get_base_type(inference_context: infer_ctxt, span: span, original_type: t)
fn get_base_type(inference_context: @InferCtxt, span: span, original_type: t)
-> Option<t> {
let resolved_type;
@ -116,7 +117,7 @@ fn get_base_type(inference_context: infer_ctxt, span: span, original_type: t)
}
// Returns the def ID of the base type, if there is one.
fn get_base_type_def_id(inference_context: infer_ctxt,
fn get_base_type_def_id(inference_context: @InferCtxt,
span: span,
original_type: t)
-> Option<def_id> {
@ -181,7 +182,7 @@ fn CoherenceChecker(crate_context: @crate_ctxt) -> CoherenceChecker {
struct CoherenceChecker {
crate_context: @crate_ctxt,
inference_context: infer_ctxt,
inference_context: @InferCtxt,
// A mapping from implementations to the corresponding base type
// definition ID.
@ -199,7 +200,7 @@ impl CoherenceChecker {
// Check implementations and traits. This populates the tables
// containing the inherent methods and extension methods. It also
// builds up the trait inheritance table.
visit_crate(*crate, (), mk_simple_visitor(@{
visit_crate(*crate, (), mk_simple_visitor(@SimpleVisitor {
visit_item: |item| {
debug!("(checking coherence) item '%s'",
self.crate_context.tcx.sess.str_of(item.ident));
@ -588,7 +589,7 @@ impl CoherenceChecker {
// Privileged scope checking
fn check_privileged_scopes(crate: @crate) {
visit_crate(*crate, (), mk_vt(@{
visit_crate(*crate, (), mk_vt(@Visitor {
visit_item: |item, _context, visitor| {
match /*bad*/copy item.node {
item_mod(module_) => {

View File

@ -100,7 +100,9 @@ fn collect_item_types(ccx: @crate_ctxt, crate: @ast::crate) {
}
}
visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{
visit::visit_crate(
*crate, (),
visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_item: |a|convert(ccx, a),
visit_foreign_item: |a|convert_foreign(ccx, a),
.. *visit::default_simple_visitor()

View File

@ -63,16 +63,16 @@ use core::prelude::*;
use middle::ty::TyVar;
use middle::ty;
use middle::typeck::infer::{ares, cres};
use middle::typeck::infer::combine::combine_fields;
use middle::typeck::infer::combine::CombineFields;
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::to_str::ToStr;
use middle::typeck::infer::to_str::InferStr;
use util::common::{indent, indenter};
use core::option;
use syntax::ast::{m_const, m_imm, m_mutbl};
use syntax::ast;
fn to_ares(+c: cres<ty::t>) -> ares {
fn to_ares<T>(+c: cres<T>) -> ares {
match c {
Ok(_) => Ok(None),
Err(ref e) => Err((*e))
@ -82,13 +82,13 @@ fn to_ares(+c: cres<ty::t>) -> ares {
// Note: Assign is not actually a combiner, in that it does not
// conform to the same interface, though it performs a similar
// function.
enum Assign = combine_fields;
enum Assign = CombineFields;
impl Assign {
fn tys(a: ty::t, b: ty::t) -> ares {
debug!("Assign.tys(%s => %s)",
a.to_str(self.infcx),
b.to_str(self.infcx));
a.inf_str(self.infcx),
b.inf_str(self.infcx));
let _r = indenter();
debug!("Assign.tys: copying first type");
@ -146,8 +146,8 @@ priv impl Assign {
+a_bnd: Option<ty::t>, +b_bnd: Option<ty::t>) -> ares {
debug!("Assign.assign_tys_or_sub(%s => %s, %s => %s)",
a.to_str(self.infcx), b.to_str(self.infcx),
a_bnd.to_str(self.infcx), b_bnd.to_str(self.infcx));
a.inf_str(self.infcx), b.inf_str(self.infcx),
a_bnd.inf_str(self.infcx), b_bnd.inf_str(self.infcx));
let _r = indenter();
fn is_borrowable(v: ty::vstore) -> bool {
@ -210,18 +210,28 @@ priv impl Assign {
let nr_b = ty::mk_fn(self.infcx.tcx, ty::FnTyBase {
meta: ty::FnMeta {proto: a_f.meta.proto,
..b_f.meta},
sig: /*bad*/copy b_f.sig
sig: copy b_f.sig
});
self.try_assign(0, ty::AutoBorrowFn,
a, nr_b, m_imm, b_f.meta.region)
}
(ty::ty_fn(ref a_f), ty::ty_fn(ref b_f))
if a_f.meta.proto == ast::ProtoBare => {
let b1_f = ty::FnTyBase {
meta: ty::FnMeta {proto: ast::ProtoBare,
..b_f.meta},
sig: copy b_f.sig
};
// Eventually we will need to add some sort of
// adjustment here so that trans can add an
// extra NULL env pointer:
to_ares(Sub(*self).fns(a_f, &b1_f))
}
// check for &T being assigned to *T:
(ty::ty_rptr(_, ref a_t), ty::ty_ptr(ref b_t)) => {
match Sub(*self).mts(*a_t, *b_t) {
Ok(_) => Ok(None),
Err(ref e) => Err((*e))
}
to_ares(Sub(*self).mts(*a_t, *b_t))
}
// otherwise, assignment follows normal subtype rules:
@ -252,10 +262,10 @@ priv impl Assign {
r_b: ty::Region) -> ares {
debug!("try_assign(a=%s, nr_b=%s, m=%?, r_b=%s)",
a.to_str(self.infcx),
nr_b.to_str(self.infcx),
a.inf_str(self.infcx),
nr_b.inf_str(self.infcx),
m,
r_b.to_str(self.infcx));
r_b.inf_str(self.infcx));
do indent {
let sub = Sub(*self);

View File

@ -61,8 +61,8 @@ use middle::ty;
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::lub::Lub;
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::to_str::ToStr;
use middle::typeck::infer::{cres, infer_ctxt, ures};
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::{cres, InferCtxt, ures, IntType, UintType};
use util::common::indent;
use core::result::{iter_vec2, map_vec2};
@ -73,8 +73,8 @@ use syntax::codemap::span;
fn macros() { include!("macros.rs"); } // FIXME(#3114): Macro import/export.
trait combine {
fn infcx() -> infer_ctxt;
trait Combine {
fn infcx() -> @InferCtxt;
fn tag() -> ~str;
fn a_is_expected() -> bool;
fn span() -> span;
@ -105,13 +105,13 @@ trait combine {
a: ty::vstore, b: ty::vstore) -> cres<ty::vstore>;
}
pub struct combine_fields {
infcx: infer_ctxt,
pub struct CombineFields {
infcx: @InferCtxt,
a_is_expected: bool,
span: span,
}
fn expected_found<C: combine,T>(
fn expected_found<C:Combine,T>(
self: &C, +a: T, +b: T) -> ty::expected_found<T> {
if self.a_is_expected() {
@ -121,7 +121,7 @@ fn expected_found<C: combine,T>(
}
}
pub fn eq_tys<C: combine>(self: &C, a: ty::t, b: ty::t) -> ures {
pub fn eq_tys<C:Combine>(self: &C, a: ty::t, b: ty::t) -> ures {
let suber = self.sub();
do self.infcx().try {
do suber.tys(a, b).chain |_ok| {
@ -130,10 +130,10 @@ pub fn eq_tys<C: combine>(self: &C, a: ty::t, b: ty::t) -> ures {
}
}
fn eq_regions<C: combine>(self: &C, a: ty::Region, b: ty::Region) -> ures {
fn eq_regions<C:Combine>(self: &C, a: ty::Region, b: ty::Region) -> ures {
debug!("eq_regions(%s, %s)",
a.to_str(self.infcx()),
b.to_str(self.infcx()));
a.inf_str(self.infcx()),
b.inf_str(self.infcx()));
let sub = self.sub();
do indent {
self.infcx().try(|| {
@ -152,7 +152,7 @@ fn eq_regions<C: combine>(self: &C, a: ty::Region, b: ty::Region) -> ures {
}
}
fn eq_opt_regions<C:combine>(
fn eq_opt_regions<C:Combine>(
self: &C,
a: Option<ty::Region>,
b: Option<ty::Region>) -> cres<Option<ty::Region>> {
@ -174,17 +174,17 @@ fn eq_opt_regions<C:combine>(
self.infcx().tcx.sess.bug(
fmt!("substitution a had opt_region %s and \
b had opt_region %s",
a.to_str(self.infcx()),
b.to_str(self.infcx())));
a.inf_str(self.infcx()),
b.inf_str(self.infcx())));
}
}
}
fn super_substs<C:combine>(
fn super_substs<C:Combine>(
self: &C, did: ast::def_id,
a: &ty::substs, b: &ty::substs) -> cres<ty::substs> {
fn relate_region_param<C:combine>(
fn relate_region_param<C:Combine>(
self: &C,
did: ast::def_id,
a: Option<ty::Region>,
@ -220,8 +220,8 @@ fn super_substs<C:combine>(
self.infcx().tcx.sess.bug(
fmt!("substitution a had opt_region %s and \
b had opt_region %s with variance %?",
a.to_str(self.infcx()),
b.to_str(self.infcx()),
a.inf_str(self.infcx()),
b.inf_str(self.infcx()),
polyty.region_param));
}
}
@ -238,7 +238,7 @@ fn super_substs<C:combine>(
}
}
fn super_tps<C:combine>(
fn super_tps<C:Combine>(
self: &C, as_: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]> {
// Note: type parameters are always treated as *invariant*
@ -256,7 +256,7 @@ fn super_tps<C:combine>(
}
}
fn super_self_tys<C:combine>(
fn super_self_tys<C:Combine>(
self: &C, a: Option<ty::t>, b: Option<ty::t>) -> cres<Option<ty::t>> {
// Note: the self type parameter is (currently) always treated as
@ -279,7 +279,17 @@ fn super_self_tys<C:combine>(
}
}
fn super_flds<C:combine>(
fn super_protos<C: Combine>(
self: &C, p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto>
{
if p1 == p2 {
Ok(p1)
} else {
Err(ty::terr_proto_mismatch(expected_found(self, p1, p2)))
}
}
fn super_flds<C:Combine>(
self: &C, a: ty::field, b: ty::field) -> cres<ty::field> {
if a.ident == b.ident {
@ -292,7 +302,7 @@ fn super_flds<C:combine>(
}
}
fn super_modes<C:combine>(
fn super_modes<C:Combine>(
self: &C, a: ast::mode, b: ast::mode)
-> cres<ast::mode> {
@ -300,7 +310,7 @@ fn super_modes<C:combine>(
ty::unify_mode(tcx, expected_found(self, a, b))
}
fn super_args<C:combine>(
fn super_args<C:Combine>(
self: &C, a: ty::arg, b: ty::arg)
-> cres<ty::arg> {
@ -311,7 +321,7 @@ fn super_args<C:combine>(
}
}
fn super_vstores<C:combine>(
fn super_vstores<C:Combine>(
self: &C, vk: ty::terr_vstore_kind,
a: ty::vstore, b: ty::vstore) -> cres<ty::vstore>
{
@ -334,7 +344,7 @@ fn super_vstores<C:combine>(
}
}
fn super_fn_metas<C:combine>(
fn super_fn_metas<C:Combine>(
self: &C, a_f: &ty::FnMeta, b_f: &ty::FnMeta) -> cres<ty::FnMeta>
{
let p = if_ok!(self.protos(a_f.proto, b_f.proto));
@ -343,17 +353,18 @@ fn super_fn_metas<C:combine>(
let onceness = if_ok!(self.oncenesses(a_f.onceness, b_f.onceness));
Ok(FnMeta {purity: purity,
proto: p,
region: r,
onceness: onceness,
region: r,
bounds: a_f.bounds}) // XXX: This is wrong!
}
fn super_fn_sigs<C:combine>(
self: &C, a_f: &ty::FnSig, b_f: &ty::FnSig) -> cres<ty::FnSig> {
fn argvecs<C:combine>(self: &C,
fn super_fn_sigs<C:Combine>(
self: &C, a_f: &ty::FnSig, b_f: &ty::FnSig) -> cres<ty::FnSig>
{
fn argvecs<C:Combine>(self: &C,
+a_args: ~[ty::arg],
+b_args: ~[ty::arg]) -> cres<~[ty::arg]> {
+b_args: ~[ty::arg]) -> cres<~[ty::arg]>
{
if vec::same_length(a_args, b_args) {
map_vec2(a_args, b_args, |a, b| self.args(*a, *b))
} else {
@ -369,19 +380,17 @@ fn super_fn_sigs<C:combine>(
}
}
fn super_fns<C:combine>(
fn super_fns<C:Combine>(
self: &C, a_f: &ty::FnTy, b_f: &ty::FnTy) -> cres<ty::FnTy>
{
do self.fn_metas(&a_f.meta, &b_f.meta).chain |m| {
do self.fn_sigs(&a_f.sig, &b_f.sig).chain |s| {
let m = if_ok!(self.fn_metas(&a_f.meta, &b_f.meta));
let s = if_ok!(self.fn_sigs(&a_f.sig, &b_f.sig));
Ok(FnTyBase {meta: m, sig: s})
}
}
}
fn super_tys<C:combine>(
self: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
fn super_tys<C:Combine>(
self: &C, a: ty::t, b: ty::t) -> cres<ty::t>
{
let tcx = self.infcx().tcx;
match (/*bad*/copy ty::get(a).sty, /*bad*/copy ty::get(b).sty) {
// The "subtype" ought to be handling cases involving bot or var:
@ -392,32 +401,49 @@ fn super_tys<C:combine>(
tcx.sess.bug(
fmt!("%s: bot and var types should have been handled (%s,%s)",
self.tag(),
a.to_str(self.infcx()),
b.to_str(self.infcx())));
a.inf_str(self.infcx()),
b.inf_str(self.infcx())));
}
// Relate integral variables to other types
(ty::ty_infer(IntVar(a_id)), ty::ty_infer(IntVar(b_id))) => {
self.infcx().int_vars(a_id, b_id).then(|| Ok(a) )
if_ok!(self.infcx().simple_vars(&self.infcx().int_var_bindings,
ty::terr_no_integral_type,
a_id, b_id));
Ok(a)
}
(ty::ty_infer(IntVar(a_id)), ty::ty_int(_)) |
(ty::ty_infer(IntVar(a_id)), ty::ty_uint(_)) => {
self.infcx().int_var_sub_t(a_id, b).then(|| Ok(a) )
(ty::ty_infer(IntVar(v_id)), ty::ty_int(v)) |
(ty::ty_int(v), ty::ty_infer(IntVar(v_id))) => {
if v == ast::ty_char {
Err(ty::terr_integer_as_char)
} else {
if_ok!(self.infcx().simple_var_t(&self.infcx().int_var_bindings,
ty::terr_no_integral_type,
v_id, IntType(v)));
Ok(ty::mk_mach_int(tcx, v))
}
(ty::ty_int(_), ty::ty_infer(IntVar(b_id))) |
(ty::ty_uint(_), ty::ty_infer(IntVar(b_id))) => {
self.infcx().t_sub_int_var(a, b_id).then(|| Ok(a) )
}
(ty::ty_infer(IntVar(v_id)), ty::ty_uint(v)) |
(ty::ty_uint(v), ty::ty_infer(IntVar(v_id))) => {
if_ok!(self.infcx().simple_var_t(&self.infcx().int_var_bindings,
ty::terr_no_integral_type,
v_id, UintType(v)));
Ok(ty::mk_mach_uint(tcx, v))
}
// Relate floating-point variables to other types
(ty::ty_infer(FloatVar(a_id)), ty::ty_infer(FloatVar(b_id))) => {
self.infcx().float_vars(a_id, b_id).then(|| Ok(a) )
if_ok!(self.infcx().simple_vars(&self.infcx().float_var_bindings,
ty::terr_no_floating_point_type,
a_id, b_id));
Ok(a)
}
(ty::ty_infer(FloatVar(a_id)), ty::ty_float(_)) => {
self.infcx().float_var_sub_t(a_id, b).then(|| Ok(a) )
}
(ty::ty_float(_), ty::ty_infer(FloatVar(b_id))) => {
self.infcx().t_sub_float_var(a, b_id).then(|| Ok(a) )
(ty::ty_infer(FloatVar(v_id)), ty::ty_float(v)) |
(ty::ty_float(v), ty::ty_infer(FloatVar(v_id))) => {
if_ok!(self.infcx().simple_var_t(&self.infcx().float_var_bindings,
ty::terr_no_floating_point_type,
v_id, v));
Ok(ty::mk_mach_float(tcx, v))
}
(ty::ty_int(_), _) |

View File

@ -1,64 +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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/*!
Code related to floating-point type inference.
*/
use core::prelude::*;
use middle::ty::{get, ty_float};
use middle::ty;
use middle::typeck::infer::to_str::ToStr;
use core::uint;
use syntax::ast;
// Bitvector to represent sets of floating-point types.
pub enum float_ty_set = uint;
// Constants representing singleton sets containing each of the floating-point
// types.
pub const FLOAT_TY_SET_EMPTY: uint = 0b000u;
pub const FLOAT_TY_SET_FLOAT: uint = 0b001u;
pub const FLOAT_TY_SET_F32: uint = 0b010u;
pub const FLOAT_TY_SET_F64: uint = 0b100u;
pub fn float_ty_set_all() -> float_ty_set {
float_ty_set(FLOAT_TY_SET_FLOAT | FLOAT_TY_SET_F32 | FLOAT_TY_SET_F64)
}
pub fn intersection(a: float_ty_set, b: float_ty_set) -> float_ty_set {
float_ty_set(*a & *b)
}
pub fn single_type_contained_in(tcx: ty::ctxt, a: float_ty_set)
-> Option<ty::t> {
debug!("single_type_contained_in(a=%s)", uint::to_str(*a, 10));
if *a == FLOAT_TY_SET_FLOAT { return Some(ty::mk_float(tcx)); }
if *a == FLOAT_TY_SET_F32 { return Some(ty::mk_f32(tcx)); }
if *a == FLOAT_TY_SET_F64 { return Some(ty::mk_f64(tcx)); }
return None;
}
pub fn convert_floating_point_ty_to_float_ty_set(tcx: ty::ctxt, t: ty::t)
-> float_ty_set {
match get(t).sty {
ty::ty_float(ast::ty_f) => float_ty_set(FLOAT_TY_SET_FLOAT),
ty::ty_float(ast::ty_f32) => float_ty_set(FLOAT_TY_SET_F32),
ty::ty_float(ast::ty_f64) => float_ty_set(FLOAT_TY_SET_F64),
_ => tcx.sess.bug(~"non-floating-point type passed to \
convert_floating_point_ty_to_float_ty_set()")
}
}

View File

@ -17,7 +17,7 @@ use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::lattice::*;
use middle::typeck::infer::lub::Lub;
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::to_str::ToStr;
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::isr_alist;
use syntax::ast::{Many, Once, extern_fn, impure_fn, m_const, m_imm, m_mutbl};
use syntax::ast::{noreturn, pure_fn, ret_style, return_val, unsafe_fn};
@ -25,10 +25,10 @@ use util::ppaux::mt_to_str;
use std::list;
enum Glb = combine_fields; // "greatest lower bound" (common subtype)
enum Glb = CombineFields; // "greatest lower bound" (common subtype)
impl Glb: combine {
fn infcx() -> infer_ctxt { self.infcx }
impl Glb: Combine {
fn infcx() -> @InferCtxt { self.infcx }
fn tag() -> ~str { ~"glb" }
fn a_is_expected() -> bool { self.a_is_expected }
fn span() -> span { self.span }
@ -94,10 +94,6 @@ impl Glb: combine {
Lub(*self).tys(a, b)
}
fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto> {
if p1 == p2 {Ok(p1)} else {Ok(ast::ProtoBare)}
}
fn purities(a: purity, b: purity) -> cres<purity> {
match (a, b) {
(pure_fn, _) | (_, pure_fn) => Ok(pure_fn),
@ -117,8 +113,8 @@ impl Glb: combine {
fn regions(a: ty::Region, b: ty::Region) -> cres<ty::Region> {
debug!("%s.regions(%?, %?)",
self.tag(),
a.to_str(self.infcx),
b.to_str(self.infcx));
a.inf_str(self.infcx),
b.inf_str(self.infcx));
do indent {
self.infcx.region_vars.glb_regions(self.span, a, b)
@ -130,7 +126,7 @@ impl Glb: combine {
}
fn tys(a: ty::t, b: ty::t) -> cres<ty::t> {
lattice_tys(&self, a, b)
super_lattice_tys(&self, a, b)
}
// Traits please (FIXME: #2794):
@ -152,12 +148,12 @@ impl Glb: combine {
super_args(&self, a, b)
}
fn fns(a: &ty::FnTy, b: &ty::FnTy) -> cres<ty::FnTy> {
fn fn_sigs(a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
// Note: this is a subtle algorithm. For a full explanation,
// please see the large comment in `region_inference.rs`.
debug!("%s.fns(%?, %?)",
self.tag(), a.to_str(self.infcx), b.to_str(self.infcx));
debug!("%s.fn_sigs(%?, %?)",
self.tag(), a.inf_str(self.infcx), b.inf_str(self.infcx));
let _indenter = indenter();
// Take a snapshot. We'll never roll this back, but in later
@ -177,20 +173,20 @@ impl Glb: combine {
let b_vars = var_ids(&self, b_isr);
// Collect constraints.
let fn_ty0 = if_ok!(super_fns(&self, &a_with_fresh, &b_with_fresh));
debug!("fn_ty0 = %s", fn_ty0.to_str(self.infcx));
let sig0 = if_ok!(super_fn_sigs(&self, &a_with_fresh, &b_with_fresh));
debug!("sig0 = %s", sig0.inf_str(self.infcx));
// Generalize the regions appearing in fn_ty0 if possible
let new_vars =
self.infcx.region_vars.vars_created_since_snapshot(snapshot);
let fn_ty1 =
let sig1 =
self.infcx.fold_regions_in_sig(
&fn_ty0,
&sig0,
|r, _in_fn| generalize_region(&self, snapshot,
new_vars, a_isr, a_vars, b_vars,
r));
debug!("fn_ty1 = %s", fn_ty1.to_str(self.infcx));
return Ok(move fn_ty1);
debug!("sig1 = %s", sig1.inf_str(self.infcx));
return Ok(move sig1);
fn generalize_region(self: &Glb,
snapshot: uint,
@ -271,12 +267,16 @@ impl Glb: combine {
}
}
fn fn_metas(a: &ty::FnMeta, b: &ty::FnMeta) -> cres<ty::FnMeta> {
super_fn_metas(&self, a, b)
fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto> {
super_protos(&self, p1, p2)
}
fn fn_sigs(a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
super_fn_sigs(&self, a, b)
fn fns(a: &ty::FnTy, b: &ty::FnTy) -> cres<ty::FnTy> {
super_fns(&self, a, b)
}
fn fn_metas(a: &ty::FnMeta, b: &ty::FnMeta) -> cres<ty::FnMeta> {
super_fn_metas(&self, a, b)
}
fn substs(did: ast::def_id,

View File

@ -1,95 +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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/*!
Code related to integral type inference.
*/
use core::prelude::*;
use middle::ty::{get, ty_int, ty_uint};
use middle::ty;
use middle::typeck::infer::to_str::ToStr;
use core::uint;
use syntax::ast;
// Bitvector to represent sets of integral types
enum int_ty_set = uint;
// Constants representing singleton sets containing each of the
// integral types
const INT_TY_SET_EMPTY : uint = 0b00_0000_0000u;
const INT_TY_SET_i8 : uint = 0b00_0000_0001u;
const INT_TY_SET_u8 : uint = 0b00_0000_0010u;
const INT_TY_SET_i16 : uint = 0b00_0000_0100u;
const INT_TY_SET_u16 : uint = 0b00_0000_1000u;
const INT_TY_SET_i32 : uint = 0b00_0001_0000u;
const INT_TY_SET_u32 : uint = 0b00_0010_0000u;
const INT_TY_SET_i64 : uint = 0b00_0100_0000u;
const INT_TY_SET_u64 : uint = 0b00_1000_0000u;
const INT_TY_SET_i : uint = 0b01_0000_0000u;
const INT_TY_SET_u : uint = 0b10_0000_0000u;
fn int_ty_set_all() -> int_ty_set {
int_ty_set(INT_TY_SET_i8 | INT_TY_SET_u8 |
INT_TY_SET_i16 | INT_TY_SET_u16 |
INT_TY_SET_i32 | INT_TY_SET_u32 |
INT_TY_SET_i64 | INT_TY_SET_u64 |
INT_TY_SET_i | INT_TY_SET_u)
}
fn intersection(a: int_ty_set, b: int_ty_set) -> int_ty_set {
int_ty_set(*a & *b)
}
fn single_type_contained_in(tcx: ty::ctxt, a: int_ty_set) ->
Option<ty::t> {
debug!("single_type_contained_in(a=%s)", uint::to_str(*a, 10u));
if *a == INT_TY_SET_i8 { return Some(ty::mk_i8(tcx)); }
if *a == INT_TY_SET_u8 { return Some(ty::mk_u8(tcx)); }
if *a == INT_TY_SET_i16 { return Some(ty::mk_i16(tcx)); }
if *a == INT_TY_SET_u16 { return Some(ty::mk_u16(tcx)); }
if *a == INT_TY_SET_i32 { return Some(ty::mk_i32(tcx)); }
if *a == INT_TY_SET_u32 { return Some(ty::mk_u32(tcx)); }
if *a == INT_TY_SET_i64 { return Some(ty::mk_i64(tcx)); }
if *a == INT_TY_SET_u64 { return Some(ty::mk_u64(tcx)); }
if *a == INT_TY_SET_i { return Some(ty::mk_int(tcx)); }
if *a == INT_TY_SET_u { return Some(ty::mk_uint(tcx)); }
return None;
}
fn convert_integral_ty_to_int_ty_set(tcx: ty::ctxt, t: ty::t)
-> int_ty_set {
match get(t).sty {
ty_int(int_ty) => match int_ty {
ast::ty_i8 => int_ty_set(INT_TY_SET_i8),
ast::ty_i16 => int_ty_set(INT_TY_SET_i16),
ast::ty_i32 => int_ty_set(INT_TY_SET_i32),
ast::ty_i64 => int_ty_set(INT_TY_SET_i64),
ast::ty_i => int_ty_set(INT_TY_SET_i),
ast::ty_char => tcx.sess.bug(
~"char type passed to convert_integral_ty_to_int_ty_set()")
},
ty_uint(uint_ty) => match uint_ty {
ast::ty_u8 => int_ty_set(INT_TY_SET_u8),
ast::ty_u16 => int_ty_set(INT_TY_SET_u16),
ast::ty_u32 => int_ty_set(INT_TY_SET_u32),
ast::ty_u64 => int_ty_set(INT_TY_SET_u64),
ast::ty_u => int_ty_set(INT_TY_SET_u)
},
_ => tcx.sess.bug(~"non-integral type passed to \
convert_integral_ty_to_int_ty_set()")
}
}

View File

@ -8,118 +8,450 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/*!
*
* # Lattice Variables
*
* This file contains generic code for operating on inference variables
* that are characterized by an upper- and lower-bound. The logic and
* reasoning is explained in detail in the large comment in `infer.rs`.
*
* The code in here is defined quite generically so that it can be
* applied both to type variables, which represent types being inferred,
* and fn variables, which represent function types being inferred.
* It may eventually be applied to ther types as well, who knows.
* In some cases, the functions are also generic with respect to the
* operation on the lattice (GLB vs LUB).
*
* Although all the functions are generic, we generally write the
* comments in a way that is specific to type variables and the LUB
* operation. It's just easier that way.
*
* In general all of the functions are defined parametrically
* over a `LatticeValue`, which is a value defined with respect to
* a lattice.
*/
use core::prelude::*;
use middle::ty::{RegionVid, TyVar};
use middle::ty;
use middle::typeck::isr_alist;
use middle::typeck::infer::*;
use middle::typeck::infer::combine::*;
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::lub::Lub;
use middle::typeck::infer::unify::*;
use middle::typeck::infer::to_str::ToStr;
use middle::typeck::isr_alist;
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::lub::Lub;
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::to_str::InferStr;
use std::list;
trait LatticeValue {
static fn sub(cf: &CombineFields, a: &self, b: &self) -> ures;
static fn lub(cf: &CombineFields, a: &self, b: &self) -> cres<self>;
static fn glb(cf: &CombineFields, a: &self, b: &self) -> cres<self>;
}
type LatticeOp<T> = &fn(cf: &CombineFields, a: &T, b: &T) -> cres<T>;
impl ty::t: LatticeValue {
static fn sub(cf: &CombineFields, a: &ty::t, b: &ty::t) -> ures {
Sub(*cf).tys(*a, *b).to_ures()
}
static fn lub(cf: &CombineFields, a: &ty::t, b: &ty::t) -> cres<ty::t> {
Lub(*cf).tys(*a, *b)
}
static fn glb(cf: &CombineFields, a: &ty::t, b: &ty::t) -> cres<ty::t> {
Glb(*cf).tys(*a, *b)
}
}
impl FnMeta: LatticeValue {
static fn sub(cf: &CombineFields,
a: &FnMeta, b: &FnMeta) -> ures {
Sub(*cf).fn_metas(a, b).to_ures()
}
static fn lub(cf: &CombineFields,
a: &FnMeta, b: &FnMeta) -> cres<FnMeta> {
Lub(*cf).fn_metas(a, b)
}
static fn glb(cf: &CombineFields,
a: &FnMeta, b: &FnMeta) -> cres<FnMeta> {
Glb(*cf).fn_metas(a, b)
}
}
impl CombineFields {
fn var_sub_var<V:Copy Eq Vid ToStr, T:Copy InferStr LatticeValue>(
&self,
vb: &ValsAndBindings<V, Bounds<T>>,
+a_id: V,
+b_id: V) -> ures
{
/*!
*
* Make one variable a subtype of another variable. This is a
* subtle and tricky process, as described in detail at the
* top of infer.rs*/
// Need to make sub_id a subtype of sup_id.
let node_a = self.infcx.get(vb, a_id);
let node_b = self.infcx.get(vb, b_id);
let a_id = node_a.root;
let b_id = node_b.root;
let a_bounds = node_a.possible_types;
let b_bounds = node_b.possible_types;
debug!("vars(%s=%s <: %s=%s)",
a_id.to_str(), a_bounds.inf_str(self.infcx),
b_id.to_str(), b_bounds.inf_str(self.infcx));
if a_id == b_id { return uok(); }
// If both A's UB and B's LB have already been bound to types,
// see if we can make those types subtypes.
match (a_bounds.ub, b_bounds.lb) {
(Some(ref a_ub), Some(ref b_lb)) => {
let r = self.infcx.try(
|| LatticeValue::sub(self, a_ub, b_lb));
match r {
Ok(()) => {
return Ok(());
}
Err(_) => { /*fallthrough */ }
}
}
_ => { /*fallthrough*/ }
}
// Otherwise, we need to merge A and B so as to guarantee that
// A remains a subtype of B. Actually, there are other options,
// but that's the route we choose to take.
self.infcx.unify(vb, &node_a, &node_b, |new_root, new_rank| {
self.set_var_to_merged_bounds(vb, new_root,
&a_bounds, &b_bounds,
new_rank)
})
}
/// make variable a subtype of T
fn var_sub_t<V:Copy Eq Vid ToStr, T:Copy InferStr LatticeValue>(
&self,
vb: &ValsAndBindings<V, Bounds<T>>,
+a_id: V,
+b: T) -> ures
{
/*!
*
* Make a variable (`a_id`) a subtype of the concrete type `b` */
let node_a = self.infcx.get(vb, a_id);
let a_id = node_a.root;
let a_bounds = &node_a.possible_types;
let b_bounds = &{lb: None, ub: Some(b)};
debug!("var_sub_t(%s=%s <: %s)",
a_id.to_str(),
a_bounds.inf_str(self.infcx),
b.inf_str(self.infcx));
self.set_var_to_merged_bounds(
vb, a_id, a_bounds, b_bounds, node_a.rank)
}
fn t_sub_var<V:Copy Eq Vid ToStr, T:Copy InferStr LatticeValue>(
&self,
vb: &ValsAndBindings<V, Bounds<T>>,
+a: T,
+b_id: V) -> ures
{
/*!
*
* Make a concrete type (`a`) a subtype of the variable `b_id` */
let a_bounds = &{lb: Some(a), ub: None};
let node_b = self.infcx.get(vb, b_id);
let b_id = node_b.root;
let b_bounds = &node_b.possible_types;
debug!("t_sub_var(%s <: %s=%s)",
a.inf_str(self.infcx),
b_id.to_str(),
b_bounds.inf_str(self.infcx));
self.set_var_to_merged_bounds(
vb, b_id, a_bounds, b_bounds, node_b.rank)
}
fn merge_bnd<T:Copy InferStr LatticeValue>(
&self,
a: &Bound<T>,
b: &Bound<T>,
lattice_op: LatticeOp<T>)
-> cres<Bound<T>>
{
/*!
*
* Combines two bounds into a more general bound. */
debug!("merge_bnd(%s,%s)",
a.inf_str(self.infcx),
b.inf_str(self.infcx));
let _r = indenter();
match (*a, *b) {
(None, None) => Ok(None),
(Some(_), None) => Ok(*a),
(None, Some(_)) => Ok(*b),
(Some(ref v_a), Some(ref v_b)) => {
do lattice_op(self, v_a, v_b).chain |v| {
Ok(Some(v))
}
}
}
}
fn set_var_to_merged_bounds<V:Copy Eq Vid ToStr,
T:Copy InferStr LatticeValue>(
&self,
vb: &ValsAndBindings<V, Bounds<T>>,
+v_id: V,
a: &Bounds<T>,
b: &Bounds<T>,
rank: uint) -> ures
{
/*!
*
* Updates the bounds for the variable `v_id` to be the intersection
* of `a` and `b`. That is, the new bounds for `v_id` will be
* a bounds c such that:
* c.ub <: a.ub
* c.ub <: b.ub
* a.lb <: c.lb
* b.lb <: c.lb
* If this cannot be achieved, the result is failure. */
// Think of the two diamonds, we want to find the
// intersection. There are basically four possibilities (you
// can swap A/B in these pictures):
//
// A A
// / \ / \
// / B \ / B \
// / / \ \ / / \ \
// * * * * * / * *
// \ \ / / \ / /
// \ B / / \ / /
// \ / * \ /
// A \ / A
// B
debug!("merge(%s,%s,%s)",
v_id.to_str(),
a.inf_str(self.infcx),
b.inf_str(self.infcx));
let _indent = indenter();
// First, relate the lower/upper bounds of A and B.
// Note that these relations *must* hold for us to
// to be able to merge A and B at all, and relating
// them explicitly gives the type inferencer more
// information and helps to produce tighter bounds
// when necessary.
let () = if_ok!(self.bnds(&a.lb, &b.ub));
let () = if_ok!(self.bnds(&b.lb, &a.ub));
let ub = if_ok!(self.merge_bnd(&a.ub, &b.ub, LatticeValue::glb));
let lb = if_ok!(self.merge_bnd(&a.lb, &b.lb, LatticeValue::lub));
let bounds = {lb: lb, ub: ub};
debug!("merge(%s): bounds=%s",
v_id.to_str(),
bounds.inf_str(self.infcx));
// the new bounds must themselves
// be relatable:
let () = if_ok!(self.bnds(&bounds.lb, &bounds.ub));
self.infcx.set(vb, v_id, Root(bounds, rank));
uok()
}
fn bnds<T:Copy InferStr LatticeValue>(
&self,
a: &Bound<T>,
b: &Bound<T>) -> ures
{
debug!("bnds(%s <: %s)", a.inf_str(self.infcx),
b.inf_str(self.infcx));
let _r = indenter();
match (*a, *b) {
(None, None) |
(Some(_), None) |
(None, Some(_)) => {
uok()
}
(Some(ref t_a), Some(ref t_b)) => {
LatticeValue::sub(self, t_a, t_b)
}
}
}
}
// ______________________________________________________________________
// Lattice operations on variables
//
// This is common code used by both LUB and GLB to compute the LUB/GLB
// for pairs of variables or for variables and values.
trait lattice_ops {
fn bnd(b: bounds<ty::t>) -> Option<ty::t>;
fn with_bnd(b: bounds<ty::t>, t: ty::t) -> bounds<ty::t>;
trait LatticeDir {
fn combine_fields() -> CombineFields;
fn bnd<T:Copy>(b: &Bounds<T>) -> Option<T>;
fn with_bnd<T:Copy>(b: &Bounds<T>, +t: T) -> Bounds<T>;
}
trait TyLatticeDir {
fn ty_bot(t: ty::t) -> cres<ty::t>;
}
impl Lub: lattice_ops {
fn bnd(b: bounds<ty::t>) -> Option<ty::t> { b.ub }
fn with_bnd(b: bounds<ty::t>, t: ty::t) -> bounds<ty::t> {
{ub: Some(t),.. b}
impl Lub: LatticeDir {
fn combine_fields() -> CombineFields { *self }
fn bnd<T:Copy>(b: &Bounds<T>) -> Option<T> { b.ub }
fn with_bnd<T:Copy>(b: &Bounds<T>, +t: T) -> Bounds<T> {
{ub: Some(t), ..*b}
}
}
impl Lub: TyLatticeDir {
fn ty_bot(t: ty::t) -> cres<ty::t> {
Ok(t)
}
}
impl Glb: lattice_ops {
fn bnd(b: bounds<ty::t>) -> Option<ty::t> { b.lb }
fn with_bnd(b: bounds<ty::t>, t: ty::t) -> bounds<ty::t> {
{lb: Some(t),.. b}
impl Glb: LatticeDir {
fn combine_fields() -> CombineFields { *self }
fn bnd<T:Copy>(b: &Bounds<T>) -> Option<T> { b.lb }
fn with_bnd<T:Copy>(b: &Bounds<T>, +t: T) -> Bounds<T> {
{lb: Some(t), ..*b}
}
}
impl Glb: TyLatticeDir {
fn ty_bot(_t: ty::t) -> cres<ty::t> {
Ok(ty::mk_bot(self.infcx.tcx))
}
}
fn lattice_tys<L:lattice_ops combine>(
self: &L, a: ty::t, b: ty::t) -> cres<ty::t> {
fn super_lattice_tys<L:LatticeDir TyLatticeDir Combine>(
self: &L,
a: ty::t,
b: ty::t) -> cres<ty::t>
{
debug!("%s.lattice_tys(%s, %s)", self.tag(),
a.to_str(self.infcx()),
b.to_str(self.infcx()));
if a == b { return Ok(a); }
do indent {
a.inf_str(self.infcx()),
b.inf_str(self.infcx()));
let _r = indenter();
if a == b {
return Ok(a);
}
let tcx = self.infcx().tcx;
match (ty::get(a).sty, ty::get(b).sty) {
(ty::ty_bot, _) => self.ty_bot(b),
(_, ty::ty_bot) => self.ty_bot(a),
(ty::ty_bot, _) => { return self.ty_bot(b); }
(_, ty::ty_bot) => { return self.ty_bot(a); }
(ty::ty_infer(TyVar(a_id)), ty::ty_infer(TyVar(b_id))) => {
lattice_vars(self, a, a_id, b_id,
|x, y| self.tys(x, y) )
let r = if_ok!(lattice_vars(self, &self.infcx().ty_var_bindings,
a_id, b_id,
|x, y| self.tys(*x, *y)));
return match r {
VarResult(v) => Ok(ty::mk_var(tcx, v)),
ValueResult(t) => Ok(t)
};
}
(ty::ty_infer(TyVar(a_id)), _) => {
lattice_var_and_t(self, a_id, b,
|x, y| self.tys(x, y) )
return lattice_var_and_t(self, &self.infcx().ty_var_bindings,
a_id, &b,
|x, y| self.tys(*x, *y));
}
(_, ty::ty_infer(TyVar(b_id))) => {
lattice_var_and_t(self, b_id, a,
|x, y| self.tys(x, y) )
return lattice_var_and_t(self, &self.infcx().ty_var_bindings,
b_id, &a,
|x, y| self.tys(*x, *y));
}
_ => {
super_tys(self, a, b)
}
return super_tys(self, a, b);
}
}
}
fn lattice_vars<L:lattice_ops combine>(
self: &L, +a_t: ty::t, +a_vid: ty::TyVid, +b_vid: ty::TyVid,
c_ts: fn(ty::t, ty::t) -> cres<ty::t>) -> cres<ty::t> {
type LatticeDirOp<T> = &fn(a: &T, b: &T) -> cres<T>;
// The comments in this function are written for LUB and types,
// but they apply equally well to GLB and regions if you inverse
// upper/lower/sub/super/etc.
enum LatticeVarResult<V,T> {
VarResult(V),
ValueResult(T)
}
// Need to find a type that is a supertype of both a and b:
let vb = &self.infcx().ty_var_bindings;
/**
* Computes the LUB or GLB of two bounded variables. These could be any
* sort of variables, but in the comments on this function I'll assume
* we are doing an LUB on two type variables.
*
* This computation can be done in one of two ways:
*
* - If both variables have an upper bound, we may just compute the
* LUB of those bounds and return that, in which case we are
* returning a type. This is indicated with a `ValueResult` return.
*
* - If the variables do not both have an upper bound, we will unify
* the variables and return the unified variable, in which case the
* result is a variable. This is indicated with a `VarResult`
* return. */
fn lattice_vars<L:LatticeDir Combine,
V:Copy Eq Vid ToStr,
T:Copy InferStr LatticeValue>(
self: &L, // defines whether we want LUB or GLB
vb: &ValsAndBindings<V, Bounds<T>>, // relevant variable bindings
+a_vid: V, // first variable
+b_vid: V, // second variable
lattice_dir_op: LatticeDirOp<T>) // LUB or GLB operation on types
-> cres<LatticeVarResult<V,T>>
{
let nde_a = self.infcx().get(vb, a_vid);
let nde_b = self.infcx().get(vb, b_vid);
let a_vid = nde_a.root;
let b_vid = nde_b.root;
let a_bounds = nde_a.possible_types;
let b_bounds = nde_b.possible_types;
let a_bounds = &nde_a.possible_types;
let b_bounds = &nde_b.possible_types;
debug!("%s.lattice_vars(%s=%s <: %s=%s)",
self.tag(),
a_vid.to_str(), a_bounds.to_str(self.infcx()),
b_vid.to_str(), b_bounds.to_str(self.infcx()));
a_vid.to_str(), a_bounds.inf_str(self.infcx()),
b_vid.to_str(), b_bounds.inf_str(self.infcx()));
// Same variable: the easy case.
if a_vid == b_vid {
return Ok(a_t);
return Ok(VarResult(a_vid));
}
// If both A and B have an UB type, then we can just compute the
// LUB of those types:
let a_bnd = self.bnd(a_bounds), b_bnd = self.bnd(b_bounds);
match (a_bnd, b_bnd) {
(Some(a_ty), Some(b_ty)) => {
match self.infcx().try(|| c_ts(a_ty, b_ty) ) {
Ok(t) => return Ok(t),
(Some(ref a_ty), Some(ref b_ty)) => {
match self.infcx().try(|| lattice_dir_op(a_ty, b_ty) ) {
Ok(t) => return Ok(ValueResult(t)),
Err(_) => { /*fallthrough */ }
}
}
@ -128,40 +460,49 @@ fn lattice_vars<L:lattice_ops combine>(
// Otherwise, we need to merge A and B into one variable. We can
// then use either variable as an upper bound:
var_sub_var(self, a_vid, b_vid).then(|| Ok(a_t) )
let cf = self.combine_fields();
do cf.var_sub_var(vb, a_vid, b_vid).then {
Ok(VarResult(a_vid))
}
}
fn lattice_var_and_t<L:lattice_ops combine>(
self: &L, a_id: ty::TyVid, b: ty::t,
c_ts: fn(ty::t, ty::t) -> cres<ty::t>) -> cres<ty::t> {
let vb = &self.infcx().ty_var_bindings;
fn lattice_var_and_t<L:LatticeDir Combine,
V:Copy Eq Vid ToStr,
T:Copy InferStr LatticeValue>(
self: &L,
vb: &ValsAndBindings<V, Bounds<T>>,
+a_id: V,
b: &T,
lattice_dir_op: LatticeDirOp<T>)
-> cres<T>
{
let nde_a = self.infcx().get(vb, a_id);
let a_id = nde_a.root;
let a_bounds = nde_a.possible_types;
let a_bounds = &nde_a.possible_types;
// The comments in this function are written for LUB, but they
// apply equally well to GLB if you inverse upper/lower/sub/super/etc.
debug!("%s.lattice_var_and_t(%s=%s <: %s)",
self.tag(),
a_id.to_str(), a_bounds.to_str(self.infcx()),
b.to_str(self.infcx()));
a_id.to_str(),
a_bounds.inf_str(self.infcx()),
b.inf_str(self.infcx()));
match self.bnd(a_bounds) {
Some(a_bnd) => {
Some(ref a_bnd) => {
// If a has an upper bound, return the LUB(a.ub, b)
debug!("bnd=some(%s)", a_bnd.to_str(self.infcx()));
return c_ts(a_bnd, b);
debug!("bnd=some(%s)", a_bnd.inf_str(self.infcx()));
lattice_dir_op(a_bnd, b)
}
None => {
// If a does not have an upper bound, make b the upper bound of a
// and then return b.
debug!("bnd=none");
let a_bounds = self.with_bnd(a_bounds, b);
do bnds(self, a_bounds.lb, a_bounds.ub).then {
self.infcx().set(vb, a_id, root(a_bounds, nde_a.rank));
Ok(b)
let a_bounds = self.with_bnd(a_bounds, *b);
do self.combine_fields().bnds(&a_bounds.lb, &a_bounds.ub).then {
self.infcx().set(vb, a_id, Root(a_bounds, nde_a.rank));
Ok(*b)
}
}
}
@ -171,7 +512,7 @@ fn lattice_var_and_t<L:lattice_ops combine>(
// Random utility functions used by LUB/GLB when computing LUB/GLB of
// fn types
fn var_ids<T: combine>(self: &T, isr: isr_alist) -> ~[RegionVid] {
fn var_ids<T: Combine>(self: &T, isr: isr_alist) -> ~[RegionVid] {
let mut result = ~[];
for list::each(isr) |pair| {
match pair.second() {

View File

@ -16,7 +16,7 @@ use middle::typeck::infer::combine::*;
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::lattice::*;
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::to_str::ToStr;
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::isr_alist;
use util::ppaux::mt_to_str;
@ -26,15 +26,15 @@ use syntax::ast::{pure_fn, ret_style, return_val, unsafe_fn};
fn macros() { include!("macros.rs"); } // FIXME(#3114): Macro import/export.
enum Lub = combine_fields; // "subtype", "subregion" etc
enum Lub = CombineFields; // least-upper-bound: common supertype
impl Lub {
fn bot_ty(b: ty::t) -> cres<ty::t> { Ok(b) }
fn ty_bot(b: ty::t) -> cres<ty::t> { self.bot_ty(b) } // commutative
}
impl Lub: combine {
fn infcx() -> infer_ctxt { self.infcx }
impl Lub: Combine {
fn infcx() -> @InferCtxt { self.infcx }
fn tag() -> ~str { ~"lub" }
fn a_is_expected() -> bool { self.a_is_expected }
fn span() -> span { self.span }
@ -80,15 +80,6 @@ impl Lub: combine {
Glb(*self).tys(a, b)
}
fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto> {
match (p1, p2) {
(ast::ProtoBare, _) => Ok(p2),
(_, ast::ProtoBare) => Ok(p1),
_ if p1 == p2 => Ok(p1),
_ => Err(ty::terr_proto_mismatch(expected_found(&self, p1, p2)))
}
}
fn purities(a: purity, b: purity) -> cres<purity> {
match (a, b) {
(unsafe_fn, _) | (_, unsafe_fn) => Ok(unsafe_fn),
@ -112,15 +103,15 @@ impl Lub: combine {
fn regions(a: ty::Region, b: ty::Region) -> cres<ty::Region> {
debug!("%s.regions(%?, %?)",
self.tag(),
a.to_str(self.infcx),
b.to_str(self.infcx));
a.inf_str(self.infcx),
b.inf_str(self.infcx));
do indent {
self.infcx.region_vars.lub_regions(self.span, a, b)
}
}
fn fns(a: &ty::FnTy, b: &ty::FnTy) -> cres<ty::FnTy> {
fn fn_sigs(a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
// Note: this is a subtle algorithm. For a full explanation,
// please see the large comment in `region_inference.rs`.
@ -139,18 +130,18 @@ impl Lub: combine {
self.span, b);
// Collect constraints.
let fn_ty0 = if_ok!(super_fns(&self, &a_with_fresh, &b_with_fresh));
debug!("fn_ty0 = %s", fn_ty0.to_str(self.infcx));
let sig0 = if_ok!(super_fn_sigs(&self, &a_with_fresh, &b_with_fresh));
debug!("sig0 = %s", sig0.inf_str(self.infcx));
// Generalize the regions appearing in fn_ty0 if possible
// Generalize the regions appearing in sig0 if possible
let new_vars =
self.infcx.region_vars.vars_created_since_snapshot(snapshot);
let fn_ty1 =
let sig1 =
self.infcx.fold_regions_in_sig(
&fn_ty0,
&sig0,
|r, _in_fn| generalize_region(&self, snapshot, new_vars,
a_isr, r));
return Ok(move fn_ty1);
return Ok(move sig1);
fn generalize_region(self: &Lub,
snapshot: uint,
@ -197,18 +188,22 @@ impl Lub: combine {
}
}
fn fns(a: &ty::FnTy, b: &ty::FnTy) -> cres<ty::FnTy> {
super_fns(&self, a, b)
}
fn fn_metas(a: &ty::FnMeta, b: &ty::FnMeta) -> cres<ty::FnMeta> {
super_fn_metas(&self, a, b)
}
fn fn_sigs(a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
super_fn_sigs(&self, a, b)
}
// Traits please (FIXME: #2794):
fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto> {
super_protos(&self, p1, p2)
}
fn tys(a: ty::t, b: ty::t) -> cres<ty::t> {
lattice_tys(&self, a, b)
super_lattice_tys(&self, a, b)
}
fn flds(a: ty::field, b: ty::field) -> cres<ty::field> {

View File

@ -197,29 +197,16 @@ is valid. This basically corresponds to the block nesting structure:
the regions for outer block scopes are superregions of those for inner
block scopes.
## Integral type variables
## Integral and floating-point type variables
There is a third variety of type variable that we use only for
inferring the types of unsuffixed integer literals. Integral type
variables differ from general-purpose type variables in that there's
no subtyping relationship among the various integral types, so instead
of associating each variable with an upper and lower bound, we
represent the set of possible integral types it can take on with an
`int_ty_set`, which is a bitvector with one bit for each integral
type. Because intersecting these sets with each other is simpler than
merging bounds, we don't need to do so transactionally as we do for
general-purpose type variables.
We could conceivably define a subtyping relationship among integral
types based on their ranges, but we choose not to open that particular
can of worms. Our strategy is to treat integral type variables as
unknown until the typing context constrains them to a unique integral
type, at which point they take on that type. If the typing context
overconstrains the type, it's a type error; if we reach the point at
which type variables must be resolved and an integral type variable is
still underconstrained, it defaults to `int` as a last resort.
Floating point types are handled similarly to integral types.
of associating each variable with an upper and lower bound, we just
use simple unification. Each integer variable is associated with at
most one integer type. Floating point types are handled similarly to
integral types.
## GLB/LUB
@ -261,16 +248,14 @@ section on "Type Combining" below for details.
use core::prelude::*;
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, vid};
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, Vid};
use middle::ty::{mk_fn, type_is_bot};
use middle::ty::{ty_int, ty_uint, get, terr_fn, TyVar, IntVar, FloatVar};
use middle::ty;
use middle::typeck::check::regionmanip::{replace_bound_regions_in_fn_ty};
use middle::typeck::check::regionmanip::{replace_bound_regions_in_fn_sig};
use middle::typeck::infer::assignment::Assign;
use middle::typeck::infer::combine::{combine_fields, eq_tys};
use middle::typeck::infer::floating::{float_ty_set, float_ty_set_all};
use middle::typeck::infer::combine::{CombineFields, eq_tys};
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::integral::{int_ty_set, int_ty_set_all};
use middle::typeck::infer::lub::Lub;
use middle::typeck::infer::region_inference::{RegionVarBindings};
use middle::typeck::infer::resolve::{force_all, not_regions};
@ -280,8 +265,8 @@ use middle::typeck::infer::resolve::{resolve_ivar, resolve_all};
use middle::typeck::infer::resolve::{resolve_nested_tvar, resolve_rvar};
use middle::typeck::infer::resolve::{resolver};
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::to_str::ToStr;
use middle::typeck::infer::unify::{vals_and_bindings, root};
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::unify::{ValsAndBindings, Root};
use middle::typeck::isr_alist;
use util::common::{indent, indenter};
use util::ppaux::{bound_region_to_str, ty_to_str, mt_to_str};
@ -302,7 +287,7 @@ use syntax::ast_util::dummy_sp;
use syntax::ast_util;
use syntax::codemap::span;
export infer_ctxt;
export InferCtxt;
export new_infer_ctxt;
export mk_subty, can_mk_subty;
export mk_subr;
@ -313,15 +298,12 @@ export force_tvar, force_rvar, force_ivar, force_all;
export resolve_and_force_all_but_regions, not_regions;
export resolve_type, resolve_region;
export resolve_borrowings;
export methods; // for infer_ctxt
export unify_methods; // for infer_ctxt
export cres, fres, fixup_err, fixup_err_to_str;
export assignment;
export root, to_str;
export int_ty_set_all;
export assignment;
export combine;
export floating;
export glb;
export integral;
export lattice;
@ -333,11 +315,12 @@ export to_str;
export unify;
export uok;
export cyclic_ty, unresolved_ty, region_var_bound_by_region_var;
export bound, bounds;
export Bound, Bounds;
export ures;
export ares;
export infer_ctxt;
export fixup_err;
export IntVarValue, IntType, UintType;
#[legacy_exports]
mod assignment;
@ -346,9 +329,6 @@ mod combine;
#[legacy_exports]
mod glb;
#[legacy_exports]
mod integral;
mod floating;
#[legacy_exports]
mod lattice;
#[legacy_exports]
mod lub;
@ -363,39 +343,48 @@ mod to_str;
#[legacy_exports]
mod unify;
type bound<T:Copy> = Option<T>;
type bounds<T:Copy> = {lb: bound<T>, ub: bound<T>};
type Bound<T> = Option<T>;
type Bounds<T> = {lb: Bound<T>, ub: Bound<T>};
type cres<T> = Result<T,ty::type_err>; // "combine result"
type ures = cres<()>; // "unify result"
type fres<T> = Result<T, fixup_err>; // "fixup result"
type ares = cres<Option<@ty::AutoAdjustment>>; // "assignment result"
enum infer_ctxt = @{
#[deriving_eq]
enum IntVarValue {
IntType(ast::int_ty),
UintType(ast::uint_ty),
}
struct InferCtxt {
tcx: ty::ctxt,
// We instantiate vals_and_bindings with bounds<ty::t> because the
// We instantiate ValsAndBindings with bounds<ty::t> because the
// types that might instantiate a general type variable have an
// order, represented by its upper and lower bounds.
ty_var_bindings: vals_and_bindings<ty::TyVid, bounds<ty::t>>,
ty_var_bindings: ValsAndBindings<ty::TyVid, Bounds<ty::t>>,
// Number of type variables created thus far.
mut ty_var_counter: uint,
// The types that might instantiate an integral type variable are
// represented by an int_ty_set.
int_var_bindings: vals_and_bindings<ty::IntVid, int_ty_set>,
int_var_bindings: ValsAndBindings<ty::IntVid, Option<IntVarValue>>,
// Number of integral variables created thus far.
mut int_var_counter: uint,
// The types that might instantiate a floating-point type variable are
// represented by an float_ty_set.
float_var_bindings: vals_and_bindings<ty::FloatVid, float_ty_set>,
float_var_bindings: ValsAndBindings<ty::FloatVid, Option<ast::float_ty>>,
// Number of floating-point variables created thus far.
mut float_var_counter: uint,
// For region variables.
region_vars: RegionVarBindings,
// For keeping track of existing type and region variables.
ty_var_counter: @mut uint,
int_var_counter: @mut uint,
float_var_counter: @mut uint,
region_var_counter: @mut uint
};
}
enum fixup_err {
unresolved_int_ty(IntVid),
@ -418,27 +407,33 @@ fn fixup_err_to_str(f: fixup_err) -> ~str {
}
}
fn new_vals_and_bindings<V:Copy, T:Copy>() -> vals_and_bindings<V, T> {
vals_and_bindings {
fn new_ValsAndBindings<V:Copy, T:Copy>() -> ValsAndBindings<V, T> {
ValsAndBindings {
vals: smallintmap::mk(),
mut bindings: ~[]
}
}
fn new_infer_ctxt(tcx: ty::ctxt) -> infer_ctxt {
infer_ctxt(@{tcx: tcx,
ty_var_bindings: new_vals_and_bindings(),
int_var_bindings: new_vals_and_bindings(),
float_var_bindings: new_vals_and_bindings(),
region_vars: RegionVarBindings(tcx),
ty_var_counter: @mut 0u,
int_var_counter: @mut 0u,
float_var_counter: @mut 0u,
region_var_counter: @mut 0u})}
fn new_infer_ctxt(tcx: ty::ctxt) -> @InferCtxt {
@InferCtxt {
tcx: tcx,
fn mk_subty(cx: infer_ctxt, a_is_expected: bool, span: span,
ty_var_bindings: new_ValsAndBindings(),
ty_var_counter: 0,
int_var_bindings: new_ValsAndBindings(),
int_var_counter: 0,
float_var_bindings: new_ValsAndBindings(),
float_var_counter: 0,
region_vars: RegionVarBindings(tcx),
}
}
fn mk_subty(cx: @InferCtxt, a_is_expected: bool, span: span,
a: ty::t, b: ty::t) -> ures {
debug!("mk_subty(%s <: %s)", a.to_str(cx), b.to_str(cx));
debug!("mk_subty(%s <: %s)", a.inf_str(cx), b.inf_str(cx));
do indent {
do cx.commit {
cx.sub(a_is_expected, span).tys(a, b)
@ -446,8 +441,8 @@ fn mk_subty(cx: infer_ctxt, a_is_expected: bool, span: span,
}.to_ures()
}
fn can_mk_subty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
debug!("can_mk_subty(%s <: %s)", a.to_str(cx), b.to_str(cx));
fn can_mk_subty(cx: @InferCtxt, a: ty::t, b: ty::t) -> ures {
debug!("can_mk_subty(%s <: %s)", a.inf_str(cx), b.inf_str(cx));
do indent {
do cx.probe {
cx.sub(true, ast_util::dummy_sp()).tys(a, b)
@ -455,9 +450,9 @@ fn can_mk_subty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
}.to_ures()
}
fn mk_subr(cx: infer_ctxt, a_is_expected: bool, span: span,
fn mk_subr(cx: @InferCtxt, a_is_expected: bool, span: span,
a: ty::Region, b: ty::Region) -> ures {
debug!("mk_subr(%s <: %s)", a.to_str(cx), b.to_str(cx));
debug!("mk_subr(%s <: %s)", a.inf_str(cx), b.inf_str(cx));
do indent {
do cx.commit {
cx.sub(a_is_expected, span).regions(a, b)
@ -465,9 +460,9 @@ fn mk_subr(cx: infer_ctxt, a_is_expected: bool, span: span,
}.to_ures()
}
fn mk_eqty(cx: infer_ctxt, a_is_expected: bool, span: span,
fn mk_eqty(cx: @InferCtxt, a_is_expected: bool, span: span,
a: ty::t, b: ty::t) -> ures {
debug!("mk_eqty(%s <: %s)", a.to_str(cx), b.to_str(cx));
debug!("mk_eqty(%s <: %s)", a.inf_str(cx), b.inf_str(cx));
do indent {
do cx.commit {
let suber = cx.sub(a_is_expected, span);
@ -476,9 +471,9 @@ fn mk_eqty(cx: infer_ctxt, a_is_expected: bool, span: span,
}.to_ures()
}
fn mk_assignty(cx: infer_ctxt, a_is_expected: bool, span: span,
fn mk_assignty(cx: @InferCtxt, a_is_expected: bool, span: span,
a: ty::t, b: ty::t) -> ares {
debug!("mk_assignty(%s -> %s)", a.to_str(cx), b.to_str(cx));
debug!("mk_assignty(%s -> %s)", a.inf_str(cx), b.inf_str(cx));
do indent {
do cx.commit {
Assign(cx.combine_fields(a_is_expected, span)).tys(a, b)
@ -486,8 +481,8 @@ fn mk_assignty(cx: infer_ctxt, a_is_expected: bool, span: span,
}
}
fn can_mk_assignty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
debug!("can_mk_assignty(%s -> %s)", a.to_str(cx), b.to_str(cx));
fn can_mk_assignty(cx: @InferCtxt, a: ty::t, b: ty::t) -> ures {
debug!("can_mk_assignty(%s -> %s)", a.inf_str(cx), b.inf_str(cx));
do indent {
do cx.probe {
let span = ast_util::dummy_sp();
@ -497,18 +492,18 @@ fn can_mk_assignty(cx: infer_ctxt, a: ty::t, b: ty::t) -> ures {
}
// See comment on the type `resolve_state` below
fn resolve_type(cx: infer_ctxt, a: ty::t, modes: uint)
fn resolve_type(cx: @InferCtxt, a: ty::t, modes: uint)
-> fres<ty::t> {
resolver(cx, modes).resolve_type_chk(a)
}
fn resolve_region(cx: infer_ctxt, r: ty::Region, modes: uint)
fn resolve_region(cx: @InferCtxt, r: ty::Region, modes: uint)
-> fres<ty::Region> {
resolver(cx, modes).resolve_region_chk(r)
}
/*
fn resolve_borrowings(cx: infer_ctxt) {
fn resolve_borrowings(cx: @InferCtxt) {
for cx.borrowings.each |item| {
match resolve_region(cx, item.scope, resolve_all|force_all) {
Ok(region) => {
@ -574,9 +569,10 @@ pub fn uok() -> ures {
Ok(())
}
fn rollback_to<V:Copy vid, T:Copy>(
vb: &vals_and_bindings<V, T>, len: uint) {
fn rollback_to<V:Copy Vid, T:Copy>(
vb: &ValsAndBindings<V, T>,
len: uint)
{
while vb.bindings.len() != len {
let (vid, old_v) = vb.bindings.pop();
vb.vals.insert(vid.to_uint(), old_v);
@ -589,10 +585,10 @@ struct Snapshot {
region_vars_snapshot: uint,
}
impl infer_ctxt {
impl @InferCtxt {
fn combine_fields(a_is_expected: bool,
span: span) -> combine_fields {
combine_fields {infcx: self,
span: span) -> CombineFields {
CombineFields {infcx: self,
a_is_expected: a_is_expected,
span: span}
}
@ -624,8 +620,7 @@ impl infer_ctxt {
//rollback_to(&self.int_var_bindings,
// snapshot.int_var_bindings_len);
self.region_vars.rollback_to(
snapshot.region_vars_snapshot);
self.region_vars.rollback_to(snapshot.region_vars_snapshot);
}
/// Execute `f` and commit the bindings if successful
@ -669,12 +664,12 @@ impl infer_ctxt {
}
}
impl infer_ctxt {
impl @InferCtxt {
fn next_ty_var_id() -> TyVid {
let id = *self.ty_var_counter;
*self.ty_var_counter += 1u;
let id = self.ty_var_counter;
self.ty_var_counter += 1;
self.ty_var_bindings.vals.insert(id,
root({lb: None, ub: None}, 0u));
Root({lb: None, ub: None}, 0u));
return TyVid(id);
}
@ -687,11 +682,10 @@ impl infer_ctxt {
}
fn next_int_var_id() -> IntVid {
let id = *self.int_var_counter;
*self.int_var_counter += 1u;
let id = self.int_var_counter;
self.int_var_counter += 1;
self.int_var_bindings.vals.insert(id,
root(int_ty_set_all(), 0u));
self.int_var_bindings.vals.insert(id, Root(None, 0));
return IntVid(id);
}
@ -700,10 +694,10 @@ impl infer_ctxt {
}
fn next_float_var_id() -> FloatVid {
let id = *self.float_var_counter;
*self.float_var_counter += 1;
let id = self.float_var_counter;
self.float_var_counter += 1;
self.float_var_bindings.vals.insert(id, root(float_ty_set_all(), 0));
self.float_var_bindings.vals.insert(id, Root(None, 0));
return FloatVid(id);
}
@ -795,10 +789,10 @@ impl infer_ctxt {
fn replace_bound_regions_with_fresh_regions(
&self, span: span,
fty: &ty::FnTy) -> (ty::FnTy, isr_alist)
fsig: &ty::FnSig) -> (ty::FnSig, isr_alist)
{
let {fn_ty: fn_ty, isr: isr, _} =
replace_bound_regions_in_fn_ty(self.tcx, @Nil, None, fty, |br| {
let {fn_sig: fn_sig, isr: isr, _} =
replace_bound_regions_in_fn_sig(self.tcx, @Nil, None, fsig, |br| {
// N.B.: The name of the bound region doesn't have anything to
// do with the region variable that's created for it. The
// only thing we're doing with `br` here is using it in the
@ -809,18 +803,17 @@ impl infer_ctxt {
rvar);
rvar
});
(fn_ty, isr)
(fn_sig, isr)
}
fn fold_regions_in_sig(
&self,
fn_ty: &ty::FnTy,
fldr: &fn(r: ty::Region, in_fn: bool) -> ty::Region) -> ty::FnTy
fn_sig: &ty::FnSig,
fldr: &fn(r: ty::Region, in_fn: bool) -> ty::Region) -> ty::FnSig
{
let sig = do ty::fold_sig(&fn_ty.sig) |t| {
do ty::fold_sig(fn_sig) |t| {
ty::fold_regions(self.tcx, t, fldr)
};
ty::FnTyBase {meta: fn_ty.meta, sig: sig}
}
}
}

View File

@ -544,10 +544,11 @@ use core::prelude::*;
use middle::region::is_subregion_of;
use middle::region;
use middle::ty;
use middle::ty::{Region, RegionVid, br_fresh, re_bound, re_free, re_infer};
use middle::ty::{re_scope, re_static, ReVar, ReSkolemized};
use middle::ty::{Region, RegionVid, re_static, re_infer, re_free, re_bound};
use middle::ty::{re_scope, ReVar, ReSkolemized, br_fresh};
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::cres;
use middle::typeck::infer::to_str::ToStr;
use syntax::codemap;
use util::common::indenter;
use util::ppaux::note_and_explain_region;

View File

@ -51,60 +51,61 @@ use core::prelude::*;
use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid};
use middle::ty::{type_is_bot};
use middle::ty;
use middle::typeck::infer::{cyclic_ty, fixup_err, fres, infer_ctxt};
use middle::typeck::infer::{cyclic_ty, fixup_err, fres, InferCtxt};
use middle::typeck::infer::{region_var_bound_by_region_var, unresolved_ty};
use middle::typeck::infer::floating::*;
use middle::typeck::infer::floating;
use middle::typeck::infer::integral::*;
use middle::typeck::infer::integral;
use middle::typeck::infer::to_str::ToStr;
use middle::typeck::infer::unify::root;
use util::common::indent;
use middle::typeck::infer::{IntType, UintType};
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::unify::Root;
use util::common::{indent, indenter};
use util::ppaux::ty_to_str;
use syntax::ast;
use core::uint;
use core::vec;
const resolve_nested_tvar: uint = 0b00000001;
const resolve_rvar: uint = 0b00000010;
const resolve_ivar: uint = 0b00000100;
const resolve_fvar: uint = 0b00001000;
const resolve_all: uint = 0b00001111;
const force_tvar: uint = 0b00010000;
const force_rvar: uint = 0b00100000;
const force_ivar: uint = 0b01000000;
const force_fvar: uint = 0b11000000;
const force_all: uint = 0b11110000;
const resolve_nested_tvar: uint = 0b0000000001;
const resolve_rvar: uint = 0b0000000010;
const resolve_ivar: uint = 0b0000000100;
const resolve_fvar: uint = 0b0000001000;
const resolve_fnvar: uint = 0b0000010000;
const resolve_all: uint = 0b0000011111;
const force_tvar: uint = 0b0000100000;
const force_rvar: uint = 0b0001000000;
const force_ivar: uint = 0b0010000000;
const force_fvar: uint = 0b0100000000;
const force_fnvar: uint = 0b1000000000;
const force_all: uint = 0b1111100000;
const not_regions: uint = !(force_rvar | resolve_rvar);
const resolve_and_force_all_but_regions: uint =
(resolve_all | force_all) & not_regions;
type resolve_state_ = {
infcx: infer_ctxt,
struct ResolveState {
infcx: @InferCtxt,
modes: uint,
mut err: Option<fixup_err>,
mut v_seen: ~[TyVid]
};
enum resolve_state {
resolve_state_(@resolve_state_)
mut v_seen: ~[TyVid],
mut type_depth: uint
}
fn resolver(infcx: infer_ctxt, modes: uint) -> resolve_state {
resolve_state_(@{infcx: infcx,
fn resolver(infcx: @InferCtxt, modes: uint) -> ResolveState {
ResolveState {
infcx: infcx,
modes: modes,
mut err: None,
mut v_seen: ~[]})
err: None,
v_seen: ~[],
type_depth: 0
}
}
impl resolve_state {
fn should(mode: uint) -> bool {
impl ResolveState {
fn should(&self, mode: uint) -> bool {
(self.modes & mode) == mode
}
fn resolve_type_chk(typ: ty::t) -> fres<ty::t> {
fn resolve_type_chk(&self, typ: ty::t) -> fres<ty::t> {
self.err = None;
debug!("Resolving %s (modes=%x)",
@ -129,7 +130,7 @@ impl resolve_state {
}
}
fn resolve_region_chk(orig: ty::Region) -> fres<ty::Region> {
fn resolve_region_chk(&self, orig: ty::Region) -> fres<ty::Region> {
self.err = None;
let resolved = indent(|| self.resolve_region(orig) );
match self.err {
@ -138,12 +139,19 @@ impl resolve_state {
}
}
fn resolve_type(typ: ty::t) -> ty::t {
debug!("resolve_type(%s)", typ.to_str(self.infcx));
indent(fn&() -> ty::t {
if !ty::type_needs_infer(typ) { return typ; }
fn resolve_type(&self, typ: ty::t) -> ty::t {
debug!("resolve_type(%s)", typ.inf_str(self.infcx));
let _i = indenter();
match copy ty::get(typ).sty {
if !ty::type_needs_infer(typ) {
return typ;
}
if self.type_depth > 0 && !self.should(resolve_nested_tvar) {
return typ;
}
match /*bad*/ copy ty::get(typ).sty {
ty::ty_infer(TyVar(vid)) => {
self.resolve_ty_var(vid)
}
@ -154,47 +162,41 @@ impl resolve_state {
self.resolve_float_var(vid)
}
_ => {
if !self.should(resolve_rvar) &&
!self.should(resolve_nested_tvar) {
// shortcircuit for efficiency
if self.modes & resolve_all == 0 {
// if we are only resolving top-level type
// variables, and this is not a top-level type
// variable, then shortcircuit for efficiency
typ
} else {
ty::fold_regions_and_ty(
self.type_depth += 1;
let result = ty::fold_regions_and_ty(
self.infcx.tcx, typ,
|r| self.resolve_region(r),
|t| self.resolve_nested_tvar(t),
|t| self.resolve_nested_tvar(t))
|t| self.resolve_type(t),
|t| self.resolve_type(t));
self.type_depth -= 1;
result
}
}
}
})
}
fn resolve_nested_tvar(typ: ty::t) -> ty::t {
debug!("Resolve_if_deep(%s)", typ.to_str(self.infcx));
if !self.should(resolve_nested_tvar) {
typ
} else {
self.resolve_type(typ)
}
}
fn resolve_region(orig: ty::Region) -> ty::Region {
debug!("Resolve_region(%s)", orig.to_str(self.infcx));
fn resolve_region(&self, orig: ty::Region) -> ty::Region {
debug!("Resolve_region(%s)", orig.inf_str(self.infcx));
match orig {
ty::re_infer(ty::ReVar(rid)) => self.resolve_region_var(rid),
_ => orig
}
}
fn resolve_region_var(rid: RegionVid) -> ty::Region {
fn resolve_region_var(&self, rid: RegionVid) -> ty::Region {
if !self.should(resolve_rvar) {
return ty::re_infer(ty::ReVar(rid));
}
self.infcx.region_vars.resolve_var(rid)
}
fn assert_not_rvar(rid: RegionVid, r: ty::Region) {
fn assert_not_rvar(&self, rid: RegionVid, r: ty::Region) {
match r {
ty::re_infer(ty::ReVar(rid2)) => {
self.err = Some(region_var_bound_by_region_var(rid, rid2));
@ -203,7 +205,7 @@ impl resolve_state {
}
}
fn resolve_ty_var(vid: TyVid) -> ty::t {
fn resolve_ty_var(&self, vid: TyVid) -> ty::t {
if vec::contains(self.v_seen, &vid) {
self.err = Some(cyclic_ty(vid));
return ty::mk_var(self.infcx.tcx, vid);
@ -236,27 +238,22 @@ impl resolve_state {
}
}
fn resolve_int_var(vid: IntVid) -> ty::t {
fn resolve_int_var(&self, vid: IntVid) -> ty::t {
if !self.should(resolve_ivar) {
return ty::mk_int_var(self.infcx.tcx, vid);
}
let nde = self.infcx.get(&self.infcx.int_var_bindings, vid);
let pt = nde.possible_types;
// If there's only one type in the set of possible types, then
// that's the answer.
match integral::single_type_contained_in(self.infcx.tcx, pt) {
Some(t) => t,
let node = self.infcx.get(&self.infcx.int_var_bindings, vid);
match node.possible_types {
Some(IntType(t)) => ty::mk_mach_int(self.infcx.tcx, t),
Some(UintType(t)) => ty::mk_mach_uint(self.infcx.tcx, t),
None => {
if self.should(force_ivar) {
// As a last resort, default to int.
let ty = ty::mk_int(self.infcx.tcx);
self.infcx.set(
&self.infcx.int_var_bindings, vid,
root(convert_integral_ty_to_int_ty_set(self.infcx.tcx,
ty),
nde.rank));
Root(Some(IntType(ast::ty_i)), node.rank));
ty
} else {
ty::mk_int_var(self.infcx.tcx, vid)
@ -265,18 +262,14 @@ impl resolve_state {
}
}
fn resolve_float_var(vid: FloatVid) -> ty::t {
fn resolve_float_var(&self, vid: FloatVid) -> ty::t {
if !self.should(resolve_fvar) {
return ty::mk_float_var(self.infcx.tcx, vid);
}
let nde = self.infcx.get(&self.infcx.float_var_bindings, vid);
let pt = nde.possible_types;
// If there's only one type in the set of possible types, then
// that's the answer.
match floating::single_type_contained_in(self.infcx.tcx, pt) {
Some(t) => t,
let node = self.infcx.get(&self.infcx.float_var_bindings, vid);
match node.possible_types {
Some(t) => ty::mk_mach_float(self.infcx.tcx, t),
None => {
if self.should(force_fvar) {
// As a last resort, default to float.
@ -284,10 +277,7 @@ impl resolve_state {
self.infcx.set(
&self.infcx.float_var_bindings,
vid,
root(
convert_floating_point_ty_to_float_ty_set(
self.infcx.tcx, ty),
nde.rank));
Root(Some(ast::ty_f), node.rank));
ty
} else {
ty::mk_float_var(self.infcx.tcx, vid)

View File

@ -11,13 +11,13 @@
use core::prelude::*;
use middle::ty;
use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_ty;
use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
use middle::typeck::infer::combine::*;
use middle::typeck::infer::cres;
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::infer_ctxt;
use middle::typeck::infer::InferCtxt;
use middle::typeck::infer::lub::Lub;
use middle::typeck::infer::to_str::ToStr;
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::unify::*;
use util::ppaux::bound_region_to_str;
@ -27,10 +27,10 @@ use syntax::ast::{m_const, purity, ret_style};
fn macros() { include!("macros.rs"); } // FIXME(#3114): Macro import/export.
enum Sub = combine_fields; // "subtype", "subregion" etc
enum Sub = CombineFields; // "subtype", "subregion" etc
impl Sub: combine {
fn infcx() -> infer_ctxt { self.infcx }
impl Sub: Combine {
fn infcx() -> @InferCtxt { self.infcx }
fn tag() -> ~str { ~"sub" }
fn a_is_expected() -> bool { self.a_is_expected }
fn span() -> span { self.span }
@ -40,14 +40,14 @@ impl Sub: combine {
fn glb() -> Glb { Glb(*self) }
fn contratys(a: ty::t, b: ty::t) -> cres<ty::t> {
let opp = combine_fields {
let opp = CombineFields {
a_is_expected: !self.a_is_expected,.. *self
};
Sub(opp).tys(b, a)
}
fn contraregions(a: ty::Region, b: ty::Region) -> cres<ty::Region> {
let opp = combine_fields {
let opp = CombineFields {
a_is_expected: !self.a_is_expected,.. *self
};
Sub(opp).regions(b, a)
@ -56,8 +56,8 @@ impl Sub: combine {
fn regions(a: ty::Region, b: ty::Region) -> cres<ty::Region> {
debug!("%s.regions(%s, %s)",
self.tag(),
a.to_str(self.infcx),
b.to_str(self.infcx));
a.inf_str(self.infcx),
b.inf_str(self.infcx));
do indent {
match self.infcx.region_vars.make_subregion(self.span, a, b) {
Ok(()) => Ok(a),
@ -67,7 +67,7 @@ impl Sub: combine {
}
fn mts(a: ty::mt, b: ty::mt) -> cres<ty::mt> {
debug!("mts(%s <: %s)", a.to_str(self.infcx), b.to_str(self.infcx));
debug!("mts(%s <: %s)", a.inf_str(self.infcx), b.inf_str(self.infcx));
if a.mutbl != b.mutbl && b.mutbl != m_const {
return Err(ty::terr_mutability);
@ -86,14 +86,6 @@ impl Sub: combine {
}
}
fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto> {
match (p1, p2) {
(ast::ProtoBare, _) => Ok(p1),
_ if p1 == p2 => Ok(p1),
_ => Err(ty::terr_proto_mismatch(expected_found(&self, p1, p2)))
}
}
fn purities(a: purity, b: purity) -> cres<purity> {
self.lub().purities(a, b).compare(b, || {
ty::terr_purity_mismatch(expected_found(&self, a, b))
@ -108,25 +100,37 @@ impl Sub: combine {
fn tys(a: ty::t, b: ty::t) -> cres<ty::t> {
debug!("%s.tys(%s, %s)", self.tag(),
a.to_str(self.infcx), b.to_str(self.infcx));
a.inf_str(self.infcx), b.inf_str(self.infcx));
if a == b { return Ok(a); }
do indent {
match (ty::get(a).sty, ty::get(b).sty) {
(ty::ty_bot, _) => {
Ok(a)
}
(ty::ty_infer(TyVar(a_id)), ty::ty_infer(TyVar(b_id))) => {
var_sub_var(&self, a_id, b_id).then(|| Ok(a) )
do self.var_sub_var(&self.infcx.ty_var_bindings,
a_id, b_id).then {
Ok(a)
}
}
(ty::ty_infer(TyVar(a_id)), _) => {
var_sub_t(&self, a_id, b).then(|| Ok(a) )
do self.var_sub_t(&self.infcx.ty_var_bindings,
a_id, b).then {
Ok(a)
}
}
(_, ty::ty_infer(TyVar(b_id))) => {
t_sub_var(&self, a, b_id).then(|| Ok(a) )
do self.t_sub_var(&self.infcx.ty_var_bindings,
a, b_id).then {
Ok(a)
}
}
(_, ty::ty_bot) => {
Err(ty::terr_sorts(expected_found(&self, a, b)))
}
_ => {
super_tys(&self, a, b)
}
@ -134,8 +138,9 @@ impl Sub: combine {
}
}
fn fns(a: &ty::FnTy, b: &ty::FnTy) -> cres<ty::FnTy> {
debug!("fns(a=%s, b=%s)", a.to_str(self.infcx), b.to_str(self.infcx));
fn fn_sigs(a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
debug!("fn_sigs(a=%s, b=%s)",
a.inf_str(self.infcx), b.inf_str(self.infcx));
let _indenter = indenter();
// Rather than checking the subtype relationship between `a` and `b`
@ -153,14 +158,14 @@ impl Sub: combine {
// First, we instantiate each bound region in the subtype with a fresh
// region variable.
let (a_fn_ty, _) =
let (a_sig, _) =
self.infcx.replace_bound_regions_with_fresh_regions(
self.span, a);
// Second, we instantiate each bound region in the supertype with a
// fresh concrete region.
let {fn_ty: b_fn_ty, isr: skol_isr, _} = {
do replace_bound_regions_in_fn_ty(self.infcx.tcx, @Nil,
let {fn_sig: b_sig, isr: skol_isr, _} = {
do replace_bound_regions_in_fn_sig(self.infcx.tcx, @Nil,
None, b) |br| {
let skol = self.infcx.region_vars.new_skolemized(br);
debug!("Bound region %s skolemized to %?",
@ -170,11 +175,11 @@ impl Sub: combine {
}
};
debug!("a_fn_ty=%s", a_fn_ty.to_str(self.infcx));
debug!("b_fn_ty=%s", b_fn_ty.to_str(self.infcx));
debug!("a_sig=%s", a_sig.inf_str(self.infcx));
debug!("b_sig=%s", b_sig.inf_str(self.infcx));
// Compare types now that bound regions have been replaced.
let fn_ty = if_ok!(super_fns(&self, &a_fn_ty, &b_fn_ty));
let sig = if_ok!(super_fn_sigs(&self, &a_sig, &b_sig));
// Presuming type comparison succeeds, we need to check
// that the skolemized regions do not "leak".
@ -206,21 +211,25 @@ impl Sub: combine {
}
}
return Ok(fn_ty)
return Ok(sig);
}
// Traits please (FIXME: #2794):
fn protos(p1: ast::Proto, p2: ast::Proto) -> cres<ast::Proto> {
super_protos(&self, p1, p2)
}
fn flds(a: ty::field, b: ty::field) -> cres<ty::field> {
super_flds(&self, a, b)
}
fn fn_metas(a: &ty::FnMeta, b: &ty::FnMeta) -> cres<ty::FnMeta> {
super_fn_metas(&self, a, b)
fn fns(a: &ty::FnTy, b: &ty::FnTy) -> cres<ty::FnTy> {
super_fns(&self, a, b)
}
fn fn_sigs(a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
super_fn_sigs(&self, a, b)
fn fn_metas(a: &ty::FnMeta, b: &ty::FnMeta) -> cres<ty::FnMeta> {
super_fn_metas(&self, a, b)
}
fn vstores(vk: ty::terr_vstore_kind,

View File

@ -10,86 +10,101 @@
use core::prelude::*;
use middle::ty::vid;
use middle::ty::{FnMeta, FnTyBase, FnSig, FnVid, Vid};
use middle::ty;
use middle::typeck::infer::{bound, bounds};
use middle::typeck::infer::floating::float_ty_set;
use middle::typeck::infer::infer_ctxt;
use middle::typeck::infer::integral::int_ty_set;
use middle::typeck::infer::unify::{redirect, root, var_value};
use middle::typeck::infer::{Bound, Bounds};
use middle::typeck::infer::{IntVarValue, IntType, UintType};
use middle::typeck::infer::InferCtxt;
use middle::typeck::infer::unify::{Redirect, Root, VarValue};
use util::ppaux::{mt_to_str, ty_to_str};
use util::ppaux;
use core::uint;
use syntax::{ast, ast_util};
trait ToStr {
fn to_str(cx: infer_ctxt) -> ~str;
use core::uint;
use core::str;
pub trait InferStr {
fn inf_str(cx: @InferCtxt) -> ~str;
}
impl ty::t: ToStr {
fn to_str(cx: infer_ctxt) -> ~str {
impl ty::t : InferStr {
fn inf_str(cx: @InferCtxt) -> ~str {
ty_to_str(cx.tcx, self)
}
}
impl ty::mt: ToStr {
fn to_str(cx: infer_ctxt) -> ~str {
impl FnMeta : InferStr {
fn inf_str(_cx: @InferCtxt) -> ~str {
fmt!("%?", self)
}
}
impl FnSig : InferStr {
fn inf_str(cx: @InferCtxt) -> ~str {
fmt!("(%s) -> %s",
str::connect(self.inputs.map(|a| a.ty.inf_str(cx)), ", "),
self.output.inf_str(cx))
}
}
impl<M:InferStr> FnTyBase<M> : InferStr {
fn inf_str(cx: @InferCtxt) -> ~str {
fmt!("%s%s", self.meta.inf_str(cx), self.sig.inf_str(cx))
}
}
impl ty::mt : InferStr {
fn inf_str(cx: @InferCtxt) -> ~str {
mt_to_str(cx.tcx, self)
}
}
impl ty::Region: ToStr {
fn to_str(cx: infer_ctxt) -> ~str {
ppaux::region_to_str(cx.tcx, self)
impl ty::Region : InferStr {
fn inf_str(_cx: @InferCtxt) -> ~str {
fmt!("%?", self)
}
}
impl ty::FnTy: ToStr {
fn to_str(cx: infer_ctxt) -> ~str {
ty::mk_fn(cx.tcx, self).to_str(cx)
}
}
impl<V:Copy ToStr> bound<V>: ToStr {
fn to_str(cx: infer_ctxt) -> ~str {
impl<V:InferStr> Bound<V> : InferStr {
fn inf_str(cx: @InferCtxt) -> ~str {
match self {
Some(ref v) => (*v).to_str(cx),
Some(ref v) => v.inf_str(cx),
None => ~"none"
}
}
}
impl<T:Copy ToStr> bounds<T>: ToStr {
fn to_str(cx: infer_ctxt) -> ~str {
impl<T:InferStr> Bounds<T> : InferStr {
fn inf_str(cx: @InferCtxt) -> ~str {
fmt!("{%s <: %s}",
self.lb.to_str(cx),
self.ub.to_str(cx))
self.lb.inf_str(cx),
self.ub.inf_str(cx))
}
}
impl int_ty_set: ToStr {
fn to_str(_cx: infer_ctxt) -> ~str {
impl<V:Vid ToStr, T:InferStr> VarValue<V, T> : InferStr {
fn inf_str(cx: @InferCtxt) -> ~str {
match self {
int_ty_set(v) => uint::to_str(v, 10u)
}
}
}
impl float_ty_set: ToStr {
fn to_str(_cx: infer_ctxt) -> ~str {
match self {
float_ty_set(v) => uint::to_str(v, 10u)
}
}
}
impl<V:Copy vid, T:Copy ToStr> var_value<V, T>: ToStr {
fn to_str(cx: infer_ctxt) -> ~str {
match self {
redirect(ref vid) => fmt!("redirect(%s)", (*vid).to_str()),
root(ref pt, rk) => fmt!("root(%s, %s)", (*pt).to_str(cx),
Redirect(ref vid) => fmt!("Redirect(%s)", vid.to_str()),
Root(ref pt, rk) => fmt!("Root(%s, %s)", pt.inf_str(cx),
uint::to_str(rk, 10u))
}
}
}
impl IntVarValue : InferStr {
fn inf_str(_cx: @InferCtxt) -> ~str {
match self {
IntType(t) => ast_util::int_ty_to_str(t),
UintType(t) => ast_util::uint_ty_to_str(t)
}
}
}
impl ast::float_ty : InferStr {
fn inf_str(_cx: @InferCtxt) -> ~str {
ast_util::float_ty_to_str(self)
}
}

View File

@ -10,40 +10,45 @@
use core::prelude::*;
use middle::ty::vid;
use middle::ty::Vid;
use middle::ty;
use middle::typeck::infer::{bound, bounds, cres, uok, ures};
use middle::typeck::infer::combine::combine;
use middle::typeck::infer::floating::*;
use middle::typeck::infer::floating;
use middle::typeck::infer::infer_ctxt;
use middle::typeck::infer::integral::*;
use middle::typeck::infer::integral;
use middle::typeck::infer::to_str::ToStr;
use middle::typeck::infer::{Bound, Bounds, cres, uok, ures};
use middle::typeck::infer::combine::Combine;
use middle::typeck::infer::InferCtxt;
use middle::typeck::infer::to_str::InferStr;
use util::common::{indent, indenter};
use core::result;
use std::smallintmap::SmallIntMap;
enum var_value<V:Copy, T:Copy> {
redirect(V),
root(T, uint),
enum VarValue<V, T> {
Redirect(V),
Root(T, uint),
}
struct vals_and_bindings<V:Copy, T:Copy> {
vals: SmallIntMap<var_value<V, T>>,
mut bindings: ~[(V, var_value<V, T>)],
struct ValsAndBindings<V:Copy, T:Copy> {
vals: SmallIntMap<VarValue<V, T>>,
mut bindings: ~[(V, VarValue<V, T>)],
}
struct node<V:Copy, T:Copy> {
struct Node<V:Copy, T:Copy> {
root: V,
possible_types: T,
rank: uint,
}
impl infer_ctxt {
fn get<V:Copy vid Eq, T:Copy>(
vb: &vals_and_bindings<V, T>, vid: V) -> node<V, T> {
impl @InferCtxt {
fn get<V:Copy Eq Vid, T:Copy>(
vb: &ValsAndBindings<V, T>,
vid: V)
-> Node<V, T>
{
/*!
*
* Find the root node for `vid`. This uses the standard
* union-find algorithm with path compression:
* http://en.wikipedia.org/wiki/Disjoint-set_data_structure
*/
let vid_u = vid.to_uint();
match vb.vals.find(vid_u) {
@ -52,435 +57,141 @@ impl infer_ctxt {
}
Some(ref var_val) => {
match (*var_val) {
redirect(ref vid) => {
Redirect(ref vid) => {
let node = self.get(vb, (*vid));
if node.root.ne(vid) {
// Path compression
vb.vals.insert((*vid).to_uint(), redirect(node.root));
vb.vals.insert(vid.to_uint(), Redirect(node.root));
}
node
}
root(ref pt, rk) => {
node {root: vid, possible_types: (*pt), rank: rk}
Root(ref pt, rk) => {
Node {root: vid, possible_types: *pt, rank: rk}
}
}
}
}
}
fn set<V:Copy vid, T:Copy ToStr>(
vb: &vals_and_bindings<V, T>, vid: V,
+new_v: var_value<V, T>) {
fn set<V:Copy Vid ToStr, T:Copy InferStr>(
vb: &ValsAndBindings<V, T>,
vid: V,
+new_v: VarValue<V, T>)
{
/*!
*
* Sets the value for `vid` to `new_v`. `vid` MUST be a root node!
*/
let old_v = vb.vals.get(vid.to_uint());
vb.bindings.push((vid, old_v));
vb.vals.insert(vid.to_uint(), new_v);
debug!("Updating variable %s from %s to %s",
vid.to_str(), old_v.to_str(self), new_v.to_str(self));
}
vid.to_str(), old_v.inf_str(self), new_v.inf_str(self));
}
// Combines the two bounds into a more general bound.
fn merge_bnd<C: combine>(
self: &C, a: bound<ty::t>, b: bound<ty::t>,
merge_op: fn(ty::t,ty::t) -> cres<ty::t>) -> cres<bound<ty::t>> {
fn unify<V:Copy Vid ToStr, T:Copy InferStr, R>(
vb: &ValsAndBindings<V, T>,
node_a: &Node<V, T>,
node_b: &Node<V, T>,
op: &fn(new_root: V, new_rank: uint) -> R
) -> R {
// Rank optimization: if you don't know what it is, check
// out <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>
debug!("merge_bnd(%s,%s)",
a.to_str(self.infcx()),
b.to_str(self.infcx()));
let _r = indenter();
debug!("unify(node_a(id=%?, rank=%?), \
node_b(id=%?, rank=%?))",
node_a.root, node_a.rank,
node_b.root, node_b.rank);
match (a, b) {
(None, None) => Ok(None),
(Some(_), None) => Ok(a),
(None, Some(_)) => Ok(b),
(Some(v_a), Some(v_b)) => {
do merge_op(v_a, v_b).chain |v| {
Ok(Some(v))
}
}
}
}
fn merge_bnds<C: combine>(
self: &C, a: bounds<ty::t>, b: bounds<ty::t>,
lub: fn(ty::t,ty::t) -> cres<ty::t>,
glb: fn(ty::t,ty::t) -> cres<ty::t>) -> cres<bounds<ty::t>> {
let _r = indenter();
do merge_bnd(self, a.ub, b.ub, glb).chain |ub| {
debug!("glb of ubs %s and %s is %s",
a.ub.to_str(self.infcx()),
b.ub.to_str(self.infcx()),
ub.to_str(self.infcx()));
do merge_bnd(self, a.lb, b.lb, lub).chain |lb| {
debug!("lub of lbs %s and %s is %s",
a.lb.to_str(self.infcx()),
b.lb.to_str(self.infcx()),
lb.to_str(self.infcx()));
Ok({lb: lb, ub: ub})
}
}
}
// Updates the bounds for the variable `v_id` to be the intersection
// of `a` and `b`. That is, the new bounds for `v_id` will be
// a bounds c such that:
// c.ub <: a.ub
// c.ub <: b.ub
// a.lb <: c.lb
// b.lb <: c.lb
// If this cannot be achieved, the result is failure.
fn set_var_to_merged_bounds<C: combine>(
self: &C,
v_id: ty::TyVid,
a: bounds<ty::t>,
b: bounds<ty::t>,
rank: uint) -> ures {
let vb = &self.infcx().ty_var_bindings;
// Think of the two diamonds, we want to find the
// intersection. There are basically four possibilities (you
// can swap A/B in these pictures):
//
// A A
// / \ / \
// / B \ / B \
// / / \ \ / / \ \
// * * * * * / * *
// \ \ / / \ / /
// \ B / / \ / /
// \ / * \ /
// A \ / A
// B
debug!("merge(%s,%s,%s)",
v_id.to_str(),
a.to_str(self.infcx()),
b.to_str(self.infcx()));
// First, relate the lower/upper bounds of A and B.
// Note that these relations *must* hold for us to
// to be able to merge A and B at all, and relating
// them explicitly gives the type inferencer more
// information and helps to produce tighter bounds
// when necessary.
do indent {
do bnds(self, a.lb, b.ub).then {
do bnds(self, b.lb, a.ub).then {
do merge_bnd(self, a.ub, b.ub,
|x, y| self.glb().tys(x, y)).chain |ub| {
do merge_bnd(self, a.lb, b.lb,
|x, y| self.lub().tys(x, y)).chain |lb| {
let bounds = {lb: lb, ub: ub};
debug!("merge(%s): bounds=%s",
v_id.to_str(),
bounds.to_str(self.infcx()));
// the new bounds must themselves
// be relatable:
do bnds(self, bounds.lb, bounds.ub).then {
self.infcx().set(vb, v_id, root(bounds, rank));
uok()
}
}
}
}
}
}
}
/// Ensure that variable A is a subtype of variable B. This is a
/// subtle and tricky process, as described in detail at the top
/// of infer.rs
fn var_sub_var<C: combine>(self: &C,
a_id: ty::TyVid,
b_id: ty::TyVid) -> ures {
let vb = &self.infcx().ty_var_bindings;
// Need to make sub_id a subtype of sup_id.
let nde_a = self.infcx().get(vb, a_id);
let nde_b = self.infcx().get(vb, b_id);
let a_id = nde_a.root;
let b_id = nde_b.root;
let a_bounds = nde_a.possible_types;
let b_bounds = nde_b.possible_types;
debug!("vars(%s=%s <: %s=%s)",
a_id.to_str(), a_bounds.to_str(self.infcx()),
b_id.to_str(), b_bounds.to_str(self.infcx()));
if a_id == b_id { return uok(); }
// If both A's UB and B's LB have already been bound to types,
// see if we can make those types subtypes.
match (a_bounds.ub, b_bounds.lb) {
(Some(a_ub), Some(b_lb)) => {
let r = self.infcx().try(|| self.sub().tys(a_ub, b_lb));
match r {
Ok(_ty) => return result::Ok(()),
Err(_) => { /*fallthrough */ }
}
}
_ => { /*fallthrough*/ }
}
// Otherwise, we need to merge A and B so as to guarantee that
// A remains a subtype of B. Actually, there are other options,
// but that's the route we choose to take.
// Rank optimization
// Make the node with greater rank the parent of the node with
// smaller rank.
if nde_a.rank > nde_b.rank {
debug!("vars(): a has smaller rank");
if node_a.rank > node_b.rank {
// a has greater rank, so a should become b's parent,
// i.e., b should redirect to a.
self.infcx().set(vb, b_id, redirect(a_id));
set_var_to_merged_bounds(
self, a_id, a_bounds, b_bounds, nde_a.rank)
} else if nde_a.rank < nde_b.rank {
debug!("vars(): b has smaller rank");
self.set(vb, node_b.root, Redirect(node_a.root));
op(node_a.root, node_a.rank)
} else if node_a.rank < node_b.rank {
// b has greater rank, so a should redirect to b.
self.infcx().set(vb, a_id, redirect(b_id));
set_var_to_merged_bounds(
self, b_id, a_bounds, b_bounds, nde_b.rank)
self.set(vb, node_a.root, Redirect(node_b.root));
op(node_b.root, node_b.rank)
} else {
debug!("vars(): a and b have equal rank");
assert nde_a.rank == nde_b.rank;
// If equal, just redirect one to the other and increment
// the other's rank. We choose arbitrarily to redirect b
// to a and increment a's rank.
self.infcx().set(vb, b_id, redirect(a_id));
set_var_to_merged_bounds(
self, a_id, a_bounds, b_bounds, nde_a.rank + 1u
)
// If equal, redirect one to the other and increment the
// other's rank.
assert node_a.rank == node_b.rank;
self.set(vb, node_b.root, Redirect(node_a.root));
op(node_a.root, node_a.rank + 1)
}
}
/// make variable a subtype of T
fn var_sub_t<C: combine>(self: &C, a_id: ty::TyVid, b: ty::t) -> ures {
let vb = &self.infcx().ty_var_bindings;
let nde_a = self.infcx().get(vb, a_id);
let a_id = nde_a.root;
let a_bounds = nde_a.possible_types;
debug!("var_sub_t(%s=%s <: %s)",
a_id.to_str(),
a_bounds.to_str(self.infcx()),
b.to_str(self.infcx()));
let b_bounds = {lb: None, ub: Some(b)};
set_var_to_merged_bounds(self, a_id, a_bounds, b_bounds, nde_a.rank)
}
/// make T a subtype of variable
fn t_sub_var<C: combine>(self: &C, a: ty::t, b_id: ty::TyVid) -> ures {
let vb = &self.infcx().ty_var_bindings;
let a_bounds = {lb: Some(a), ub: None};
let nde_b = self.infcx().get(vb, b_id);
let b_id = nde_b.root;
let b_bounds = nde_b.possible_types;
debug!("t_sub_var(%s <: %s=%s)",
a.to_str(self.infcx()),
b_id.to_str(),
b_bounds.to_str(self.infcx()));
set_var_to_merged_bounds(self, b_id, a_bounds, b_bounds, nde_b.rank)
}
fn bnds<C: combine>(
self: &C, a: bound<ty::t>, b: bound<ty::t>) -> ures {
debug!("bnds(%s <: %s)", a.to_str(self.infcx()), b.to_str(self.infcx()));
do indent {
match (a, b) {
(None, None) |
(Some(_), None) |
(None, Some(_)) => {
uok()
}
(Some(t_a), Some(t_b)) => {
self.sub().tys(t_a, t_b).to_ures()
}
}
}
}
// ______________________________________________________________________
// Integral variables
// Code to handle simple variables like ints, floats---anything that
// doesn't have a subtyping relationship we need to worry about.
impl infer_ctxt {
fn optimize_ranks<V:Copy vid Eq,T:Copy ToStr>(vb: &vals_and_bindings<V,T>,
nde_a: node<V,T>,
nde_b: node<V,T>,
impl @InferCtxt {
fn simple_vars<V:Copy Eq Vid ToStr, T:Copy Eq InferStr>(
vb: &ValsAndBindings<V, Option<T>>,
err: ty::type_err,
a_id: V,
b_id: V,
intersection: T) {
if nde_a.rank > nde_b.rank {
debug!("int_vars(): a has smaller rank");
// a has greater rank, so a should become b's parent,
// i.e., b should redirect to a.
self.set(vb, a_id, root(intersection, nde_a.rank));
self.set(vb, b_id, redirect(a_id));
} else if nde_a.rank < nde_b.rank {
debug!("int_vars(): b has smaller rank");
// b has greater rank, so a should redirect to b.
self.set(vb, b_id, root(intersection, nde_b.rank));
self.set(vb, a_id, redirect(b_id));
} else {
debug!("int_vars(): a and b have equal rank");
assert nde_a.rank == nde_b.rank;
// If equal, just redirect one to the other and increment
// the other's rank. We choose arbitrarily to redirect b
// to a and increment a's rank.
self.set(vb, a_id, root(intersection, nde_a.rank + 1u));
self.set(vb, b_id, redirect(a_id));
b_id: V) -> ures
{
/*!
*
* Unifies two simple variables. Because simple variables do
* not have any subtyping relationships, if both variables
* have already been associated with a value, then those two
* values must be the same. */
let node_a = self.get(vb, a_id);
let node_b = self.get(vb, b_id);
let a_id = node_a.root;
let b_id = node_b.root;
if a_id == b_id { return uok(); }
let combined = match (&node_a.possible_types, &node_b.possible_types)
{
(&None, &None) => None,
(&Some(ref v), &None) | (&None, &Some(ref v)) => Some(*v),
(&Some(ref v1), &Some(ref v2)) => {
if *v1 != *v2 { return Err(err); }
Some(*v1)
}
};
self.unify(vb, &node_a, &node_b, |new_root, new_rank| {
self.set(vb, new_root, Root(combined, new_rank));
});
return uok();
}
fn int_vars(a_id: ty::IntVid, b_id: ty::IntVid) -> ures {
let vb = &self.int_var_bindings;
fn simple_var_t<V:Copy Eq Vid ToStr, T:Copy Eq InferStr>(
vb: &ValsAndBindings<V, Option<T>>,
err: ty::type_err,
a_id: V,
b: T) -> ures
{
/*!
*
* Sets the value of the variable `a_id` to `b`. Because
* simple variables do not have any subtyping relationships,
* if `a_id` already has a value, it must be the same as
* `b`. */
let nde_a = self.get(vb, a_id);
let nde_b = self.get(vb, b_id);
let a_id = nde_a.root;
let b_id = nde_b.root;
let a_pt = nde_a.possible_types;
let b_pt = nde_b.possible_types;
let node_a = self.get(vb, a_id);
let a_id = node_a.root;
// If we're already dealing with the same two variables,
// there's nothing to do.
if a_id == b_id { return uok(); }
// Otherwise, take the intersection of the two sets of
// possible types.
let intersection = integral::intersection(a_pt, b_pt);
if *intersection == INT_TY_SET_EMPTY {
return Err(ty::terr_no_integral_type);
if node_a.possible_types.is_none() {
self.set(vb, a_id, Root(Some(b), node_a.rank));
return uok();
}
// Rank optimization
self.optimize_ranks(vb, nde_a, nde_b, a_id, b_id, intersection);
uok()
if node_a.possible_types == Some(b) {
return uok();
}
fn int_var_sub_t(a_id: ty::IntVid, b: ty::t) -> ures {
if ty::type_is_char(b) {
return Err(ty::terr_integer_as_char);
}
assert ty::type_is_integral(b);
let vb = &self.int_var_bindings;
let nde_a = self.get(vb, a_id);
let a_id = nde_a.root;
let a_pt = nde_a.possible_types;
let intersection =
integral::intersection(a_pt,
convert_integral_ty_to_int_ty_set(self.tcx, b));
if *intersection == INT_TY_SET_EMPTY {
return Err(ty::terr_no_integral_type);
}
self.set(vb, a_id, root(intersection, nde_a.rank));
uok()
}
fn t_sub_int_var(a: ty::t, b_id: ty::IntVid) -> ures {
assert ty::type_is_integral(a);
let vb = &self.int_var_bindings;
let nde_b = self.get(vb, b_id);
let b_id = nde_b.root;
let b_pt = nde_b.possible_types;
let intersection =
integral::intersection(b_pt,
convert_integral_ty_to_int_ty_set(self.tcx, a));
if *intersection == INT_TY_SET_EMPTY {
return Err(ty::terr_no_integral_type);
}
self.set(vb, b_id, root(intersection, nde_b.rank));
uok()
}
}
// ______________________________________________________________________
// Floating point variables
impl infer_ctxt {
fn float_vars(a_id: ty::FloatVid, b_id: ty::FloatVid) -> ures {
let vb = &self.float_var_bindings;
let nde_a = self.get(vb, a_id);
let nde_b = self.get(vb, b_id);
let a_id = nde_a.root;
let b_id = nde_b.root;
let a_pt = nde_a.possible_types;
let b_pt = nde_b.possible_types;
// If we're already dealing with the same two variables,
// there's nothing to do.
if a_id == b_id { return uok(); }
// Otherwise, take the intersection of the two sets of
// possible types.
let intersection = floating::intersection(a_pt, b_pt);
if *intersection == FLOAT_TY_SET_EMPTY {
return Err(ty::terr_no_floating_point_type);
}
// Rank optimization
self.optimize_ranks(vb, nde_a, nde_b, a_id, b_id, intersection);
uok()
}
fn float_var_sub_t(a_id: ty::FloatVid, b: ty::t) -> ures {
assert ty::type_is_fp(b);
let vb = &self.float_var_bindings;
let nde_a = self.get(vb, a_id);
let a_id = nde_a.root;
let a_pt = nde_a.possible_types;
let intersection =
floating::intersection(
a_pt,
convert_floating_point_ty_to_float_ty_set(self.tcx, b));
if *intersection == FLOAT_TY_SET_EMPTY {
return Err(ty::terr_no_floating_point_type);
}
self.set(vb, a_id, root(intersection, nde_a.rank));
uok()
}
fn t_sub_float_var(a: ty::t, b_id: ty::FloatVid) -> ures {
assert ty::type_is_fp(a);
let vb = &self.float_var_bindings;
let nde_b = self.get(vb, b_id);
let b_id = nde_b.root;
let b_pt = nde_b.possible_types;
let intersection =
floating::intersection(
b_pt,
convert_floating_point_ty_to_float_ty_set(self.tcx, a));
if *intersection == FLOAT_TY_SET_EMPTY {
return Err(ty::terr_no_floating_point_type);
}
self.set(vb, b_id, root(intersection, nde_b.rank));
uok()
return Err(err);
}
}

View File

@ -271,7 +271,7 @@ fn no_params(t: ty::t) -> ty::ty_param_bounds_and_ty {
fn require_same_types(
tcx: ty::ctxt,
maybe_infcx: Option<infer::infer_ctxt>,
maybe_infcx: Option<@infer::InferCtxt>,
t1_is_expected: bool,
span: span,
t1: ty::t,

View File

@ -69,8 +69,9 @@ fn loop_query(b: ast::blk, p: fn@(ast::expr_) -> bool) -> bool {
_ => visit::visit_expr(e, flag, v)
}
};
let v = visit::mk_vt(@{visit_expr: visit_expr
,.. *visit::default_visitor()});
let v = visit::mk_vt(@visit::Visitor {
visit_expr: visit_expr,
.. *visit::default_visitor()});
visit::visit_block(b, rs, v);
return *rs;
}
@ -84,8 +85,9 @@ fn block_query(b: ast::blk, p: fn@(@ast::expr) -> bool) -> bool {
*flag |= p(e);
visit::visit_expr(e, flag, v)
};
let v = visit::mk_vt(@{visit_expr: visit_expr
,.. *visit::default_visitor()});
let v = visit::mk_vt(@visit::Visitor{
visit_expr: visit_expr,
.. *visit::default_visitor()});
visit::visit_block(b, rs, v);
return *rs;
}

View File

@ -25,14 +25,12 @@ use middle::ty::{ty_err, ty_estr, ty_evec, ty_float, ty_fn, ty_trait, ty_int};
use middle::ty::{ty_nil, ty_opaque_box, ty_opaque_closure_ptr, ty_param};
use middle::ty::{ty_ptr, ty_rec, ty_rptr, ty_self, ty_tup};
use middle::ty::{ty_type, ty_uniq, ty_uint, ty_infer};
use middle::ty::{ty_unboxed_vec, vid};
use middle::ty::{ty_unboxed_vec};
use metadata::encoder;
use syntax::codemap;
use syntax::codemap::span;
use syntax::print::pprust;
use syntax::print::pprust::{path_to_str, proto_to_str,
mode_to_str, purity_to_str,
onceness_to_str};
use syntax::print::pprust::{path_to_str, proto_to_str, mode_to_str};
use syntax::{ast, ast_util};
use syntax::ast_map;
@ -248,9 +246,11 @@ fn vstore_ty_to_str(cx: ctxt, ty: ~str, vs: ty::vstore) -> ~str {
}
}
fn proto_ty_to_str(_cx: ctxt, proto: ast::Proto) -> &static/str {
fn proto_ty_to_str(_cx: ctxt, proto: ast::Proto,
followed_by_word: bool) -> &static/str {
match proto {
ast::ProtoBare => "",
ast::ProtoBare if followed_by_word => "extern ",
ast::ProtoBare => "extern",
ast::ProtoBox => "@",
ast::ProtoBorrowed => "&",
ast::ProtoUniq => "~",
@ -265,13 +265,19 @@ fn expr_repr(cx: ctxt, expr: @ast::expr) -> ~str {
fn tys_to_str(cx: ctxt, ts: &[t]) -> ~str {
let tstrs = ts.map(|t| ty_to_str(cx, *t));
fmt!("[%s]", str::connect(tstrs, ", "))
fmt!("(%s)", str::connect(tstrs, ", "))
}
fn bound_to_str(cx: ctxt, b: param_bound) -> ~str {
ty::param_bound_to_str(cx, &b)
}
fn fn_sig_to_str(cx: ctxt, typ: &ty::FnSig) -> ~str {
fmt!("fn%s -> %s",
tys_to_str(cx, typ.inputs.map(|a| a.ty)),
ty_to_str(cx, typ.output))
}
fn ty_to_str(cx: ctxt, typ: t) -> ~str {
fn fn_input_to_str(cx: ctxt, input: {mode: ast::mode, ty: t}) ->
~str {
@ -301,15 +307,15 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str {
s = match purity {
ast::impure_fn => ~"",
_ => purity_to_str(purity) + ~" "
_ => purity.to_str() + ~" "
};
s += match onceness {
ast::Many => ~"",
ast::Once => onceness_to_str(onceness) + ~" "
ast::Once => onceness.to_str() + ~" "
};
s += proto_ty_to_str(cx, proto);
s += proto_ty_to_str(cx, proto, true);
match (proto, region) {
(ast::ProtoBox, ty::re_static) |

View File

@ -35,7 +35,7 @@ use std::map::HashMap;
use std::par;
pub fn mk_pass() -> Pass {
{
Pass {
name: ~"attr",
f: run
}

View File

@ -29,7 +29,7 @@ use core::vec;
use std::par;
pub fn mk_pass() -> Pass {
{
Pass {
name: ~"desc_to_brief",
f: run
}

View File

@ -26,7 +26,7 @@ use core::str;
use std::par;
pub fn mk_pass(+config: config::Config) -> Pass {
{
Pass {
name: ~"markdown_index",
f: fn~(srv: astsrv::Srv, +doc: doc::Doc) -> doc::Doc {
run(srv, doc, config)

View File

@ -47,7 +47,7 @@ pub fn mk_pass(+writer_factory: WriterFactory) -> Pass {
run(srv, doc, copy writer_factory)
};
{
Pass {
name: ~"markdown",
f: move f
}

View File

@ -34,7 +34,7 @@ use core::vec;
use syntax::ast;
pub fn mk_pass(output_style: config::OutputStyle) -> Pass {
{
Pass {
name: ~"page",
f: fn~(srv: astsrv::Srv, +doc: doc::Doc) -> doc::Doc {
run(srv, doc, output_style)

View File

@ -18,10 +18,10 @@ use time;
use core::vec;
/// A single operation on the document model
pub type Pass = {
pub struct Pass {
name: ~str,
f: fn~(srv: astsrv::Srv, +doc: doc::Doc) -> doc::Doc
};
}
pub fn run_passes(
srv: astsrv::Srv,
@ -82,11 +82,11 @@ fn test_run_passes() {
let source = ~"";
do astsrv::from_str(source) |srv| {
let passes = ~[
{
Pass {
name: ~"",
f: pass1
},
{
Pass {
name: ~"",
f: pass2
}

View File

@ -23,7 +23,7 @@ use pass::Pass;
use syntax::ast;
pub fn mk_pass() -> Pass {
{
Pass {
name: ~"path",
f: run
}

View File

@ -22,7 +22,7 @@ use core::vec;
use std::map::HashMap;
pub fn mk_pass() -> Pass {
{
Pass {
name: ~"prune_hidden",
f: run
}

View File

@ -28,7 +28,7 @@ export mk_pass;
export run;
fn mk_pass() -> Pass {
{
Pass {
name: ~"prune_private",
f: run
}

View File

@ -26,7 +26,7 @@ use core::vec;
use std::par;
pub fn mk_pass() -> Pass {
{
Pass {
name: ~"sectionalize",
f: run
}

View File

@ -28,7 +28,7 @@ pub type ItemLtEqOp = pure fn~(v1: &doc::ItemTag, v2: &doc::ItemTag) -> bool;
type ItemLtEq = NominalOp<ItemLtEqOp>;
pub fn mk_pass(name: ~str, +lteq: ItemLtEqOp) -> Pass {
{
Pass {
name: name,
f: fn~(move lteq, srv: astsrv::Srv, +doc: doc::Doc) -> doc::Doc {
run(srv, doc, NominalOp { op: copy lteq })

View File

@ -23,7 +23,7 @@ use util::NominalOp;
use std::par;
pub fn mk_pass(name: ~str, +op: fn~(~str) -> ~str) -> Pass {
{
Pass {
name: name,
f: fn~(move op, srv: astsrv::Srv, +doc: doc::Doc) -> doc::Doc {
run(srv, doc, copy op)

View File

@ -29,7 +29,7 @@ use syntax::print::pprust;
use syntax::ast_map;
pub fn mk_pass() -> Pass {
{
Pass {
name: ~"tystr",
f: run
}

View File

@ -56,12 +56,12 @@ pub type TestFn = fn~();
// The definition of a single test. A test runner will run a list of
// these.
pub type TestDesc = {
pub struct TestDesc {
name: TestName,
testfn: TestFn,
ignore: bool,
should_fail: bool
};
}
// The default console test runner. It accepts the command line
// arguments and a vector of test_descs (generated at compile time).
@ -242,14 +242,14 @@ fn print_failures(st: ConsoleTestState) {
#[test]
fn should_sort_failures_before_printing_them() {
let s = do io::with_str_writer |wr| {
let test_a = {
let test_a = TestDesc {
name: ~"a",
testfn: fn~() { },
ignore: false,
should_fail: false
};
let test_b = {
let test_b = TestDesc {
name: ~"b",
testfn: fn~() { },
ignore: false,
@ -372,7 +372,8 @@ pub fn filter_tests(opts: &TestOpts,
} else {
fn filter(test: &TestDesc) -> Option<TestDesc> {
if test.ignore {
return option::Some({name: test.name,
return option::Some(TestDesc {
name: test.name,
testfn: copy test.testfn,
ignore: false,
should_fail: test.should_fail});
@ -427,7 +428,8 @@ fn calc_result(test: &TestDesc, task_succeeded: bool) -> TestResult {
mod tests {
#[legacy_exports];
use test::{TrFailed, TrIgnored, TrOk, filter_tests, parse_opts, run_test};
use test::{TrFailed, TrIgnored, TrOk, filter_tests, parse_opts, TestDesc};
use test::{run_test};
use core::either;
use core::oldcomm;
@ -437,7 +439,7 @@ mod tests {
#[test]
fn do_not_run_ignored_tests() {
fn f() { fail; }
let desc = {
let desc = TestDesc {
name: ~"whatever",
testfn: f,
ignore: true,
@ -453,7 +455,7 @@ mod tests {
#[test]
fn ignored_tests_result_in_ignored() {
fn f() { }
let desc = {
let desc = TestDesc {
name: ~"whatever",
testfn: f,
ignore: true,
@ -470,7 +472,7 @@ mod tests {
#[ignore(cfg(windows))]
fn test_should_fail() {
fn f() { fail; }
let desc = {
let desc = TestDesc {
name: ~"whatever",
testfn: f,
ignore: false,
@ -486,7 +488,7 @@ mod tests {
#[test]
fn test_should_fail_but_succeeds() {
fn f() { }
let desc = {
let desc = TestDesc {
name: ~"whatever",
testfn: f,
ignore: false,
@ -527,9 +529,9 @@ mod tests {
let opts = {filter: option::None, run_ignored: true,
logfile: option::None};
let tests =
~[{name: ~"1", testfn: fn~() { },
~[TestDesc {name: ~"1", testfn: fn~() { },
ignore: true, should_fail: false},
{name: ~"2", testfn: fn~() { },
TestDesc {name: ~"2", testfn: fn~() { },
ignore: false, should_fail: false}];
let filtered = filter_tests(&opts, tests);
@ -555,7 +557,8 @@ mod tests {
let testfn = fn~() { };
let mut tests = ~[];
for vec::each(names) |name| {
let test = {name: *name, testfn: copy testfn, ignore: false,
let test = TestDesc {
name: *name, testfn: copy testfn, ignore: false,
should_fail: false};
tests.push(move test);
}

View File

@ -19,6 +19,7 @@ use core::option::{None, Option, Some};
use core::ptr;
use core::task;
use core::to_bytes;
use core::to_str::ToStr;
use std::serialize::{Encodable, Decodable, Encoder, Decoder};
#[auto_encode]
@ -415,6 +416,7 @@ impl mutability : cmp::Eq {
#[auto_encode]
#[auto_decode]
#[deriving_eq]
pub enum Proto {
ProtoBare, // bare functions (deprecated)
ProtoUniq, // ~fn
@ -422,13 +424,6 @@ pub enum Proto {
ProtoBorrowed, // &fn
}
impl Proto : cmp::Eq {
pure fn eq(&self, other: &Proto) -> bool {
((*self) as uint) == ((*other) as uint)
}
pure fn ne(&self, other: &Proto) -> bool { !(*self).eq(other) }
}
impl Proto : to_bytes::IterBytes {
pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
(*self as uint).iter_bytes(lsb0, f);
@ -1068,20 +1063,24 @@ enum region_ {
#[auto_encode]
#[auto_decode]
#[deriving_eq]
enum Onceness {
Once,
Many
}
impl Onceness : cmp::Eq {
pure fn eq(&self, other: &Onceness) -> bool {
match ((*self), *other) {
(Once, Once) | (Many, Many) => true,
_ => false
impl Onceness : ToStr {
pure fn to_str() -> ~str {
match self {
ast::Once => ~"once",
ast::Many => ~"many"
}
}
pure fn ne(&self, other: &Onceness) -> bool {
!(*self).eq(other)
}
impl Onceness : to_bytes::IterBytes {
pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
(*self as uint).iter_bytes(lsb0, f);
}
}
@ -1156,6 +1155,17 @@ pub enum purity {
extern_fn, // declared with "extern fn"
}
impl purity : ToStr {
pure fn to_str() -> ~str {
match self {
impure_fn => ~"impure",
unsafe_fn => ~"unsafe",
pure_fn => ~"pure",
extern_fn => ~"extern"
}
}
}
impl purity : to_bytes::IterBytes {
pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
(*self as u8).iter_bytes(lsb0, f)

View File

@ -110,7 +110,7 @@ fn extend(cx: ctx, +elt: ident) -> @path {
}
fn mk_ast_map_visitor() -> vt {
return visit::mk_vt(@{
return visit::mk_vt(@visit::Visitor {
visit_item: map_item,
visit_expr: map_expr,
visit_stmt: map_stmt,

View File

@ -440,10 +440,8 @@ fn empty(range: id_range) -> bool {
}
fn id_visitor(vfn: fn@(node_id)) -> visit::vt<()> {
visit::mk_simple_visitor(@{
visit_mod: fn@(_m: _mod, _sp: span, id: node_id) {
vfn(id)
},
visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_mod: |_m, _sp, id| vfn(id),
visit_view_item: fn@(vi: @view_item) {
match vi.node {

View File

@ -322,8 +322,8 @@ fn expand_crate(parse_sess: parse::parse_sess,
let exts = syntax_expander_table();
let afp = default_ast_fold();
let cx: ext_ctxt = mk_ctxt(parse_sess, cfg);
let f_pre =
@{fold_expr: |a,b,c| expand_expr(exts, cx, a, b, c, afp.fold_expr),
let f_pre = @AstFoldFns {
fold_expr: |a,b,c| expand_expr(exts, cx, a, b, c, afp.fold_expr),
fold_mod: |a,b| expand_mod_items(exts, cx, a, b, afp.fold_mod),
fold_item: |a,b| expand_item(exts, cx, a, b, afp.fold_item),
fold_stmt: |a,b,c| expand_stmt(exts, cx, a, b, c, afp.fold_stmt),

View File

@ -17,7 +17,7 @@ use codemap::span;
use core::option;
use core::vec;
export ast_fold_precursor;
export ast_fold_fns;
export ast_fold;
export default_ast_fold;
export make_fold;
@ -34,6 +34,7 @@ export fold_ty_param;
export fold_ty_params;
export fold_fn_decl;
export extensions;
export AstFoldFns;
trait ast_fold {
fn fold_crate(crate) -> crate;
@ -63,7 +64,7 @@ trait ast_fold {
// We may eventually want to be able to fold over type parameters, too
type ast_fold_precursor = @{
struct AstFoldFns {
//unlike the others, item_ is non-trivial
fold_crate: fn@(crate_, span, ast_fold) -> (crate_, span),
fold_view_item: fn@(view_item_, ast_fold) -> view_item_,
@ -87,7 +88,10 @@ type ast_fold_precursor = @{
fold_local: fn@(local_, span, ast_fold) -> (local_, span),
map_exprs: fn@(fn@(&&v: @expr) -> @expr, ~[@expr]) -> ~[@expr],
new_id: fn@(node_id) -> node_id,
new_span: fn@(span) -> span};
new_span: fn@(span) -> span
}
type ast_fold_fns = @AstFoldFns;
/* some little folds that probably aren't useful to have in ast_fold itself*/
@ -631,8 +635,8 @@ fn noop_id(i: node_id) -> node_id { return i; }
fn noop_span(sp: span) -> span { return sp; }
fn default_ast_fold() -> ast_fold_precursor {
return @{fold_crate: wrap(noop_fold_crate),
fn default_ast_fold() -> ast_fold_fns {
return @AstFoldFns {fold_crate: wrap(noop_fold_crate),
fold_view_item: noop_fold_view_item,
fold_foreign_item: noop_fold_foreign_item,
fold_item: noop_fold_item,
@ -657,7 +661,7 @@ fn default_ast_fold() -> ast_fold_precursor {
new_span: noop_span};
}
impl ast_fold_precursor: ast_fold {
impl ast_fold_fns: ast_fold {
/* naturally, a macro to write these would be nice */
fn fold_crate(c: crate) -> crate {
let (n, s) = (self.fold_crate)(c.node, c.span, self as ast_fold);
@ -763,7 +767,7 @@ impl ast_fold {
}
}
fn make_fold(afp: ast_fold_precursor) -> ast_fold {
fn make_fold(afp: ast_fold_fns) -> ast_fold {
afp as ast_fold
}

View File

@ -44,11 +44,14 @@ enum ann_node {
node_expr(ps, @ast::expr),
node_pat(ps, @ast::pat),
}
type pp_ann = {pre: fn@(ann_node), post: fn@(ann_node)};
struct pp_ann {
pre: fn@(ann_node),
post: fn@(ann_node)
}
fn no_ann() -> pp_ann {
fn ignore(_node: ann_node) { }
return {pre: ignore, post: ignore};
return pp_ann {pre: ignore, post: ignore};
}
type ps =

View File

@ -59,8 +59,8 @@ fn tps_of_fn(fk: fn_kind) -> ~[ty_param] {
}
}
type visitor<E> =
@{visit_mod: fn@(_mod, span, node_id, E, vt<E>),
struct Visitor<E> {
visit_mod: fn@(_mod, span, node_id, E, vt<E>),
visit_view_item: fn@(@view_item, E, vt<E>),
visit_foreign_item: fn@(@foreign_item, E, vt<E>),
visit_item: fn@(@item, E, vt<E>),
@ -80,10 +80,14 @@ type visitor<E> =
visit_struct_def: fn@(@struct_def, ident, ~[ty_param], node_id, E,
vt<E>),
visit_struct_field: fn@(@struct_field, E, vt<E>),
visit_struct_method: fn@(@method, E, vt<E>)};
visit_struct_method: fn@(@method, E, vt<E>)
}
type visitor<E> = @Visitor<E>;
fn default_visitor<E>() -> visitor<E> {
return @{visit_mod: |a,b,c,d,e|visit_mod::<E>(a, b, c, d, e),
return @Visitor {
visit_mod: |a,b,c,d,e|visit_mod::<E>(a, b, c, d, e),
visit_view_item: |a,b,c|visit_view_item::<E>(a, b, c),
visit_foreign_item: |a,b,c|visit_foreign_item::<E>(a, b, c),
visit_item: |a,b,c|visit_item::<E>(a, b, c),
@ -103,7 +107,8 @@ fn default_visitor<E>() -> visitor<E> {
visit_struct_def: |a,b,c,d,e,f|visit_struct_def::<E>(a, b, c,
d, e, f),
visit_struct_field: |a,b,c|visit_struct_field::<E>(a, b, c),
visit_struct_method: |a,b,c|visit_struct_method::<E>(a, b, c)};
visit_struct_method: |a,b,c|visit_struct_method::<E>(a, b, c)
};
}
fn visit_crate<E>(c: crate, e: E, v: vt<E>) {
@ -499,8 +504,8 @@ fn visit_arm<E>(a: arm, e: E, v: vt<E>) {
// Simpler, non-context passing interface. Always walks the whole tree, simply
// calls the given functions on the nodes.
type simple_visitor =
@{visit_mod: fn@(_mod, span, node_id),
struct SimpleVisitor {
visit_mod: fn@(_mod, span, node_id),
visit_view_item: fn@(@view_item),
visit_foreign_item: fn@(@foreign_item),
visit_item: fn@(@item),
@ -519,23 +524,26 @@ type simple_visitor =
visit_trait_method: fn@(trait_method),
visit_struct_def: fn@(@struct_def, ident, ~[ty_param], node_id),
visit_struct_field: fn@(@struct_field),
visit_struct_method: fn@(@method)};
visit_struct_method: fn@(@method)
}
type simple_visitor = @SimpleVisitor;
fn simple_ignore_ty(_t: @Ty) {}
fn default_simple_visitor() -> simple_visitor {
return @{visit_mod: fn@(_m: _mod, _sp: span, _id: node_id) { },
visit_view_item: fn@(_vi: @view_item) { },
visit_foreign_item: fn@(_ni: @foreign_item) { },
visit_item: fn@(_i: @item) { },
visit_local: fn@(_l: @local) { },
visit_block: fn@(_b: ast::blk) { },
visit_stmt: fn@(_s: @stmt) { },
visit_arm: fn@(_a: arm) { },
visit_pat: fn@(_p: @pat) { },
visit_decl: fn@(_d: @decl) { },
visit_expr: fn@(_e: @expr) { },
visit_expr_post: fn@(_e: @expr) { },
fn default_simple_visitor() -> @SimpleVisitor {
return @SimpleVisitor {visit_mod: |_m: _mod, _sp: span, _id: node_id| { },
visit_view_item: |_vi: @view_item| { },
visit_foreign_item: |_ni: @foreign_item| { },
visit_item: |_i: @item| { },
visit_local: |_l: @local| { },
visit_block: |_b: ast::blk| { },
visit_stmt: |_s: @stmt| { },
visit_arm: |_a: arm| { },
visit_pat: |_p: @pat| { },
visit_decl: |_d: @decl| { },
visit_expr: |_e: @expr| { },
visit_expr_post: |_e: @expr| { },
visit_ty: simple_ignore_ty,
visit_ty_params: fn@(_ps: ~[ty_param]) {},
visit_fn: fn@(_fk: fn_kind, _d: fn_decl, _b: blk, _sp: span,
@ -640,9 +648,9 @@ fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
f(m);
visit_struct_method(m, e, v);
}
return mk_vt(@{visit_mod: |a,b,c,d,e|v_mod(v.visit_mod, a, b, c, d, e),
visit_view_item: |a,b,c|
v_view_item(v.visit_view_item, a, b, c),
return mk_vt(@Visitor {
visit_mod: |a,b,c,d,e|v_mod(v.visit_mod, a, b, c, d, e),
visit_view_item: |a,b,c| v_view_item(v.visit_view_item, a, b, c),
visit_foreign_item:
|a,b,c|v_foreign_item(v.visit_foreign_item, a, b, c),
visit_item: |a,b,c|v_item(v.visit_item, a, b, c),

View File

@ -14,7 +14,7 @@
use dvec::DVec;
type entry<A,B> = {key: A, value: B};
type alist<A,B> = { eq_fn: fn@(A,A) -> bool, data: DVec<entry<A,B>> };
struct alist<A,B> { eq_fn: fn@(A,A) -> bool, data: DVec<entry<A,B>> }
fn alist_add<A: Copy, B: Copy>(lst: alist<A,B>, k: A, v: B) {
lst.data.push({key:k, value:v});
@ -31,12 +31,12 @@ fn alist_get<A: Copy, B: Copy>(lst: alist<A,B>, k: A) -> B {
#[inline]
fn new_int_alist<B: Copy>() -> alist<int, B> {
fn eq_int(&&a: int, &&b: int) -> bool { a == b }
return {eq_fn: eq_int, data: DVec()};
return alist {eq_fn: eq_int, data: DVec()};
}
#[inline]
fn new_int_alist_2<B: Copy>() -> alist<int, B> {
#[inline]
fn eq_int(&&a: int, &&b: int) -> bool { a == b }
return {eq_fn: eq_int, data: DVec()};
return alist {eq_fn: eq_int, data: DVec()};
}

View File

@ -19,5 +19,5 @@ fn main() {
}
f(g);
//~^ ERROR mismatched types: expected `fn(fn(fn()))`
//~^ ERROR mismatched types: expected `extern fn(extern fn(extern fn()))`
}

View File

@ -9,9 +9,9 @@
// except according to those terms.
use core::either::*;
enum X = Either<(uint,uint),fn()>;
enum X = Either<(uint,uint),extern fn()>;
impl &X {
fn with(blk: fn(x: &Either<(uint,uint),fn()>)) {
fn with(blk: fn(x: &Either<(uint,uint),extern fn()>)) {
blk(&**self)
}
}

View File

@ -9,5 +9,5 @@
// except according to those terms.
fn main() -> char {
//~^ ERROR Wrong type in main function: found `fn() -> char`
//~^ ERROR Wrong type in main function: found `extern fn() -> char`
}

View File

@ -9,5 +9,5 @@
// except according to those terms.
fn main(foo: {x: int, y: int}) {
//~^ ERROR Wrong type in main function: found `fn({x: int,y: int})`
//~^ ERROR Wrong type in main function: found `extern fn({x: int,y: int})`
}

View File

@ -14,6 +14,6 @@ fn foo(f: fn()) { f() }
fn main() {
~"" || 42; //~ ERROR binary operation || cannot be applied to type `~str`
foo || {}; //~ ERROR binary operation || cannot be applied to type `fn(&fn())`
foo || {}; //~ ERROR binary operation || cannot be applied to type `extern fn(&fn())`
//~^ NOTE did you forget the 'do' keyword for the call?
}

View File

@ -8,11 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
type r = {
struct r {
field: fn@()
};
}
fn main() {
fn f() {}
let i: r = {field: f};
let i: r = r {field: f};
}

View File

@ -13,7 +13,7 @@
#[abi = "rust-intrinsic"]
extern mod rusti {
#[legacy_exports];
fn frame_address(f: fn(*u8));
fn frame_address(f: &once fn(*u8));
}
fn main() {

View File

@ -12,7 +12,7 @@ fn plus_one(f: fn() -> int) -> int {
return f() + 1;
}
fn ret_plus_one() -> fn(fn() -> int) -> int {
fn ret_plus_one() -> extern fn(fn() -> int) -> int {
return plus_one;
}