Auto merge of #26282 - arielb1:probe-leak, r=nikomatsakis
It can introduce obligations to the fulfillment context, which would incorrectly still remain after the probe finished. Fixes #25679. r? @eddyb
This commit is contained in:
commit
c656e99e43
4 changed files with 114 additions and 21 deletions
|
@ -389,15 +389,19 @@ fn opt_normalize_projection_type<'a,'b,'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(ProjectedTy::NoProgress(projected_ty)) => {
|
Ok(ProjectedTy::NoProgress(projected_ty)) => {
|
||||||
|
debug!("normalize_projection_type: projected_ty={} no progress",
|
||||||
|
projected_ty.repr(selcx.tcx()));
|
||||||
Some(Normalized {
|
Some(Normalized {
|
||||||
value: projected_ty,
|
value: projected_ty,
|
||||||
obligations: vec!()
|
obligations: vec!()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Err(ProjectionTyError::TooManyCandidates) => {
|
Err(ProjectionTyError::TooManyCandidates) => {
|
||||||
|
debug!("normalize_projection_type: too many candidates");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Err(ProjectionTyError::TraitSelectionError(_)) => {
|
Err(ProjectionTyError::TraitSelectionError(_)) => {
|
||||||
|
debug!("normalize_projection_type: ERROR");
|
||||||
// if we got an error processing the `T as Trait` part,
|
// if we got an error processing the `T as Trait` part,
|
||||||
// just return `ty::err` but add the obligation `T :
|
// just return `ty::err` but add the obligation `T :
|
||||||
// Trait`, which when processed will cause the error to be
|
// Trait`, which when processed will cause the error to be
|
||||||
|
|
|
@ -59,10 +59,12 @@ struct Candidate<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CandidateKind<'tcx> {
|
enum CandidateKind<'tcx> {
|
||||||
InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>),
|
InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>,
|
||||||
|
/* Normalize obligations */ Vec<traits::PredicateObligation<'tcx>>),
|
||||||
ObjectCandidate(/* Trait */ ast::DefId, /* method_num */ usize, /* vtable index */ usize),
|
ObjectCandidate(/* Trait */ ast::DefId, /* method_num */ usize, /* vtable index */ usize),
|
||||||
ExtensionImplCandidate(/* Impl */ ast::DefId, ty::TraitRef<'tcx>,
|
ExtensionImplCandidate(/* Impl */ ast::DefId, ty::TraitRef<'tcx>,
|
||||||
subst::Substs<'tcx>, ItemIndex),
|
subst::Substs<'tcx>, ItemIndex,
|
||||||
|
/* Normalize obligations */ Vec<traits::PredicateObligation<'tcx>>),
|
||||||
ClosureCandidate(/* Trait */ ast::DefId, ItemIndex),
|
ClosureCandidate(/* Trait */ ast::DefId, ItemIndex),
|
||||||
WhereClauseCandidate(ty::PolyTraitRef<'tcx>, ItemIndex),
|
WhereClauseCandidate(ty::PolyTraitRef<'tcx>, ItemIndex),
|
||||||
ProjectionCandidate(ast::DefId, ItemIndex),
|
ProjectionCandidate(ast::DefId, ItemIndex),
|
||||||
|
@ -398,16 +400,24 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
|
let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
|
||||||
let impl_ty = self.fcx.instantiate_type_scheme(self.span, &impl_substs, &impl_ty);
|
let impl_ty = impl_ty.subst(self.tcx(), &impl_substs);
|
||||||
|
|
||||||
// Determine the receiver type that the method itself expects.
|
// Determine the receiver type that the method itself expects.
|
||||||
let xform_self_ty =
|
let xform_self_ty = self.xform_self_ty(&item, impl_ty, &impl_substs);
|
||||||
self.xform_self_ty(&item, impl_ty, &impl_substs);
|
|
||||||
|
// We can't use normalize_associated_types_in as it will pollute the
|
||||||
|
// fcx's fulfillment context after this probe is over.
|
||||||
|
let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
|
||||||
|
let mut selcx = &mut traits::SelectionContext::new(self.fcx.infcx(), self.fcx);
|
||||||
|
let traits::Normalized { value: xform_self_ty, obligations } =
|
||||||
|
traits::normalize(selcx, cause, &xform_self_ty);
|
||||||
|
debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}",
|
||||||
|
xform_self_ty.repr(self.tcx()));
|
||||||
|
|
||||||
self.inherent_candidates.push(Candidate {
|
self.inherent_candidates.push(Candidate {
|
||||||
xform_self_ty: xform_self_ty,
|
xform_self_ty: xform_self_ty,
|
||||||
item: item,
|
item: item,
|
||||||
kind: InherentImplCandidate(impl_def_id, impl_substs)
|
kind: InherentImplCandidate(impl_def_id, impl_substs, obligations)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -653,12 +663,24 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
||||||
impl_trait_ref.self_ty(),
|
impl_trait_ref.self_ty(),
|
||||||
impl_trait_ref.substs);
|
impl_trait_ref.substs);
|
||||||
|
|
||||||
|
// Normalize the receiver. We can't use normalize_associated_types_in
|
||||||
|
// as it will pollute the fcx's fulfillment context after this probe
|
||||||
|
// is over.
|
||||||
|
let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
|
||||||
|
let mut selcx = &mut traits::SelectionContext::new(self.fcx.infcx(), self.fcx);
|
||||||
|
let traits::Normalized { value: xform_self_ty, obligations } =
|
||||||
|
traits::normalize(selcx, cause, &xform_self_ty);
|
||||||
|
|
||||||
debug!("xform_self_ty={}", xform_self_ty.repr(self.tcx()));
|
debug!("xform_self_ty={}", xform_self_ty.repr(self.tcx()));
|
||||||
|
|
||||||
self.extension_candidates.push(Candidate {
|
self.extension_candidates.push(Candidate {
|
||||||
xform_self_ty: xform_self_ty,
|
xform_self_ty: xform_self_ty,
|
||||||
item: item.clone(),
|
item: item.clone(),
|
||||||
kind: ExtensionImplCandidate(impl_def_id, impl_trait_ref, impl_substs, item_index)
|
kind: ExtensionImplCandidate(impl_def_id,
|
||||||
|
impl_trait_ref,
|
||||||
|
impl_substs,
|
||||||
|
item_index,
|
||||||
|
obligations)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1026,8 +1048,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
||||||
// match as well (or at least may match, sometimes we
|
// match as well (or at least may match, sometimes we
|
||||||
// don't have enough information to fully evaluate).
|
// don't have enough information to fully evaluate).
|
||||||
match probe.kind {
|
match probe.kind {
|
||||||
InherentImplCandidate(impl_def_id, ref substs) |
|
InherentImplCandidate(impl_def_id, ref substs, ref ref_obligations) |
|
||||||
ExtensionImplCandidate(impl_def_id, _, ref substs, _) => {
|
ExtensionImplCandidate(impl_def_id, _, ref substs, _, ref ref_obligations) => {
|
||||||
let selcx = &mut traits::SelectionContext::new(self.infcx(), self.fcx);
|
let selcx = &mut traits::SelectionContext::new(self.infcx(), self.fcx);
|
||||||
let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
|
let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
|
||||||
|
|
||||||
|
@ -1046,8 +1068,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
||||||
debug!("impl_obligations={}", obligations.repr(self.tcx()));
|
debug!("impl_obligations={}", obligations.repr(self.tcx()));
|
||||||
|
|
||||||
// Evaluate those obligations to see if they might possibly hold.
|
// Evaluate those obligations to see if they might possibly hold.
|
||||||
obligations.iter().all(|o| selcx.evaluate_obligation(o)) &&
|
obligations.iter()
|
||||||
norm_obligations.iter().all(|o| selcx.evaluate_obligation(o))
|
.chain(norm_obligations.iter()).chain(ref_obligations.iter())
|
||||||
|
.all(|o| selcx.evaluate_obligation(o))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectionCandidate(..) |
|
ProjectionCandidate(..) |
|
||||||
|
@ -1281,13 +1305,13 @@ impl<'tcx> Candidate<'tcx> {
|
||||||
Pick {
|
Pick {
|
||||||
item: self.item.clone(),
|
item: self.item.clone(),
|
||||||
kind: match self.kind {
|
kind: match self.kind {
|
||||||
InherentImplCandidate(def_id, _) => {
|
InherentImplCandidate(def_id, _, _) => {
|
||||||
InherentImplPick(def_id)
|
InherentImplPick(def_id)
|
||||||
}
|
}
|
||||||
ObjectCandidate(def_id, item_num, real_index) => {
|
ObjectCandidate(def_id, item_num, real_index) => {
|
||||||
ObjectPick(def_id, item_num, real_index)
|
ObjectPick(def_id, item_num, real_index)
|
||||||
}
|
}
|
||||||
ExtensionImplCandidate(def_id, _, _, index) => {
|
ExtensionImplCandidate(def_id, _, _, index, _) => {
|
||||||
ExtensionImplPick(def_id, index)
|
ExtensionImplPick(def_id, index)
|
||||||
}
|
}
|
||||||
ClosureCandidate(trait_def_id, index) => {
|
ClosureCandidate(trait_def_id, index) => {
|
||||||
|
@ -1315,9 +1339,9 @@ impl<'tcx> Candidate<'tcx> {
|
||||||
|
|
||||||
fn to_source(&self) -> CandidateSource {
|
fn to_source(&self) -> CandidateSource {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
InherentImplCandidate(def_id, _) => ImplSource(def_id),
|
InherentImplCandidate(def_id, _, _) => ImplSource(def_id),
|
||||||
ObjectCandidate(def_id, _, _) => TraitSource(def_id),
|
ObjectCandidate(def_id, _, _) => TraitSource(def_id),
|
||||||
ExtensionImplCandidate(def_id, _, _, _) => ImplSource(def_id),
|
ExtensionImplCandidate(def_id, _, _, _, _) => ImplSource(def_id),
|
||||||
ClosureCandidate(trait_def_id, _) => TraitSource(trait_def_id),
|
ClosureCandidate(trait_def_id, _) => TraitSource(trait_def_id),
|
||||||
WhereClauseCandidate(ref trait_ref, _) => TraitSource(trait_ref.def_id()),
|
WhereClauseCandidate(ref trait_ref, _) => TraitSource(trait_ref.def_id()),
|
||||||
ProjectionCandidate(trait_def_id, _) => TraitSource(trait_def_id),
|
ProjectionCandidate(trait_def_id, _) => TraitSource(trait_def_id),
|
||||||
|
@ -1335,7 +1359,7 @@ impl<'tcx> Candidate<'tcx> {
|
||||||
ClosureCandidate(trait_def_id, item_num) => {
|
ClosureCandidate(trait_def_id, item_num) => {
|
||||||
Some((trait_def_id, item_num))
|
Some((trait_def_id, item_num))
|
||||||
}
|
}
|
||||||
ExtensionImplCandidate(_, ref trait_ref, _, item_num) => {
|
ExtensionImplCandidate(_, ref trait_ref, _, item_num, _) => {
|
||||||
Some((trait_ref.def_id, item_num))
|
Some((trait_ref.def_id, item_num))
|
||||||
}
|
}
|
||||||
WhereClauseCandidate(ref trait_ref, item_num) => {
|
WhereClauseCandidate(ref trait_ref, item_num) => {
|
||||||
|
@ -1359,13 +1383,14 @@ impl<'tcx> Repr<'tcx> for Candidate<'tcx> {
|
||||||
impl<'tcx> Repr<'tcx> for CandidateKind<'tcx> {
|
impl<'tcx> Repr<'tcx> for CandidateKind<'tcx> {
|
||||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||||
match *self {
|
match *self {
|
||||||
InherentImplCandidate(ref a, ref b) =>
|
InherentImplCandidate(ref a, ref b, ref c) =>
|
||||||
format!("InherentImplCandidate({},{})", a.repr(tcx), b.repr(tcx)),
|
format!("InherentImplCandidate({},{},{})", a.repr(tcx), b.repr(tcx),
|
||||||
|
c.repr(tcx)),
|
||||||
ObjectCandidate(a, b, c) =>
|
ObjectCandidate(a, b, c) =>
|
||||||
format!("ObjectCandidate({},{},{})", a.repr(tcx), b, c),
|
format!("ObjectCandidate({},{},{})", a.repr(tcx), b, c),
|
||||||
ExtensionImplCandidate(ref a, ref b, ref c, ref d) =>
|
ExtensionImplCandidate(ref a, ref b, ref c, ref d, ref e) =>
|
||||||
format!("ExtensionImplCandidate({},{},{},{})", a.repr(tcx), b.repr(tcx),
|
format!("ExtensionImplCandidate({},{},{},{},{})", a.repr(tcx), b.repr(tcx),
|
||||||
c.repr(tcx), d),
|
c.repr(tcx), d, e.repr(tcx)),
|
||||||
ClosureCandidate(ref a, ref b) =>
|
ClosureCandidate(ref a, ref b) =>
|
||||||
format!("ClosureCandidate({},{})", a.repr(tcx), b),
|
format!("ClosureCandidate({},{})", a.repr(tcx), b),
|
||||||
WhereClauseCandidate(ref a, ref b) =>
|
WhereClauseCandidate(ref a, ref b) =>
|
||||||
|
|
36
src/test/run-pass/associated-types-method.rs
Normal file
36
src/test/run-pass/associated-types-method.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test that methods whose impl-trait-ref contains associated types
|
||||||
|
// are supported.
|
||||||
|
|
||||||
|
trait Device {
|
||||||
|
type Resources;
|
||||||
|
}
|
||||||
|
struct Foo<D, R>(D, R);
|
||||||
|
|
||||||
|
trait Tr {
|
||||||
|
fn present(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: Device> Tr for Foo<D, D::Resources> {
|
||||||
|
fn present(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Res;
|
||||||
|
struct Dev;
|
||||||
|
impl Device for Dev {
|
||||||
|
type Resources = Res;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let foo = Foo(Dev, Res);
|
||||||
|
foo.present();
|
||||||
|
}
|
28
src/test/run-pass/issue-25679.rs
Normal file
28
src/test/run-pass/issue-25679.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
trait Device {
|
||||||
|
type Resources;
|
||||||
|
}
|
||||||
|
struct Foo<D, R>(D, R);
|
||||||
|
|
||||||
|
impl<D: Device> Foo<D, D::Resources> {
|
||||||
|
fn present(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Res;
|
||||||
|
struct Dev;
|
||||||
|
|
||||||
|
impl Device for Dev { type Resources = Res; }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let foo = Foo(Dev, Res);
|
||||||
|
foo.present();
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue