Skip to content

Commit 2299235

Browse files
committed
Auto merge of rust-lang#22436 - nikomatsakis:issue-22246-bound-lifetimes-of-assoc-types, r=nikomatsakis
Take 2. This PR includes a bunch of refactoring that was part of an experimental branch implementing [implied bounds]. That particular idea isn't ready to go yet, but the refactoring proved useful for fixing rust-lang#22246. The implied bounds branch also exposed rust-lang#22110 so a simple fix for that is included here. I still think some more refactoring would be a good idea here -- in particular I think most of the code in wf.rs is kind of duplicating the logic in implicator and should go, but I decided to post this PR and call it a day before diving into that. I'll write a bit more details about the solutions I adopted in the various bugs. I patched the two issues I was concerned about, which was the handling of supertraits and HRTB (the latter turned out to be fine, so I added a comment explaining why.) r? @pnkfelix (for now, anyway) cc @aturon [implied bounds]: http://smallcultfollowing.com/babysteps/blog/2014/07/06/implied-bounds/
2 parents dfc5c0f + 9bb3b37 commit 2299235

23 files changed

+684
-296
lines changed

Diff for: src/librustc/middle/expr_use_visitor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -838,7 +838,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
838838
// the method call infrastructure should have
839839
// replaced all late-bound regions with variables:
840840
let self_ty = ty::ty_fn_sig(method_ty).input(0);
841-
let self_ty = ty::assert_no_late_bound_regions(self.tcx(), &self_ty);
841+
let self_ty = ty::no_late_bound_regions(self.tcx(), &self_ty).unwrap();
842842

843843
let (m, r) = match self_ty.sty {
844844
ty::ty_rptr(r, ref m) => (m.mutbl, r),

Diff for: src/librustc/middle/infer/unify.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ impl<K:UnifyKey> UnificationTable<K> {
212212
}
213213
}
214214

215-
impl<K> sv::SnapshotVecDelegate for Delegate<K> {
215+
impl<K:UnifyKey> sv::SnapshotVecDelegate for Delegate<K> {
216216
type Value = VarValue<K>;
217217
type Undo = ();
218218

Diff for: src/librustc/middle/mem_categorization.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,6 @@ pub type McResult<T> = Result<T, ()>;
281281
/// know that no errors have occurred, so we simply consult the tcx and we
282282
/// can be sure that only `Ok` results will occur.
283283
pub trait Typer<'tcx> : ty::ClosureTyper<'tcx> {
284-
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>;
285284
fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>>;
286285
fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>>;
287286
fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool;
@@ -905,8 +904,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
905904
let base_cmt = match method_ty {
906905
Some(method_ty) => {
907906
let ref_ty =
908-
ty::assert_no_late_bound_regions(
909-
self.tcx(), &ty::ty_fn_ret(method_ty)).unwrap();
907+
ty::no_late_bound_regions(
908+
self.tcx(), &ty::ty_fn_ret(method_ty)).unwrap().unwrap();
910909
self.cat_rvalue_node(node.id(), node.span(), ref_ty)
911910
}
912911
None => base_cmt
@@ -996,7 +995,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
996995

997996
// FIXME(#20649) -- why are we using the `self_ty` as the element type...?
998997
let self_ty = ty::ty_fn_sig(method_ty).input(0);
999-
ty::assert_no_late_bound_regions(self.tcx(), &self_ty)
998+
ty::no_late_bound_regions(self.tcx(), &self_ty).unwrap()
1000999
}
10011000
None => {
10021001
match ty::array_element_ty(self.tcx(), base_cmt.ty) {
@@ -1336,8 +1335,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
13361335
// types are generated by method resolution and always have
13371336
// all late-bound regions fully instantiated, so we just want
13381337
// to skip past the binder.
1339-
ty::assert_no_late_bound_regions(self.tcx(), &ty::ty_fn_ret(method_ty))
1340-
.unwrap() // overloaded ops do not diverge, either
1338+
ty::no_late_bound_regions(self.tcx(), &ty::ty_fn_ret(method_ty))
1339+
.unwrap()
1340+
.unwrap() // overloaded ops do not diverge, either
13411341
}
13421342
}
13431343

Diff for: src/librustc/middle/traits/fulfill.rs

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
// except according to those terms.
1010

1111
use middle::infer::{InferCtxt};
12-
use middle::mem_categorization::Typer;
1312
use middle::ty::{self, RegionEscape, Ty};
1413
use std::collections::HashSet;
1514
use std::collections::hash_map::Entry::{Occupied, Vacant};

Diff for: src/librustc/middle/traits/mod.rs

+33-14
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ pub use self::FulfillmentErrorCode::*;
1515
pub use self::Vtable::*;
1616
pub use self::ObligationCauseCode::*;
1717

18-
use middle::mem_categorization::Typer;
1918
use middle::subst;
20-
use middle::ty::{self, Ty};
19+
use middle::ty::{self, HasProjectionTypes, Ty};
20+
use middle::ty_fold::TypeFoldable;
2121
use middle::infer::{self, InferCtxt};
2222
use std::slice::Iter;
2323
use std::rc::Rc;
@@ -432,25 +432,44 @@ pub fn normalize_param_env<'a,'tcx>(param_env: &ty::ParameterEnvironment<'a,'tcx
432432
debug!("normalize_param_env(param_env={})",
433433
param_env.repr(tcx));
434434

435-
let predicates: Vec<ty::Predicate<'tcx>> = {
436-
let infcx = infer::new_infer_ctxt(tcx);
437-
let mut selcx = &mut SelectionContext::new(&infcx, param_env);
438-
let mut fulfill_cx = FulfillmentContext::new();
439-
let Normalized { value: predicates, obligations } =
440-
project::normalize(selcx, cause, &param_env.caller_bounds);
441-
for obligation in obligations {
442-
fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation);
443-
}
444-
try!(fulfill_cx.select_all_or_error(selcx.infcx(), param_env));
445-
predicates.iter().map(|p| infcx.resolve_type_vars_if_possible(p)).collect()
446-
};
435+
let infcx = infer::new_infer_ctxt(tcx);
436+
let predicates = try!(fully_normalize(&infcx, param_env, cause, &param_env.caller_bounds));
447437

448438
debug!("normalize_param_env: predicates={}",
449439
predicates.repr(tcx));
450440

451441
Ok(param_env.with_caller_bounds(predicates))
452442
}
453443

444+
pub fn fully_normalize<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
445+
closure_typer: &ty::ClosureTyper<'tcx>,
446+
cause: ObligationCause<'tcx>,
447+
value: &T)
448+
-> Result<T, Vec<FulfillmentError<'tcx>>>
449+
where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone + Repr<'tcx>
450+
{
451+
let tcx = closure_typer.tcx();
452+
453+
debug!("normalize_param_env(value={})",
454+
value.repr(tcx));
455+
456+
let mut selcx = &mut SelectionContext::new(infcx, closure_typer);
457+
let mut fulfill_cx = FulfillmentContext::new();
458+
let Normalized { value: normalized_value, obligations } =
459+
project::normalize(selcx, cause, value);
460+
debug!("normalize_param_env: normalized_value={} obligations={}",
461+
normalized_value.repr(tcx),
462+
obligations.repr(tcx));
463+
for obligation in obligations {
464+
fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation);
465+
}
466+
try!(fulfill_cx.select_all_or_error(infcx, closure_typer));
467+
let resolved_value = infcx.resolve_type_vars_if_possible(&normalized_value);
468+
debug!("normalize_param_env: resolved_value={}",
469+
resolved_value.repr(tcx));
470+
Ok(resolved_value)
471+
}
472+
454473
impl<'tcx,O> Obligation<'tcx,O> {
455474
pub fn new(cause: ObligationCause<'tcx>,
456475
trait_ref: O)

Diff for: src/librustc/middle/traits/select.rs

+14-58
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ use super::object_safety;
3232
use super::{util};
3333

3434
use middle::fast_reject;
35-
use middle::mem_categorization::Typer;
3635
use middle::subst::{Subst, Substs, TypeSpace, VecPerParamSpace};
3736
use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
3837
use middle::infer;
@@ -653,8 +652,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
653652
let is_dup =
654653
(0..candidates.len())
655654
.filter(|&j| i != j)
656-
.any(|j| self.candidate_should_be_dropped_in_favor_of(stack,
657-
&candidates[i],
655+
.any(|j| self.candidate_should_be_dropped_in_favor_of(&candidates[i],
658656
&candidates[j]));
659657
if is_dup {
660658
debug!("Dropping candidate #{}/{}: {}",
@@ -1236,31 +1234,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12361234
self.evaluate_predicates_recursively(stack, selection.iter_nested())
12371235
}
12381236

1239-
/// Returns true if `candidate_i` should be dropped in favor of `candidate_j`.
1240-
///
1241-
/// This is generally true if either:
1242-
/// - candidate i and candidate j are equivalent; or,
1243-
/// - candidate i is a concrete impl and candidate j is a where clause bound,
1244-
/// and the concrete impl is applicable to the types in the where clause bound.
1245-
///
1246-
/// The last case refers to cases where there are blanket impls (often conditional
1247-
/// blanket impls) as well as a where clause. This can come down to one of two cases:
1248-
///
1249-
/// - The impl is truly unconditional (it has no where clauses
1250-
/// of its own), in which case the where clause is
1251-
/// unnecessary, because coherence requires that we would
1252-
/// pick that particular impl anyhow (at least so long as we
1253-
/// don't have specialization).
1254-
///
1255-
/// - The impl is conditional, in which case we may not have winnowed it out
1256-
/// because we don't know if the conditions apply, but the where clause is basically
1257-
/// telling us that there is some impl, though not necessarily the one we see.
1258-
///
1259-
/// In both cases we prefer to take the where clause, which is
1260-
/// essentially harmless. See issue #18453 for more details of
1261-
/// a case where doing the opposite caused us harm.
1237+
/// Returns true if `candidate_i` should be dropped in favor of
1238+
/// `candidate_j`. Generally speaking we will drop duplicate
1239+
/// candidates and prefer where-clause candidates.
12621240
fn candidate_should_be_dropped_in_favor_of<'o>(&mut self,
1263-
stack: &TraitObligationStack<'o, 'tcx>,
12641241
candidate_i: &SelectionCandidate<'tcx>,
12651242
candidate_j: &SelectionCandidate<'tcx>)
12661243
-> bool
@@ -1270,37 +1247,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12701247
}
12711248

12721249
match (candidate_i, candidate_j) {
1273-
(&ImplCandidate(impl_def_id), &ParamCandidate(ref bound)) => {
1274-
debug!("Considering whether to drop param {} in favor of impl {}",
1275-
candidate_i.repr(self.tcx()),
1276-
candidate_j.repr(self.tcx()));
1277-
1278-
self.infcx.probe(|snapshot| {
1279-
let (skol_obligation_trait_ref, skol_map) =
1280-
self.infcx().skolemize_late_bound_regions(
1281-
&stack.obligation.predicate, snapshot);
1282-
let impl_substs =
1283-
self.rematch_impl(impl_def_id, stack.obligation, snapshot,
1284-
&skol_map, skol_obligation_trait_ref.trait_ref.clone());
1285-
let impl_trait_ref =
1286-
ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap();
1287-
let impl_trait_ref =
1288-
impl_trait_ref.subst(self.tcx(), &impl_substs.value);
1289-
let poly_impl_trait_ref =
1290-
ty::Binder(impl_trait_ref);
1291-
let origin =
1292-
infer::RelateOutputImplTypes(stack.obligation.cause.span);
1293-
self.infcx
1294-
.sub_poly_trait_refs(false, origin, poly_impl_trait_ref, bound.clone())
1295-
.is_ok()
1296-
})
1297-
}
1298-
(&BuiltinCandidate(_), &ParamCandidate(_)) => {
1299-
// If we have a where-clause like `Option<K> : Send`,
1300-
// then we wind up in a situation where there is a
1301-
// default rule (`Option<K>:Send if K:Send) and the
1302-
// where-clause that both seem applicable. Just take
1303-
// the where-clause in that case.
1250+
(&ImplCandidate(..), &ParamCandidate(..)) |
1251+
(&ClosureCandidate(..), &ParamCandidate(..)) |
1252+
(&FnPointerCandidate(..), &ParamCandidate(..)) |
1253+
(&BuiltinCandidate(..), &ParamCandidate(..)) => {
1254+
// We basically prefer always prefer to use a
1255+
// where-clause over another option. Where clauses
1256+
// impose the burden of finding the exact match onto
1257+
// the caller. Using an impl in preference of a where
1258+
// clause can also lead us to "overspecialize", as in
1259+
// #18453.
13041260
true
13051261
}
13061262
(&ProjectionCandidate, &ParamCandidate(_)) => {

Diff for: src/librustc/middle/ty.rs

+14-11
Original file line numberDiff line numberDiff line change
@@ -2337,6 +2337,10 @@ impl ClosureKind {
23372337
}
23382338

23392339
pub trait ClosureTyper<'tcx> {
2340+
fn tcx(&self) -> &ty::ctxt<'tcx> {
2341+
self.param_env().tcx
2342+
}
2343+
23402344
fn param_env<'a>(&'a self) -> &'a ty::ParameterEnvironment<'a, 'tcx>;
23412345

23422346
/// Is this a `Fn`, `FnMut` or `FnOnce` closure? During typeck,
@@ -4384,8 +4388,8 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
43844388
// overloaded deref operators have all late-bound
43854389
// regions fully instantiated and coverge
43864390
let fn_ret =
4387-
ty::assert_no_late_bound_regions(cx,
4388-
&ty_fn_ret(method_ty));
4391+
ty::no_late_bound_regions(cx,
4392+
&ty_fn_ret(method_ty)).unwrap();
43894393
adjusted_ty = fn_ret.unwrap();
43904394
}
43914395
None => {}
@@ -5186,7 +5190,7 @@ impl<'tcx> VariantInfo<'tcx> {
51865190
let arg_tys = if args.len() > 0 {
51875191
// the regions in the argument types come from the
51885192
// enum def'n, and hence will all be early bound
5189-
ty::assert_no_late_bound_regions(cx, &ty_fn_args(ctor_ty))
5193+
ty::no_late_bound_regions(cx, &ty_fn_args(ctor_ty)).unwrap()
51905194
} else {
51915195
Vec::new()
51925196
};
@@ -6463,10 +6467,6 @@ impl<'tcx> ctxt<'tcx> {
64636467
}
64646468

64656469
impl<'a,'tcx> mc::Typer<'tcx> for ParameterEnvironment<'a,'tcx> {
6466-
fn tcx(&self) -> &ty::ctxt<'tcx> {
6467-
self.tcx
6468-
}
6469-
64706470
fn node_ty(&self, id: ast::NodeId) -> mc::McResult<Ty<'tcx>> {
64716471
Ok(ty::node_id_to_type(self.tcx, id))
64726472
}
@@ -6677,14 +6677,17 @@ pub fn binds_late_bound_regions<'tcx, T>(
66776677
count_late_bound_regions(tcx, value) > 0
66786678
}
66796679

6680-
pub fn assert_no_late_bound_regions<'tcx, T>(
6680+
pub fn no_late_bound_regions<'tcx, T>(
66816681
tcx: &ty::ctxt<'tcx>,
66826682
value: &Binder<T>)
6683-
-> T
6683+
-> Option<T>
66846684
where T : TypeFoldable<'tcx> + Repr<'tcx> + Clone
66856685
{
6686-
assert!(!binds_late_bound_regions(tcx, value));
6687-
value.0.clone()
6686+
if binds_late_bound_regions(tcx, value) {
6687+
None
6688+
} else {
6689+
Some(value.0.clone())
6690+
}
66886691
}
66896692

66906693
/// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also

Diff for: src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs

-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use borrowck::gather_loans::move_error::{MoveError, MoveErrorCollector};
1616
use borrowck::move_data::*;
1717
use rustc::middle::expr_use_visitor as euv;
1818
use rustc::middle::mem_categorization as mc;
19-
use rustc::middle::mem_categorization::Typer;
2019
use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
2120
use rustc::middle::ty;
2221
use rustc::util::ppaux::Repr;

Diff for: src/librustc_borrowck/borrowck/gather_loans/move_error.rs

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
use borrowck::BorrowckCtxt;
1212
use rustc::middle::mem_categorization as mc;
13-
use rustc::middle::mem_categorization::Typer;
1413
use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
1514
use rustc::middle::ty;
1615
use rustc::util::ppaux::UserString;

Diff for: src/librustc_trans/trans/common.rs

-4
Original file line numberDiff line numberDiff line change
@@ -637,10 +637,6 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> {
637637
}
638638

639639
impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> {
640-
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
641-
self.tcx()
642-
}
643-
644640
fn node_ty(&self, id: ast::NodeId) -> mc::McResult<Ty<'tcx>> {
645641
Ok(node_id_type(self, id))
646642
}

Diff for: src/librustc_trans/trans/expr.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -781,8 +781,8 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
781781
let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
782782

783783
let ref_ty = // invoked methods have LB regions instantiated:
784-
ty::assert_no_late_bound_regions(
785-
bcx.tcx(), &ty::ty_fn_ret(method_ty)).unwrap();
784+
ty::no_late_bound_regions(
785+
bcx.tcx(), &ty::ty_fn_ret(method_ty)).unwrap().unwrap();
786786
let elt_ty = match ty::deref(ref_ty, true) {
787787
None => {
788788
bcx.tcx().sess.span_bug(index_expr.span,
@@ -2214,8 +2214,8 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
22142214
};
22152215

22162216
let ref_ty = // invoked methods have their LB regions instantiated
2217-
ty::assert_no_late_bound_regions(
2218-
ccx.tcx(), &ty::ty_fn_ret(method_ty)).unwrap();
2217+
ty::no_late_bound_regions(
2218+
ccx.tcx(), &ty::ty_fn_ret(method_ty)).unwrap().unwrap();
22192219
let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref");
22202220

22212221
unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,

Diff for: src/librustc_typeck/check/_match.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
509509
let ctor_scheme = ty::lookup_item_type(tcx, enum_def);
510510
let ctor_predicates = ty::lookup_predicates(tcx, enum_def);
511511
let path_scheme = if ty::is_fn_ty(ctor_scheme.ty) {
512-
let fn_ret = ty::assert_no_late_bound_regions(tcx, &ty::ty_fn_ret(ctor_scheme.ty));
512+
let fn_ret = ty::no_late_bound_regions(tcx, &ty::ty_fn_ret(ctor_scheme.ty)).unwrap();
513513
ty::TypeScheme {
514514
ty: fn_ret.unwrap(),
515515
generics: ctor_scheme.generics,

Diff for: src/librustc_typeck/check/callee.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -367,8 +367,8 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> {
367367
// (This always bites me, should find a way to
368368
// refactor it.)
369369
let method_sig =
370-
ty::assert_no_late_bound_regions(fcx.tcx(),
371-
ty::ty_fn_sig(method_callee.ty));
370+
ty::no_late_bound_regions(fcx.tcx(),
371+
ty::ty_fn_sig(method_callee.ty)).unwrap();
372372

373373
debug!("attempt_resolution: method_callee={}",
374374
method_callee.repr(fcx.tcx()));

0 commit comments

Comments
 (0)