Skip to content

Commit 797095a

Browse files
committed
Auto merge of #88149 - Mark-Simulacrum:prep-never-type, r=jackh726
Refactor fallback code to prepare for never type This PR contains cherry-picks of some of `@nikomatsakis's` work from #79366, and shouldn't (AFAICT) represent any change in behavior. However, the refactoring is good regardless of the never type work being landed, and will reduce the size of those eventual PR(s) (and rebase pain). I am not personally an expert on this code, and the commits are essentially 100% `@nikomatsakis's,` but they do seem reasonable to me by my understanding. Happy to edit with review, of course. Commits are best reviewed in sequence rather than all together. r? `@jackh726` perhaps?
2 parents 1e3d632 + 60cc00f commit 797095a

File tree

32 files changed

+470
-210
lines changed

32 files changed

+470
-210
lines changed

compiler/rustc_infer/src/infer/combine.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@
2222
// is also useful to track which value is the "expected" value in
2323
// terms of error reporting.
2424

25-
use super::equate::Equate;
2625
use super::glb::Glb;
2726
use super::lub::Lub;
2827
use super::sub::Sub;
2928
use super::type_variable::TypeVariableValue;
3029
use super::unify_key::replace_if_possible;
3130
use super::unify_key::{ConstVarValue, ConstVariableValue};
3231
use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
32+
use super::{equate::Equate, type_variable::Diverging};
3333
use super::{InferCtxt, MiscVariable, TypeTrace};
3434

3535
use crate::traits::{Obligation, PredicateObligations};
@@ -643,8 +643,13 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
643643
.inner
644644
.borrow_mut()
645645
.type_variables()
646-
.new_var(self.for_universe, false, origin);
646+
.new_var(self.for_universe, Diverging::NotDiverging, origin);
647647
let u = self.tcx().mk_ty_var(new_var_id);
648+
649+
// Record that we replaced `vid` with `new_var_id` as part of a generalization
650+
// operation. This is needed to detect cyclic types. To see why, see the
651+
// docs in the `type_variables` module.
652+
self.infcx.inner.borrow_mut().type_variables().sub(vid, new_var_id);
648653
debug!("generalize: replacing original vid={:?} with new={:?}", vid, u);
649654
Ok(u)
650655
}
@@ -881,7 +886,7 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
881886
*self.infcx.inner.borrow_mut().type_variables().var_origin(vid);
882887
let new_var_id = self.infcx.inner.borrow_mut().type_variables().new_var(
883888
self.for_universe,
884-
false,
889+
Diverging::NotDiverging,
885890
origin,
886891
);
887892
let u = self.tcx().mk_ty_var(new_var_id);

compiler/rustc_infer/src/infer/mod.rs

+78-46
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
2323
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
2424
use rustc_middle::mir::interpret::EvalToConstValueResult;
2525
use rustc_middle::traits::select;
26-
use rustc_middle::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
26+
use rustc_middle::ty::error::{ExpectedFound, TypeError};
2727
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
2828
use rustc_middle::ty::relate::RelateResult;
2929
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef};
@@ -46,7 +46,7 @@ use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, Veri
4646
use self::region_constraints::{
4747
RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot,
4848
};
49-
use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
49+
use self::type_variable::{Diverging, TypeVariableOrigin, TypeVariableOriginKind};
5050

5151
pub mod at;
5252
pub mod canonical;
@@ -679,10 +679,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
679679
t.fold_with(&mut self.freshener())
680680
}
681681

682-
pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> bool {
682+
/// Returns whether `ty` is a diverging type variable or not.
683+
/// (If `ty` is not a type variable at all, returns not diverging.)
684+
///
685+
/// No attempt is made to resolve `ty`.
686+
pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> Diverging {
683687
match *ty.kind() {
684688
ty::Infer(ty::TyVar(vid)) => self.inner.borrow_mut().type_variables().var_diverges(vid),
685-
_ => false,
689+
_ => Diverging::NotDiverging,
690+
}
691+
}
692+
693+
/// Returns the origin of the type variable identified by `vid`, or `None`
694+
/// if this is not a type variable.
695+
///
696+
/// No attempt is made to resolve `ty`.
697+
pub fn type_var_origin(&'a self, ty: Ty<'tcx>) -> Option<TypeVariableOrigin> {
698+
match *ty.kind() {
699+
ty::Infer(ty::TyVar(vid)) => {
700+
Some(*self.inner.borrow_mut().type_variables().var_origin(vid))
701+
}
702+
_ => None,
686703
}
687704
}
688705

@@ -695,28 +712,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
695712
freshen::TypeFreshener::new(self, true)
696713
}
697714

698-
pub fn type_is_unconstrained_numeric(&'a self, ty: Ty<'_>) -> UnconstrainedNumeric {
699-
use rustc_middle::ty::error::UnconstrainedNumeric::Neither;
700-
use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
701-
match *ty.kind() {
702-
ty::Infer(ty::IntVar(vid)) => {
703-
if self.inner.borrow_mut().int_unification_table().probe_value(vid).is_some() {
704-
Neither
705-
} else {
706-
UnconstrainedInt
707-
}
708-
}
709-
ty::Infer(ty::FloatVar(vid)) => {
710-
if self.inner.borrow_mut().float_unification_table().probe_value(vid).is_some() {
711-
Neither
712-
} else {
713-
UnconstrainedFloat
714-
}
715-
}
716-
_ => Neither,
717-
}
718-
}
719-
720715
pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {
721716
let mut inner = self.inner.borrow_mut();
722717
let mut vars: Vec<Ty<'_>> = inner
@@ -969,29 +964,62 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
969964
);
970965
}
971966

967+
/// Processes a `Coerce` predicate from the fulfillment context.
968+
/// This is NOT the preferred way to handle coercion, which is to
969+
/// invoke `FnCtxt::coerce` or a similar method (see `coercion.rs`).
970+
///
971+
/// This method here is actually a fallback that winds up being
972+
/// invoked when `FnCtxt::coerce` encounters unresolved type variables
973+
/// and records a coercion predicate. Presently, this method is equivalent
974+
/// to `subtype_predicate` -- that is, "coercing" `a` to `b` winds up
975+
/// actually requiring `a <: b`. This is of course a valid coercion,
976+
/// but it's not as flexible as `FnCtxt::coerce` would be.
977+
///
978+
/// (We may refactor this in the future, but there are a number of
979+
/// practical obstacles. Among other things, `FnCtxt::coerce` presently
980+
/// records adjustments that are required on the HIR in order to perform
981+
/// the coercion, and we don't currently have a way to manage that.)
982+
pub fn coerce_predicate(
983+
&self,
984+
cause: &ObligationCause<'tcx>,
985+
param_env: ty::ParamEnv<'tcx>,
986+
predicate: ty::PolyCoercePredicate<'tcx>,
987+
) -> Option<InferResult<'tcx, ()>> {
988+
let subtype_predicate = predicate.map_bound(|p| ty::SubtypePredicate {
989+
a_is_expected: false, // when coercing from `a` to `b`, `b` is expected
990+
a: p.a,
991+
b: p.b,
992+
});
993+
self.subtype_predicate(cause, param_env, subtype_predicate)
994+
}
995+
972996
pub fn subtype_predicate(
973997
&self,
974998
cause: &ObligationCause<'tcx>,
975999
param_env: ty::ParamEnv<'tcx>,
9761000
predicate: ty::PolySubtypePredicate<'tcx>,
9771001
) -> Option<InferResult<'tcx, ()>> {
978-
// Subtle: it's ok to skip the binder here and resolve because
979-
// `shallow_resolve` just ignores anything that is not a type
980-
// variable, and because type variable's can't (at present, at
1002+
// Check for two unresolved inference variables, in which case we can
1003+
// make no progress. This is partly a micro-optimization, but it's
1004+
// also an opportunity to "sub-unify" the variables. This isn't
1005+
// *necessary* to prevent cycles, because they would eventually be sub-unified
1006+
// anyhow during generalization, but it helps with diagnostics (we can detect
1007+
// earlier that they are sub-unified).
1008+
//
1009+
// Note that we can just skip the binders here because
1010+
// type variables can't (at present, at
9811011
// least) capture any of the things bound by this binder.
9821012
//
983-
// NOTE(nmatsakis): really, there is no *particular* reason to do this
984-
// `shallow_resolve` here except as a micro-optimization.
985-
// Naturally I could not resist.
986-
let two_unbound_type_vars = {
987-
let a = self.shallow_resolve(predicate.skip_binder().a);
988-
let b = self.shallow_resolve(predicate.skip_binder().b);
989-
a.is_ty_var() && b.is_ty_var()
990-
};
991-
992-
if two_unbound_type_vars {
993-
// Two unbound type variables? Can't make progress.
994-
return None;
1013+
// Note that this sub here is not just for diagnostics - it has semantic
1014+
// effects as well.
1015+
let r_a = self.shallow_resolve(predicate.skip_binder().a);
1016+
let r_b = self.shallow_resolve(predicate.skip_binder().b);
1017+
match (r_a.kind(), r_b.kind()) {
1018+
(&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
1019+
self.inner.borrow_mut().type_variables().sub(a_vid, b_vid);
1020+
return None;
1021+
}
1022+
_ => {}
9951023
}
9961024

9971025
Some(self.commit_if_ok(|_snapshot| {
@@ -1020,25 +1048,29 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
10201048
})
10211049
}
10221050

1023-
pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
1051+
pub fn next_ty_var_id(&self, diverging: Diverging, origin: TypeVariableOrigin) -> TyVid {
10241052
self.inner.borrow_mut().type_variables().new_var(self.universe(), diverging, origin)
10251053
}
10261054

10271055
pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
1028-
self.tcx.mk_ty_var(self.next_ty_var_id(false, origin))
1056+
self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::NotDiverging, origin))
10291057
}
10301058

10311059
pub fn next_ty_var_in_universe(
10321060
&self,
10331061
origin: TypeVariableOrigin,
10341062
universe: ty::UniverseIndex,
10351063
) -> Ty<'tcx> {
1036-
let vid = self.inner.borrow_mut().type_variables().new_var(universe, false, origin);
1064+
let vid = self.inner.borrow_mut().type_variables().new_var(
1065+
universe,
1066+
Diverging::NotDiverging,
1067+
origin,
1068+
);
10371069
self.tcx.mk_ty_var(vid)
10381070
}
10391071

10401072
pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
1041-
self.tcx.mk_ty_var(self.next_ty_var_id(true, origin))
1073+
self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::Diverges, origin))
10421074
}
10431075

10441076
pub fn next_const_var(
@@ -1152,7 +1184,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
11521184
// as the substitutions for the default, `(T, U)`.
11531185
let ty_var_id = self.inner.borrow_mut().type_variables().new_var(
11541186
self.universe(),
1155-
false,
1187+
Diverging::NotDiverging,
11561188
TypeVariableOrigin {
11571189
kind: TypeVariableOriginKind::TypeParameterDefinition(
11581190
param.name,

compiler/rustc_infer/src/infer/nll_relate/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
//! constituents)
2323
2424
use crate::infer::combine::ConstEquateRelation;
25+
use crate::infer::type_variable::Diverging;
2526
use crate::infer::InferCtxt;
2627
use crate::infer::{ConstVarValue, ConstVariableValue};
2728
use rustc_data_structures::fx::FxHashMap;
@@ -920,7 +921,8 @@ where
920921
// Replacing with a new variable in the universe `self.universe`,
921922
// it will be unified later with the original type variable in
922923
// the universe `_universe`.
923-
let new_var_id = variables.new_var(self.universe, false, origin);
924+
let new_var_id =
925+
variables.new_var(self.universe, Diverging::NotDiverging, origin);
924926

925927
let u = self.tcx().mk_ty_var(new_var_id);
926928
debug!("generalize: replacing original vid={:?} with new={:?}", vid, u);

compiler/rustc_infer/src/infer/outlives/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub fn explicit_outlives_bounds<'tcx>(
1919
.filter_map(move |kind| match kind {
2020
ty::PredicateKind::Projection(..)
2121
| ty::PredicateKind::Trait(..)
22+
| ty::PredicateKind::Coerce(..)
2223
| ty::PredicateKind::Subtype(..)
2324
| ty::PredicateKind::WellFormed(..)
2425
| ty::PredicateKind::ObjectSafe(..)

compiler/rustc_infer/src/infer/sub.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -85,19 +85,15 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> {
8585
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
8686
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
8787
match (a.kind(), b.kind()) {
88-
(&ty::Infer(TyVar(a_vid)), &ty::Infer(TyVar(b_vid))) => {
88+
(&ty::Infer(TyVar(_)), &ty::Infer(TyVar(_))) => {
8989
// Shouldn't have any LBR here, so we can safely put
9090
// this under a binder below without fear of accidental
9191
// capture.
9292
assert!(!a.has_escaping_bound_vars());
9393
assert!(!b.has_escaping_bound_vars());
9494

9595
// can't make progress on `A <: B` if both A and B are
96-
// type variables, so record an obligation. We also
97-
// have to record in the `type_variables` tracker that
98-
// the two variables are equal modulo subtyping, which
99-
// is important to the occurs check later on.
100-
infcx.inner.borrow_mut().type_variables().sub(a_vid, b_vid);
96+
// type variables, so record an obligation.
10197
self.fields.obligations.push(Obligation::new(
10298
self.fields.trace.cause.clone(),
10399
self.fields.param_env,

compiler/rustc_infer/src/infer/type_variable.rs

+29-7
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,30 @@ pub struct TypeVariableStorage<'tcx> {
7575
/// ?1 <: ?3
7676
/// Box<?3> <: ?1
7777
///
78-
/// This works because `?1` and `?3` are unified in the
79-
/// `sub_relations` relation (not in `eq_relations`). Then when we
80-
/// process the `Box<?3> <: ?1` constraint, we do an occurs check
81-
/// on `Box<?3>` and find a potential cycle.
78+
/// Without this second table, what would happen in a case like
79+
/// this is that we would instantiate `?1` with a generalized
80+
/// type like `Box<?6>`. We would then relate `Box<?3> <: Box<?6>`
81+
/// and infer that `?3 <: ?6`. Next, since `?1` was instantiated,
82+
/// we would process `?1 <: ?3`, generalize `?1 = Box<?6>` to `Box<?9>`,
83+
/// and instantiate `?3` with `Box<?9>`. Finally, we would relate
84+
/// `?6 <: ?9`. But now that we instantiated `?3`, we can process
85+
/// `?3 <: ?6`, which gives us `Box<?9> <: ?6`... and the cycle
86+
/// continues. (This is `occurs-check-2.rs`.)
87+
///
88+
/// What prevents this cycle is that when we generalize
89+
/// `Box<?3>` to `Box<?6>`, we also sub-unify `?3` and `?6`
90+
/// (in the generalizer). When we then process `Box<?6> <: ?3`,
91+
/// the occurs check then fails because `?6` and `?3` are sub-unified,
92+
/// and hence generalization fails.
8293
///
8394
/// This is reasonable because, in Rust, subtypes have the same
8495
/// "skeleton" and hence there is no possible type such that
8596
/// (e.g.) `Box<?3> <: ?3` for any `?3`.
97+
///
98+
/// In practice, we sometimes sub-unify variables in other spots, such
99+
/// as when processing subtype predicates. This is not necessary but is
100+
/// done to aid diagnostics, as it allows us to be more effective when
101+
/// we guide the user towards where they should insert type hints.
86102
sub_relations: ut::UnificationTableStorage<ty::TyVid>,
87103
}
88104

@@ -119,7 +135,13 @@ pub enum TypeVariableOriginKind {
119135

120136
pub(crate) struct TypeVariableData {
121137
origin: TypeVariableOrigin,
122-
diverging: bool,
138+
diverging: Diverging,
139+
}
140+
141+
#[derive(Copy, Clone, Debug)]
142+
pub enum Diverging {
143+
NotDiverging,
144+
Diverges,
123145
}
124146

125147
#[derive(Copy, Clone, Debug)]
@@ -173,7 +195,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
173195
///
174196
/// Note that this function does not return care whether
175197
/// `vid` has been unified with something else or not.
176-
pub fn var_diverges(&self, vid: ty::TyVid) -> bool {
198+
pub fn var_diverges(&self, vid: ty::TyVid) -> Diverging {
177199
self.storage.values.get(vid.index as usize).diverging
178200
}
179201

@@ -238,7 +260,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
238260
pub fn new_var(
239261
&mut self,
240262
universe: ty::UniverseIndex,
241-
diverging: bool,
263+
diverging: Diverging,
242264
origin: TypeVariableOrigin,
243265
) -> ty::TyVid {
244266
let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe });

compiler/rustc_infer/src/traits/util.rs

+4
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ impl Elaborator<'tcx> {
158158
// Currently, we do not "elaborate" predicates like `X <: Y`,
159159
// though conceivably we might.
160160
}
161+
ty::PredicateKind::Coerce(..) => {
162+
// Currently, we do not "elaborate" predicates like `X -> Y`,
163+
// though conceivably we might.
164+
}
161165
ty::PredicateKind::Projection(..) => {
162166
// Nothing to elaborate in a projection predicate.
163167
}

compiler/rustc_lint/src/builtin.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1652,6 +1652,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
16521652
ObjectSafe(..) |
16531653
ClosureKind(..) |
16541654
Subtype(..) |
1655+
Coerce(..) |
16551656
ConstEvaluatable(..) |
16561657
ConstEquate(..) |
16571658
TypeWellFormedFromEnv(..) => continue,

compiler/rustc_middle/src/ty/error.rs

-6
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,6 @@ pub enum TypeError<'tcx> {
7171
TargetFeatureCast(DefId),
7272
}
7373

74-
pub enum UnconstrainedNumeric {
75-
UnconstrainedFloat,
76-
UnconstrainedInt,
77-
Neither,
78-
}
79-
8074
/// Explains the source of a type err in a short, human readable way. This is meant to be placed
8175
/// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
8276
/// afterwards to present additional details, particularly when it comes to lifetime-related

compiler/rustc_middle/src/ty/flags.rs

+4
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,10 @@ impl FlagComputation {
231231
self.add_ty(a);
232232
self.add_ty(b);
233233
}
234+
ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
235+
self.add_ty(a);
236+
self.add_ty(b);
237+
}
234238
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
235239
self.add_projection_ty(projection_ty);
236240
self.add_ty(ty);

0 commit comments

Comments
 (0)