Skip to content

Commit

Permalink
Defer reasoning about region relationships until after regionck.
Browse files Browse the repository at this point in the history
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 rust-lang#3238.
  • Loading branch information
nikomatsakis committed Jul 2, 2013
1 parent e482856 commit 9e6d5e1
Show file tree
Hide file tree
Showing 39 changed files with 1,211 additions and 522 deletions.
14 changes: 5 additions & 9 deletions src/librustc/middle/typeck/check/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use middle::typeck::check::demand;
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};
Expand All @@ -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);}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/typeck/check/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand All @@ -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);
Expand Down
17 changes: 12 additions & 5 deletions src/librustc/middle/typeck/check/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,14 +619,18 @@ impl<'self> LookupContext<'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,
Expand Down Expand Up @@ -758,7 +762,9 @@ impl<'self> LookupContext<'self> {
-> 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) {
Expand Down Expand Up @@ -970,7 +976,8 @@ impl<'self> LookupContext<'self> {
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));
Expand All @@ -982,7 +989,7 @@ impl<'self> LookupContext<'self> {
// 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(_) => {
Expand Down
64 changes: 38 additions & 26 deletions src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,8 +467,6 @@ pub fn check_fn(ccx: @mut CrateCtxt,
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);
}
Expand Down Expand Up @@ -686,9 +684,14 @@ impl FnCtxt {
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))
}
})
}
}
Expand All @@ -698,7 +701,7 @@ impl FnCtxt {

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)
Expand Down Expand Up @@ -845,21 +848,28 @@ impl FnCtxt {

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)
-> Result<(), ty::type_err> {
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)) => {
Expand All @@ -876,20 +886,19 @@ impl FnCtxt {

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)
Expand All @@ -905,7 +914,9 @@ impl FnCtxt {
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,
Expand Down Expand Up @@ -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
};
Expand Down Expand Up @@ -1352,7 +1364,8 @@ pub fn check_expr_with_unifier(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,
Expand Down Expand Up @@ -2085,7 +2098,7 @@ pub fn check_expr_with_unifier(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 {
Expand Down Expand Up @@ -2395,7 +2408,8 @@ pub fn check_expr_with_unifier(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) {
Expand Down Expand Up @@ -2437,7 +2451,7 @@ pub fn check_expr_with_unifier(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(_) => {
Expand Down Expand Up @@ -2686,7 +2700,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
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()
}
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
}
}
Expand Down
Loading

0 comments on commit 9e6d5e1

Please sign in to comment.