diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index cae1eba5797cf..7cce9c398bb44 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -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); } diff --git a/src/test/run-pass/issue-43132.rs b/src/test/run-pass/issue-43132.rs new file mode 100644 index 0000000000000..64b3b092b8936 --- /dev/null +++ b/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 or the MIT license +// , 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>,)>, + >(); + b.map_err(|_| ()).join(); +} + +fn mk() -> T { + loop {} +} + +impl, E> Future for (I,) { + type Error = E; +} + +struct Forward { + _a: T, +} + +impl Future for Forward +where + T::Error: From, +{ + type Error = T::Error; +} + +trait Future { + type Error; + + fn map_err(self, _: F) -> (Self, F) + where + F: FnOnce(Self::Error) -> E, + Self: Sized, + { + loop {} + } + + fn join(self) -> (MaybeDone, ()) + where + Self: Sized, + { + loop {} + } +} + +impl Future for Box { + type Error = S::Error; +} + +enum MaybeDone { + _Done(A::Error), +} + +impl Future for (A, F) +where + F: FnOnce(A::Error) -> U, +{ + type Error = U; +}