Skip to content

Commit f6d7873

Browse files
committed
Auto merge of #43546 - nikomatsakis:issue-43132, r=arielb1
save subobligations in the projection cache The projection cache explicitly chose not to "preserve" subobligations for projections, since the fulfillment context ought to have been doing so. But for the trait evaluation scheme that causes problems. This PR reproduces subobligations. This has the potential to slow down compilation, but minimal investigation suggests it does not do so. One hesitation about this PR: I could not find a way to make a standalone test case for #43132 (but admittedly I did not try very hard). Fixes #43132. r? @arielb1
2 parents 2789db2 + 2574f31 commit f6d7873

File tree

2 files changed

+86
-6
lines changed

2 files changed

+86
-6
lines changed

Diff for: src/librustc/traits/project.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -462,13 +462,19 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
462462
selcx.infcx().report_overflow_error(&obligation, false);
463463
}
464464
Err(ProjectionCacheEntry::NormalizedTy(ty)) => {
465-
// If we find the value in the cache, then the obligations
466-
// have already been returned from the previous entry (and
467-
// should therefore have been honored).
465+
// If we find the value in the cache, then return it along
466+
// with the obligations that went along with it. Note
467+
// that, when using a fulfillment context, these
468+
// obligations could in principle be ignored: they have
469+
// already been registered when the cache entry was
470+
// created (and hence the new ones will quickly be
471+
// discarded as duplicated). But when doing trait
472+
// evaluation this is not the case, and dropping the trait
473+
// evaluations can causes ICEs (e.g. #43132).
468474
debug!("opt_normalize_projection_type: \
469475
found normalized ty `{:?}`",
470476
ty);
471-
return Some(NormalizedTy { value: ty, obligations: vec![] });
477+
return Some(ty);
472478
}
473479
Err(ProjectionCacheEntry::Error) => {
474480
debug!("opt_normalize_projection_type: \
@@ -1326,7 +1332,7 @@ enum ProjectionCacheEntry<'tcx> {
13261332
InProgress,
13271333
Ambiguous,
13281334
Error,
1329-
NormalizedTy(Ty<'tcx>),
1335+
NormalizedTy(NormalizedTy<'tcx>),
13301336
}
13311337

13321338
// NB: intentionally not Clone
@@ -1374,7 +1380,7 @@ impl<'tcx> ProjectionCache<'tcx> {
13741380
fn complete(&mut self, key: ty::ProjectionTy<'tcx>, value: &NormalizedTy<'tcx>) {
13751381
debug!("ProjectionCacheEntry::complete: adding cache entry: key={:?}, value={:?}",
13761382
key, value);
1377-
let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value.value));
1383+
let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value.clone()));
13781384
assert!(!fresh_key, "never started projecting `{:?}`", key);
13791385
}
13801386

Diff for: src/test/run-pass/issue-43132.rs

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(unused)]
12+
13+
fn main() {
14+
}
15+
16+
fn foo() {
17+
let b = mk::<
18+
Forward<(Box<Future<Error = u32>>,)>,
19+
>();
20+
b.map_err(|_| ()).join();
21+
}
22+
23+
fn mk<T>() -> T {
24+
loop {}
25+
}
26+
27+
impl<I: Future<Error = E>, E> Future for (I,) {
28+
type Error = E;
29+
}
30+
31+
struct Forward<T: Future> {
32+
_a: T,
33+
}
34+
35+
impl<T: Future> Future for Forward<T>
36+
where
37+
T::Error: From<u32>,
38+
{
39+
type Error = T::Error;
40+
}
41+
42+
trait Future {
43+
type Error;
44+
45+
fn map_err<F, E>(self, _: F) -> (Self, F)
46+
where
47+
F: FnOnce(Self::Error) -> E,
48+
Self: Sized,
49+
{
50+
loop {}
51+
}
52+
53+
fn join(self) -> (MaybeDone<Self>, ())
54+
where
55+
Self: Sized,
56+
{
57+
loop {}
58+
}
59+
}
60+
61+
impl<S: ?Sized + Future> Future for Box<S> {
62+
type Error = S::Error;
63+
}
64+
65+
enum MaybeDone<A: Future> {
66+
_Done(A::Error),
67+
}
68+
69+
impl<U, A: Future, F> Future for (A, F)
70+
where
71+
F: FnOnce(A::Error) -> U,
72+
{
73+
type Error = U;
74+
}

0 commit comments

Comments
 (0)