Skip to content

Commit 27f1540

Browse files
authored
Unrolled build for rust-lang#123578
Rollup merge of rust-lang#123578 - lqd:regression-123275, r=compiler-errors Restore `pred_known_to_hold_modulo_regions` As requested by `@lcnr` in rust-lang#123275 (comment) this PR restores `pred_known_to_hold_modulo_regions` to fix that "unexpected unsized tail" beta regression. This also adds the reduced repro from rust-lang#123275 (comment) as a sub-optimal test is better than no test at all, and it'll also cover rust-lang#108721. It still ICEs on master, even though https://github.com/phlip9/rustc-warp-ice doesn't on nightly anymore, since rust-lang#122493. Fixes rust-lang#123275. r? `@compiler-errors` but feel free to close if you'd rather have a better test instead cc `@wesleywiser` who had signed up to do the revert Will need a backport if we go with this PR: `@rustbot` label +beta-nominated
2 parents 211518e + 68b4257 commit 27f1540

File tree

2 files changed

+291
-3
lines changed

2 files changed

+291
-3
lines changed

compiler/rustc_trait_selection/src/traits/mod.rs

+47-3
Original file line numberDiff line numberDiff line change
@@ -119,16 +119,60 @@ pub fn predicates_for_generics<'tcx>(
119119

120120
/// Determines whether the type `ty` is known to meet `bound` and
121121
/// returns true if so. Returns false if `ty` either does not meet
122-
/// `bound` or is not known to meet bound.
122+
/// `bound` or is not known to meet bound (note that this is
123+
/// conservative towards *no impl*, which is the opposite of the
124+
/// `evaluate` methods).
123125
pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
124126
infcx: &InferCtxt<'tcx>,
125127
param_env: ty::ParamEnv<'tcx>,
126128
ty: Ty<'tcx>,
127129
def_id: DefId,
128130
) -> bool {
129131
let trait_ref = ty::TraitRef::new(infcx.tcx, def_id, [ty]);
130-
let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, trait_ref);
131-
infcx.predicate_must_hold_modulo_regions(&obligation)
132+
pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref)
133+
}
134+
135+
/// FIXME(@lcnr): this function doesn't seem right and shouldn't exist?
136+
///
137+
/// Ping me on zulip if you want to use this method and need help with finding
138+
/// an appropriate replacement.
139+
#[instrument(level = "debug", skip(infcx, param_env, pred), ret)]
140+
fn pred_known_to_hold_modulo_regions<'tcx>(
141+
infcx: &InferCtxt<'tcx>,
142+
param_env: ty::ParamEnv<'tcx>,
143+
pred: impl ToPredicate<'tcx>,
144+
) -> bool {
145+
let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred);
146+
147+
let result = infcx.evaluate_obligation_no_overflow(&obligation);
148+
debug!(?result);
149+
150+
if result.must_apply_modulo_regions() {
151+
true
152+
} else if result.may_apply() {
153+
// Sometimes obligations are ambiguous because the recursive evaluator
154+
// is not smart enough, so we fall back to fulfillment when we're not certain
155+
// that an obligation holds or not. Even still, we must make sure that
156+
// the we do no inference in the process of checking this obligation.
157+
let goal = infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
158+
infcx.probe(|_| {
159+
let ocx = ObligationCtxt::new(infcx);
160+
ocx.register_obligation(obligation);
161+
162+
let errors = ocx.select_all_or_error();
163+
match errors.as_slice() {
164+
// Only known to hold if we did no inference.
165+
[] => infcx.shallow_resolve(goal) == goal,
166+
167+
errors => {
168+
debug!(?errors);
169+
false
170+
}
171+
}
172+
})
173+
} else {
174+
false
175+
}
132176
}
133177

134178
#[instrument(level = "debug", skip(tcx, elaborated_env))]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
// This is a non-regression test for issues #108721 and its duplicate #123275 (hopefully, because
2+
// the test is still convoluted and the ICE is fiddly).
3+
//
4+
// `pred_known_to_hold_modulo_regions` prevented "unexpected unsized tail" ICEs with warp/hyper but
5+
// was unknowingly removed in #120463.
6+
7+
//@ build-pass: the ICE happened in codegen
8+
9+
use std::future::Future;
10+
trait TryFuture: Future {
11+
type Ok;
12+
}
13+
impl<F, T> TryFuture for F
14+
where
15+
F: ?Sized + Future<Output = Option<T>>,
16+
{
17+
type Ok = T;
18+
}
19+
trait Executor {}
20+
struct Exec {}
21+
trait HttpBody {
22+
type Data;
23+
}
24+
trait ConnStreamExec<F> {}
25+
impl<F> ConnStreamExec<F> for Exec where H2Stream<F>: Send {}
26+
impl<E, F> ConnStreamExec<F> for E where E: Executor {}
27+
struct H2Stream<F> {
28+
_fut: F,
29+
}
30+
trait NewSvcExec<S, E, W: Watcher<S, E>> {
31+
fn execute_new_svc(&mut self, _fut: NewSvcTask<S, E, W>) {
32+
unimplemented!()
33+
}
34+
}
35+
impl<S, E, W> NewSvcExec<S, E, W> for Exec where W: Watcher<S, E> {}
36+
trait Watcher<S, E> {
37+
type Future;
38+
}
39+
struct NoopWatcher;
40+
impl<S, E> Watcher<S, E> for NoopWatcher
41+
where
42+
S: HttpService,
43+
E: ConnStreamExec<S::Future>,
44+
{
45+
type Future = Option<<<S as HttpService>::ResBody as HttpBody>::Data>;
46+
}
47+
trait Service<Request> {
48+
type Response;
49+
type Future;
50+
}
51+
trait HttpService {
52+
type ResBody: HttpBody;
53+
type Future;
54+
}
55+
struct Body {}
56+
impl HttpBody for Body {
57+
type Data = String;
58+
}
59+
impl<S> HttpService for S
60+
where
61+
S: Service<(), Response = ()>,
62+
{
63+
type ResBody = Body;
64+
type Future = S::Future;
65+
}
66+
trait MakeServiceRef<Target> {
67+
type ResBody;
68+
type Service: HttpService<ResBody = Self::ResBody>;
69+
}
70+
impl<T, Target, S, F> MakeServiceRef<Target> for T
71+
where
72+
T: for<'a> Service<&'a Target, Response = S, Future = F>,
73+
S: HttpService,
74+
{
75+
type Service = S;
76+
type ResBody = S::ResBody;
77+
}
78+
fn make_service_fn<F, Target, Ret>(_f: F) -> MakeServiceFn<F>
79+
where
80+
F: FnMut(&Target) -> Ret,
81+
Ret: Future,
82+
{
83+
unimplemented!()
84+
}
85+
struct MakeServiceFn<F> {
86+
_func: F,
87+
}
88+
impl<'t, F, Ret, Target, Svc> Service<&'t Target> for MakeServiceFn<F>
89+
where
90+
F: FnMut(&Target) -> Ret,
91+
Ret: Future<Output = Option<Svc>>,
92+
{
93+
type Response = Svc;
94+
type Future = Option<()>;
95+
}
96+
struct AddrIncoming {}
97+
struct Server<I, S, E> {
98+
_incoming: I,
99+
_make_service: S,
100+
_protocol: E,
101+
}
102+
impl<I, S, E, B> Server<I, S, E>
103+
where
104+
S: MakeServiceRef<(), ResBody = B>,
105+
B: HttpBody,
106+
E: ConnStreamExec<<S::Service as HttpService>::Future>,
107+
E: NewSvcExec<S::Service, E, NoopWatcher>,
108+
{
109+
fn serve(&mut self) {
110+
let fut = NewSvcTask::new();
111+
self._protocol.execute_new_svc(fut);
112+
}
113+
}
114+
fn serve<S>(_make_service: S) -> Server<AddrIncoming, S, Exec> {
115+
unimplemented!()
116+
}
117+
struct NewSvcTask<S, E, W: Watcher<S, E>> {
118+
_state: State<S, E, W>,
119+
}
120+
struct State<S, E, W: Watcher<S, E>> {
121+
_fut: W::Future,
122+
}
123+
impl<S, E, W: Watcher<S, E>> NewSvcTask<S, E, W> {
124+
fn new() -> Self {
125+
unimplemented!()
126+
}
127+
}
128+
trait Filter {
129+
type Extract;
130+
type Future;
131+
fn map<F>(self, _fun: F) -> MapFilter<Self, F>
132+
where
133+
Self: Sized,
134+
{
135+
unimplemented!()
136+
}
137+
fn wrap_with<W>(self, _wrapper: W) -> W::Wrapped
138+
where
139+
Self: Sized,
140+
W: Wrap<Self>,
141+
{
142+
unimplemented!()
143+
}
144+
}
145+
fn service<F>(_filter: F) -> FilteredService<F>
146+
where
147+
F: Filter,
148+
{
149+
unimplemented!()
150+
}
151+
struct FilteredService<F> {
152+
_filter: F,
153+
}
154+
impl<F> Service<()> for FilteredService<F>
155+
where
156+
F: Filter,
157+
{
158+
type Response = ();
159+
type Future = FilteredFuture<F::Future>;
160+
}
161+
struct FilteredFuture<F> {
162+
_fut: F,
163+
}
164+
struct MapFilter<T, F> {
165+
_filter: T,
166+
_func: F,
167+
}
168+
impl<T, F> Filter for MapFilter<T, F>
169+
where
170+
T: Filter,
171+
F: Func<T::Extract>,
172+
{
173+
type Extract = F::Output;
174+
type Future = MapFilterFuture<T, F>;
175+
}
176+
struct MapFilterFuture<T: Filter, F> {
177+
_extract: T::Future,
178+
_func: F,
179+
}
180+
trait Wrap<F> {
181+
type Wrapped;
182+
}
183+
fn make_filter_fn<F, U>(_func: F) -> FilterFn<F>
184+
where
185+
F: Fn() -> U,
186+
{
187+
unimplemented!()
188+
}
189+
struct FilterFn<F> {
190+
_func: F,
191+
}
192+
impl<F, U> Filter for FilterFn<F>
193+
where
194+
F: Fn() -> U,
195+
U: TryFuture,
196+
U::Ok: Send,
197+
{
198+
type Extract = U::Ok;
199+
type Future = Option<U>;
200+
}
201+
fn trace<F>(_func: F) -> Trace<F>
202+
where
203+
F: Fn(),
204+
{
205+
unimplemented!()
206+
}
207+
struct Trace<F> {
208+
_func: F,
209+
}
210+
impl<FN, F> Wrap<F> for Trace<FN> {
211+
type Wrapped = WithTrace<FN, F>;
212+
}
213+
struct WithTrace<FN, F> {
214+
_filter: F,
215+
_trace: FN,
216+
}
217+
impl<FN, F> Filter for WithTrace<FN, F>
218+
where
219+
F: Filter,
220+
{
221+
type Extract = ();
222+
type Future = (F::Future, fn(F::Extract));
223+
}
224+
trait Func<Args> {
225+
type Output;
226+
}
227+
impl<F, R> Func<()> for F
228+
where
229+
F: Fn() -> R,
230+
{
231+
type Output = R;
232+
}
233+
fn main() {
234+
let make_service = make_service_fn(|_| {
235+
let tracer = trace(|| unimplemented!());
236+
let filter = make_filter_fn(|| std::future::ready(Some(())))
237+
.map(|| "Hello, world")
238+
.wrap_with(tracer);
239+
let svc = service(filter);
240+
std::future::ready(Some(svc))
241+
});
242+
let mut server = serve(make_service);
243+
server.serve();
244+
}

0 commit comments

Comments
 (0)