save the subobligations as well
This commit is contained in:
parent
477e9f0171
commit
2574f31b9b
2 changed files with 86 additions and 6 deletions
|
|
@ -462,13 +462,19 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
|
|||
selcx.infcx().report_overflow_error(&obligation, false);
|
||||
}
|
||||
Err(ProjectionCacheEntry::NormalizedTy(ty)) => {
|
||||
// If we find the value in the cache, then the obligations
|
||||
// have already been returned from the previous entry (and
|
||||
// should therefore have been honored).
|
||||
// If we find the value in the cache, then return it along
|
||||
// with the obligations that went along with it. Note
|
||||
// that, when using a fulfillment context, these
|
||||
// obligations could in principle be ignored: they have
|
||||
// already been registered when the cache entry was
|
||||
// created (and hence the new ones will quickly be
|
||||
// discarded as duplicated). But when doing trait
|
||||
// evaluation this is not the case, and dropping the trait
|
||||
// evaluations can causes ICEs (e.g. #43132).
|
||||
debug!("opt_normalize_projection_type: \
|
||||
found normalized ty `{:?}`",
|
||||
ty);
|
||||
return Some(NormalizedTy { value: ty, obligations: vec![] });
|
||||
return Some(ty);
|
||||
}
|
||||
Err(ProjectionCacheEntry::Error) => {
|
||||
debug!("opt_normalize_projection_type: \
|
||||
|
|
@ -1326,7 +1332,7 @@ enum ProjectionCacheEntry<'tcx> {
|
|||
InProgress,
|
||||
Ambiguous,
|
||||
Error,
|
||||
NormalizedTy(Ty<'tcx>),
|
||||
NormalizedTy(NormalizedTy<'tcx>),
|
||||
}
|
||||
|
||||
// NB: intentionally not Clone
|
||||
|
|
@ -1374,7 +1380,7 @@ impl<'tcx> ProjectionCache<'tcx> {
|
|||
fn complete(&mut self, key: ty::ProjectionTy<'tcx>, value: &NormalizedTy<'tcx>) {
|
||||
debug!("ProjectionCacheEntry::complete: adding cache entry: key={:?}, value={:?}",
|
||||
key, value);
|
||||
let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value.value));
|
||||
let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value.clone()));
|
||||
assert!(!fresh_key, "never started projecting `{:?}`", key);
|
||||
}
|
||||
|
||||
|
|
|
|||
74
src/test/run-pass/issue-43132.rs
Normal file
74
src/test/run-pass/issue-43132.rs
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
// Copyright 2017 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.
|
||||
|
||||
#![allow(unused)]
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
let b = mk::<
|
||||
Forward<(Box<Future<Error = u32>>,)>,
|
||||
>();
|
||||
b.map_err(|_| ()).join();
|
||||
}
|
||||
|
||||
fn mk<T>() -> T {
|
||||
loop {}
|
||||
}
|
||||
|
||||
impl<I: Future<Error = E>, E> Future for (I,) {
|
||||
type Error = E;
|
||||
}
|
||||
|
||||
struct Forward<T: Future> {
|
||||
_a: T,
|
||||
}
|
||||
|
||||
impl<T: Future> Future for Forward<T>
|
||||
where
|
||||
T::Error: From<u32>,
|
||||
{
|
||||
type Error = T::Error;
|
||||
}
|
||||
|
||||
trait Future {
|
||||
type Error;
|
||||
|
||||
fn map_err<F, E>(self, _: F) -> (Self, F)
|
||||
where
|
||||
F: FnOnce(Self::Error) -> E,
|
||||
Self: Sized,
|
||||
{
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn join(self) -> (MaybeDone<Self>, ())
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: ?Sized + Future> Future for Box<S> {
|
||||
type Error = S::Error;
|
||||
}
|
||||
|
||||
enum MaybeDone<A: Future> {
|
||||
_Done(A::Error),
|
||||
}
|
||||
|
||||
impl<U, A: Future, F> Future for (A, F)
|
||||
where
|
||||
F: FnOnce(A::Error) -> U,
|
||||
{
|
||||
type Error = U;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue