mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-28 01:34:21 +00:00
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:
parent
11a307294a
commit
2b92962aa2
@ -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),
|
||||
|
@ -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()
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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| {
|
||||
|
@ -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"),
|
||||
|
@ -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(),
|
||||
|
@ -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());
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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),
|
||||
|
@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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};
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
},
|
||||
|
@ -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 \
|
||||
|
@ -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()
|
||||
});
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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|
|
||||
|
@ -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,
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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|
|
||||
|
@ -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()
|
||||
}));
|
||||
|
@ -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 {
|
||||
|
@ -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(*) => {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>) {},
|
||||
|
@ -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};
|
||||
|
@ -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_) => {
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -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(_), _) |
|
||||
|
@ -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()")
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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()")
|
||||
}
|
||||
}
|
@ -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() {
|
||||
|
@ -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> {
|
||||
|
@ -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}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) |
|
||||
|
@ -35,7 +35,7 @@ use std::map::HashMap;
|
||||
use std::par;
|
||||
|
||||
pub fn mk_pass() -> Pass {
|
||||
{
|
||||
Pass {
|
||||
name: ~"attr",
|
||||
f: run
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ use core::vec;
|
||||
use std::par;
|
||||
|
||||
pub fn mk_pass() -> Pass {
|
||||
{
|
||||
Pass {
|
||||
name: ~"desc_to_brief",
|
||||
f: run
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -47,7 +47,7 @@ pub fn mk_pass(+writer_factory: WriterFactory) -> Pass {
|
||||
run(srv, doc, copy writer_factory)
|
||||
};
|
||||
|
||||
{
|
||||
Pass {
|
||||
name: ~"markdown",
|
||||
f: move f
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ use pass::Pass;
|
||||
use syntax::ast;
|
||||
|
||||
pub fn mk_pass() -> Pass {
|
||||
{
|
||||
Pass {
|
||||
name: ~"path",
|
||||
f: run
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ use core::vec;
|
||||
use std::map::HashMap;
|
||||
|
||||
pub fn mk_pass() -> Pass {
|
||||
{
|
||||
Pass {
|
||||
name: ~"prune_hidden",
|
||||
f: run
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ export mk_pass;
|
||||
export run;
|
||||
|
||||
fn mk_pass() -> Pass {
|
||||
{
|
||||
Pass {
|
||||
name: ~"prune_private",
|
||||
f: run
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ use core::vec;
|
||||
use std::par;
|
||||
|
||||
pub fn mk_pass() -> Pass {
|
||||
{
|
||||
Pass {
|
||||
name: ~"sectionalize",
|
||||
f: run
|
||||
}
|
||||
|
@ -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 })
|
||||
|
@ -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)
|
||||
|
@ -29,7 +29,7 @@ use syntax::print::pprust;
|
||||
use syntax::ast_map;
|
||||
|
||||
pub fn mk_pass() -> Pass {
|
||||
{
|
||||
Pass {
|
||||
name: ~"tystr",
|
||||
f: run
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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 =
|
||||
|
@ -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),
|
||||
|
@ -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()};
|
||||
}
|
||||
|
@ -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()))`
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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`
|
||||
}
|
||||
|
@ -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})`
|
||||
}
|
||||
|
@ -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?
|
||||
}
|
||||
|
@ -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};
|
||||
}
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user