diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2012-04-30 10:37:58 -0700 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2012-04-30 19:53:02 -0700 |
| commit | 2db4259b3531e0cfa1f6df2ff95e30a4c871a105 (patch) | |
| tree | 192b8d969e34bd1390bd769e17d68b2e9c57e77e /src/rustc | |
| parent | 079c3b02a86aa73d0d070876612ed889dc187354 (diff) | |
| download | rust-2db4259b3531e0cfa1f6df2ff95e30a4c871a105.tar.gz rust-2db4259b3531e0cfa1f6df2ff95e30a4c871a105.zip | |
Stop inferring bot/static when types/regions are unconstrained.
Also, some other changes that came up along the way: - add a 'blk' region for the current block. - detect unused type/region variables.
Diffstat (limited to 'src/rustc')
| -rw-r--r-- | src/rustc/metadata/creader.rs | 8 | ||||
| -rw-r--r-- | src/rustc/middle/infer.rs | 23 | ||||
| -rw-r--r-- | src/rustc/middle/kind.rs | 2 | ||||
| -rw-r--r-- | src/rustc/middle/ty.rs | 26 | ||||
| -rw-r--r-- | src/rustc/middle/typeck.rs | 139 |
5 files changed, 150 insertions, 48 deletions
diff --git a/src/rustc/metadata/creader.rs b/src/rustc/metadata/creader.rs index 1f4bc2cdcf7..bae50d13d17 100644 --- a/src/rustc/metadata/creader.rs +++ b/src/rustc/metadata/creader.rs @@ -251,23 +251,23 @@ fn find_library_crate_aux(sess: session::session, if !(str::starts_with(f, prefix) && str::ends_with(f, suffix)) { #debug("skipping %s, doesn't look like %s*%s", path, prefix, suffix); - option::none + option::none::<()> } else { #debug("%s is a candidate", path); alt get_metadata_section(sess, path) { option::some(cvec) { if !crate_matches(cvec, metas, hash) { #debug("skipping %s, metadata doesn't match", path); - option::none + option::none::<()> } else { #debug("found %s with matching metadata", path); matches += [{ident: path, data: cvec}]; - option::none + option::none::<()> } } _ { #debug("could not load metadata for %s", path); - option::none + option::none::<()> } } } diff --git a/src/rustc/middle/infer.rs b/src/rustc/middle/infer.rs index d5e22815b7b..0477f6469cc 100644 --- a/src/rustc/middle/infer.rs +++ b/src/rustc/middle/infer.rs @@ -579,11 +579,8 @@ impl unify_methods for infer_ctxt { // [B]. Deep resolution, on the other hand, would yield [int]. // // But there is one more knob: the force_vars variable controls the -// behavior in the face of unconstrained variables. If we have A, B -// and only the constraint that A <: B, then the result is [_|_] if -// force_vars is true and [B] otherwise. We use force_vars == true -// when resolving types after typeck, but false otherwise (for -// example, when pretty-printing them for errors). +// behavior in the face of unconstrained variables. If it is true, +// then unconstrained variables result in an error. type resolve_state = @{ infcx: infer_ctxt, @@ -673,8 +670,12 @@ impl methods for resolve_state { let r1 = alt bounds { { ub:_, lb:some(t) } { self.resolve_region(t) } { ub:some(t), lb:_ } { self.resolve_region(t) } - { ub:none, lb:none } if self.force_vars { ty::re_static } - { ub:none, lb:none } { ty::re_var(rid) } + { ub:none, lb:none } { + if self.force_vars { + self.err = some(unresolved_region(rid)); + } + ty::re_var(rid) + } }; vec::pop(self.r_seen); ret r1; @@ -700,8 +701,12 @@ impl methods for resolve_state { { ub:_, lb:some(t) } if !type_is_bot(t) { self.resolve1(t) } { ub:some(t), lb:_ } { self.resolve1(t) } { ub:_, lb:some(t) } { self.resolve1(t) } - { ub:none, lb:none } if self.force_vars { ty::mk_bot(tcx) } - { ub:none, lb:none } { ty::mk_var(tcx, vid) } + { ub:none, lb:none } { + if self.force_vars { + self.err = some(unresolved_ty(vid)); + } + ty::mk_var(tcx, vid) + } }; vec::pop(self.v_seen); ret t1; diff --git a/src/rustc/middle/kind.rs b/src/rustc/middle/kind.rs index 0b29b0c52cd..dee278e7ed0 100644 --- a/src/rustc/middle/kind.rs +++ b/src/rustc/middle/kind.rs @@ -4,6 +4,7 @@ import syntax::codemap::span; import ty::{kind, kind_copyable, kind_sendable, kind_noncopyable}; import driver::session::session; import std::map::hashmap; +import syntax::print::pprust::expr_to_str; // Kind analysis pass. There are three kinds: // @@ -138,6 +139,7 @@ fn check_block(b: blk, cx: ctx, v: visit::vt<ctx>) { } fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) { + #debug["kind::check_expr(%s)", expr_to_str(e)]; alt e.node { expr_assign(_, ex) | expr_assign_op(_, _, ex) | expr_unary(box(_), ex) | expr_unary(uniq(_), ex) | diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 9830fe9c36b..cf8f223afd9 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -37,7 +37,7 @@ export expr_ty_params_and_ty; export expr_is_lval; export field_ty; export fold_ty, fold_sty_to_ty, fold_region, fold_regions, fold_ty_var; -export fold_regions_and_ty; +export fold_regions_and_ty, walk_regions_and_ty; export field; export field_idx; export get_field; @@ -97,7 +97,7 @@ 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_var, mk_var; +export ty_var, mk_var, type_is_var; export ty_self, mk_self; export region, bound_region; export get, type_has_params, type_has_vars, type_has_regions; @@ -818,6 +818,21 @@ fn fold_ty_var(cx: ctxt, t0: t, fldop: fn(ty_vid) -> t) -> t { } } +fn walk_regions_and_ty( + cx: ctxt, + ty: t, + walkr: fn(r: region), + walkt: fn(t: t) -> bool) { + + if (walkt(ty)) { + fold_regions_and_ty( + cx, ty, + { |r| walkr(r); r }, + { |t| walkt(t); walk_regions_and_ty(cx, t, walkr, walkt); t }, + { |t| walkt(t); walk_regions_and_ty(cx, t, walkr, walkt); t }); + } +} + fn fold_regions_and_ty( cx: ctxt, ty: t, @@ -1000,6 +1015,13 @@ fn type_is_nil(ty: t) -> bool { get(ty).struct == ty_nil } fn type_is_bot(ty: t) -> bool { get(ty).struct == ty_bot } +fn type_is_var(ty: t) -> bool { + alt get(ty).struct { + ty_var(_) { true } + _ { false } + } +} + fn type_is_bool(ty: t) -> bool { get(ty).struct == ty_bool } fn type_is_structural(ty: t) -> bool { diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index d8c275bfd04..931d3d9e790 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -105,6 +105,7 @@ type fn_ctxt = ty_var_counter: @mut uint, region_var_counter: @mut uint, + mut blocks: [ast::node_id], // stack of blocks in scope, may be empty in_scope_regions: isr_alist, // While type checking a function, the intermediate types for the @@ -276,10 +277,8 @@ fn instantiate_path(fcx: @fn_ctxt, // Type tests fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t { - alt infer::resolve_shallow(fcx.infcx, tp, true) { - // note: the bot type doesn't count as resolved; it's what we use when - // there is no information about a variable. - result::ok(t_s) if !ty::type_is_bot(t_s) { ret t_s; } + alt infer::resolve_shallow(fcx.infcx, tp, false) { + result::ok(t_s) if !ty::type_is_var(t_s) { ret t_s; } _ { fcx.ccx.tcx.sess.span_fatal (sp, "the type of this value must be known in this context"); @@ -322,7 +321,16 @@ fn ast_expr_vstore_to_vstore(fcx: @fn_ctxt, e: @ast::expr, n: uint, ast::vstore_uniq { ty::vstore_uniq } ast::vstore_box { ty::vstore_box } ast::vstore_slice(r) { - ty::vstore_slice(ast_region_to_region(fcx, fcx, e.span, r)) + alt fcx.block_region() { + result::ok(b_r) { + let rscope = in_anon_rscope(fcx, b_r); + ty::vstore_slice(ast_region_to_region(fcx, rscope, e.span, r)) + } + result::err(msg) { + fcx.ccx.tcx.sess.span_err(e.span, msg); + ty::vstore_slice(ty::re_static) + } + } } } } @@ -386,8 +394,9 @@ impl of region_scope for empty_rscope { fn anon_region() -> result<ty::region, str> { result::err("region types are not allowed here") } - fn named_region(_id: str) -> result<ty::region, str> { - result::err("region types are not allowed here") + fn named_region(id: str) -> result<ty::region, str> { + if id == "static" { result::ok(ty::re_static) } + else { result::err("only the static region is allowed here") } } } @@ -395,9 +404,7 @@ enum type_rscope = ast::region_param; impl of region_scope for type_rscope { fn anon_region() -> result<ty::region, str> { alt *self { - ast::rp_self { - result::ok(ty::re_bound(ty::br_self)) - } + ast::rp_self { result::ok(ty::re_bound(ty::br_self)) } ast::rp_none { result::err("to use region types here, the containing type \ must be declared with a region bound") @@ -405,11 +412,12 @@ impl of region_scope for type_rscope { } } fn named_region(id: str) -> result<ty::region, str> { - if id == "self" { - self.anon_region() - } else { - result::err("named regions other than `self` are not \ - allowed as part of a type declaration") + empty_rscope.named_region(id).chain_err { |_e| + if id == "self" { self.anon_region() } + else { + result::err("named regions other than `self` are not \ + allowed as part of a type declaration") + } } } } @@ -419,11 +427,14 @@ impl of region_scope for @fn_ctxt { result::ok(self.next_region_var()) } fn named_region(id: str) -> result<ty::region, str> { - alt self.in_scope_regions.find(ty::br_named(id)) { - some(r) { result::ok(r) } - none { - result::err(#fmt["named region `%s` not in scope here", id]) - } + empty_rscope.named_region(id).chain_err { |_e| + alt self.in_scope_regions.find(ty::br_named(id)) { + some(r) { result::ok(r) } + none if id == "blk" { self.block_region() } + none { + result::err(#fmt["named region `%s` not in scope here", id]) + } + } } } } @@ -477,7 +488,6 @@ fn ast_region_to_region<AC: ast_conv, RS: region_scope>( let res = alt a_r.node { ast::re_anon { rscope.anon_region() } ast::re_named(id) { rscope.named_region(id) } - ast::re_static { result::ok(ty::re_static) } }; get_region_reporting_err(self.tcx(), span, res) @@ -772,6 +782,49 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>( ret typ; } +fn check_bounds_are_used(ccx: @crate_ctxt, + span: span, + tps: [ast::ty_param], + rp: ast::region_param, + ty: ty::t) { + let mut r_used = alt rp { + ast::rp_self { false } + ast::rp_none { true } + }; + + if tps.len() == 0u && r_used { ret; } + let tps_used = vec::to_mut(vec::from_elem(tps.len(), false)); + + ty::walk_regions_and_ty( + ccx.tcx, ty, + { |r| + alt r { + ty::re_bound(_) { r_used = true; } + _ { } + } + }, + { |t| + alt ty::get(t).struct { + ty::ty_param(idx, _) { tps_used[idx] = true; } + _ { } + } + true + }); + + if !r_used { + ccx.tcx.sess.span_err( + span, "lifetime `self` unused inside \ + reference-parameterized type."); + } + + for tps_used.eachi { |i, b| + if !b { + ccx.tcx.sess.span_err( + span, #fmt["Type parameter %s is unused.", tps[i].ident]); + } + } +} + fn ty_of_item(ccx: @crate_ctxt, it: @ast::item) -> ty::ty_param_bounds_and_ty { @@ -816,6 +869,9 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item) }; {bounds: ty_param_bounds(ccx, tps), rp: rp, ty: ty} }; + + check_bounds_are_used(ccx, t.span, tps, rp, tpt.ty); + tcx.tcache.insert(local_def(it.id), tpt); ret tpt; } @@ -1125,6 +1181,12 @@ impl methods for @fn_ctxt { fn ty_to_str(t: ty::t) -> str { ty_to_str(self.ccx.tcx, resolve_type_vars_if_possible(self, t)) } + fn block_region() -> result<ty::region, str> { + alt vec::last_opt(self.blocks) { + some(bid) { result::ok(ty::re_scope(bid)) } + none { result::err("no block is in scope here") } + } + } fn write_ty(node_id: ast::node_id, ty: ty::t) { #debug["write_ty(%d, %s) in fcx %s", node_id, ty_to_str(self.tcx(), ty), self.tag()]; @@ -3144,7 +3206,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, -> option<O> { alt expected { some(t) { - alt infer::resolve_shallow(fcx.infcx, t, true) { + alt infer::resolve_shallow(fcx.infcx, t, false) { result::ok(t) { unpack(ty::get(t).struct) } _ { none } } @@ -3913,6 +3975,7 @@ fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool { ast::unsafe_blk { @{purity: ast::unsafe_fn with *fcx0} } ast::default_blk { fcx0 } }; + vec::push(fcx.blocks, blk.node.id); let mut bot = false; let mut warned = false; for blk.node.stmts.each {|s| @@ -3943,6 +4006,7 @@ fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool { if bot { fcx.write_bot(blk.node.id); } + vec::pop(fcx.blocks); ret bot; } @@ -3960,6 +4024,7 @@ fn check_const(ccx: @crate_ctxt, _sp: span, e: @ast::expr, id: ast::node_id) { locals: int_hash(), ty_var_counter: @mut 0u, region_var_counter: @mut 0u, + mut blocks: [], in_scope_regions: @nil, node_types: smallintmap::mk(), node_type_substs: map::int_hash(), @@ -4000,6 +4065,7 @@ fn check_enum_variants(ccx: @crate_ctxt, locals: int_hash(), ty_var_counter: @mut 0u, region_var_counter: @mut 0u, + mut blocks: [], in_scope_regions: @nil, node_types: smallintmap::mk(), node_type_substs: map::int_hash(), @@ -4262,6 +4328,7 @@ fn check_fn(ccx: @crate_ctxt, locals: locals, ty_var_counter: tvc, region_var_counter: rvc, + mut blocks: [], in_scope_regions: isr, node_types: node_types, node_type_substs: node_type_substs, @@ -4350,21 +4417,27 @@ fn check_fn(ccx: @crate_ctxt, visit::visit_pat(p, e, v); }; + let visit_block = fn@(b: ast::blk, &&e: (), v: visit::vt<()>) { + vec::push(fcx.blocks, b.node.id); + visit::visit_block(b, e, v); + vec::pop(fcx.blocks); + }; + // Don't descend into fns and items - fn visit_fn<T>(_fk: visit::fn_kind, _decl: ast::fn_decl, - _body: ast::blk, _sp: span, - _id: ast::node_id, _t: T, _v: visit::vt<T>) { + fn visit_fn(_fk: visit::fn_kind, _decl: ast::fn_decl, + _body: ast::blk, _sp: span, + _id: ast::node_id, &&_t: (), _v: visit::vt<()>) { } - fn visit_item<E>(_i: @ast::item, _e: E, _v: visit::vt<E>) { } + fn visit_item(_i: @ast::item, &&_e: (), _v: visit::vt<()>) { } - let visit = - @{visit_local: visit_local, - visit_pat: visit_pat, - visit_fn: bind visit_fn(_, _, _, _, _, _, _), - visit_item: bind visit_item(_, _, _) - with *visit::default_visitor()}; + let visit = visit::mk_vt(@{visit_local: visit_local, + visit_pat: visit_pat, + visit_fn: visit_fn, + visit_item: visit_item, + visit_block: visit_block + with *visit::default_visitor()}); - visit::visit_block(body, (), visit::mk_vt(visit)); + visit.visit_block(body, (), visit); } } |
