Skip to content

Commit 21fd312

Browse files
arielb1Ariel Ben-Yehuda
authored and
Ariel Ben-Yehuda
committed
Normalize associated types in closure signatures
Fixes rust-lang#25700.
1 parent 56d765d commit 21fd312

File tree

7 files changed

+169
-48
lines changed

7 files changed

+169
-48
lines changed

src/librustc/middle/traits/mod.rs

+18-5
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ pub enum Vtable<'tcx, N> {
245245
/// Vtable automatically generated for a closure. The def ID is the ID
246246
/// of the closure expression. This is a `VtableImpl` in spirit, but the
247247
/// impl is generated by the compiler and does not appear in the source.
248-
VtableClosure(ast::DefId, subst::Substs<'tcx>),
248+
VtableClosure(VtableClosureData<'tcx, N>),
249249

250250
/// Same as above, but for a fn pointer type with the given signature.
251251
VtableFnPointer(ty::Ty<'tcx>),
@@ -268,7 +268,16 @@ pub struct VtableImplData<'tcx, N> {
268268
pub nested: Vec<N>
269269
}
270270

271-
#[derive(Debug,Clone)]
271+
#[derive(Clone, PartialEq, Eq)]
272+
pub struct VtableClosureData<'tcx, N> {
273+
pub closure_def_id: ast::DefId,
274+
pub substs: subst::Substs<'tcx>,
275+
/// Nested obligations. This can be non-empty if the closure
276+
/// signature contains associated types.
277+
pub nested: Vec<N>
278+
}
279+
280+
#[derive(Debug, Clone)]
272281
pub struct VtableDefaultImplData<N> {
273282
pub trait_def_id: ast::DefId,
274283
pub nested: Vec<N>
@@ -502,8 +511,8 @@ impl<'tcx, N> Vtable<'tcx, N> {
502511
VtableParam(n) => n,
503512
VtableBuiltin(i) => i.nested,
504513
VtableDefaultImpl(d) => d.nested,
505-
VtableObject(_) | VtableFnPointer(..) |
506-
VtableClosure(..) => vec![]
514+
VtableClosure(c) => c.nested,
515+
VtableObject(_) | VtableFnPointer(..) => vec![]
507516
}
508517
}
509518

@@ -524,7 +533,11 @@ impl<'tcx, N> Vtable<'tcx, N> {
524533
nested: d.nested.into_iter().map(f).collect()
525534
}),
526535
VtableFnPointer(f) => VtableFnPointer(f),
527-
VtableClosure(d, s) => VtableClosure(d, s),
536+
VtableClosure(c) => VtableClosure(VtableClosureData {
537+
closure_def_id: c.closure_def_id,
538+
substs: c.substs,
539+
nested: c.nested.into_iter().map(f).collect()
540+
})
528541
}
529542
}
530543
}

src/librustc/middle/traits/project.rs

+30-14
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ use super::ObligationCause;
1717
use super::PredicateObligation;
1818
use super::SelectionContext;
1919
use super::SelectionError;
20+
use super::VtableClosureData;
2021
use super::VtableImplData;
2122
use super::util;
2223

2324
use middle::infer;
24-
use middle::subst::{Subst, Substs};
25+
use middle::subst::Subst;
2526
use middle::ty::{self, AsPredicate, ReferencesError, RegionEscape,
2627
HasProjectionTypes, ToPolyTraitRef, Ty};
2728
use middle::ty_fold::{self, TypeFoldable, TypeFolder};
28-
use syntax::ast;
2929
use syntax::parse::token;
3030
use util::common::FN_OUTPUT_NAME;
3131
use util::ppaux::Repr;
@@ -57,7 +57,7 @@ pub struct MismatchedProjectionTypes<'tcx> {
5757
enum ProjectionTyCandidate<'tcx> {
5858
ParamEnv(ty::PolyProjectionPredicate<'tcx>),
5959
Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>),
60-
Closure(ast::DefId, Substs<'tcx>),
60+
Closure(VtableClosureData<'tcx, PredicateObligation<'tcx>>),
6161
FnPointer(Ty<'tcx>),
6262
}
6363

@@ -162,11 +162,16 @@ fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext
162162
self_ty,
163163
&closure_type.sig,
164164
util::TupleArgumentsFlag::No);
165+
// We don't have to normalize the return type here - this is only
166+
// reached for TyClosure: Fn inputs where the closure kind is
167+
// still unknown, which should only occur in typeck where the
168+
// closure type is already normalized.
165169
let (ret_type, _) =
166170
infcx.replace_late_bound_regions_with_fresh_var(
167171
obligation.cause.span,
168172
infer::AssocTypeProjection(obligation.predicate.projection_ty.item_name),
169173
&ty::Binder(ret_type));
174+
170175
debug!("consider_unification_despite_ambiguity: ret_type={:?}",
171176
ret_type.repr(selcx.tcx()));
172177
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
@@ -686,9 +691,9 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
686691
selcx, obligation, obligation_trait_ref, candidate_set,
687692
data.object_ty);
688693
}
689-
super::VtableClosure(closure_def_id, substs) => {
694+
super::VtableClosure(data) => {
690695
candidate_set.vec.push(
691-
ProjectionTyCandidate::Closure(closure_def_id, substs));
696+
ProjectionTyCandidate::Closure(data));
692697
}
693698
super::VtableFnPointer(fn_type) => {
694699
candidate_set.vec.push(
@@ -755,8 +760,8 @@ fn confirm_candidate<'cx,'tcx>(
755760
confirm_impl_candidate(selcx, obligation, impl_vtable)
756761
}
757762

758-
ProjectionTyCandidate::Closure(def_id, substs) => {
759-
confirm_closure_candidate(selcx, obligation, def_id, &substs)
763+
ProjectionTyCandidate::Closure(closure_vtable) => {
764+
confirm_closure_candidate(selcx, obligation, closure_vtable)
760765
}
761766

762767
ProjectionTyCandidate::FnPointer(fn_type) => {
@@ -779,13 +784,24 @@ fn confirm_fn_pointer_candidate<'cx,'tcx>(
779784
fn confirm_closure_candidate<'cx,'tcx>(
780785
selcx: &mut SelectionContext<'cx,'tcx>,
781786
obligation: &ProjectionTyObligation<'tcx>,
782-
closure_def_id: ast::DefId,
783-
substs: &Substs<'tcx>)
787+
vtable: VtableClosureData<'tcx, PredicateObligation<'tcx>>)
784788
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
785789
{
786790
let closure_typer = selcx.closure_typer();
787-
let closure_type = closure_typer.closure_type(closure_def_id, substs);
788-
confirm_callable_candidate(selcx, obligation, &closure_type.sig, util::TupleArgumentsFlag::No)
791+
let closure_type = closure_typer.closure_type(vtable.closure_def_id, &vtable.substs);
792+
let Normalized {
793+
value: closure_type,
794+
mut obligations
795+
} = normalize_with_depth(selcx,
796+
obligation.cause.clone(),
797+
obligation.recursion_depth+1,
798+
&closure_type);
799+
let (ty, mut cc_obligations) = confirm_callable_candidate(selcx,
800+
obligation,
801+
&closure_type.sig,
802+
util::TupleArgumentsFlag::No);
803+
obligations.append(&mut cc_obligations);
804+
(ty, obligations)
789805
}
790806

791807
fn confirm_callable_candidate<'cx,'tcx>(
@@ -797,7 +813,7 @@ fn confirm_callable_candidate<'cx,'tcx>(
797813
{
798814
let tcx = selcx.tcx();
799815

800-
debug!("confirm_closure_candidate({},{})",
816+
debug!("confirm_callable_candidate({},{})",
801817
obligation.repr(tcx),
802818
fn_sig.repr(tcx));
803819

@@ -921,8 +937,8 @@ impl<'tcx> Repr<'tcx> for ProjectionTyCandidate<'tcx> {
921937
format!("ParamEnv({})", data.repr(tcx)),
922938
ProjectionTyCandidate::Impl(ref data) =>
923939
format!("Impl({})", data.repr(tcx)),
924-
ProjectionTyCandidate::Closure(ref a, ref b) =>
925-
format!("Closure(({},{}))", a.repr(tcx), b.repr(tcx)),
940+
ProjectionTyCandidate::Closure(ref data) =>
941+
format!("Closure({})", data.repr(tcx)),
926942
ProjectionTyCandidate::FnPointer(a) =>
927943
format!("FnPointer(({}))", a.repr(tcx)),
928944
}

src/librustc/middle/traits/select.rs

+53-19
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ use super::Selection;
3131
use super::SelectionResult;
3232
use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure,
3333
VtableFnPointer, VtableObject, VtableDefaultImpl};
34-
use super::{VtableImplData, VtableObjectData, VtableBuiltinData, VtableDefaultImplData};
34+
use super::{VtableImplData, VtableObjectData, VtableBuiltinData,
35+
VtableClosureData, VtableDefaultImplData};
3536
use super::object_safety;
3637
use super::util;
3738

@@ -355,7 +356,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
355356
};
356357
assert!(!substs.has_escaping_regions());
357358

358-
let closure_trait_ref = self.closure_trait_ref(obligation, closure_def_id, substs);
359+
// It is OK to call the unnormalized variant here - this is only
360+
// reached for TyClosure: Fn inputs where the closure kind is
361+
// still unknown, which should only occur in typeck where the
362+
// closure type is already normalized.
363+
let closure_trait_ref = self.closure_trait_ref_unnormalized(obligation,
364+
closure_def_id,
365+
substs);
366+
359367
match self.confirm_poly_trait_refs(obligation.cause.clone(),
360368
obligation.predicate.to_poly_trait_ref(),
361369
closure_trait_ref) {
@@ -2001,8 +2009,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
20012009
}
20022010

20032011
ClosureCandidate(closure_def_id, substs) => {
2004-
try!(self.confirm_closure_candidate(obligation, closure_def_id, &substs));
2005-
Ok(VtableClosure(closure_def_id, substs))
2012+
let vtable_closure =
2013+
try!(self.confirm_closure_candidate(obligation, closure_def_id, &substs));
2014+
Ok(VtableClosure(vtable_closure))
20062015
}
20072016

20082017
BuiltinObjectCandidate => {
@@ -2343,24 +2352,33 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
23432352
obligation: &TraitObligation<'tcx>,
23442353
closure_def_id: ast::DefId,
23452354
substs: &Substs<'tcx>)
2346-
-> Result<(),SelectionError<'tcx>>
2355+
-> Result<VtableClosureData<'tcx, PredicateObligation<'tcx>>,
2356+
SelectionError<'tcx>>
23472357
{
23482358
debug!("confirm_closure_candidate({},{},{})",
23492359
obligation.repr(self.tcx()),
23502360
closure_def_id.repr(self.tcx()),
23512361
substs.repr(self.tcx()));
23522362

2353-
let trait_ref = self.closure_trait_ref(obligation,
2354-
closure_def_id,
2355-
substs);
2363+
let Normalized {
2364+
value: trait_ref,
2365+
obligations
2366+
} = self.closure_trait_ref(obligation, closure_def_id, substs);
23562367

2357-
debug!("confirm_closure_candidate(closure_def_id={}, trait_ref={})",
2368+
debug!("confirm_closure_candidate(closure_def_id={}, trait_ref={}, obligations={})",
23582369
closure_def_id.repr(self.tcx()),
2359-
trait_ref.repr(self.tcx()));
2370+
trait_ref.repr(self.tcx()),
2371+
obligations.repr(self.tcx()));
2372+
2373+
try!(self.confirm_poly_trait_refs(obligation.cause.clone(),
2374+
obligation.predicate.to_poly_trait_ref(),
2375+
trait_ref));
23602376

2361-
self.confirm_poly_trait_refs(obligation.cause.clone(),
2362-
obligation.predicate.to_poly_trait_ref(),
2363-
trait_ref)
2377+
Ok(VtableClosureData {
2378+
closure_def_id: closure_def_id,
2379+
substs: substs.clone(),
2380+
nested: obligations
2381+
})
23642382
}
23652383

23662384
/// In the case of closure types and fn pointers,
@@ -2819,11 +2837,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
28192837
}
28202838
}
28212839

2822-
fn closure_trait_ref(&self,
2823-
obligation: &TraitObligation<'tcx>,
2824-
closure_def_id: ast::DefId,
2825-
substs: &Substs<'tcx>)
2826-
-> ty::PolyTraitRef<'tcx>
2840+
fn closure_trait_ref_unnormalized(&mut self,
2841+
obligation: &TraitObligation<'tcx>,
2842+
closure_def_id: ast::DefId,
2843+
substs: &Substs<'tcx>)
2844+
-> ty::PolyTraitRef<'tcx>
28272845
{
28282846
let closure_type = self.closure_typer.closure_type(closure_def_id, substs);
28292847
let ty::Binder((trait_ref, _)) =
@@ -2832,7 +2850,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
28322850
obligation.predicate.0.self_ty(), // (1)
28332851
&closure_type.sig,
28342852
util::TupleArgumentsFlag::No);
2835-
28362853
// (1) Feels icky to skip the binder here, but OTOH we know
28372854
// that the self-type is an unboxed closure type and hence is
28382855
// in fact unparameterized (or at least does not reference any
@@ -2842,6 +2859,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
28422859
ty::Binder(trait_ref)
28432860
}
28442861

2862+
fn closure_trait_ref(&mut self,
2863+
obligation: &TraitObligation<'tcx>,
2864+
closure_def_id: ast::DefId,
2865+
substs: &Substs<'tcx>)
2866+
-> Normalized<'tcx, ty::PolyTraitRef<'tcx>>
2867+
{
2868+
let trait_ref = self.closure_trait_ref_unnormalized(
2869+
obligation, closure_def_id, substs);
2870+
2871+
// A closure signature can contain associated types which
2872+
// must be normalized.
2873+
normalize_with_depth(self,
2874+
obligation.cause.clone(),
2875+
obligation.recursion_depth+1,
2876+
&trait_ref)
2877+
}
2878+
28452879
/// Returns the obligations that are implied by instantiating an
28462880
/// impl or trait. The obligations are substituted and fully
28472881
/// normalized. This is used when confirming an impl or default

src/librustc/middle/traits/util.rs

+17-4
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,12 @@ impl<'tcx, N> fmt::Debug for VtableImplData<'tcx, N> {
308308
}
309309
}
310310

311+
impl<'tcx, N> fmt::Debug for super::VtableClosureData<'tcx, N> {
312+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
313+
write!(f, "VtableClosure({:?})", self.closure_def_id)
314+
}
315+
}
316+
311317
impl<'tcx> fmt::Debug for super::VtableObjectData<'tcx> {
312318
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
313319
write!(f, "VtableObject(...)")
@@ -497,10 +503,8 @@ impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::Vtable<'tcx, N> {
497503
super::VtableDefaultImpl(ref t) =>
498504
t.repr(tcx),
499505

500-
super::VtableClosure(ref d, ref s) =>
501-
format!("VtableClosure({},{})",
502-
d.repr(tcx),
503-
s.repr(tcx)),
506+
super::VtableClosure(ref d) =>
507+
d.repr(tcx),
504508

505509
super::VtableFnPointer(ref d) =>
506510
format!("VtableFnPointer({})",
@@ -529,6 +533,15 @@ impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableImplData<'tcx, N> {
529533
}
530534
}
531535

536+
impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableClosureData<'tcx, N> {
537+
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
538+
format!("VtableClosure(closure_def_id={}, substs={}, nested={})",
539+
self.closure_def_id.repr(tcx),
540+
self.substs.repr(tcx),
541+
self.nested.repr(tcx))
542+
}
543+
}
544+
532545
impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableBuiltinData<N> {
533546
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
534547
format!("VtableBuiltin(nested={})",

src/librustc/middle/ty_fold.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,16 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<
479479
}
480480
}
481481

482+
impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableClosureData<'tcx, N> {
483+
fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableClosureData<'tcx, N> {
484+
traits::VtableClosureData {
485+
closure_def_id: self.closure_def_id,
486+
substs: self.substs.fold_with(folder),
487+
nested: self.nested.fold_with(folder),
488+
}
489+
}
490+
}
491+
482492
impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableDefaultImplData<N> {
483493
fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableDefaultImplData<N> {
484494
traits::VtableDefaultImplData {
@@ -501,8 +511,8 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N>
501511
match *self {
502512
traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)),
503513
traits::VtableDefaultImpl(ref t) => traits::VtableDefaultImpl(t.fold_with(folder)),
504-
traits::VtableClosure(d, ref s) => {
505-
traits::VtableClosure(d, s.fold_with(folder))
514+
traits::VtableClosure(ref d) => {
515+
traits::VtableClosure(d.fold_with(folder))
506516
}
507517
traits::VtableFnPointer(ref d) => {
508518
traits::VtableFnPointer(d.fold_with(folder))

src/librustc_trans/trans/meth.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -359,13 +359,13 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
359359

360360
Callee { bcx: bcx, data: Fn(llfn) }
361361
}
362-
traits::VtableClosure(closure_def_id, substs) => {
362+
traits::VtableClosure(vtable_closure) => {
363363
// The substitutions should have no type parameters remaining
364364
// after passing through fulfill_obligation
365365
let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
366366
let llfn = closure::trans_closure_method(bcx.ccx(),
367-
closure_def_id,
368-
substs,
367+
vtable_closure.closure_def_id,
368+
vtable_closure.substs,
369369
MethodCallKey(method_call),
370370
bcx.fcx.param_substs,
371371
trait_closure_kind);
@@ -716,7 +716,11 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
716716
nested: _ }) => {
717717
emit_vtable_methods(ccx, id, substs, param_substs).into_iter()
718718
}
719-
traits::VtableClosure(closure_def_id, substs) => {
719+
traits::VtableClosure(
720+
traits::VtableClosureData {
721+
closure_def_id,
722+
substs,
723+
nested: _ }) => {
720724
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
721725
let llfn = closure::trans_closure_method(ccx,
722726
closure_def_id,

0 commit comments

Comments
 (0)