Skip to content

Commit 6d0b6c0

Browse files
Tweaks and a test
1 parent 4ce2123 commit 6d0b6c0

File tree

3 files changed

+97
-51
lines changed

3 files changed

+97
-51
lines changed

compiler/rustc_infer/src/infer/generalize.rs

+52-51
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub trait GeneralizerDelegate<'tcx> {
5252

5353
fn forbid_inference_vars() -> bool;
5454

55-
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>;
55+
fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>;
5656
}
5757

5858
pub struct CombineDelegate<'cx, 'tcx> {
@@ -70,7 +70,9 @@ impl<'tcx> GeneralizerDelegate<'tcx> for CombineDelegate<'_, 'tcx> {
7070
false
7171
}
7272

73-
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
73+
fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
74+
// FIXME: This is non-ideal because we don't give a
75+
// very descriptive origin for this region variable.
7476
self.infcx
7577
.next_region_var_in_universe(RegionVariableOrigin::MiscVariable(self.span), universe)
7678
}
@@ -88,18 +90,17 @@ where
8890
<Self as TypeRelatingDelegate<'tcx>>::forbid_inference_vars()
8991
}
9092

91-
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
93+
fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
9294
<Self as TypeRelatingDelegate<'tcx>>::generalize_existential(self, universe)
9395
}
9496
}
9597

96-
/// The "type generalizer" is used when handling inference variables.
98+
/// The "generalizer" is used when handling inference variables.
9799
///
98100
/// The basic strategy for handling a constraint like `?A <: B` is to
99-
/// apply a "generalization strategy" to the type `B` -- this replaces
100-
/// all the lifetimes in the type `B` with fresh inference
101-
/// variables. (You can read more about the strategy in this [blog
102-
/// post].)
101+
/// apply a "generalization strategy" to the term `B` -- this replaces
102+
/// all the lifetimes in the term `B` with fresh inference variables.
103+
/// (You can read more about the strategy in this [blog post].)
103104
///
104105
/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
105106
/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
@@ -110,9 +111,11 @@ where
110111
struct Generalizer<'me, 'tcx, D> {
111112
infcx: &'me InferCtxt<'tcx>,
112113

113-
// An delegate used to abstract the behaviors of the three previous
114-
// generalizer-like implementations.
115-
pub delegate: &'me mut D,
114+
/// This is used to abstract the behaviors of the three previous
115+
/// generalizer-like implementations (`Generalizer`, `TypeGeneralizer`,
116+
/// and `ConstInferUnifier`). See [`GeneralizerDelegate`] for more
117+
/// information.
118+
delegate: &'me mut D,
116119

117120
/// After we generalize this type, we are going to relate it to
118121
/// some other type. What will be the variance at this point?
@@ -138,6 +141,7 @@ struct Generalizer<'me, 'tcx, D> {
138141
}
139142

140143
impl<'tcx, D> Generalizer<'_, 'tcx, D> {
144+
/// Create an error that corresponds to the term kind in `root_term`
141145
fn cyclic_term_error(&self) -> TypeError<'tcx> {
142146
match self.root_term.unpack() {
143147
ty::TermKind::Ty(ty) => TypeError::CyclicTy(ty),
@@ -183,44 +187,37 @@ where
183187
relate::relate_substs_with_variances(
184188
self,
185189
item_def_id,
186-
&opt_variances,
190+
opt_variances,
187191
a_subst,
188192
b_subst,
189193
true,
190194
)
191195
}
192196
}
193197

198+
#[instrument(level = "debug", skip(self, variance, b), ret)]
194199
fn relate_with_variance<T: Relate<'tcx>>(
195200
&mut self,
196201
variance: ty::Variance,
197202
_info: ty::VarianceDiagInfo<'tcx>,
198203
a: T,
199204
b: T,
200205
) -> RelateResult<'tcx, T> {
201-
debug!("Generalizer::relate_with_variance(variance={:?}, a={:?}, b={:?})", variance, a, b);
202-
203206
let old_ambient_variance = self.ambient_variance;
204207
self.ambient_variance = self.ambient_variance.xform(variance);
205-
206-
debug!("Generalizer::relate_with_variance: ambient_variance = {:?}", self.ambient_variance);
207-
208+
debug!(?self.ambient_variance, "new ambient variance");
208209
let r = self.relate(a, b)?;
209-
210210
self.ambient_variance = old_ambient_variance;
211-
212-
debug!("Generalizer::relate_with_variance: r={:?}", r);
213-
214211
Ok(r)
215212
}
216213

214+
#[instrument(level = "debug", skip(self, t2), ret)]
217215
fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
218216
assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
219217

220218
if let Some(&result) = self.cache.get(&t) {
221219
return Ok(result);
222220
}
223-
debug!("generalize: t={:?}", t);
224221

225222
// Check to see whether the type we are generalizing references
226223
// any other type variable related to `vid` via
@@ -241,21 +238,22 @@ where
241238
let mut inner = self.infcx.inner.borrow_mut();
242239
let vid = inner.type_variables().root_var(vid);
243240
let sub_vid = inner.type_variables().sub_root_var(vid);
244-
if TermVid::Ty(sub_vid) == self.root_vid {
245-
// If sub-roots are equal, then `for_vid` and
241+
242+
if ty::TermVid::Ty(sub_vid) == self.root_vid {
243+
// If sub-roots are equal, then `root_vid` and
246244
// `vid` are related via subtyping.
247245
Err(self.cyclic_term_error())
248246
} else {
249247
let probe = inner.type_variables().probe(vid);
250248
match probe {
251249
TypeVariableValue::Known { value: u } => {
252-
debug!("generalize: known value {:?}", u);
253250
drop(inner);
254251
self.relate(u, u)
255252
}
256253
TypeVariableValue::Unknown { universe } => {
257254
match self.ambient_variance {
258-
// Invariant: no need to make a fresh type variable.
255+
// Invariant: no need to make a fresh type variable
256+
// if we can name the universe.
259257
ty::Invariant => {
260258
if self.for_universe.can_name(universe) {
261259
return Ok(t);
@@ -282,7 +280,7 @@ where
282280
// operation. This is needed to detect cyclic types. To see why, see the
283281
// docs in the `type_variables` module.
284282
inner.type_variables().sub(vid, new_var_id);
285-
debug!("generalize: replacing original vid={:?} with new={:?}", vid, u);
283+
debug!("replacing original vid={:?} with new={:?}", vid, u);
286284
Ok(u)
287285
}
288286
}
@@ -297,45 +295,41 @@ where
297295
}
298296

299297
ty::Placeholder(placeholder) => {
300-
if self.for_universe.cannot_name(placeholder.universe) {
298+
if self.for_universe.can_name(placeholder.universe) {
299+
Ok(t)
300+
} else {
301301
debug!(
302-
"Generalizer::tys: root universe {:?} cannot name\
303-
placeholder in universe {:?}",
302+
"root universe {:?} cannot name placeholder in universe {:?}",
304303
self.for_universe, placeholder.universe
305304
);
306305
Err(TypeError::Mismatch)
307-
} else {
308-
Ok(t)
309306
}
310307
}
311308

312-
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
313-
let s = self.relate(substs, substs)?;
314-
Ok(if s == substs { t } else { self.tcx().mk_opaque(def_id, s) })
315-
}
316309
_ => relate::super_relate_tys(self, t, t),
317310
}?;
318311

319312
self.cache.insert(t, g);
320313
Ok(g)
321314
}
322315

316+
#[instrument(level = "debug", skip(self, r2), ret)]
323317
fn regions(
324318
&mut self,
325319
r: ty::Region<'tcx>,
326320
r2: ty::Region<'tcx>,
327321
) -> RelateResult<'tcx, ty::Region<'tcx>> {
328322
assert_eq!(r, r2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
329323

330-
debug!("generalize: regions r={:?}", r);
331-
332324
match *r {
333325
// Never make variables for regions bound within the type itself,
334326
// nor for erased regions.
335327
ty::ReLateBound(..) | ty::ReErased => {
336328
return Ok(r);
337329
}
338330

331+
// It doesn't really matter for correctness if we generalize ReError,
332+
// since we're already on a doomed compilation path.
339333
ty::ReError(_) => {
340334
return Ok(r);
341335
}
@@ -359,13 +353,10 @@ where
359353
}
360354
}
361355

362-
// FIXME: This is non-ideal because we don't give a
363-
// very descriptive origin for this region variable.
364-
let replacement_region_vid = self.delegate.generalize_existential(self.for_universe);
365-
366-
Ok(replacement_region_vid)
356+
Ok(self.delegate.generalize_region(self.for_universe))
367357
}
368358

359+
#[instrument(level = "debug", skip(self, c2), ret)]
369360
fn consts(
370361
&mut self,
371362
c: ty::Const<'tcx>,
@@ -378,13 +369,12 @@ where
378369
bug!("unexpected inference variable encountered in NLL generalization: {:?}", c);
379370
}
380371
ty::ConstKind::Infer(InferConst::Var(vid)) => {
381-
// Check if the current unification would end up
382-
// unifying `target_vid` with a const which contains
383-
// an inference variable which is unioned with `target_vid`.
384-
//
385-
// Not doing so can easily result in stack overflows.
386-
if TermVid::Const(self.infcx.inner.borrow_mut().const_unification_table().find(vid))
387-
== self.root_vid
372+
// If root const vids are equal, then `root_vid` and
373+
// `vid` are related and we'd be inferring an infinitely
374+
// deep const.
375+
if ty::TermVid::Const(
376+
self.infcx.inner.borrow_mut().const_unification_table().find(vid),
377+
) == self.root_vid
388378
{
389379
return Err(self.cyclic_term_error());
390380
}
@@ -421,10 +411,22 @@ where
421411
)?;
422412
Ok(self.tcx().mk_const(ty::UnevaluatedConst { def, substs }, c.ty()))
423413
}
414+
ty::ConstKind::Placeholder(placeholder) => {
415+
if self.for_universe.can_name(placeholder.universe) {
416+
Ok(c)
417+
} else {
418+
debug!(
419+
"root universe {:?} cannot name placeholder in universe {:?}",
420+
self.for_universe, placeholder.universe
421+
);
422+
Err(TypeError::Mismatch)
423+
}
424+
}
424425
_ => relate::super_relate_consts(self, c, c),
425426
}
426427
}
427428

429+
#[instrument(level = "debug", skip(self), ret)]
428430
fn binders<T>(
429431
&mut self,
430432
a: ty::Binder<'tcx, T>,
@@ -433,7 +435,6 @@ where
433435
where
434436
T: Relate<'tcx>,
435437
{
436-
debug!("Generalizer::binders(a={:?})", a);
437438
let result = self.relate(a.skip_binder(), a.skip_binder())?;
438439
Ok(a.rebind(result))
439440
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#![feature(non_lifetime_binders)]
2+
//~^ WARN the feature `non_lifetime_binders` is incomplete
3+
4+
trait Other<U: ?Sized> {}
5+
6+
impl<U: ?Sized> Other<U> for U {}
7+
8+
#[rustfmt::skip]
9+
fn foo<U: ?Sized>()
10+
where
11+
for<T> T: Other<U> {}
12+
13+
fn bar() {
14+
foo::<_>();
15+
//~^ ERROR the trait bound `T: Other<_>` is not satisfied
16+
}
17+
18+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/universe-error1.rs:1:12
3+
|
4+
LL | #![feature(non_lifetime_binders)]
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
error[E0277]: the trait bound `T: Other<_>` is not satisfied
11+
--> $DIR/universe-error1.rs:14:11
12+
|
13+
LL | foo::<_>();
14+
| ^ the trait `Other<_>` is not implemented for `T`
15+
|
16+
note: required by a bound in `foo`
17+
--> $DIR/universe-error1.rs:11:15
18+
|
19+
LL | fn foo<U: ?Sized>()
20+
| --- required by a bound in this function
21+
LL | where
22+
LL | for<T> T: Other<U> {}
23+
| ^^^^^^^^ required by this bound in `foo`
24+
25+
error: aborting due to previous error; 1 warning emitted
26+
27+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)