提交 9e6d5e15 编写于 作者: N Niko Matsakis

Defer reasoning about region relationships until after regionck.

This patch makes error handling for region inference failures more
uniform by not reporting *any* region errors until the reigon inference
step. This requires threading through more information about what
caused a region constraint, so that we can still give informative
error messages.

I have only taken partial advantage of this information: when region
inference fails, we still report the same error we always did, despite
the fact that we now know precisely what caused the various constriants
and what the region variable represents, which we did not know before.

This change is required not only to improve error messages but
because the region hierarchy is not in fact fully known until regionck,
because it is not clear where closure bodies fit in (our current
treatment is unsound). Moreover, the relationships between free variables
cannot be fully determined until type inference is otherwise complete.

cc #3238.
上级 e482856d
......@@ -15,6 +15,7 @@
use middle::typeck::check::{check_block, check_expr_has_type, FnCtxt};
use middle::typeck::check::{instantiate_path, lookup_def};
use middle::typeck::check::{structure_of, valid_range_bounds};
use middle::typeck::infer;
use middle::typeck::require_same_types;
use std::hashmap::{HashMap, HashSet};
......@@ -38,8 +39,6 @@ pub fn check_match(fcx: @mut FnCtxt,
let pcx = pat_ctxt {
fcx: fcx,
map: pat_id_map(tcx.def_map, arm.pats[0]),
match_region: ty::re_scope(expr.id),
block_region: ty::re_scope(arm.body.node.id)
};
for arm.pats.iter().advance |p| { check_pat(&pcx, *p, pattern_ty);}
......@@ -93,8 +92,6 @@ pub fn check_match(fcx: @mut FnCtxt,
pub struct pat_ctxt {
fcx: @mut FnCtxt,
map: PatIdMap,
match_region: ty::Region, // Region for the match as a whole
block_region: ty::Region, // Region for the block of the arm
}
pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: @ast::Path,
......@@ -442,8 +439,8 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) {
// then the type of x is &M T where M is the mutability
// and T is the expected type
let region_var =
fcx.infcx().next_region_var_with_lb(
pat.span, pcx.block_region);
fcx.infcx().next_region_var(
infer::PatternRegion(pat.span));
let mt = ty::mt {ty: expected, mutbl: mutbl};
let region_ty = ty::mk_rptr(tcx, region_var, mt);
demand::eqtype(fcx, pat.span, region_ty, typ);
......@@ -544,9 +541,8 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) {
}
ast::pat_vec(ref before, slice, ref after) => {
let default_region_var =
fcx.infcx().next_region_var_with_lb(
pat.span, pcx.block_region
);
fcx.infcx().next_region_var(
infer::PatternRegion(pat.span));
let (elt_type, region_var) = match structure_of(
fcx, pat.span, expected
......
......@@ -35,7 +35,7 @@ pub fn suptype_with_fn(fcx: @mut FnCtxt,
ty_a: ty::t, ty_b: ty::t,
handle_err: &fn(span, ty::t, ty::t, &ty::type_err)) {
// n.b.: order of actual, expected is reversed
match infer::mk_subty(fcx.infcx(), b_is_expected, sp,
match infer::mk_subty(fcx.infcx(), b_is_expected, infer::Misc(sp),
ty_b, ty_a) {
result::Ok(()) => { /* ok */ }
result::Err(ref err) => {
......@@ -45,7 +45,7 @@ pub fn suptype_with_fn(fcx: @mut FnCtxt,
}
pub fn eqtype(fcx: @mut FnCtxt, sp: span, expected: ty::t, actual: ty::t) {
match infer::mk_eqty(fcx.infcx(), false, sp, actual, expected) {
match infer::mk_eqty(fcx.infcx(), false, infer::Misc(sp), actual, expected) {
Ok(()) => { /* ok */ }
Err(ref err) => {
fcx.report_mismatched_types(sp, expected, actual, err);
......
......@@ -619,14 +619,18 @@ pub fn consider_reborrow(&self,
autoref: None}))
}
ty::ty_rptr(_, self_mt) => {
let region = self.infcx().next_region_var_nb(self.expr.span);
let region =
self.infcx().next_region_var(
infer::Autoref(self.expr.span));
(ty::mk_rptr(tcx, region, self_mt),
ty::AutoDerefRef(ty::AutoDerefRef {
autoderefs: autoderefs+1,
autoref: Some(ty::AutoPtr(region, self_mt.mutbl))}))
}
ty::ty_evec(self_mt, vstore_slice(_)) => {
let region = self.infcx().next_region_var_nb(self.expr.span);
let region =
self.infcx().next_region_var(
infer::Autoref(self.expr.span));
(ty::mk_evec(tcx, self_mt, vstore_slice(region)),
ty::AutoDerefRef(ty::AutoDerefRef {
autoderefs: autoderefs,
......@@ -758,7 +762,9 @@ pub fn search_for_some_kind_of_autorefd_method(
-> Option<method_map_entry> {
// This is hokey. We should have mutability inference as a
// variable. But for now, try &const, then &, then &mut:
let region = self.infcx().next_region_var_nb(self.expr.span);
let region =
self.infcx().next_region_var(
infer::Autoref(self.expr.span));
for mutbls.iter().advance |mutbl| {
let autoref_ty = mk_autoref_ty(*mutbl, region);
match self.search_for_method(autoref_ty) {
......@@ -970,7 +976,8 @@ pub fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate)
let (_, opt_transformed_self_ty, fn_sig) =
replace_bound_regions_in_fn_sig(
tcx, @Nil, Some(transformed_self_ty), &bare_fn_ty.sig,
|_br| self.fcx.infcx().next_region_var_nb(self.expr.span));
|br| self.fcx.infcx().next_region_var(
infer::BoundRegionInFnCall(self.expr.span, br)));
let transformed_self_ty = opt_transformed_self_ty.get();
let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {sig: fn_sig, ..bare_fn_ty});
debug!("after replacing bound regions, fty=%s", self.ty_to_str(fty));
......@@ -982,7 +989,7 @@ pub fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate)
// variables to unify etc). Since we checked beforehand, and
// nothing has changed in the meantime, this unification
// should never fail.
match self.fcx.mk_subty(false, self.self_expr.span,
match self.fcx.mk_subty(false, infer::Misc(self.self_expr.span),
rcvr_ty, transformed_self_ty) {
result::Ok(_) => (),
result::Err(_) => {
......
......@@ -467,8 +467,6 @@ fn gather_locals(fcx: @mut FnCtxt,
let pcx = pat_ctxt {
fcx: fcx,
map: pat_id_map(tcx.def_map, input.pat),
match_region: region,
block_region: region,
};
_match::check_pat(&pcx, input.pat, *arg_ty);
}
......@@ -686,9 +684,14 @@ pub fn search_in_scope_regions(&self,
result::Ok(self.block_region())
} else {
result::Err(RegionError {
msg: fmt!("named region `%s` not in scope here",
bound_region_ptr_to_str(self.tcx(), br)),
replacement: self.infcx().next_region_var_nb(span)
msg: {
fmt!("named region `%s` not in scope here",
bound_region_to_str(self.tcx(), br))
},
replacement: {
self.infcx().next_region_var(
infer::BoundRegionError(span))
}
})
}
}
......@@ -698,7 +701,7 @@ pub fn search_in_scope_regions(&self,
impl region_scope for FnCtxt {
fn anon_region(&self, span: span) -> Result<ty::Region, RegionError> {
result::Ok(self.infcx().next_region_var_nb(span))
result::Ok(self.infcx().next_region_var(infer::MiscVariable(span)))
}
fn self_region(&self, span: span) -> Result<ty::Region, RegionError> {
self.search_in_scope_regions(span, ty::br_self)
......@@ -845,11 +848,11 @@ pub fn opt_node_ty_substs(&self,
pub fn mk_subty(&self,
a_is_expected: bool,
span: span,
origin: infer::SubtypeOrigin,
sub: ty::t,
sup: ty::t)
-> Result<(), ty::type_err> {
infer::mk_subty(self.infcx(), a_is_expected, span, sub, sup)
infer::mk_subty(self.infcx(), a_is_expected, origin, sub, sup)
}
pub fn can_mk_subty(&self, sub: ty::t, sup: ty::t)
......@@ -857,9 +860,16 @@ pub fn can_mk_subty(&self, sub: ty::t, sup: ty::t)
infer::can_mk_subty(self.infcx(), sub, sup)
}
pub fn mk_assignty(&self, expr: @ast::expr, sub: ty::t, sup: ty::t)
pub fn mk_assignty(&self,
expr: @ast::expr,
sub: ty::t,
sup: ty::t)
-> Result<(), ty::type_err> {
match infer::mk_coercety(self.infcx(), false, expr.span, sub, sup) {
match infer::mk_coercety(self.infcx(),
false,
infer::ExprAssignable(expr),
sub,
sup) {
Ok(None) => result::Ok(()),
Err(ref e) => result::Err((*e)),
Ok(Some(adjustment)) => {
......@@ -876,20 +886,19 @@ pub fn can_mk_assignty(&self, sub: ty::t, sup: ty::t)
pub fn mk_eqty(&self,
a_is_expected: bool,
span: span,
origin: infer::SubtypeOrigin,
sub: ty::t,
sup: ty::t)
-> Result<(), ty::type_err> {
infer::mk_eqty(self.infcx(), a_is_expected, span, sub, sup)
infer::mk_eqty(self.infcx(), a_is_expected, origin, sub, sup)
}
pub fn mk_subr(&self,
a_is_expected: bool,
span: span,
origin: infer::SubregionOrigin,
sub: ty::Region,
sup: ty::Region)
-> Result<(), ty::type_err> {
infer::mk_subr(self.infcx(), a_is_expected, span, sub, sup)
sup: ty::Region) {
infer::mk_subr(self.infcx(), a_is_expected, origin, sub, sup)
}
pub fn with_region_lb<R>(@mut self, lb: ast::node_id, f: &fn() -> R)
......@@ -905,7 +914,9 @@ pub fn region_var_if_parameterized(&self,
rp: Option<ty::region_variance>,
span: span)
-> Option<ty::Region> {
rp.map(|_rp| self.infcx().next_region_var_nb(span))
rp.map(
|_| self.infcx().next_region_var(
infer::BoundRegionInTypeOrImpl(span)))
}
pub fn type_error_message(&self,
......@@ -1089,7 +1100,8 @@ pub fn impl_self_ty(vcx: &VtableContext,
};
let self_r = if region_param.is_some() {
Some(vcx.infcx.next_region_var_nb(location_info.span))
Some(vcx.infcx.next_region_var(
infer::BoundRegionInTypeOrImpl(location_info.span)))
} else {
None
};
......@@ -1352,7 +1364,8 @@ fn check_call(fcx: @mut FnCtxt,
let (_, _, fn_sig) =
replace_bound_regions_in_fn_sig(
fcx.tcx(), @Nil, None, &fn_sig,
|_br| fcx.infcx().next_region_var_nb(call_expr.span));
|br| fcx.infcx().next_region_var(
infer::BoundRegionInFnCall(call_expr.span, br)));
// Call the generic checker.
check_argument_types(fcx, call_expr.span, fn_sig.inputs, f,
......@@ -2085,7 +2098,7 @@ fn check_loop_body(fcx: @mut FnCtxt,
let expected_sty = unpack_expected(fcx, expected, |x| Some(copy *x));
let inner_ty = match expected_sty {
Some(ty::ty_closure(ref fty)) => {
match fcx.mk_subty(false, expr.span,
match fcx.mk_subty(false, infer::Misc(expr.span),
fty.sig.output, ty::mk_bool()) {
result::Ok(_) => {
ty::mk_closure(tcx, ty::ClosureTy {
......@@ -2395,7 +2408,8 @@ fn check_loop_body(fcx: @mut FnCtxt,
// Finally, borrowck is charged with guaranteeing that the
// value whose address was taken can actually be made to live
// as long as it needs to live.
let region = fcx.infcx().next_region_var_nb(expr.span);
let region = fcx.infcx().next_region_var(
infer::AddrOfRegion(expr.span));
let tm = ty::mt { ty: fcx.expr_ty(oprnd), mutbl: mutbl };
let oprnd_t = if ty::type_is_error(tm.ty) {
......@@ -2437,7 +2451,7 @@ fn check_loop_body(fcx: @mut FnCtxt,
Some(t) => t, None => fcx.ret_ty
};
match expr_opt {
None => match fcx.mk_eqty(false, expr.span,
None => match fcx.mk_eqty(false, infer::Misc(expr.span),
ret_ty, ty::mk_nil()) {
result::Ok(_) => { /* fall through */ }
result::Err(_) => {
......@@ -2686,7 +2700,7 @@ fn types_compatible(fcx: @mut FnCtxt, sp: span,
let el = ty::sequence_element_type(fcx.tcx(),
t1);
infer::mk_eqty(fcx.infcx(), false,
sp, el, t2).is_ok()
infer::Misc(sp), el, t2).is_ok()
}
}
......@@ -2907,8 +2921,6 @@ pub fn check_decl_local(fcx: @mut FnCtxt, local: @ast::local) {
let pcx = pat_ctxt {
fcx: fcx,
map: pat_id_map(tcx.def_map, local.node.pat),
match_region: region,
block_region: region,
};
_match::check_pat(&pcx, local.node.pat, t);
let pat_ty = fcx.node_ty(local.node.pat.id);
......@@ -3412,7 +3424,7 @@ pub fn ast_expr_vstore_to_vstore(fcx: @mut FnCtxt,
ast::expr_vstore_uniq => ty::vstore_uniq,
ast::expr_vstore_box | ast::expr_vstore_mut_box => ty::vstore_box,
ast::expr_vstore_slice | ast::expr_vstore_mut_slice => {
let r = fcx.infcx().next_region_var_nb(e.span);
let r = fcx.infcx().next_region_var(infer::AddrOfSlice(e.span));
ty::vstore_slice(r)
}
}
......
......@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/*
/*!
The region check is a final pass that runs over the AST after we have
inferred the type constraints but before we have actually finalized
......@@ -35,7 +35,9 @@
use middle::typeck::check::regionmanip::relate_nested_regions;
use middle::typeck::infer::resolve_and_force_all_but_regions;
use middle::typeck::infer::resolve_type;
use util::ppaux::{note_and_explain_region, ty_to_str, region_to_str};
use middle::typeck::infer;
use util::ppaux::{note_and_explain_region, ty_to_str,
region_to_str};
use middle::pat_util;
use std::result;
......@@ -224,7 +226,9 @@ fn constrain_bindings_in_pat(pat: @ast::pat, rcx: @mut Rcx) {
// variable's type enclose at least the variable's scope.
let encl_region = tcx.region_maps.encl_region(id);
constrain_regions_in_type_of_node(rcx, id, encl_region, span);
constrain_regions_in_type_of_node(
rcx, id, encl_region,
infer::BindingTypeIsNotValidAtDecl(span));
}
}
......@@ -298,7 +302,8 @@ fn visit_expr(expr: @ast::expr, (rcx, v): (@mut Rcx, rvt)) {
//
// FIXME(#6268) remove to support nested method calls
constrain_regions_in_type_of_node(
rcx, expr.id, ty::re_scope(expr.id), expr.span);
rcx, expr.id, ty::re_scope(expr.id),
infer::AutoBorrow(expr.span));
}
}
_ => {}
......@@ -361,8 +366,11 @@ fn visit_expr(expr: @ast::expr, (rcx, v): (@mut Rcx, rvt)) {
match ty::get(target_ty).sty {
ty::ty_trait(_, _, ty::RegionTraitStore(trait_region), _, _) => {
let source_ty = rcx.fcx.expr_ty(source);
constrain_regions_in_type(rcx, trait_region,
expr.span, source_ty);
constrain_regions_in_type(
rcx,
trait_region,
infer::RelateObjectBound(expr.span),
source_ty);
}
_ => ()
}
......@@ -379,7 +387,8 @@ fn visit_expr(expr: @ast::expr, (rcx, v): (@mut Rcx, rvt)) {
//
// FIXME(#6268) nested method calls requires that this rule change
let ty0 = rcx.resolve_node_type(expr.id);
constrain_regions_in_type(rcx, ty::re_scope(expr.id), expr.span, ty0);
constrain_regions_in_type(rcx, ty::re_scope(expr.id),
infer::AddrOf(expr.span), ty0);
}
ast::expr_match(discr, ref arms) => {
......@@ -418,20 +427,8 @@ fn constrain_callee(rcx: @mut Rcx,
match ty::get(callee_ty).sty {
ty::ty_bare_fn(*) => { }
ty::ty_closure(ref closure_ty) => {
match rcx.fcx.mk_subr(true, callee_expr.span,
call_region, closure_ty.region) {
result::Err(_) => {
tcx.sess.span_err(
callee_expr.span,
fmt!("cannot invoke closure outside of its lifetime"));
note_and_explain_region(
tcx,
"the closure is only valid for ",
closure_ty.region,
"");
}
result::Ok(_) => {}
}
rcx.fcx.mk_subr(true, infer::InvokeClosure(callee_expr.span),
call_region, closure_ty.region);
}
_ => {
// this should not happen, but it does if the program is
......@@ -479,7 +476,8 @@ fn constrain_call(rcx: @mut Rcx,
// ensure that any regions appearing in the argument type are
// valid for at least the lifetime of the function:
constrain_regions_in_type_of_node(
rcx, arg_expr.id, callee_region, arg_expr.span);
rcx, arg_expr.id, callee_region,
infer::CallArg(arg_expr.span));
// unfortunately, there are two means of taking implicit
// references, and we need to propagate constraints as a
......@@ -493,7 +491,7 @@ fn constrain_call(rcx: @mut Rcx,
// as loop above, but for receiver
for receiver.iter().advance |&r| {
constrain_regions_in_type_of_node(
rcx, r.id, callee_region, r.span);
rcx, r.id, callee_region, infer::CallRcvr(r.span));
if implicitly_ref_args {
guarantor::for_by_ref(rcx, r, callee_scope);
}
......@@ -502,7 +500,8 @@ fn constrain_call(rcx: @mut Rcx,
// constrain regions that may appear in the return type to be
// valid for the function call:
constrain_regions_in_type(
rcx, callee_region, call_expr.span, fn_sig.output);
rcx, callee_region, infer::CallReturn(call_expr.span),
fn_sig.output);
}
fn constrain_derefs(rcx: @mut Rcx,
......@@ -545,20 +544,8 @@ pub fn mk_subregion_due_to_derefence(rcx: @mut Rcx,
deref_span: span,
minimum_lifetime: ty::Region,
maximum_lifetime: ty::Region) {
match rcx.fcx.mk_subr(true, deref_span,
minimum_lifetime, maximum_lifetime) {
result::Ok(*) => {}
result::Err(*) => {
rcx.tcx().sess.span_err(
deref_span,
fmt!("dereference of reference outside its lifetime"));
note_and_explain_region(
rcx.tcx(),
"the reference is only valid for ",
maximum_lifetime,
"");
}
}
rcx.fcx.mk_subr(true, infer::DerefPointer(deref_span),
minimum_lifetime, maximum_lifetime)
}
......@@ -581,19 +568,8 @@ fn constrain_index(rcx: @mut Rcx,
match ty::get(indexed_ty).sty {
ty::ty_estr(ty::vstore_slice(r_ptr)) |
ty::ty_evec(_, ty::vstore_slice(r_ptr)) => {
match rcx.fcx.mk_subr(true, index_expr.span, r_index_expr, r_ptr) {
result::Ok(*) => {}
result::Err(*) => {
tcx.sess.span_err(
index_expr.span,
fmt!("index of slice outside its lifetime"));
note_and_explain_region(
tcx,
"the slice is only valid for ",
r_ptr,
"");
}
}
rcx.fcx.mk_subr(true, infer::IndexSlice(index_expr.span),
r_index_expr, r_ptr);
}
_ => {}
......@@ -616,25 +592,8 @@ fn constrain_free_variables(rcx: @mut Rcx,
let def = freevar.def;
let en_region = encl_region_of_def(rcx.fcx, def);
debug!("en_region = %s", en_region.repr(tcx));
match rcx.fcx.mk_subr(true, freevar.span,
region, en_region) {
result::Ok(()) => {}
result::Err(_) => {
tcx.sess.span_err(
freevar.span,
"captured variable does not outlive the enclosing closure");
note_and_explain_region(
tcx,
"captured variable is valid for ",
en_region,
"");
note_and_explain_region(
tcx,
"closure is valid for ",
region,
"");
}
}
rcx.fcx.mk_subr(true, infer::FreeVariable(freevar.span),
region, en_region);
}
}
......@@ -642,7 +601,7 @@ fn constrain_regions_in_type_of_node(
rcx: @mut Rcx,
id: ast::node_id,
minimum_lifetime: ty::Region,
span: span) -> bool
origin: infer::SubregionOrigin) -> bool
{
//! Guarantees that any lifetimes which appear in the type of
//! the node `id` (after applying adjustments) are valid for at
......@@ -655,18 +614,18 @@ fn constrain_regions_in_type_of_node(
// report errors later on in the writeback phase.
let ty0 = rcx.resolve_node_type(id);
let adjustment = rcx.fcx.inh.adjustments.find_copy(&id);
let ty = ty::adjust_ty(tcx, span, ty0, adjustment);
let ty = ty::adjust_ty(tcx, origin.span(), ty0, adjustment);
debug!("constrain_regions_in_type_of_node(\
ty=%s, ty0=%s, id=%d, minimum_lifetime=%?, adjustment=%?)",
ty_to_str(tcx, ty), ty_to_str(tcx, ty0),
id, minimum_lifetime, adjustment);
constrain_regions_in_type(rcx, minimum_lifetime, span, ty)
constrain_regions_in_type(rcx, minimum_lifetime, origin, ty)
}
fn constrain_regions_in_type(
rcx: @mut Rcx,
minimum_lifetime: ty::Region,
span: span,
origin: infer::SubregionOrigin,
ty: ty::t) -> bool
{
/*!
......@@ -700,40 +659,14 @@ fn constrain_regions_in_type(
// (e.g., the `&` in `fn(&T)`). Such regions need not be
// constrained by `minimum_lifetime` as they are placeholders
// for regions that are as-yet-unknown.
} else if r_sub == minimum_lifetime {
rcx.fcx.mk_subr(
true, origin,
r_sub, r_sup);
} else {
match rcx.fcx.mk_subr(true, span, r_sub, r_sup) {
result::Err(_) => {
if r_sub == minimum_lifetime {
tcx.sess.span_err(
span,
fmt!("reference is not valid outside of its lifetime"));
note_and_explain_region(
tcx,
"the reference is only valid for ",
r_sup,
"");
} else {
tcx.sess.span_err(
span,
fmt!("in type `%s`, pointer has a longer lifetime than \
the data it references",
rcx.fcx.infcx().ty_to_str(ty)));
note_and_explain_region(
tcx,
"the pointer is valid for ",
r_sub,
"");
note_and_explain_region(
tcx,
"but the referenced data is only valid for ",
r_sup,
"");
}
rcx.errors_reported += 1u;
}
result::Ok(()) => {
}
}
rcx.fcx.mk_subr(
true, infer::ReferenceOutlivesReferent(ty, origin.span()),
r_sub, r_sup);
}
}
......@@ -788,8 +721,9 @@ pub mod guarantor {
*/
use middle::typeck::check::regionck::{Rcx, infallibly_mk_subr};
use middle::typeck::check::regionck::Rcx;
use middle::typeck::check::regionck::mk_subregion_due_to_derefence;
use middle::typeck::infer;
use middle::ty;
use syntax::ast;
use syntax::codemap::span;
......@@ -869,9 +803,11 @@ fn maybe_make_subregion(
rcx: @mut Rcx,
expr: @ast::expr,
sub_region: ty::Region,
sup_region: Option<ty::Region>) {
sup_region: Option<ty::Region>)
{
for sup_region.iter().advance |r| {
infallibly_mk_subr(rcx, true, expr.span, sub_region, *r);
rcx.fcx.mk_subr(true, infer::Reborrow(expr.span),
sub_region, *r);
}
}
}
......@@ -929,7 +865,7 @@ fn link(
let tcx = rcx.fcx.ccx.tcx;
debug!("rptr_ty=%s", ty_to_str(tcx, rptr_ty));
let r = ty::ty_region(tcx, span, rptr_ty);
infallibly_mk_subr(rcx, true, span, r, bound);
rcx.fcx.mk_subr(true, infer::Reborrow(span), r, bound);
}
}
......@@ -1259,27 +1195,3 @@ fn link_ref_bindings_in_pats(rcx: @mut Rcx,
}
}
pub fn infallibly_mk_subr(rcx: @mut Rcx,
a_is_expected: bool,
span: span,
a: ty::Region,
b: ty::Region) {
/*!
* Constrains `a` to be a subregion of `b`. In many cases, we
* know that this can never yield an error due to the way that
* region inferencing works. Therefore just report a bug if we
* ever see `Err(_)`.
*/
match rcx.fcx.mk_subr(a_is_expected, span, a, b) {
result::Ok(()) => {}
result::Err(e) => {
rcx.fcx.ccx.tcx.sess.span_bug(
span,
fmt!("Supposedly infallible attempt to \
make %? < %? failed: %?",
a, b, e));
}
}
}
......@@ -101,18 +101,18 @@ fn lookup_vtables(vcx: &VtableContext,
// Substitute the values of the type parameters that may
// appear in the bound.
let trait_ref = (*trait_ref).subst(tcx, substs);
let trait_ref = trait_ref.subst(tcx, substs);
debug!("after subst: %s", trait_ref.repr(tcx));
match lookup_vtable(vcx, location_info, *ty, &trait_ref, is_early) {
match lookup_vtable(vcx, location_info, *ty, trait_ref, is_early) {
Some(vtable) => param_result.push(vtable),
None => {
vcx.tcx().sess.span_fatal(
location_info.span,
fmt!("failed to find an implementation of \
trait %s for %s",
vcx.infcx.trait_ref_to_str(&trait_ref),
vcx.infcx.trait_ref_to_str(trait_ref),
vcx.infcx.ty_to_str(*ty)));
}
}
......@@ -152,8 +152,8 @@ fn fixup_substs(vcx: &VtableContext, location_info: &LocationInfo,
fn relate_trait_refs(vcx: &VtableContext,
location_info: &LocationInfo,
act_trait_ref: &ty::TraitRef,
exp_trait_ref: &ty::TraitRef)
act_trait_ref: @ty::TraitRef,
exp_trait_ref: @ty::TraitRef)
{
/*!
*
......@@ -162,8 +162,11 @@ fn relate_trait_refs(vcx: &VtableContext,
* error otherwise.
*/
match infer::mk_sub_trait_refs(vcx.infcx, false, location_info.span,
act_trait_ref, exp_trait_ref)
match infer::mk_sub_trait_refs(vcx.infcx,
false,
infer::RelateTraitRefs(location_info.span),
act_trait_ref,
exp_trait_ref)
{
result::Ok(()) => {} // Ok.
result::Err(ref err) => {
......@@ -191,7 +194,7 @@ fn relate_trait_refs(vcx: &VtableContext,
fn lookup_vtable(vcx: &VtableContext,
location_info: &LocationInfo,
ty: ty::t,
trait_ref: &ty::TraitRef,
trait_ref: @ty::TraitRef,
is_early: bool)
-> Option<vtable_origin>
{
......@@ -304,7 +307,8 @@ fn lookup_vtable(vcx: &VtableContext,
} = impl_self_ty(vcx, location_info, im.did);
match infer::mk_subty(vcx.infcx,
false,
location_info.span,
infer::RelateSelfType(
location_info.span),
ty,
for_ty) {
result::Err(_) => loop,
......@@ -337,11 +341,10 @@ fn lookup_vtable(vcx: &VtableContext,
vcx.infcx.trait_ref_to_str(trait_ref),
vcx.infcx.trait_ref_to_str(of_trait_ref));
let of_trait_ref =
(*of_trait_ref).subst(tcx, &substs);
let of_trait_ref = of_trait_ref.subst(tcx, &substs);
relate_trait_refs(
vcx, location_info,
&of_trait_ref, trait_ref);
of_trait_ref, trait_ref);
// Recall that trait_ref -- the trait type
// we're casting to -- is the trait with
......@@ -450,7 +453,7 @@ fn fixup_ty(vcx: &VtableContext,
fn connect_trait_tps(vcx: &VtableContext,
location_info: &LocationInfo,
impl_substs: &ty::substs,
trait_ref: &ty::TraitRef,
trait_ref: @ty::TraitRef,
impl_did: ast::def_id)
{
let tcx = vcx.tcx();
......@@ -461,8 +464,8 @@ fn connect_trait_tps(vcx: &VtableContext,
"connect_trait_tps invoked on a type impl")
};
let impl_trait_ref = (*impl_trait_ref).subst(tcx, impl_substs);
relate_trait_refs(vcx, location_info, &impl_trait_ref, trait_ref);
let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
relate_trait_refs(vcx, location_info, impl_trait_ref, trait_ref);
}
fn insert_vtables(fcx: @mut FnCtxt,
......@@ -581,7 +584,7 @@ fn mutability_allowed(a_mutbl: ast::mutability,
ccx: fcx.ccx,
infcx: fcx.infcx()
};
let target_trait_ref = ty::TraitRef {
let target_trait_ref = @ty::TraitRef {
def_id: target_def_id,
substs: ty::substs {
tps: copy target_substs.tps,
......@@ -593,7 +596,7 @@ fn mutability_allowed(a_mutbl: ast::mutability,
lookup_vtable(&vcx,
location_info,
mt.ty,
&target_trait_ref,
target_trait_ref,
is_early);
match vtable_opt {
Some(vtable) => {
......@@ -622,7 +625,8 @@ fn mutability_allowed(a_mutbl: ast::mutability,
ty::RegionTraitStore(rb)) => {
infer::mk_subr(fcx.infcx(),
false,
ex.span,
infer::RelateObjectBound(
ex.span),
rb,
ra);
}
......
......@@ -36,6 +36,7 @@
use middle::typeck::infer::InferCtxt;
use middle::typeck::infer::{new_infer_ctxt, resolve_ivar};
use middle::typeck::infer::{resolve_nested_tvar, resolve_type};
use middle::typeck::infer;
use syntax::ast::{crate, def_id, def_struct, def_ty};
use syntax::ast::{item, item_enum, item_impl, item_mod, item_struct};
use syntax::ast::{local_crate, method, trait_ref, ty_path};
......@@ -546,10 +547,10 @@ pub fn polytypes_unify(&self,
pub fn universally_quantify_polytype(&self,
polytype: ty_param_bounds_and_ty)
-> UniversalQuantificationResult {
// NDM--this span is bogus.
let self_region =
polytype.generics.region_param.map(
|_r| self.inference_context.next_region_var_nb(dummy_sp()));
|_| self.inference_context.next_region_var(
infer::BoundRegionInCoherence));
let bounds_count = polytype.generics.type_param_defs.len();
let type_parameters = self.inference_context.next_ty_vars(bounds_count);
......@@ -580,11 +581,9 @@ pub fn can_unify_universally_quantified<'a>(&self,
b: &'a
UniversalQuantificationResult)
-> bool {
let mut might_unify = true;
let _ = do self.inference_context.probe {
let result = self.inference_context.sub(true, dummy_sp())
.tys(a.monotype, b.monotype);
if result.is_ok() {
match infer::can_mk_subty(self.inference_context,
a.monotype, b.monotype) {
Ok(_) => {
// Check to ensure that each parameter binding respected its
// kind bounds.
let xs = [a, b];
......@@ -604,8 +603,7 @@ pub fn can_unify_universally_quantified<'a>(&self,
self.inference_context.tcx,
resolved_ty)
{
might_unify = false;
break;
return false;
}
}
Err(*) => {
......@@ -615,13 +613,13 @@ pub fn can_unify_universally_quantified<'a>(&self,
}
}
}
} else {
might_unify = false;
true
}
result
};
might_unify
Err(_) => {
false
}
}
}
pub fn get_self_type_for_implementation(&self, implementation: @Impl)
......
......@@ -615,7 +615,8 @@ pub fn compare_impl_method(tcx: ty::ctxt,
};
debug!("trait_fty (post-subst): %s", trait_fty.repr(tcx));
match infer::mk_subty(infcx, false, cm.span, impl_fty, trait_fty) {
match infer::mk_subty(infcx, false, infer::MethodCompatCheck(cm.span),
impl_fty, trait_fty) {
result::Ok(()) => {}
result::Err(ref terr) => {
tcx.sess.span_err(
......
......@@ -70,7 +70,7 @@ fn foo<A>(a: A, b: A) { ... }
use middle::ty::{vstore_slice, vstore_box, vstore_uniq};
use middle::ty::{mt};
use middle::ty;
use middle::typeck::infer::{CoerceResult, resolve_type};
use middle::typeck::infer::{CoerceResult, resolve_type, Coercion};
use middle::typeck::infer::combine::CombineFields;
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::to_str::InferStr;
......@@ -165,7 +165,7 @@ pub fn unpack_actual_value(&self,
}
Err(e) => {
self.infcx.tcx.sess.span_bug(
self.span,
self.trace.origin.span(),
fmt!("Failed to resolve even without \
any force options: %?", e));
}
......@@ -189,7 +189,7 @@ pub fn coerce_borrowed_pointer(&self,
// yield.
let sub = Sub(**self);
let r_borrow = self.infcx.next_region_var_nb(self.span);
let r_borrow = self.infcx.next_region_var(Coercion(self.trace));
let inner_ty = match *sty_a {
ty::ty_box(mt_a) => mt_a.ty,
......@@ -227,7 +227,7 @@ pub fn coerce_borrowed_string(&self,
}
};
let r_a = self.infcx.next_region_var_nb(self.span);
let r_a = self.infcx.next_region_var(Coercion(self.trace));
let a_borrowed = ty::mk_estr(self.infcx.tcx, vstore_slice(r_a));
if_ok!(self.subtype(a_borrowed, b));
Ok(Some(@AutoDerefRef(AutoDerefRef {
......@@ -247,7 +247,7 @@ pub fn coerce_borrowed_vector(&self,
b.inf_str(self.infcx));
let sub = Sub(**self);
let r_borrow = self.infcx.next_region_var_nb(self.span);
let r_borrow = self.infcx.next_region_var(Coercion(self.trace));
let ty_inner = match *sty_a {
ty::ty_evec(mt, _) => mt.ty,
_ => {
......@@ -285,7 +285,7 @@ pub fn coerce_borrowed_fn(&self,
}
};
let r_borrow = self.infcx.next_region_var_nb(self.span);
let r_borrow = self.infcx.next_region_var(Coercion(self.trace));
let a_borrowed = ty::mk_closure(
self.infcx.tcx,
ty::ClosureTy {
......
......@@ -65,6 +65,7 @@
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::unify::{InferCtxtMethods};
use middle::typeck::infer::{InferCtxt, cres, ures};
use middle::typeck::infer::{SubtypeOrigin, SubtypeTrace};
use util::common::indent;
use std::result::{iter_vec2, map_vec2};
......@@ -79,7 +80,7 @@ pub trait Combine {
fn infcx(&self) -> @mut InferCtxt;
fn tag(&self) -> ~str;
fn a_is_expected(&self) -> bool;
fn span(&self) -> span;
fn trace(&self) -> SubtypeTrace;
fn sub(&self) -> Sub;
fn lub(&self) -> Lub;
......@@ -121,7 +122,7 @@ fn trait_stores(&self,
pub struct CombineFields {
infcx: @mut InferCtxt,
a_is_expected: bool,
span: span,
trace: SubtypeTrace,
}
pub fn expected_found<C:Combine,T>(
......
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <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.
/*!
Error Reporting Code for the inference engine
Because of the way inference, and in particular region inference,
works, it often happens that errors are not detected until far after
the relevant line of code has been type-checked. Therefore, there is
an elaborate system to track why a particular constraint in the
inference graph arose so that we can explain to the user what gave
rise to a patricular error.
The basis of the system are the "origin" types. An "origin" is the
reason that a constraint or inference variable arose. There are
different "origin" enums for different kinds of constraints/variables
(e.g., `SubtypeOrigin`, `RegionVariableOrigin`). An origin always has
a span, but also more information so that we can generate a meaningful
error message.
Having a catalogue of all the different reasons an error can arise is
also useful for other reasons, like cross-referencing FAQs etc, though
we are not really taking advantage of this yet.
# Region Inference
Region inference is particularly tricky because it always succeeds "in
the moment" and simply registers a constraint. Then, at the end, we
can compute the full graph and report errors, so we need to be able to
store and later report what gave rise to the conflicting constraints.
# Subtype Trace
Determing whether `T1 <: T2` often involves a number of subtypes and
subconstraints along the way. A "SubtypeTrace" is an extended version
of an origin that traces the types and other values that were being
compared. It is not necessarily comprehensive (in fact, at the time of
this writing it only tracks the root values being compared) but I'd
like to extend it to include significant "waypoints". For example, if
you are comparing `(T1, T2) <: (T3, T4)`, and the problem is that `T2
<: T4` fails, I'd like the trace to include enough information to say
"in the 2nd element of the tuple". Similarly, failures when comparing
arguments or return types in fn types should be able to cite the
specific position, etc.
# Reality vs plan
Of course, there is still a LOT of code in typeck that has yet to be
ported to this system, and which relies on string concatenation at the
time of error detection.
*/
use core::prelude::*;
use middle::ty;
use middle::ty::Region;
use middle::typeck::infer;
use middle::typeck::infer::InferCtxt;
use middle::typeck::infer::SubtypeTrace;
use middle::typeck::infer::SubtypeOrigin;
use middle::typeck::infer::SubregionOrigin;
use middle::typeck::infer::RegionVariableOrigin;
use middle::typeck::infer::Types;
use middle::typeck::infer::TraitRefs;
use middle::typeck::infer::ValuePairs;
use middle::typeck::infer::region_inference::RegionResolutionError;
use middle::typeck::infer::region_inference::ConcreteFailure;
use middle::typeck::infer::region_inference::SubSupConflict;
use middle::typeck::infer::region_inference::SupSupConflict;
use syntax::opt_vec;
use syntax::opt_vec::OptVec;
use util::ppaux::UserString;
use util::ppaux::note_and_explain_region;
impl InferCtxt {
pub fn report_region_errors(@mut self,
errors: &OptVec<RegionResolutionError>) {
for errors.each |error| {
match *error {
ConcreteFailure(origin, sub, sup) => {
self.report_concrete_failure(origin, sub, sup);
}
SubSupConflict(var_origin,
sub_origin, sub_r,
sup_origin, sup_r) => {
self.report_sub_sup_conflict(var_origin,
sub_origin, sub_r,
sup_origin, sup_r);
}
SupSupConflict(var_origin,
origin1, r1,
origin2, r2) => {
self.report_sup_sup_conflict(var_origin,
origin1, r1,
origin2, r2);
}
}
}
}
fn report_and_explain_type_error(@mut self,
trace: SubtypeTrace,
terr: &ty::type_err) {
let tcx = self.tcx;
let expected_found_str = match self.values_str(&trace.values) {
Some(v) => v,
None => {
return; /* derived error */
}
};
let message_root_str = match trace.origin {
infer::Misc(_) => "mismatched types",
infer::MethodCompatCheck(_) => "method not compatible with trait",
infer::ExprAssignable(_) => "mismatched types",
infer::RelateTraitRefs(_) => "mismatched traits",
infer::RelateSelfType(_) => "mismatched types"
};
self.tcx.sess.span_err(
trace.origin.span(),
fmt!("%s: %s (%s)",
message_root_str,
expected_found_str,
ty::type_err_to_str(tcx, terr)));
ty::note_and_explain_type_err(self.tcx, terr);
}
fn values_str(@mut self, values: &ValuePairs) -> Option<~str> {
/*!
* Returns a string of the form "expected `%s` but found `%s`",
* or None if this is a derived error.
*/
match *values {
infer::Types(ref exp_found) => {
self.expected_found_str(exp_found)
}
infer::TraitRefs(ref exp_found) => {
self.expected_found_str(exp_found)
}
}
}
fn expected_found_str<T:UserString+Resolvable>(
@mut self,
exp_found: &ty::expected_found<T>)
-> Option<~str>
{
let expected = exp_found.expected.resolve(self);
if expected.contains_error() {
return None;
}
let found = exp_found.found.resolve(self);
if found.contains_error() {
return None;
}
Some(fmt!("expected `%s` but found `%s`",
expected.user_string(self.tcx),
found.user_string(self.tcx)))
}
fn report_concrete_failure(@mut self,
origin: SubregionOrigin,
sub: Region,
sup: Region) {
match origin {
infer::Subtype(trace) => {
let terr = ty::terr_regions_does_not_outlive(sub, sup);
self.report_and_explain_type_error(trace, &terr);
}
infer::Reborrow(span) => {
self.tcx.sess.span_err(
span,
"lifetime of borrowed pointer outlines \
lifetime of borrowed content...");
note_and_explain_region(
self.tcx,
"...the borrowed pointer is valid for ",
sub,
"...");
note_and_explain_region(
self.tcx,
"...but the borrowed content is only valid for ",
sup,
"");
}
infer::InvokeClosure(span) => {
self.tcx.sess.span_err(
span,
"cannot invoke closure outside of its lifetime");
note_and_explain_region(
self.tcx,
"the closure is only valid for ",
sup,
"");
}
infer::DerefPointer(span) => {
self.tcx.sess.span_err(
span,
"dereference of reference outside its lifetime");
note_and_explain_region(
self.tcx,
"the reference is only valid for ",
sup,
"");
}
infer::FreeVariable(span) => {
self.tcx.sess.span_err(
span,
"captured variable does not outlive the enclosing closure");
note_and_explain_region(
self.tcx,
"captured variable is valid for ",
sup,
"");
note_and_explain_region(
self.tcx,
"closure is valid for ",
sub,
"");
}
infer::IndexSlice(span) => {
self.tcx.sess.span_err(
span,
fmt!("index of slice outside its lifetime"));
note_and_explain_region(
self.tcx,
"the slice is only valid for ",
sup,
"");
}
infer::RelateObjectBound(span) => {
self.tcx.sess.span_err(
span,
"lifetime of the source pointer does not outlive \
lifetime bound of the object type");
note_and_explain_region(
self.tcx,
"object type is valid for ",
sub,
"");
note_and_explain_region(
self.tcx,
"source pointer is only valid for ",
sup,
"");
}
infer::CallRcvr(span) => {
self.tcx.sess.span_err(
span,
"lifetime of method receiver does not outlive \
the method call");
note_and_explain_region(
self.tcx,
"the receiver is only valid for ",
sup,
"");
}
infer::CallArg(span) => {
self.tcx.sess.span_err(
span,
"lifetime of function argument does not outlive \
the function call");
note_and_explain_region(
self.tcx,
"the function argument is only valid for ",
sup,
"");
}
infer::CallReturn(span) => {
self.tcx.sess.span_err(
span,
"lifetime of return value does not outlive \
the function call");
note_and_explain_region(
self.tcx,
"the return value is only valid for ",
sup,
"");
}
infer::AddrOf(span) => {
self.tcx.sess.span_err(
span,
"borrowed pointer is not valid \
at the time of borrow");
note_and_explain_region(
self.tcx,
"the borrow is only valid for ",
sup,
"");
}
infer::AutoBorrow(span) => {
self.tcx.sess.span_err(
span,
"automatically borrowed pointer is not valid \
at the time of borrow");
note_and_explain_region(
self.tcx,
"the automatic borrow is only valid for ",
sup,
"");
}
infer::BindingTypeIsNotValidAtDecl(span) => {
self.tcx.sess.span_err(
span,
"lifetime of variable does not enclose its declaration");
note_and_explain_region(
self.tcx,
"the variable is only valid for ",
sup,
"");
}
infer::ReferenceOutlivesReferent(ty, span) => {
self.tcx.sess.span_err(
origin.span(),
fmt!("in type `%s`, pointer has a longer lifetime than \
the data it references",
ty.user_string(self.tcx)));
note_and_explain_region(
self.tcx,
"the pointer is valid for ",
sub,
"");
note_and_explain_region(
self.tcx,
"but the referenced data is only valid for ",
sup,
"");
}
}
}
fn report_sub_sup_conflict(@mut self,
var_origin: RegionVariableOrigin,
sub_origin: SubregionOrigin,
sub_region: Region,
sup_origin: SubregionOrigin,
sup_region: Region) {
self.tcx.sess.span_err(
var_origin.span(),
fmt!("cannot infer an appropriate lifetime \
due to conflicting requirements"));
note_and_explain_region(
self.tcx,
"first, the lifetime cannot outlive ",
sup_region,
"...");
self.tcx.sess.span_note(
sup_origin.span(),
fmt!("...due to the following expression"));
note_and_explain_region(
self.tcx,
"but, the lifetime must be valid for ",
sub_region,
"...");
self.tcx.sess.span_note(
sub_origin.span(),
fmt!("...due to the following expression"));
}
fn report_sup_sup_conflict(@mut self,
var_origin: RegionVariableOrigin,
origin1: SubregionOrigin,
region1: Region,
origin2: SubregionOrigin,
region2: Region) {
self.tcx.sess.span_err(
var_origin.span(),
fmt!("cannot infer an appropriate lifetime \
due to conflicting requirements"));
note_and_explain_region(
self.tcx,
"first, the lifetime must be contained by ",
region1,
"...");
self.tcx.sess.span_note(
origin1.span(),
fmt!("...due to the following expression"));
note_and_explain_region(
self.tcx,
"but, the lifetime must also be contained by ",
region2,
"...");
self.tcx.sess.span_note(
origin2.span(),
fmt!("...due to the following expression"));
}
}
trait Resolvable {
fn resolve(&self, infcx: @mut InferCtxt) -> Self;
fn contains_error(&self) -> bool;
}
impl Resolvable for ty::t {
fn resolve(&self, infcx: @mut InferCtxt) -> ty::t {
infcx.resolve_type_vars_if_possible(*self)
}
fn contains_error(&self) -> bool {
ty::type_is_error(*self)
}
}
impl Resolvable for @ty::TraitRef {
fn resolve(&self, infcx: @mut InferCtxt) -> @ty::TraitRef {
@infcx.resolve_type_vars_in_trait_ref_if_possible(*self)
}
fn contains_error(&self) -> bool {
ty::trait_ref_contains_error(*self)
}
}
......@@ -18,6 +18,7 @@
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::{cres, InferCtxt};
use middle::typeck::infer::{SubtypeTrace, Subtype};
use middle::typeck::infer::fold_regions_in_sig;
use middle::typeck::isr_alist;
use syntax::ast;
......@@ -37,7 +38,7 @@ impl Combine for Glb {
fn infcx(&self) -> @mut InferCtxt { self.infcx }
fn tag(&self) -> ~str { ~"glb" }
fn a_is_expected(&self) -> bool { self.a_is_expected }
fn span(&self) -> span { self.span }
fn trace(&self) -> SubtypeTrace { self.trace }
fn sub(&self) -> Sub { Sub(**self) }
fn lub(&self) -> Lub { Lub(**self) }
......@@ -127,9 +128,7 @@ fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
a.inf_str(self.infcx),
b.inf_str(self.infcx));
do indent {
self.infcx.region_vars.glb_regions(self.span, a, b)
}
Ok(self.infcx.region_vars.glb_regions(Subtype(self.trace), a, b))
}
fn contraregions(&self, a: ty::Region, b: ty::Region)
......@@ -181,11 +180,11 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
// Instantiate each bound region with a fresh region variable.
let (a_with_fresh, a_isr) =
self.infcx.replace_bound_regions_with_fresh_regions(
self.span, a);
self.trace, a);
let a_vars = var_ids(self, a_isr);
let (b_with_fresh, b_isr) =
self.infcx.replace_bound_regions_with_fresh_regions(
self.span, b);
self.trace, b);
let b_vars = var_ids(self, b_isr);
// Collect constraints.
......@@ -277,7 +276,7 @@ fn rev_lookup(this: &Glb,
}
this.infcx.tcx.sess.span_bug(
this.span,
this.trace.origin.span(),
fmt!("could not find original bound region for %?", r));
}
......
......@@ -530,7 +530,7 @@ pub fn var_ids<T:Combine>(this: &T, isr: isr_alist) -> ~[RegionVid] {
ty::re_infer(ty::ReVar(r)) => { result.push(r); }
r => {
this.infcx().tcx.sess.span_bug(
this.span(),
this.trace().origin.span(),
fmt!("Found non-region-vid: %?", r));
}
}
......
......@@ -19,6 +19,7 @@
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::{cres, InferCtxt};
use middle::typeck::infer::fold_regions_in_sig;
use middle::typeck::infer::{SubtypeTrace, Subtype};
use middle::typeck::isr_alist;
use util::common::indent;
use util::ppaux::mt_to_str;
......@@ -44,7 +45,7 @@ impl Combine for Lub {
fn infcx(&self) -> @mut InferCtxt { self.infcx }
fn tag(&self) -> ~str { ~"lub" }
fn a_is_expected(&self) -> bool { self.a_is_expected }
fn span(&self) -> span { self.span }
fn trace(&self) -> SubtypeTrace { self.trace }
fn sub(&self) -> Sub { Sub(**self) }
fn lub(&self) -> Lub { Lub(**self) }
......@@ -119,9 +120,7 @@ fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
a.inf_str(self.infcx),
b.inf_str(self.infcx));
do indent {
self.infcx.region_vars.lub_regions(self.span, a, b)
}
Ok(self.infcx.region_vars.lub_regions(Subtype(self.trace), a, b))
}
fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
......@@ -137,10 +136,10 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
// Instantiate each bound region with a fresh region variable.
let (a_with_fresh, a_isr) =
self.infcx.replace_bound_regions_with_fresh_regions(
self.span, a);
self.trace, a);
let (b_with_fresh, _) =
self.infcx.replace_bound_regions_with_fresh_regions(
self.span, b);
self.trace, b);
// Collect constraints.
let sig0 = if_ok!(super_fn_sigs(self, &a_with_fresh, &b_with_fresh));
......@@ -196,7 +195,7 @@ fn generalize_region(this: &Lub,
}
this.infcx.tcx.sess.span_bug(
this.span,
this.trace.origin.span(),
fmt!("Region %? is not associated with \
any bound region from A!", r0));
}
......
......@@ -264,7 +264,8 @@ fn bar() {
use middle::typeck::infer::unify::{ValsAndBindings, Root};
use middle::typeck::isr_alist;
use util::common::indent;
use util::ppaux::{bound_region_to_str, ty_to_str, trait_ref_to_str};
use util::ppaux::{bound_region_to_str, ty_to_str, trait_ref_to_str, Repr,
UserString};
use std::result;
use std::vec;
......@@ -286,6 +287,7 @@ fn bar() {
pub mod to_str;
pub mod unify;
pub mod coercion;
pub mod error_reporting;
pub type Bound<T> = Option<T>;
pub struct Bounds<T> {
......@@ -319,6 +321,127 @@ pub struct InferCtxt {
region_vars: RegionVarBindings,
}
/// Why did we require that the two types be related?
///
/// See `error_reporting.rs` for more details
pub enum SubtypeOrigin {
// Not yet categorized in a better way
Misc(span),
// Checking that method of impl is compatible with trait
MethodCompatCheck(span),
// Checking that this expression can be assigned where it needs to be
ExprAssignable(@ast::expr),
// Relating trait refs when resolving vtables
RelateTraitRefs(span),
// Relating trait refs when resolving vtables
RelateSelfType(span),
}
/// See `error_reporting.rs` for more details
pub enum ValuePairs {
Types(ty::expected_found<ty::t>),
TraitRefs(ty::expected_found<@ty::TraitRef>),
}
/// The trace designates the path through inference that we took to
/// encounter an error or subtyping constraint.
///
/// See `error_reporting.rs` for more details.
pub struct SubtypeTrace {
origin: SubtypeOrigin,
values: ValuePairs,
}
/// The origin of a `r1 <= r2` constraint.
///
/// See `error_reporting.rs` for more details
pub enum SubregionOrigin {
// Arose from a subtyping relation
Subtype(SubtypeTrace),
// Invocation of closure must be within its lifetime
InvokeClosure(span),
// Dereference of borrowed pointer must be within its lifetime
DerefPointer(span),
// Closure bound must not outlive captured free variables
FreeVariable(span),
// Index into slice must be within its lifetime
IndexSlice(span),
// When casting `&'a T` to an `&'b Trait` object,
// relating `'a` to `'b`
RelateObjectBound(span),
// Creating a pointer `b` to contents of another borrowed pointer
Reborrow(span),
// (&'a &'b T) where a >= b
ReferenceOutlivesReferent(ty::t, span),
// A `ref b` whose region does not enclose the decl site
BindingTypeIsNotValidAtDecl(span),
// Regions appearing in a method receiver must outlive method call
CallRcvr(span),
// Regions appearing in a function argument must outlive func call
CallArg(span),
// Region in return type of invoked fn must enclose call
CallReturn(span),
// Region resulting from a `&` expr must enclose the `&` expr
AddrOf(span),
// An auto-borrow that does not enclose the expr where it occurs
AutoBorrow(span),
}
/// Reasons to create a region inference variable
///
/// See `error_reporting.rs` for more details
pub enum RegionVariableOrigin {
// Region variables created for ill-categorized reasons,
// mostly indicates places in need of refactoring
MiscVariable(span),
// Regions created by a `&P` or `[...]` pattern
PatternRegion(span),
// Regions created by `&` operator
AddrOfRegion(span),
// Regions created by `&[...]` literal
AddrOfSlice(span),
// Regions created as part of an autoref of a method receiver
Autoref(span),
// Regions created as part of an automatic coercion
Coercion(SubtypeTrace),
// Region variables created for bound regions
// in a function or method that is called
BoundRegionInFnCall(span, ty::bound_region),
// Region variables created for bound regions
// when doing subtyping/lub/glb computations
BoundRegionInFnType(span, ty::bound_region),
BoundRegionInTypeOrImpl(span),
BoundRegionInCoherence,
BoundRegionError(span),
}
pub enum fixup_err {
unresolved_int_ty(IntVid),
unresolved_ty(TyVid),
......@@ -366,14 +489,18 @@ pub fn new_infer_ctxt(tcx: ty::ctxt) -> @mut InferCtxt {
pub fn mk_subty(cx: @mut InferCtxt,
a_is_expected: bool,
span: span,
origin: SubtypeOrigin,
a: ty::t,
b: ty::t)
-> ures {
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)
let trace = SubtypeTrace {
origin: origin,
values: Types(expected_found(a_is_expected, a, b))
};
cx.sub(a_is_expected, trace).tys(a, b)
}
}.to_ures()
}
......@@ -382,35 +509,40 @@ pub fn can_mk_subty(cx: @mut 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, codemap::dummy_sp()).tys(a, b)
let trace = SubtypeTrace {
origin: Misc(codemap::dummy_sp()),
values: Types(expected_found(true, a, b))
};
cx.sub(true, trace).tys(a, b)
}
}.to_ures()
}
pub fn mk_subr(cx: @mut InferCtxt,
a_is_expected: bool,
span: span,
origin: SubregionOrigin,
a: ty::Region,
b: ty::Region)
-> ures {
b: ty::Region) {
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)
}
}.to_ures()
cx.region_vars.start_snapshot();
cx.region_vars.make_subregion(origin, a, b);
cx.region_vars.commit();
}
pub fn mk_eqty(cx: @mut InferCtxt,
a_is_expected: bool,
span: span,
origin: SubtypeOrigin,
a: ty::t,
b: ty::t)
-> ures {
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);
let trace = SubtypeTrace {
origin: origin,
values: Types(expected_found(a_is_expected, a, b))
};
let suber = cx.sub(a_is_expected, trace);
eq_tys(&suber, a, b)
}
}.to_ures()
......@@ -418,31 +550,49 @@ pub fn mk_eqty(cx: @mut InferCtxt,
pub fn mk_sub_trait_refs(cx: @mut InferCtxt,
a_is_expected: bool,
span: span,
a: &ty::TraitRef,
b: &ty::TraitRef)
origin: SubtypeOrigin,
a: @ty::TraitRef,
b: @ty::TraitRef)
-> ures
{
debug!("mk_sub_trait_refs(%s <: %s)",
a.inf_str(cx), b.inf_str(cx));
do indent {
do cx.commit {
let suber = cx.sub(a_is_expected, span);
let trace = SubtypeTrace {
origin: origin,
values: TraitRefs(expected_found(a_is_expected, a, b))
};
let suber = cx.sub(a_is_expected, trace);
suber.trait_refs(a, b)
}
}.to_ures()
}
fn expected_found<T>(a_is_expected: bool,
a: T,
b: T) -> ty::expected_found<T> {
if a_is_expected {
ty::expected_found {expected: a, found: b}
} else {
ty::expected_found {expected: b, found: a}
}
}
pub fn mk_coercety(cx: @mut InferCtxt,
a_is_expected: bool,
span: span,
origin: SubtypeOrigin,
a: ty::t,
b: ty::t)
-> CoerceResult {
debug!("mk_coercety(%s -> %s)", a.inf_str(cx), b.inf_str(cx));
do indent {
do cx.commit {
Coerce(cx.combine_fields(a_is_expected, span)).tys(a, b)
let trace = SubtypeTrace {
origin: origin,
values: Types(expected_found(a_is_expected, a, b))
};
Coerce(cx.combine_fields(a_is_expected, trace)).tys(a, b)
}
}
}
......@@ -451,8 +601,11 @@ pub fn can_mk_coercety(cx: @mut InferCtxt, a: ty::t, b: ty::t) -> ures {
debug!("can_mk_coercety(%s -> %s)", a.inf_str(cx), b.inf_str(cx));
do indent {
do cx.probe {
let span = codemap::dummy_sp();
Coerce(cx.combine_fields(true, span)).tys(a, b)
let trace = SubtypeTrace {
origin: Misc(codemap::dummy_sp()),
values: Types(expected_found(true, a, b))
};
Coerce(cx.combine_fields(true, trace)).tys(a, b)
}
}.to_ures()
}
......@@ -535,15 +688,17 @@ struct Snapshot {
}
impl InferCtxt {
pub fn combine_fields(@mut self, a_is_expected: bool, span: span)
pub fn combine_fields(@mut self,
a_is_expected: bool,
trace: SubtypeTrace)
-> CombineFields {
CombineFields {infcx: self,
a_is_expected: a_is_expected,
span: span}
trace: trace}
}
pub fn sub(@mut self, a_is_expected: bool, span: span) -> Sub {
Sub(self.combine_fields(a_is_expected, span))
pub fn sub(@mut self, a_is_expected: bool, trace: SubtypeTrace) -> Sub {
Sub(self.combine_fields(a_is_expected, trace))
}
pub fn in_snapshot(&self) -> bool {
......@@ -663,31 +818,13 @@ pub fn next_float_var(&mut self) -> ty::t {
ty::mk_float_var(self.tcx, self.next_float_var_id())
}
pub fn next_region_var_nb(&mut self, span: span) -> ty::Region {
ty::re_infer(ty::ReVar(self.region_vars.new_region_var(span)))
}
pub fn next_region_var_with_lb(&mut self,
span: span,
lb_region: ty::Region)
-> ty::Region {
let region_var = self.next_region_var_nb(span);
// add lb_region as a lower bound on the newly built variable
assert!(self.region_vars.make_subregion(span,
lb_region,
region_var).is_ok());
return region_var;
pub fn next_region_var(&mut self, origin: RegionVariableOrigin) -> ty::Region {
ty::re_infer(ty::ReVar(self.region_vars.new_region_var(origin)))
}
pub fn next_region_var(&mut self, span: span, scope_id: ast::node_id)
-> ty::Region {
self.next_region_var_with_lb(span, ty::re_scope(scope_id))
}
pub fn resolve_regions(&mut self) {
self.region_vars.resolve_regions();
pub fn resolve_regions(@mut self) {
let errors = self.region_vars.resolve_regions();
self.report_region_errors(&errors); // see error_reporting.rs
}
pub fn ty_to_str(@mut self, t: ty::t) -> ~str {
......@@ -809,17 +946,13 @@ pub fn report_mismatched_types(@mut self,
}
pub fn replace_bound_regions_with_fresh_regions(&mut self,
span: span,
trace: SubtypeTrace,
fsig: &ty::FnSig)
-> (ty::FnSig,
isr_alist) {
-> (ty::FnSig, isr_alist) {
let(isr, _, fn_sig) =
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
// debug message.
let rvar = self.next_region_var_nb(span);
let rvar = self.next_region_var(
BoundRegionInFnType(trace.origin.span(), br));
debug!("Bound region %s maps to %?",
bound_region_to_str(self.tcx, "", false, br),
rvar);
......@@ -838,3 +971,121 @@ pub fn fold_regions_in_sig(
ty::fold_regions(tcx, t, |r, in_fn| fldr(r, in_fn))
}
}
impl SubtypeTrace {
pub fn span(&self) -> span {
self.origin.span()
}
}
impl Repr for SubtypeTrace {
fn repr(&self, tcx: ty::ctxt) -> ~str {
fmt!("SubtypeTrace(%s)", self.origin.repr(tcx))
}
}
impl SubtypeOrigin {
pub fn span(&self) -> span {
match *self {
MethodCompatCheck(span) => span,
ExprAssignable(expr) => expr.span,
Misc(span) => span,
RelateTraitRefs(span) => span,
RelateSelfType(span) => span,
}
}
}
impl Repr for SubtypeOrigin {
fn repr(&self, tcx: ty::ctxt) -> ~str {
match *self {
MethodCompatCheck(a) => fmt!("MethodCompatCheck(%s)", a.repr(tcx)),
ExprAssignable(a) => fmt!("ExprAssignable(%s)", a.repr(tcx)),
Misc(a) => fmt!("Misc(%s)", a.repr(tcx)),
RelateTraitRefs(a) => fmt!("RelateTraitRefs(%s)", a.repr(tcx)),
RelateSelfType(a) => fmt!("RelateSelfType(%s)", a.repr(tcx)),
}
}
}
impl SubregionOrigin {
pub fn span(&self) -> span {
match *self {
Subtype(a) => a.span(),
InvokeClosure(a) => a,
DerefPointer(a) => a,
FreeVariable(a) => a,
IndexSlice(a) => a,
RelateObjectBound(a) => a,
Reborrow(a) => a,
ReferenceOutlivesReferent(_, a) => a,
BindingTypeIsNotValidAtDecl(a) => a,
CallRcvr(a) => a,
CallArg(a) => a,
CallReturn(a) => a,
AddrOf(a) => a,
AutoBorrow(a) => a,
}
}
}
impl Repr for SubregionOrigin {
fn repr(&self, tcx: ty::ctxt) -> ~str {
match *self {
Subtype(a) => fmt!("Subtype(%s)", a.repr(tcx)),
InvokeClosure(a) => fmt!("InvokeClosure(%s)", a.repr(tcx)),
DerefPointer(a) => fmt!("DerefPointer(%s)", a.repr(tcx)),
FreeVariable(a) => fmt!("FreeVariable(%s)", a.repr(tcx)),
IndexSlice(a) => fmt!("IndexSlice(%s)", a.repr(tcx)),
RelateObjectBound(a) => fmt!("RelateObjectBound(%s)", a.repr(tcx)),
Reborrow(a) => fmt!("Reborrow(%s)", a.repr(tcx)),
ReferenceOutlivesReferent(_, a) => fmt!("ReferenceOutlivesReferent(%s)", a.repr(tcx)),
BindingTypeIsNotValidAtDecl(a) => fmt!("BindingTypeIsNotValidAtDecl(%s)", a.repr(tcx)),
CallRcvr(a) => fmt!("CallRcvr(%s)", a.repr(tcx)),
CallArg(a) => fmt!("CallArg(%s)", a.repr(tcx)),
CallReturn(a) => fmt!("CallReturn(%s)", a.repr(tcx)),
AddrOf(a) => fmt!("AddrOf(%s)", a.repr(tcx)),
AutoBorrow(a) => fmt!("AutoBorrow(%s)", a.repr(tcx)),
}
}
}
impl RegionVariableOrigin {
pub fn span(&self) -> span {
match *self {
MiscVariable(a) => a,
PatternRegion(a) => a,
AddrOfRegion(a) => a,
AddrOfSlice(a) => a,
Autoref(a) => a,
Coercion(a) => a.span(),
BoundRegionInFnCall(a, _) => a,
BoundRegionInFnType(a, _) => a,
BoundRegionInTypeOrImpl(a) => a,
BoundRegionInCoherence => codemap::dummy_sp(),
BoundRegionError(a) => a,
}
}
}
impl Repr for RegionVariableOrigin {
fn repr(&self, tcx: ty::ctxt) -> ~str {
match *self {
MiscVariable(a) => fmt!("MiscVariable(%s)", a.repr(tcx)),
PatternRegion(a) => fmt!("PatternRegion(%s)", a.repr(tcx)),
AddrOfRegion(a) => fmt!("AddrOfRegion(%s)", a.repr(tcx)),
AddrOfSlice(a) => fmt!("AddrOfSlice(%s)", a.repr(tcx)),
Autoref(a) => fmt!("Autoref(%s)", a.repr(tcx)),
Coercion(a) => fmt!("Coercion(%s)", a.repr(tcx)),
BoundRegionInFnCall(a, b) => fmt!("BoundRegionInFnCall(%s,%s)",
a.repr(tcx), b.repr(tcx)),
BoundRegionInFnType(a, b) => fmt!("BoundRegionInFnType(%s,%s)",
a.repr(tcx), b.repr(tcx)),
BoundRegionInTypeOrImpl(a) => fmt!("BoundRegionInTypeOrImpl(%s)",
a.repr(tcx)),
BoundRegionInCoherence => fmt!("BoundRegionInCoherence"),
BoundRegionError(a) => fmt!("BoundRegionError(%s)", a.repr(tcx)),
}
}
}
......@@ -20,6 +20,7 @@
use middle::typeck::infer::lattice::CombineFieldsLatticeMethods;
use middle::typeck::infer::lub::Lub;
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::{SubtypeTrace, Subtype};
use util::common::{indent, indenter};
use util::ppaux::bound_region_to_str;
......@@ -36,7 +37,7 @@ impl Combine for Sub {
fn infcx(&self) -> @mut InferCtxt { self.infcx }
fn tag(&self) -> ~str { ~"sub" }
fn a_is_expected(&self) -> bool { self.a_is_expected }
fn span(&self) -> span { self.span }
fn trace(&self) -> SubtypeTrace { self.trace }
fn sub(&self) -> Sub { Sub(**self) }
fn lub(&self) -> Lub { Lub(**self) }
......@@ -62,12 +63,8 @@ fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
self.tag(),
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),
Err(ref e) => Err((*e))
}
}
self.infcx.region_vars.make_subregion(Subtype(self.trace), a, b);
Ok(a)
}
fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
......@@ -170,7 +167,7 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
// region variable.
let (a_sig, _) =
self.infcx.replace_bound_regions_with_fresh_regions(
self.span, a);
self.trace, a);
// Second, we instantiate each bound region in the supertype with a
// fresh concrete region.
......
......@@ -263,7 +263,7 @@ pub fn require_same_types(
}
}
match infer::mk_eqty(l_infcx, t1_is_expected, span, t1, t2) {
match infer::mk_eqty(l_infcx, t1_is_expected, infer::Misc(span), t1, t2) {
result::Ok(()) => true,
result::Err(ref terr) => {
l_tcx.sess.span_err(span, msg() + ": " +
......
......@@ -608,6 +608,12 @@ fn repr(&self, tcx: ctxt) -> ~str {
}
}
impl Repr for ty::bound_region {
fn repr(&self, tcx: ctxt) -> ~str {
bound_region_to_str(tcx, *self)
}
}
impl Repr for ty::Region {
fn repr(&self, tcx: ctxt) -> ~str {
region_to_str(tcx, "", false, *self)
......@@ -793,6 +799,19 @@ fn repr(&self, tcx: ctxt) -> ~str {
}
}
impl Repr for span {
fn repr(&self, tcx: ctxt) -> ~str {
tcx.sess.codemap.span_to_str(*self)
}
}
impl<A:UserString> UserString for @A {
fn user_string(&self, tcx: ctxt) -> ~str {
let this: &A = &**self;
this.user_string(tcx)
}
}
impl UserString for ty::BuiltinBounds {
fn user_string(&self, tcx: ctxt) -> ~str {
if self.is_empty() { ~"<no-bounds>" } else {
......
......@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern: reference is not valid outside of its lifetime
// error-pattern: lifetime of return value does not outlive the function call
extern mod extra;
use extra::arc;
fn main() {
......
......@@ -8,14 +8,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern: reference is not valid outside of its lifetime
extern mod extra;
use extra::arc;
fn main() {
let x = ~arc::RWARC(1);
let mut y = None;
let mut y = None; //~ ERROR lifetime of variable does not enclose its declaration
do x.write |one| {
y = Some(one);
}
*y.unwrap() = 2;
//~^ ERROR lifetime of return value does not outlive the function call
//~^^ ERROR dereference of reference outside its lifetime
}
......@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern: reference is not valid outside of its lifetime
// error-pattern: lifetime of variable does not enclose its declaration
extern mod extra;
use extra::arc;
fn main() {
......
......@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern: reference is not valid outside of its lifetime
// error-pattern: lifetime of variable does not enclose its declaration
extern mod extra;
use extra::arc;
fn main() {
......
extern mod extra;
fn main() {
pub fn main() {
let foo = ~3;
let _pfoo = &foo;
let _f: @fn() -> int = || *foo + 5;
......
......@@ -23,13 +23,13 @@ fn main() {
// Error results because the type of is inferred to be
// @repeat<&'blk int> where blk is the lifetime of the block below.
let y = { //~ ERROR reference is not valid
let y = { //~ ERROR lifetime of variable does not enclose its declaration
let x: &'blk int = &3;
repeater(@x)
};
assert!(3 == *(y.get())); //~ ERROR dereference of reference outside its lifetime
//~^ ERROR reference is not valid outside of its lifetime
//~^^ ERROR reference is not valid outside of its lifetime
//~^^^ ERROR reference is not valid outside of its lifetime
assert!(3 == *(y.get()));
//~^ ERROR dereference of reference outside its lifetime
//~^^ ERROR automatically borrowed pointer is not valid at the time of borrow
//~^^^ ERROR lifetime of return value does not outlive the function call
//~^^^^ ERROR cannot infer an appropriate lifetime
}
......@@ -16,11 +16,13 @@
struct a_class<'self> { x:&'self int }
fn a_fn1<'a,'b>(e: an_enum<'a>) -> an_enum<'b> {
return e; //~ ERROR mismatched types: expected `an_enum<'b>` but found `an_enum<'a>`
return e; //~ ERROR mismatched types: expected `an_enum<'b> ` but found `an_enum<'a> `
//~^ ERROR cannot infer an appropriate lifetime
}
fn a_fn3<'a,'b>(e: a_class<'a>) -> a_class<'b> {
return e; //~ ERROR mismatched types: expected `a_class<'b>` but found `a_class<'a>`
return e; //~ ERROR mismatched types: expected `a_class<'b> ` but found `a_class<'a> `
//~^ ERROR cannot infer an appropriate lifetime
}
fn a_fn4<'a,'b>() {
......
......@@ -15,6 +15,6 @@ fn with_int(f: &fn(x: &int)) {
fn main() {
let mut x = None;
//~^ ERROR reference is not valid outside of its lifetime
//~^ ERROR lifetime of variable does not enclose its declaration
with_int(|y| x = Some(y));
}
......@@ -23,7 +23,7 @@ fn with<R:deref>(f: &fn(x: &int) -> R) -> int {
}
fn return_it() -> int {
with(|o| o) //~ ERROR reference is not valid outside of its lifetime
with(|o| o) //~ ERROR lifetime of function argument does not outlive the function call
}
fn main() {
......
......@@ -20,7 +20,10 @@ struct not_parameterized2 {
g: @fn()
}
fn take1(p: parameterized1) -> parameterized1 { p } //~ ERROR mismatched types
fn take1(p: parameterized1) -> parameterized1 { p }
//~^ ERROR mismatched types
//~^^ ERROR cannot infer an appropriate lifetime
fn take3(p: not_parameterized1) -> not_parameterized1 { p }
fn take4(p: not_parameterized2) -> not_parameterized2 { p }
......
......@@ -22,6 +22,7 @@ fn to_same_lifetime<'r>(bi: covariant<'r>) {
fn to_shorter_lifetime<'r>(bi: covariant<'r>) {
let bj: covariant<'blk> = bi; //~ ERROR mismatched types
//~^ ERROR cannot infer an appropriate lifetime
}
fn to_longer_lifetime<'r>(bi: covariant<'r>) -> covariant<'static> {
......
......@@ -23,6 +23,11 @@ struct indirect2<'self> {
}
fn take_direct(p: direct) -> direct { p } //~ ERROR mismatched types
//~^ ERROR cannot infer an appropriate lifetime
fn take_indirect1(p: indirect1) -> indirect1 { p }
fn take_indirect2(p: indirect2) -> indirect2 { p } //~ ERROR mismatched types
//~^ ERROR cannot infer an appropriate lifetime
fn main() {}
......@@ -30,6 +30,7 @@ fn set_f_ok(&self, b: @b<'self>) {
fn set_f_bad(&self, b: @b) {
self.f = b; //~ ERROR mismatched types: expected `@@&'self int` but found `@@&int`
//~^ ERROR cannot infer an appropriate lifetime
}
}
......
......@@ -22,6 +22,7 @@ fn nested<'x>(x: &'x int) {
ignore::<&fn<'z>(&'z int) -> &'z int>(|z| {
if false { return x; } //~ ERROR mismatched types
//~^ ERROR cannot infer an appropriate lifetime
if false { return ay; }
return z;
});
......
......@@ -18,6 +18,8 @@ fn with<'a, R>(f: &fn(x: &'a int) -> R) -> R {
fn return_it<'a>() -> &'a int {
with(|o| o) //~ ERROR mismatched types
//~^ ERROR lifetime of return value does not outlive the function call
//~^^ ERROR cannot infer an appropriate lifetime
}
fn main() {
......
......@@ -21,6 +21,8 @@ fn with<R>(f: &fn(x: &int) -> R) -> R {
fn return_it() -> &int {
with(|o| o) //~ ERROR mismatched types
//~^ ERROR lifetime of return value does not outlive the function call
//~^^ ERROR cannot infer an appropriate lifetime
}
fn main() {
......
......@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern: reference is not valid outside of its lifetime
// error-pattern: lifetime of variable does not enclose its declaration
extern mod extra;
use extra::sync;
......
......@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern: reference is not valid outside of its lifetime
// error-pattern: lifetime of method receiver does not outlive the method call
extern mod extra;
use extra::sync;
fn main() {
......
......@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern: reference is not valid outside of its lifetime
// error-pattern: lifetime of variable does not enclose its declaration
extern mod extra;
use extra::sync;
fn main() {
......
......@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern: reference is not valid outside of its lifetime
// error-pattern: lifetime of variable does not enclose its declaration
extern mod extra;
use extra::sync;
fn main() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册