Skip to content

Commit

Permalink
save the subobligations as well
Browse files Browse the repository at this point in the history
  • Loading branch information
nikomatsakis authored and alexcrichton committed Jul 30, 2017
1 parent 477e9f0 commit 2574f31
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 6 deletions.
18 changes: 12 additions & 6 deletions src/librustc/traits/project.rs
Expand Up @@ -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: \
Expand Down Expand Up @@ -1326,7 +1332,7 @@ enum ProjectionCacheEntry<'tcx> {
InProgress,
Ambiguous,
Error,
NormalizedTy(Ty<'tcx>),
NormalizedTy(NormalizedTy<'tcx>),
}

// NB: intentionally not Clone
Expand Down Expand Up @@ -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);
}

Expand Down
74 changes: 74 additions & 0 deletions src/test/run-pass/issue-43132.rs
@@ -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;
}

0 comments on commit 2574f31

Please sign in to comment.