Skip to content

Commit 73b743b

Browse files
committed
move fallback_if_possible and friends to fallback.rs
Along the way, simplify and document the logic more clearly.
1 parent de3bf35 commit 73b743b

File tree

5 files changed

+125
-126
lines changed

5 files changed

+125
-126
lines changed

compiler/rustc_infer/src/infer/mod.rs

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKin
2121
use rustc_middle::mir;
2222
use rustc_middle::mir::interpret::EvalToConstValueResult;
2323
use rustc_middle::traits::select;
24-
use rustc_middle::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
24+
use rustc_middle::ty::error::{ExpectedFound, TypeError};
2525
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
2626
use rustc_middle::ty::relate::RelateResult;
2727
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef};
@@ -641,39 +641,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
641641
t.fold_with(&mut self.freshener())
642642
}
643643

644+
/// Returns whether `ty` is a diverging type variable or not.
645+
/// (If `ty` is not a type variable at all, returns not diverging.)
646+
///
647+
/// No attempt is made to resolve `ty`.
644648
pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> Diverging {
645649
match *ty.kind() {
646650
ty::Infer(ty::TyVar(vid)) => self.inner.borrow_mut().type_variables().var_diverges(vid),
647651
_ => Diverging::NotDiverging,
648652
}
649653
}
650654

651-
pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
652-
freshen::TypeFreshener::new(self)
653-
}
654-
655-
pub fn type_is_unconstrained_numeric(&'a self, ty: Ty<'_>) -> UnconstrainedNumeric {
656-
use rustc_middle::ty::error::UnconstrainedNumeric::Neither;
657-
use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
655+
/// Returns the origin of the type variable identified by `vid`, or `None`
656+
/// if this is not a type variable.
657+
///
658+
/// No attempt is made to resolve `ty`.
659+
pub fn type_var_origin(&'a self, ty: Ty<'tcx>) -> Option<TypeVariableOrigin> {
658660
match *ty.kind() {
659-
ty::Infer(ty::IntVar(vid)) => {
660-
if self.inner.borrow_mut().int_unification_table().probe_value(vid).is_some() {
661-
Neither
662-
} else {
663-
UnconstrainedInt
664-
}
661+
ty::Infer(ty::TyVar(vid)) => {
662+
Some(*self.inner.borrow_mut().type_variables().var_origin(vid))
665663
}
666-
ty::Infer(ty::FloatVar(vid)) => {
667-
if self.inner.borrow_mut().float_unification_table().probe_value(vid).is_some() {
668-
Neither
669-
} else {
670-
UnconstrainedFloat
671-
}
672-
}
673-
_ => Neither,
664+
_ => None,
674665
}
675666
}
676667

668+
pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
669+
freshen::TypeFreshener::new(self)
670+
}
677671
pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {
678672
let mut inner = self.inner.borrow_mut();
679673
let mut vars: Vec<Ty<'_>> = inner

compiler/rustc_middle/src/ty/error.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,6 @@ pub enum TypeError<'tcx> {
6767
TargetFeatureCast(DefId),
6868
}
6969

70-
pub enum UnconstrainedNumeric {
71-
UnconstrainedFloat,
72-
UnconstrainedInt,
73-
Neither,
74-
}
75-
7670
/// Explains the source of a type err in a short, human readable way. This is meant to be placed
7771
/// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
7872
/// afterwards to present additional details, particularly when it comes to lifetime-related

compiler/rustc_typeck/src/check/fallback.rs

Lines changed: 107 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
use crate::check::FallbackMode;
21
use crate::check::FnCtxt;
2+
use rustc_infer::infer::type_variable::Diverging;
3+
use rustc_middle::ty::{self, Ty};
34

45
impl<'tcx> FnCtxt<'_, 'tcx> {
56
pub(super) fn type_inference_fallback(&self) {
@@ -12,8 +13,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
1213
// The first time, we do *not* replace opaque types.
1314
for ty in &self.unsolved_variables() {
1415
debug!("unsolved_variable = {:?}", ty);
15-
fallback_has_occurred |= self.fallback_if_possible(ty, FallbackMode::NoOpaque);
16+
fallback_has_occurred |= self.fallback_if_possible(ty);
1617
}
18+
1719
// We now see if we can make progress. This might
1820
// cause us to unify inference variables for opaque types,
1921
// since we may have unified some other type variables
@@ -43,10 +45,112 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
4345
// unconstrained opaque type variables, in addition to performing
4446
// other kinds of fallback.
4547
for ty in &self.unsolved_variables() {
46-
fallback_has_occurred |= self.fallback_if_possible(ty, FallbackMode::All);
48+
fallback_has_occurred |= self.fallback_opaque_type_vars(ty);
4749
}
4850

4951
// See if we can make any more progress.
5052
self.select_obligations_where_possible(fallback_has_occurred, |_| {});
5153
}
54+
55+
// Tries to apply a fallback to `ty` if it is an unsolved variable.
56+
//
57+
// - Unconstrained ints are replaced with `i32`.
58+
//
59+
// - Unconstrained floats are replaced with with `f64`.
60+
//
61+
// - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
62+
// is enabled. Otherwise, they are replaced with `()`.
63+
//
64+
// Fallback becomes very dubious if we have encountered type-checking errors.
65+
// In that case, fallback to Error.
66+
// The return value indicates whether fallback has occurred.
67+
fn fallback_if_possible(&self, ty: Ty<'tcx>) -> bool {
68+
// Careful: we do NOT shallow-resolve `ty`. We know that `ty`
69+
// is an unsolved variable, and we determine its fallback based
70+
// solely on how it was created, not what other type variables
71+
// it may have been unified with since then.
72+
//
73+
// The reason this matters is that other attempts at fallback may
74+
// (in principle) conflict with this fallback, and we wish to generate
75+
// a type error in that case. (However, this actually isn't true right now,
76+
// because we're only using the builtin fallback rules. This would be
77+
// true if we were using user-supplied fallbacks. But it's still useful
78+
// to write the code to detect bugs.)
79+
//
80+
// (Note though that if we have a general type variable `?T` that is then unified
81+
// with an integer type variable `?I` that ultimately never gets
82+
// resolved to a special integral type, `?T` is not considered unsolved,
83+
// but `?I` is. The same is true for float variables.)
84+
let fallback = match ty.kind() {
85+
_ if self.is_tainted_by_errors() => self.tcx.ty_error(),
86+
ty::Infer(ty::IntVar(_)) => self.tcx.types.i32,
87+
ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64,
88+
_ => match self.type_var_diverges(ty) {
89+
Diverging::Diverges => self.tcx.mk_diverging_default(),
90+
Diverging::NotDiverging => return false,
91+
},
92+
};
93+
debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback);
94+
95+
let span = self
96+
.infcx
97+
.type_var_origin(ty)
98+
.map(|origin| origin.span)
99+
.unwrap_or(rustc_span::DUMMY_SP);
100+
self.demand_eqtype(span, ty, fallback);
101+
true
102+
}
103+
104+
/// Second round of fallback: Unconstrained type variables
105+
/// created from the instantiation of an opaque
106+
/// type fall back to the opaque type itself. This is a
107+
/// somewhat incomplete attempt to manage "identity passthrough"
108+
/// for `impl Trait` types.
109+
///
110+
/// For example, in this code:
111+
///
112+
///```
113+
/// type MyType = impl Copy;
114+
/// fn defining_use() -> MyType { true }
115+
/// fn other_use() -> MyType { defining_use() }
116+
/// ```
117+
///
118+
/// `defining_use` will constrain the instantiated inference
119+
/// variable to `bool`, while `other_use` will constrain
120+
/// the instantiated inference variable to `MyType`.
121+
///
122+
/// When we process opaque types during writeback, we
123+
/// will handle cases like `other_use`, and not count
124+
/// them as defining usages
125+
///
126+
/// However, we also need to handle cases like this:
127+
///
128+
/// ```rust
129+
/// pub type Foo = impl Copy;
130+
/// fn produce() -> Option<Foo> {
131+
/// None
132+
/// }
133+
/// ```
134+
///
135+
/// In the above snippet, the inference variable created by
136+
/// instantiating `Option<Foo>` will be completely unconstrained.
137+
/// We treat this as a non-defining use by making the inference
138+
/// variable fall back to the opaque type itself.
139+
fn fallback_opaque_type_vars(&self, ty: Ty<'tcx>) -> bool {
140+
let span = self
141+
.infcx
142+
.type_var_origin(ty)
143+
.map(|origin| origin.span)
144+
.unwrap_or(rustc_span::DUMMY_SP);
145+
if let Some(&opaque_ty) = self.opaque_types_vars.borrow().get(ty) {
146+
debug!(
147+
"fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}",
148+
ty, opaque_ty
149+
);
150+
self.demand_eqtype(span, ty, opaque_ty);
151+
true
152+
} else {
153+
return false;
154+
}
155+
}
52156
}

compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs

Lines changed: 2 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::astconv::{
44
};
55
use crate::check::callee::{self, DeferredCallResolution};
66
use crate::check::method::{self, MethodCallee, SelfSource};
7-
use crate::check::{BreakableCtxt, Diverges, Expectation, FallbackMode, FnCtxt, LocalTy};
7+
use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
88

99
use rustc_data_structures::captures::Captures;
1010
use rustc_data_structures::fx::FxHashSet;
@@ -14,11 +14,8 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
1414
use rustc_hir::def_id::DefId;
1515
use rustc_hir::lang_items::LangItem;
1616
use rustc_hir::{ExprKind, GenericArg, Node, QPath};
17+
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
1718
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
18-
use rustc_infer::infer::{
19-
canonical::{Canonical, OriginalQueryValues, QueryResponse},
20-
type_variable::Diverging,
21-
};
2219
use rustc_infer::infer::{InferOk, InferResult};
2320
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
2421
use rustc_middle::ty::fold::TypeFoldable;
@@ -612,86 +609,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
612609
}
613610
}
614611

615-
// Tries to apply a fallback to `ty` if it is an unsolved variable.
616-
//
617-
// - Unconstrained ints are replaced with `i32`.
618-
//
619-
// - Unconstrained floats are replaced with with `f64`.
620-
//
621-
// - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
622-
// is enabled. Otherwise, they are replaced with `()`.
623-
//
624-
// Fallback becomes very dubious if we have encountered type-checking errors.
625-
// In that case, fallback to Error.
626-
// The return value indicates whether fallback has occurred.
627-
pub(in super::super) fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool {
628-
use rustc_middle::ty::error::UnconstrainedNumeric::Neither;
629-
use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
630-
631-
assert!(ty.is_ty_infer());
632-
let fallback = match self.type_is_unconstrained_numeric(ty) {
633-
_ if self.is_tainted_by_errors() => self.tcx().ty_error(),
634-
UnconstrainedInt => self.tcx.types.i32,
635-
UnconstrainedFloat => self.tcx.types.f64,
636-
Neither => match self.type_var_diverges(ty) {
637-
Diverging::Diverges => self.tcx.mk_diverging_default(),
638-
639-
Diverging::NotDiverging => {
640-
// This type variable was created from the instantiation of an opaque
641-
// type. The fact that we're attempting to perform fallback for it
642-
// means that the function neither constrained it to a concrete
643-
// type, nor to the opaque type itself.
644-
//
645-
// For example, in this code:
646-
//
647-
//```
648-
// type MyType = impl Copy;
649-
// fn defining_use() -> MyType { true }
650-
// fn other_use() -> MyType { defining_use() }
651-
// ```
652-
//
653-
// `defining_use` will constrain the instantiated inference
654-
// variable to `bool`, while `other_use` will constrain
655-
// the instantiated inference variable to `MyType`.
656-
//
657-
// When we process opaque types during writeback, we
658-
// will handle cases like `other_use`, and not count
659-
// them as defining usages
660-
//
661-
// However, we also need to handle cases like this:
662-
//
663-
// ```rust
664-
// pub type Foo = impl Copy;
665-
// fn produce() -> Option<Foo> {
666-
// None
667-
// }
668-
// ```
669-
//
670-
// In the above snippet, the inference variable created by
671-
// instantiating `Option<Foo>` will be completely unconstrained.
672-
// We treat this as a non-defining use by making the inference
673-
// variable fall back to the opaque type itself.
674-
if let FallbackMode::All = mode {
675-
if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) {
676-
debug!(
677-
"fallback_if_possible: falling back opaque type var {:?} to {:?}",
678-
ty, opaque_ty
679-
);
680-
*opaque_ty
681-
} else {
682-
return false;
683-
}
684-
} else {
685-
return false;
686-
}
687-
}
688-
},
689-
};
690-
debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback);
691-
self.demand_eqtype(rustc_span::DUMMY_SP, ty, fallback);
692-
true
693-
}
694-
695612
pub(in super::super) fn select_all_obligations_or_error(&self) {
696613
debug!("select_all_obligations_or_error");
697614
if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) {

compiler/rustc_typeck/src/check/mod.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,16 +1046,6 @@ enum TupleArgumentsFlag {
10461046
TupleArguments,
10471047
}
10481048

1049-
/// Controls how we perform fallback for unconstrained
1050-
/// type variables.
1051-
enum FallbackMode {
1052-
/// Do not fallback type variables to opaque types.
1053-
NoOpaque,
1054-
/// Perform all possible kinds of fallback, including
1055-
/// turning type variables to opaque types.
1056-
All,
1057-
}
1058-
10591049
/// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field.
10601050
#[derive(Copy, Clone)]
10611051
struct MaybeInProgressTables<'a, 'tcx> {

0 commit comments

Comments
 (0)