Skip to content

Commit 06e5b65

Browse files
committed
Auto merge of rust-lang#121211 - lcnr:nll-relate-handle-infer, r=<try>
deduplicate infer var instantiation Having 3 separate implementations of one of the most subtle parts of our type system is not a good strategy if we want to maintain a sound type system ✨ while working on this I already found some subtle bugs in the existing code, so that's awesome 🎉 This was necessary as I am not confident in my nll changes in rust-lang#119106, so I am first cleaning this up in a separate PR. r? `@BoxyUwU`
2 parents bccb9bb + fea82c9 commit 06e5b65

File tree

15 files changed

+345
-566
lines changed

15 files changed

+345
-566
lines changed

compiler/rustc_borrowck/src/type_check/relate_tys.rs

-16
Original file line numberDiff line numberDiff line change
@@ -143,22 +143,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
143143
reg
144144
}
145145

146-
#[instrument(skip(self), level = "debug")]
147-
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
148-
let reg = self.type_checker.infcx.next_nll_region_var_in_universe(
149-
NllRegionVariableOrigin::Existential { from_forall: false },
150-
universe,
151-
);
152-
153-
if cfg!(debug_assertions) {
154-
let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
155-
let prev = var_to_origin.insert(reg.as_var(), RegionCtxt::Existential(None));
156-
assert_eq!(prev, None);
157-
}
158-
159-
reg
160-
}
161-
162146
fn push_outlives(
163147
&mut self,
164148
sup: ty::Region<'tcx>,

compiler/rustc_infer/src/infer/canonical/query_response.rs

-7
Original file line numberDiff line numberDiff line change
@@ -731,13 +731,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
731731
ty::Region::new_placeholder(self.infcx.tcx, placeholder)
732732
}
733733

734-
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
735-
self.infcx.next_nll_region_var_in_universe(
736-
NllRegionVariableOrigin::Existential { from_forall: false },
737-
universe,
738-
)
739-
}
740-
741734
fn push_outlives(
742735
&mut self,
743736
sup: ty::Region<'tcx>,

compiler/rustc_infer/src/infer/relate/combine.rs

+6-193
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,18 @@
2323
//! this should be correctly updated.
2424
2525
use super::equate::Equate;
26-
use super::generalize::{self, CombineDelegate, Generalization};
2726
use super::glb::Glb;
2827
use super::lub::Lub;
2928
use super::sub::Sub;
3029
use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
3130
use crate::traits::{Obligation, PredicateObligations};
3231
use rustc_middle::infer::canonical::OriginalQueryValues;
33-
use rustc_middle::infer::unify_key::{ConstVariableValue, EffectVarValue};
32+
use rustc_middle::infer::unify_key::EffectVarValue;
3433
use rustc_middle::ty::error::{ExpectedFound, TypeError};
3534
use rustc_middle::ty::relate::{RelateResult, TypeRelation};
3635
use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
37-
use rustc_middle::ty::{AliasRelationDirection, TyVar};
3836
use rustc_middle::ty::{IntType, UintType};
37+
use rustc_span::Span;
3938

4039
#[derive(Clone)]
4140
pub struct CombineFields<'infcx, 'tcx> {
@@ -221,11 +220,11 @@ impl<'tcx> InferCtxt<'tcx> {
221220
}
222221

223222
(ty::ConstKind::Infer(InferConst::Var(vid)), _) => {
224-
return self.unify_const_variable(vid, b);
223+
return self.instantiate_const_var(vid, b);
225224
}
226225

227226
(_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
228-
return self.unify_const_variable(vid, a);
227+
return self.instantiate_const_var(vid, a);
229228
}
230229

231230
(ty::ConstKind::Infer(InferConst::EffectVar(vid)), _) => {
@@ -259,69 +258,6 @@ impl<'tcx> InferCtxt<'tcx> {
259258
ty::relate::structurally_relate_consts(relation, a, b)
260259
}
261260

262-
/// Unifies the const variable `target_vid` with the given constant.
263-
///
264-
/// This also tests if the given const `ct` contains an inference variable which was previously
265-
/// unioned with `target_vid`. If this is the case, inferring `target_vid` to `ct`
266-
/// would result in an infinite type as we continuously replace an inference variable
267-
/// in `ct` with `ct` itself.
268-
///
269-
/// This is especially important as unevaluated consts use their parents generics.
270-
/// They therefore often contain unused args, making these errors far more likely.
271-
///
272-
/// A good example of this is the following:
273-
///
274-
/// ```compile_fail,E0308
275-
/// #![feature(generic_const_exprs)]
276-
///
277-
/// fn bind<const N: usize>(value: [u8; N]) -> [u8; 3 + 4] {
278-
/// todo!()
279-
/// }
280-
///
281-
/// fn main() {
282-
/// let mut arr = Default::default();
283-
/// arr = bind(arr);
284-
/// }
285-
/// ```
286-
///
287-
/// Here `3 + 4` ends up as `ConstKind::Unevaluated` which uses the generics
288-
/// of `fn bind` (meaning that its args contain `N`).
289-
///
290-
/// `bind(arr)` now infers that the type of `arr` must be `[u8; N]`.
291-
/// The assignment `arr = bind(arr)` now tries to equate `N` with `3 + 4`.
292-
///
293-
/// As `3 + 4` contains `N` in its args, this must not succeed.
294-
///
295-
/// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant.
296-
#[instrument(level = "debug", skip(self))]
297-
fn unify_const_variable(
298-
&self,
299-
target_vid: ty::ConstVid,
300-
ct: ty::Const<'tcx>,
301-
) -> RelateResult<'tcx, ty::Const<'tcx>> {
302-
let span = match self.inner.borrow_mut().const_unification_table().probe_value(target_vid) {
303-
ConstVariableValue::Known { value } => {
304-
bug!("instantiating a known const var: {target_vid:?} {value} {ct}")
305-
}
306-
ConstVariableValue::Unknown { origin, universe: _ } => origin.span,
307-
};
308-
// FIXME(generic_const_exprs): Occurs check failures for unevaluated
309-
// constants and generic expressions are not yet handled correctly.
310-
let Generalization { value_may_be_infer: value, needs_wf: _ } = generalize::generalize(
311-
self,
312-
&mut CombineDelegate { infcx: self, span },
313-
ct,
314-
target_vid,
315-
ty::Variance::Invariant,
316-
)?;
317-
318-
self.inner
319-
.borrow_mut()
320-
.const_unification_table()
321-
.union_value(target_vid, ConstVariableValue::Known { value });
322-
Ok(value)
323-
}
324-
325261
fn unify_integral_variable(
326262
&self,
327263
vid_is_expected: bool,
@@ -383,131 +319,6 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
383319
Glb::new(self, a_is_expected)
384320
}
385321

386-
/// Here, `dir` is either `EqTo`, `SubtypeOf`, or `SupertypeOf`.
387-
/// The idea is that we should ensure that the type `a_ty` is equal
388-
/// to, a subtype of, or a supertype of (respectively) the type
389-
/// to which `b_vid` is bound.
390-
///
391-
/// Since `b_vid` has not yet been instantiated with a type, we
392-
/// will first instantiate `b_vid` with a *generalized* version
393-
/// of `a_ty`. Generalization introduces other inference
394-
/// variables wherever subtyping could occur.
395-
#[instrument(skip(self), level = "debug")]
396-
pub fn instantiate(
397-
&mut self,
398-
a_ty: Ty<'tcx>,
399-
ambient_variance: ty::Variance,
400-
b_vid: ty::TyVid,
401-
a_is_expected: bool,
402-
) -> RelateResult<'tcx, ()> {
403-
// Get the actual variable that b_vid has been inferred to
404-
debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown());
405-
406-
// Generalize type of `a_ty` appropriately depending on the
407-
// direction. As an example, assume:
408-
//
409-
// - `a_ty == &'x ?1`, where `'x` is some free region and `?1` is an
410-
// inference variable,
411-
// - and `dir` == `SubtypeOf`.
412-
//
413-
// Then the generalized form `b_ty` would be `&'?2 ?3`, where
414-
// `'?2` and `?3` are fresh region/type inference
415-
// variables. (Down below, we will relate `a_ty <: b_ty`,
416-
// adding constraints like `'x: '?2` and `?1 <: ?3`.)
417-
let Generalization { value_may_be_infer: b_ty, needs_wf } = generalize::generalize(
418-
self.infcx,
419-
&mut CombineDelegate { infcx: self.infcx, span: self.trace.span() },
420-
a_ty,
421-
b_vid,
422-
ambient_variance,
423-
)?;
424-
425-
// Constrain `b_vid` to the generalized type `b_ty`.
426-
if let &ty::Infer(TyVar(b_ty_vid)) = b_ty.kind() {
427-
self.infcx.inner.borrow_mut().type_variables().equate(b_vid, b_ty_vid);
428-
} else {
429-
self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty);
430-
}
431-
432-
if needs_wf {
433-
self.obligations.push(Obligation::new(
434-
self.tcx(),
435-
self.trace.cause.clone(),
436-
self.param_env,
437-
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
438-
b_ty.into(),
439-
))),
440-
));
441-
}
442-
443-
// Finally, relate `b_ty` to `a_ty`, as described in previous comment.
444-
//
445-
// FIXME(#16847): This code is non-ideal because all these subtype
446-
// relations wind up attributed to the same spans. We need
447-
// to associate causes/spans with each of the relations in
448-
// the stack to get this right.
449-
if b_ty.is_ty_var() {
450-
// This happens for cases like `<?0 as Trait>::Assoc == ?0`.
451-
// We can't instantiate `?0` here as that would result in a
452-
// cyclic type. We instead delay the unification in case
453-
// the alias can be normalized to something which does not
454-
// mention `?0`.
455-
if self.infcx.next_trait_solver() {
456-
let (lhs, rhs, direction) = match ambient_variance {
457-
ty::Variance::Invariant => {
458-
(a_ty.into(), b_ty.into(), AliasRelationDirection::Equate)
459-
}
460-
ty::Variance::Covariant => {
461-
(a_ty.into(), b_ty.into(), AliasRelationDirection::Subtype)
462-
}
463-
ty::Variance::Contravariant => {
464-
(b_ty.into(), a_ty.into(), AliasRelationDirection::Subtype)
465-
}
466-
ty::Variance::Bivariant => unreachable!("bivariant generalization"),
467-
};
468-
self.obligations.push(Obligation::new(
469-
self.tcx(),
470-
self.trace.cause.clone(),
471-
self.param_env,
472-
ty::PredicateKind::AliasRelate(lhs, rhs, direction),
473-
));
474-
} else {
475-
match a_ty.kind() {
476-
&ty::Alias(ty::Projection, data) => {
477-
// FIXME: This does not handle subtyping correctly, we could
478-
// instead create a new inference variable for `a_ty`, emitting
479-
// `Projection(a_ty, a_infer)` and `a_infer <: b_ty`.
480-
self.obligations.push(Obligation::new(
481-
self.tcx(),
482-
self.trace.cause.clone(),
483-
self.param_env,
484-
ty::ProjectionPredicate { projection_ty: data, term: b_ty.into() },
485-
))
486-
}
487-
// The old solver only accepts projection predicates for associated types.
488-
ty::Alias(ty::Inherent | ty::Weak | ty::Opaque, _) => {
489-
return Err(TypeError::CyclicTy(a_ty));
490-
}
491-
_ => bug!("generalizated `{a_ty:?} to infer, not an alias"),
492-
}
493-
}
494-
} else {
495-
match ambient_variance {
496-
ty::Variance::Invariant => self.equate(a_is_expected).relate(a_ty, b_ty),
497-
ty::Variance::Covariant => self.sub(a_is_expected).relate(a_ty, b_ty),
498-
ty::Variance::Contravariant => self.sub(a_is_expected).relate_with_variance(
499-
ty::Contravariant,
500-
ty::VarianceDiagInfo::default(),
501-
a_ty,
502-
b_ty,
503-
),
504-
ty::Variance::Bivariant => unreachable!("bivariant generalization"),
505-
}?;
506-
}
507-
508-
Ok(())
509-
}
510-
511322
pub fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
512323
self.obligations.extend(obligations);
513324
}
@@ -520,6 +331,8 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
520331
}
521332

522333
pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
334+
fn span(&self) -> Span;
335+
523336
fn param_env(&self) -> ty::ParamEnv<'tcx>;
524337

525338
/// Register obligations that must hold in order for this relation to hold

compiler/rustc_infer/src/infer/relate/equate.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_middle::ty::TyVar;
88
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
99

1010
use rustc_hir::def_id::DefId;
11+
use rustc_span::Span;
1112

1213
/// Ensures `a` is made equal to `b`. Returns `a` on success.
1314
pub struct Equate<'combine, 'infcx, 'tcx> {
@@ -81,12 +82,12 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
8182
infcx.inner.borrow_mut().type_variables().equate(a_id, b_id);
8283
}
8384

84-
(&ty::Infer(TyVar(a_id)), _) => {
85-
self.fields.instantiate(b, ty::Invariant, a_id, self.a_is_expected)?;
85+
(&ty::Infer(TyVar(a_vid)), _) => {
86+
infcx.instantiate_ty_var(self, self.a_is_expected, a_vid, ty::Invariant, b)?;
8687
}
8788

88-
(_, &ty::Infer(TyVar(b_id))) => {
89-
self.fields.instantiate(a, ty::Invariant, b_id, self.a_is_expected)?;
89+
(_, &ty::Infer(TyVar(b_vid))) => {
90+
infcx.instantiate_ty_var(self, !self.a_is_expected, b_vid, ty::Invariant, a)?;
9091
}
9192

9293
(
@@ -170,6 +171,10 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
170171
}
171172

172173
impl<'tcx> ObligationEmittingRelation<'tcx> for Equate<'_, '_, 'tcx> {
174+
fn span(&self) -> Span {
175+
self.fields.trace.span()
176+
}
177+
173178
fn param_env(&self) -> ty::ParamEnv<'tcx> {
174179
self.fields.param_env
175180
}

0 commit comments

Comments
 (0)