Skip to content

Commit f0f13f8

Browse files
committed
Rather than expanding the where-clauses in the environment over and over
again, do it once and then just remember the expanded form. At the same time, filter globally nameable predicates out of the environment, since they can cause cache errors (and they are not necessary in any case).
1 parent ff89fcf commit f0f13f8

File tree

5 files changed

+79
-23
lines changed

5 files changed

+79
-23
lines changed

src/librustc/middle/traits/mod.rs

+22-7
Original file line numberDiff line numberDiff line change
@@ -414,9 +414,27 @@ pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvi
414414
debug!("normalize_param_env_or_error(unnormalized_env={})",
415415
unnormalized_env.repr(tcx));
416416

417+
let predicates: Vec<_> =
418+
util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.clone())
419+
.filter(|p| !p.is_global()) // (*)
420+
.collect();
421+
422+
// (*) Any predicate like `i32: Trait<u32>` or whatever doesn't
423+
// need to be in the *environment* to be proven, so screen those
424+
// out. This is important for the soundness of inter-fn
425+
// caching. Note though that we should probably check that these
426+
// predicates hold at the point where the environment is
427+
// constructed, but I am not currently doing so out of laziness.
428+
// -nmatsakis
429+
430+
debug!("normalize_param_env_or_error: elaborated-predicates={}",
431+
predicates.repr(tcx));
432+
433+
let elaborated_env = unnormalized_env.with_caller_bounds(predicates);
434+
417435
let infcx = infer::new_infer_ctxt(tcx);
418-
let predicates = match fully_normalize(&infcx, &unnormalized_env, cause,
419-
&unnormalized_env.caller_bounds) {
436+
let predicates = match fully_normalize(&infcx, &elaborated_env, cause,
437+
&elaborated_env.caller_bounds) {
420438
Ok(predicates) => predicates,
421439
Err(errors) => {
422440
report_fulfillment_errors(&infcx, &errors);
@@ -438,14 +456,11 @@ pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvi
438456
// all things considered.
439457
let err_msg = fixup_err_to_string(fixup_err);
440458
tcx.sess.span_err(span, &err_msg);
441-
return unnormalized_env; // an unnormalized env is better than nothing
459+
return elaborated_env; // an unnormalized env is better than nothing
442460
}
443461
};
444462

445-
debug!("normalize_param_env_or_error: predicates={}",
446-
predicates.repr(tcx));
447-
448-
unnormalized_env.with_caller_bounds(predicates)
463+
elaborated_env.with_caller_bounds(predicates)
449464
}
450465

451466
pub fn fully_normalize<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,

src/librustc/middle/traits/project.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ fn assemble_candidates_from_param_env<'cx,'tcx>(
531531
obligation_trait_ref: &ty::TraitRef<'tcx>,
532532
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
533533
{
534-
let env_predicates = selcx.param_env().caller_bounds.clone();
534+
let env_predicates = selcx.param_env().caller_bounds.iter().cloned();
535535
assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref,
536536
candidate_set, env_predicates);
537537
}
@@ -567,22 +567,25 @@ fn assemble_candidates_from_trait_def<'cx,'tcx>(
567567
// If so, extract what we know from the trait and try to come up with a good answer.
568568
let trait_predicates = ty::lookup_predicates(selcx.tcx(), trait_ref.def_id);
569569
let bounds = trait_predicates.instantiate(selcx.tcx(), trait_ref.substs);
570+
let bounds = elaborate_predicates(selcx.tcx(), bounds.predicates.into_vec());
570571
assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref,
571-
candidate_set, bounds.predicates.into_vec());
572+
candidate_set, bounds)
572573
}
573574

574-
fn assemble_candidates_from_predicates<'cx,'tcx>(
575+
fn assemble_candidates_from_predicates<'cx,'tcx,I>(
575576
selcx: &mut SelectionContext<'cx,'tcx>,
576577
obligation: &ProjectionTyObligation<'tcx>,
577578
obligation_trait_ref: &ty::TraitRef<'tcx>,
578579
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
579-
env_predicates: Vec<ty::Predicate<'tcx>>)
580+
env_predicates: I)
581+
where I: Iterator<Item=ty::Predicate<'tcx>>
580582
{
581-
debug!("assemble_candidates_from_predicates(obligation={}, env_predicates={})",
582-
obligation.repr(selcx.tcx()),
583-
env_predicates.repr(selcx.tcx()));
583+
debug!("assemble_candidates_from_predicates(obligation={})",
584+
obligation.repr(selcx.tcx()));
584585
let infcx = selcx.infcx();
585-
for predicate in elaborate_predicates(selcx.tcx(), env_predicates) {
586+
for predicate in env_predicates {
587+
debug!("assemble_candidates_from_predicates: predicate={}",
588+
predicate.repr(selcx.tcx()));
586589
match predicate {
587590
ty::Predicate::Projection(ref data) => {
588591
let same_name = data.item_name() == obligation.predicate.item_name;
@@ -637,6 +640,7 @@ fn assemble_candidates_from_object_type<'cx,'tcx>(
637640
let env_predicates = projection_bounds.iter()
638641
.map(|p| p.as_predicate())
639642
.collect();
643+
let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates);
640644
assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref,
641645
candidate_set, env_predicates)
642646
}

src/librustc/middle/traits/select.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -1083,14 +1083,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10831083
debug!("assemble_candidates_from_caller_bounds({})",
10841084
stack.obligation.repr(self.tcx()));
10851085

1086-
let caller_trait_refs: Vec<_> =
1087-
self.param_env().caller_bounds.iter()
1088-
.filter_map(|o| o.to_opt_poly_trait_ref())
1089-
.collect();
1090-
10911086
let all_bounds =
1092-
util::transitive_bounds(
1093-
self.tcx(), &caller_trait_refs[..]);
1087+
self.param_env().caller_bounds
1088+
.iter()
1089+
.filter_map(|o| o.to_opt_poly_trait_ref());
10941090

10951091
let matching_bounds =
10961092
all_bounds.filter(

src/librustc/middle/ty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2371,7 +2371,7 @@ pub struct ParameterEnvironment<'a, 'tcx:'a> {
23712371

23722372
/// Obligations that the caller must satisfy. This is basically
23732373
/// the set of bounds on the in-scope type parameters, translated
2374-
/// into Obligations.
2374+
/// into Obligations, and elaborated and normalized.
23752375
pub caller_bounds: Vec<ty::Predicate<'tcx>>,
23762376

23772377
/// Caches the results of trait selection. This cache is used
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Check that when there are vacuous predicates in the environment
12+
// (which make a fn uncallable) we don't erroneously cache those and
13+
// then consider them satisfied elsewhere. The current technique for
14+
// doing this is just to filter "global" predicates out of the
15+
// environment, which means that we wind up with an error in the
16+
// function `vacuous`, because even though `i32: Bar<u32>` is implied
17+
// by its where clause, that where clause never holds.
18+
19+
trait Foo<X,Y>: Bar<X> {
20+
}
21+
22+
trait Bar<X> { }
23+
24+
fn vacuous<A>()
25+
where i32: Foo<u32, A>
26+
{
27+
// vacuous could never be called, because it requires that i32:
28+
// Bar<u32>. But the code doesn't check that this could never be
29+
// satisfied.
30+
require::<i32, u32>();
31+
//~^ ERROR the trait `Bar<u32>` is not implemented for the type `i32`
32+
}
33+
34+
fn require<A,B>()
35+
where A: Bar<B>
36+
{
37+
}
38+
39+
fn main() {
40+
require::<i32, u32>();
41+
}

0 commit comments

Comments
 (0)