Skip to content

Commit 88a559f

Browse files
committed
move ty var instantiation into the generalize module
1 parent f65e743 commit 88a559f

File tree

10 files changed

+243
-221
lines changed

10 files changed

+243
-221
lines changed

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

+6-198
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,73 +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, has_unconstrained_ty_var } =
311-
generalize::generalize(
312-
self,
313-
&mut CombineDelegate { infcx: self, span },
314-
ct,
315-
target_vid,
316-
ty::Variance::Invariant,
317-
)?;
318-
319-
if has_unconstrained_ty_var {
320-
span_bug!(span, "unconstrained ty var when generalizing `{ct:?}`");
321-
}
322-
self.inner
323-
.borrow_mut()
324-
.const_unification_table()
325-
.union_value(target_vid, ConstVariableValue::Known { value });
326-
Ok(value)
327-
}
328-
329261
fn unify_integral_variable(
330262
&self,
331263
vid_is_expected: bool,
@@ -387,132 +319,6 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
387319
Glb::new(self, a_is_expected)
388320
}
389321

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

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

530338
/// 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)