Skip to content

Commit c61d788

Browse files
committed
Add the notion of normalizing a parameter environment and ensure that
all parameter environments are normalized. Correspondingly, stop normalizing predicates we extract out of the environment. Fixes #21664.
1 parent c73a1d0 commit c61d788

File tree

9 files changed

+203
-63
lines changed

9 files changed

+203
-63
lines changed

src/librustc/middle/traits/mod.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub use self::ObligationCauseCode::*;
1818
use middle::mem_categorization::Typer;
1919
use middle::subst;
2020
use middle::ty::{self, Ty};
21-
use middle::infer::InferCtxt;
21+
use middle::infer::{self, InferCtxt};
2222
use std::slice::Iter;
2323
use std::rc::Rc;
2424
use syntax::ast;
@@ -392,6 +392,52 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
392392
}
393393
}
394394

395+
pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvironment<'a,'tcx>,
396+
cause: ObligationCause<'tcx>)
397+
-> ty::ParameterEnvironment<'a,'tcx>
398+
{
399+
match normalize_param_env(&unnormalized_env, cause) {
400+
Ok(p) => p,
401+
Err(errors) => {
402+
// this isn't really the ideal place to report errors, but it seems ok
403+
let infcx = infer::new_infer_ctxt(unnormalized_env.tcx);
404+
report_fulfillment_errors(&infcx, &errors);
405+
406+
// normalized failed? use what they gave us, it's better than nothing
407+
unnormalized_env
408+
}
409+
}
410+
}
411+
412+
pub fn normalize_param_env<'a,'tcx>(param_env: &ty::ParameterEnvironment<'a,'tcx>,
413+
cause: ObligationCause<'tcx>)
414+
-> Result<ty::ParameterEnvironment<'a,'tcx>,
415+
Vec<FulfillmentError<'tcx>>>
416+
{
417+
let tcx = param_env.tcx;
418+
419+
debug!("normalize_param_env(param_env={})",
420+
param_env.repr(tcx));
421+
422+
let predicates: Vec<ty::Predicate<'tcx>> = {
423+
let infcx = infer::new_infer_ctxt(tcx);
424+
let mut selcx = &mut SelectionContext::new(&infcx, param_env);
425+
let mut fulfill_cx = FulfillmentContext::new();
426+
let Normalized { value: predicates, obligations } =
427+
project::normalize(selcx, cause, &param_env.caller_bounds);
428+
for obligation in obligations.into_iter() {
429+
fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation);
430+
}
431+
try!(fulfill_cx.select_all_or_error(selcx.infcx(), param_env));
432+
predicates.iter().map(|p| infcx.resolve_type_vars_if_possible(p)).collect()
433+
};
434+
435+
debug!("normalize_param_env: predicates={}",
436+
predicates.repr(tcx));
437+
438+
Ok(param_env.with_caller_bounds(predicates))
439+
}
440+
395441
impl<'tcx,O> Obligation<'tcx,O> {
396442
pub fn new(cause: ObligationCause<'tcx>,
397443
trait_ref: O)

src/librustc/middle/traits/object_safety.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,17 +122,15 @@ fn trait_has_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
122122
trait_def_id: ast::DefId)
123123
-> bool
124124
{
125-
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
126-
let param_env = ty::construct_parameter_environment(tcx,
127-
&trait_def.generics,
128-
ast::DUMMY_NODE_ID);
129-
let predicates = param_env.caller_bounds.clone();
130125
let sized_def_id = match tcx.lang_items.sized_trait() {
131126
Some(def_id) => def_id,
132127
None => { return false; /* No Sized trait, can't require it! */ }
133128
};
134129

135130
// Search for a predicate like `Self : Sized` amongst the trait bounds.
131+
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
132+
let free_substs = ty::construct_free_substs(tcx, &trait_def.generics, ast::DUMMY_NODE_ID);
133+
let predicates = trait_def.generics.to_bounds(tcx, &free_substs).predicates.into_vec();
136134
elaborate_predicates(tcx, predicates)
137135
.any(|predicate| {
138136
match predicate {

src/librustc/middle/traits/project.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ struct ProjectionTyCandidateSet<'tcx> {
6060
ambiguous: bool
6161
}
6262

63+
/// Evaluates constraints of the form:
64+
///
65+
/// for<...> <T as Trait>::U == V
66+
///
67+
/// If successful, this may result in additional obligations.
6368
pub fn poly_project_and_unify_type<'cx,'tcx>(
6469
selcx: &mut SelectionContext<'cx,'tcx>,
6570
obligation: &PolyProjectionObligation<'tcx>)
@@ -102,8 +107,11 @@ pub fn poly_project_and_unify_type<'cx,'tcx>(
102107
}
103108
}
104109

105-
/// Compute result of projecting an associated type and unify it with
106-
/// `obligation.predicate.ty` (if we can).
110+
/// Evaluates constraints of the form:
111+
///
112+
/// <T as Trait>::U == V
113+
///
114+
/// If successful, this may result in additional obligations.
107115
fn project_and_unify_type<'cx,'tcx>(
108116
selcx: &mut SelectionContext<'cx,'tcx>,
109117
obligation: &ProjectionObligation<'tcx>)
@@ -133,6 +141,10 @@ fn project_and_unify_type<'cx,'tcx>(
133141
}
134142
}
135143

144+
/// Normalizes any associated type projections in `value`, replacing
145+
/// them with a fully resolved type where possible. The return value
146+
/// combines the normalized result and any additional obligations that
147+
/// were incurred as result.
136148
pub fn normalize<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tcx>,
137149
cause: ObligationCause<'tcx>,
138150
value: &T)
@@ -142,6 +154,7 @@ pub fn normalize<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tcx>,
142154
normalize_with_depth(selcx, cause, 0, value)
143155
}
144156

157+
/// As `normalize`, but with a custom depth.
145158
pub fn normalize_with_depth<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tcx>,
146159
cause: ObligationCause<'tcx>,
147160
depth: uint,
@@ -251,6 +264,12 @@ impl<'tcx,T> Normalized<'tcx,T> {
251264
}
252265
}
253266

267+
/// The guts of `normalize`: normalize a specific projection like `<T
268+
/// as Trait>::Item`. The result is always a type (and possibly
269+
/// additional obligations). If ambiguity arises, which implies that
270+
/// there are unresolved type variables in the projection, we will
271+
/// substitute a fresh type variable `$X` and generate a new
272+
/// obligation `<T as Trait>::Item == $X` for later.
254273
pub fn normalize_projection_type<'a,'b,'tcx>(
255274
selcx: &'a mut SelectionContext<'b,'tcx>,
256275
projection_ty: ty::ProjectionTy<'tcx>,
@@ -277,6 +296,10 @@ pub fn normalize_projection_type<'a,'b,'tcx>(
277296
})
278297
}
279298

299+
/// The guts of `normalize`: normalize a specific projection like `<T
300+
/// as Trait>::Item`. The result is always a type (and possibly
301+
/// additional obligations). Returns `None` in the case of ambiguity,
302+
/// which indicates that there are unbound type variables.
280303
fn opt_normalize_projection_type<'a,'b,'tcx>(
281304
selcx: &'a mut SelectionContext<'b,'tcx>,
282305
projection_ty: ty::ProjectionTy<'tcx>,

src/librustc/middle/traits/select.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2157,16 +2157,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
21572157
where_clause_trait_ref: ty::PolyTraitRef<'tcx>)
21582158
-> Result<Vec<PredicateObligation<'tcx>>,()>
21592159
{
2160-
let where_clause_trait_ref =
2161-
project::normalize_with_depth(self,
2162-
obligation.cause.clone(),
2163-
obligation.recursion_depth+1,
2164-
&where_clause_trait_ref);
2165-
21662160
let () =
2167-
try!(self.match_poly_trait_ref(obligation, where_clause_trait_ref.value.clone()));
2161+
try!(self.match_poly_trait_ref(obligation, where_clause_trait_ref));
21682162

2169-
Ok(where_clause_trait_ref.obligations)
2163+
Ok(Vec::new())
21702164
}
21712165

21722166
/// Returns `Ok` if `poly_trait_ref` being true implies that the

src/librustc/middle/ty.rs

Lines changed: 77 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2084,11 +2084,7 @@ impl<'tcx> TraitRef<'tcx> {
20842084
pub struct ParameterEnvironment<'a, 'tcx:'a> {
20852085
pub tcx: &'a ctxt<'tcx>,
20862086

2087-
/// A substitution that can be applied to move from
2088-
/// the "outer" view of a type or method to the "inner" view.
2089-
/// In general, this means converting from bound parameters to
2090-
/// free parameters. Since we currently represent bound/free type
2091-
/// parameters in the same way, this only has an effect on regions.
2087+
/// See `construct_free_substs` for details.
20922088
pub free_substs: Substs<'tcx>,
20932089

20942090
/// Each type parameter has an implicit region bound that
@@ -2108,6 +2104,19 @@ pub struct ParameterEnvironment<'a, 'tcx:'a> {
21082104
}
21092105

21102106
impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
2107+
pub fn with_caller_bounds(&self,
2108+
caller_bounds: Vec<ty::Predicate<'tcx>>)
2109+
-> ParameterEnvironment<'a,'tcx>
2110+
{
2111+
ParameterEnvironment {
2112+
tcx: self.tcx,
2113+
free_substs: self.free_substs.clone(),
2114+
implicit_region_bound: self.implicit_region_bound,
2115+
caller_bounds: caller_bounds,
2116+
selection_cache: traits::SelectionCache::new(),
2117+
}
2118+
}
2119+
21112120
pub fn for_item(cx: &'a ctxt<'tcx>, id: NodeId) -> ParameterEnvironment<'a, 'tcx> {
21122121
match cx.map.find(id) {
21132122
Some(ast_map::NodeImplItem(ref impl_item)) => {
@@ -2119,6 +2128,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
21192128
let method_generics = &method_ty.generics;
21202129
construct_parameter_environment(
21212130
cx,
2131+
method.span,
21222132
method_generics,
21232133
method.pe_body().id)
21242134
}
@@ -2153,6 +2163,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
21532163
let method_generics = &method_ty.generics;
21542164
construct_parameter_environment(
21552165
cx,
2166+
method.span,
21562167
method_generics,
21572168
method.pe_body().id)
21582169
}
@@ -2179,6 +2190,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
21792190
let fn_pty = ty::lookup_item_type(cx, fn_def_id);
21802191

21812192
construct_parameter_environment(cx,
2193+
item.span,
21822194
&fn_pty.generics,
21832195
body.id)
21842196
}
@@ -2189,7 +2201,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
21892201
ast::ItemStatic(..) => {
21902202
let def_id = ast_util::local_def(id);
21912203
let pty = ty::lookup_item_type(cx, def_id);
2192-
construct_parameter_environment(cx, &pty.generics, id)
2204+
construct_parameter_environment(cx, item.span, &pty.generics, id)
21932205
}
21942206
_ => {
21952207
cx.sess.span_bug(item.span,
@@ -6263,18 +6275,17 @@ pub fn empty_parameter_environment<'a,'tcx>(cx: &'a ctxt<'tcx>) -> ParameterEnvi
62636275
selection_cache: traits::SelectionCache::new(), }
62646276
}
62656277

6266-
/// See `ParameterEnvironment` struct def'n for details
6267-
pub fn construct_parameter_environment<'a,'tcx>(
6278+
/// Constructs and returns a substitution that can be applied to move from
6279+
/// the "outer" view of a type or method to the "inner" view.
6280+
/// In general, this means converting from bound parameters to
6281+
/// free parameters. Since we currently represent bound/free type
6282+
/// parameters in the same way, this only has an effect on regions.
6283+
pub fn construct_free_substs<'a,'tcx>(
62686284
tcx: &'a ctxt<'tcx>,
62696285
generics: &ty::Generics<'tcx>,
62706286
free_id: ast::NodeId)
6271-
-> ParameterEnvironment<'a, 'tcx>
6287+
-> Substs<'tcx>
62726288
{
6273-
6274-
//
6275-
// Construct the free substs.
6276-
//
6277-
62786289
// map T => T
62796290
let mut types = VecPerParamSpace::empty();
62806291
push_types_from_defs(tcx, &mut types, generics.types.as_slice());
@@ -6283,11 +6294,45 @@ pub fn construct_parameter_environment<'a,'tcx>(
62836294
let mut regions = VecPerParamSpace::empty();
62846295
push_region_params(&mut regions, free_id, generics.regions.as_slice());
62856296

6286-
let free_substs = Substs {
6297+
return Substs {
62876298
types: types,
62886299
regions: subst::NonerasedRegions(regions)
62896300
};
62906301

6302+
fn push_region_params(regions: &mut VecPerParamSpace<ty::Region>,
6303+
free_id: ast::NodeId,
6304+
region_params: &[RegionParameterDef])
6305+
{
6306+
for r in region_params.iter() {
6307+
regions.push(r.space, ty::free_region_from_def(free_id, r));
6308+
}
6309+
}
6310+
6311+
fn push_types_from_defs<'tcx>(tcx: &ty::ctxt<'tcx>,
6312+
types: &mut VecPerParamSpace<Ty<'tcx>>,
6313+
defs: &[TypeParameterDef<'tcx>]) {
6314+
for def in defs.iter() {
6315+
debug!("construct_parameter_environment(): push_types_from_defs: def={:?}",
6316+
def.repr(tcx));
6317+
let ty = ty::mk_param_from_def(tcx, def);
6318+
types.push(def.space, ty);
6319+
}
6320+
}
6321+
}
6322+
6323+
/// See `ParameterEnvironment` struct def'n for details
6324+
pub fn construct_parameter_environment<'a,'tcx>(
6325+
tcx: &'a ctxt<'tcx>,
6326+
span: Span,
6327+
generics: &ty::Generics<'tcx>,
6328+
free_id: ast::NodeId)
6329+
-> ParameterEnvironment<'a, 'tcx>
6330+
{
6331+
//
6332+
// Construct the free substs.
6333+
//
6334+
6335+
let free_substs = construct_free_substs(tcx, generics, free_id);
62916336
let free_id_scope = region::CodeExtent::from_node_id(free_id);
62926337

62936338
//
@@ -6311,33 +6356,30 @@ pub fn construct_parameter_environment<'a,'tcx>(
63116356
free_substs.repr(tcx),
63126357
predicates.repr(tcx));
63136358

6314-
return ty::ParameterEnvironment {
6359+
//
6360+
// Finally, we have to normalize the bounds in the environment, in
6361+
// case they contain any associated type projections. This process
6362+
// can yield errors if the put in illegal associated types, like
6363+
// `<i32 as Foo>::Bar` where `i32` does not implement `Foo`. We
6364+
// report these errors right here; this doesn't actually feel
6365+
// right to me, because constructing the environment feels like a
6366+
// kind of a "idempotent" action, but I'm not sure where would be
6367+
// a better place. In practice, we construct environments for
6368+
// every fn once during type checking, and we'll abort if there
6369+
// are any errors at that point, so after type checking you can be
6370+
// sure that this will succeed without errors anyway.
6371+
//
6372+
6373+
let unnormalized_env = ty::ParameterEnvironment {
63156374
tcx: tcx,
63166375
free_substs: free_substs,
63176376
implicit_region_bound: ty::ReScope(free_id_scope),
63186377
caller_bounds: predicates,
63196378
selection_cache: traits::SelectionCache::new(),
63206379
};
63216380

6322-
fn push_region_params(regions: &mut VecPerParamSpace<ty::Region>,
6323-
free_id: ast::NodeId,
6324-
region_params: &[RegionParameterDef])
6325-
{
6326-
for r in region_params.iter() {
6327-
regions.push(r.space, ty::free_region_from_def(free_id, r));
6328-
}
6329-
}
6330-
6331-
fn push_types_from_defs<'tcx>(tcx: &ty::ctxt<'tcx>,
6332-
types: &mut VecPerParamSpace<Ty<'tcx>>,
6333-
defs: &[TypeParameterDef<'tcx>]) {
6334-
for def in defs.iter() {
6335-
debug!("construct_parameter_environment(): push_types_from_defs: def={:?}",
6336-
def.repr(tcx));
6337-
let ty = ty::mk_param_from_def(tcx, def);
6338-
types.push(def.space, ty);
6339-
}
6340-
}
6381+
let cause = traits::ObligationCause::misc(span, free_id);
6382+
return traits::normalize_param_env_or_error(unnormalized_env, cause);
63416383

63426384
fn record_region_bounds<'tcx>(tcx: &ty::ctxt<'tcx>, predicates: &[ty::Predicate<'tcx>]) {
63436385
debug!("record_region_bounds(predicates={:?})", predicates.repr(tcx));

src/librustc_typeck/check/compare_method.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -215,14 +215,8 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
215215
debug!("compare_impl_method: impl_bounds={}",
216216
impl_bounds.repr(tcx));
217217

218-
// // Normalize the associated types in the impl_bounds.
219-
// let traits::Normalized { value: impl_bounds, .. } =
220-
// traits::normalize(&mut selcx, normalize_cause.clone(), &impl_bounds);
221-
222218
// Normalize the associated types in the trait_bounds.
223219
let trait_bounds = trait_m.generics.to_bounds(tcx, &trait_to_skol_substs);
224-
// let traits::Normalized { value: trait_bounds, .. } =
225-
// traits::normalize(&mut selcx, normalize_cause, &trait_bounds);
226220

227221
// Obtain the predicate split predicate sets for each.
228222
let trait_pred = trait_bounds.predicates.split();
@@ -242,19 +236,18 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
242236
);
243237

244238
// Construct trait parameter environment and then shift it into the skolemized viewpoint.
245-
let mut trait_param_env = impl_param_env.clone();
246239
// The key step here is to update the caller_bounds's predicates to be
247240
// the new hybrid bounds we computed.
248-
trait_param_env.caller_bounds = hybrid_preds.into_vec();
241+
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id);
242+
let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.into_vec());
243+
let trait_param_env = traits::normalize_param_env_or_error(trait_param_env,
244+
normalize_cause.clone());
249245

250246
debug!("compare_impl_method: trait_bounds={}",
251247
trait_param_env.caller_bounds.repr(tcx));
252248

253249
let mut selcx = traits::SelectionContext::new(&infcx, &trait_param_env);
254250

255-
let normalize_cause =
256-
traits::ObligationCause::misc(impl_m_span, impl_m_body_id);
257-
258251
for predicate in impl_pred.fns.into_iter() {
259252
let traits::Normalized { value: predicate, .. } =
260253
traits::normalize(&mut selcx, normalize_cause.clone(), &predicate);

0 commit comments

Comments
 (0)