]>
git.proxmox.com Git - rustc.git/blob - compiler/rustc_typeck/src/check/fallback.rs
1 use crate::check
::FnCtxt
;
2 use rustc_infer
::infer
::type_variable
::Diverging
;
3 use rustc_middle
::ty
::{self, Ty}
;
5 impl<'tcx
> FnCtxt
<'_
, 'tcx
> {
6 /// Performs type inference fallback, returning true if any fallback
8 pub(super) fn type_inference_fallback(&self) -> bool
{
9 // All type checking constraints were added, try to fallback unsolved variables.
10 self.select_obligations_where_possible(false, |_
| {}
);
11 let mut fallback_has_occurred
= false;
13 // We do fallback in two passes, to try to generate
14 // better error messages.
15 // The first time, we do *not* replace opaque types.
16 for ty
in &self.unsolved_variables() {
17 debug
!("unsolved_variable = {:?}", ty
);
18 fallback_has_occurred
|= self.fallback_if_possible(ty
);
21 // We now see if we can make progress. This might
22 // cause us to unify inference variables for opaque types,
23 // since we may have unified some other type variables
24 // during the first phase of fallback.
25 // This means that we only replace inference variables with their underlying
26 // opaque types as a last resort.
31 // type MyType = impl Copy;
32 // fn produce() -> MyType { true }
33 // fn bad_produce() -> MyType { panic!() }
36 // we want to unify the opaque inference variable in `bad_produce`
37 // with the diverging fallback for `panic!` (e.g. `()` or `!`).
38 // This will produce a nice error message about conflicting concrete
39 // types for `MyType`.
41 // If we had tried to fallback the opaque inference variable to `MyType`,
42 // we will generate a confusing type-check error that does not explicitly
43 // refer to opaque types.
44 self.select_obligations_where_possible(fallback_has_occurred
, |_
| {}
);
46 // We now run fallback again, but this time we allow it to replace
47 // unconstrained opaque type variables, in addition to performing
48 // other kinds of fallback.
49 for ty
in &self.unsolved_variables() {
50 fallback_has_occurred
|= self.fallback_opaque_type_vars(ty
);
53 // See if we can make any more progress.
54 self.select_obligations_where_possible(fallback_has_occurred
, |_
| {}
);
59 // Tries to apply a fallback to `ty` if it is an unsolved variable.
61 // - Unconstrained ints are replaced with `i32`.
63 // - Unconstrained floats are replaced with with `f64`.
65 // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
66 // is enabled. Otherwise, they are replaced with `()`.
68 // Fallback becomes very dubious if we have encountered type-checking errors.
69 // In that case, fallback to Error.
70 // The return value indicates whether fallback has occurred.
71 fn fallback_if_possible(&self, ty
: Ty
<'tcx
>) -> bool
{
72 // Careful: we do NOT shallow-resolve `ty`. We know that `ty`
73 // is an unsolved variable, and we determine its fallback based
74 // solely on how it was created, not what other type variables
75 // it may have been unified with since then.
77 // The reason this matters is that other attempts at fallback may
78 // (in principle) conflict with this fallback, and we wish to generate
79 // a type error in that case. (However, this actually isn't true right now,
80 // because we're only using the builtin fallback rules. This would be
81 // true if we were using user-supplied fallbacks. But it's still useful
82 // to write the code to detect bugs.)
84 // (Note though that if we have a general type variable `?T` that is then unified
85 // with an integer type variable `?I` that ultimately never gets
86 // resolved to a special integral type, `?T` is not considered unsolved,
87 // but `?I` is. The same is true for float variables.)
88 let fallback
= match ty
.kind() {
89 _
if self.is_tainted_by_errors() => self.tcx
.ty_error(),
90 ty
::Infer(ty
::IntVar(_
)) => self.tcx
.types
.i32,
91 ty
::Infer(ty
::FloatVar(_
)) => self.tcx
.types
.f64,
92 _
=> match self.type_var_diverges(ty
) {
93 Diverging
::Diverges
=> self.tcx
.mk_diverging_default(),
94 Diverging
::NotDiverging
=> return false,
97 debug
!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty
, fallback
);
102 .map(|origin
| origin
.span
)
103 .unwrap_or(rustc_span
::DUMMY_SP
);
104 self.demand_eqtype(span
, ty
, fallback
);
108 /// Second round of fallback: Unconstrained type variables
109 /// created from the instantiation of an opaque
110 /// type fall back to the opaque type itself. This is a
111 /// somewhat incomplete attempt to manage "identity passthrough"
112 /// for `impl Trait` types.
114 /// For example, in this code:
117 /// type MyType = impl Copy;
118 /// fn defining_use() -> MyType { true }
119 /// fn other_use() -> MyType { defining_use() }
122 /// `defining_use` will constrain the instantiated inference
123 /// variable to `bool`, while `other_use` will constrain
124 /// the instantiated inference variable to `MyType`.
126 /// When we process opaque types during writeback, we
127 /// will handle cases like `other_use`, and not count
128 /// them as defining usages
130 /// However, we also need to handle cases like this:
133 /// pub type Foo = impl Copy;
134 /// fn produce() -> Option<Foo> {
139 /// In the above snippet, the inference variable created by
140 /// instantiating `Option<Foo>` will be completely unconstrained.
141 /// We treat this as a non-defining use by making the inference
142 /// variable fall back to the opaque type itself.
143 fn fallback_opaque_type_vars(&self, ty
: Ty
<'tcx
>) -> bool
{
147 .map(|origin
| origin
.span
)
148 .unwrap_or(rustc_span
::DUMMY_SP
);
149 let oty
= self.inner
.borrow().opaque_types_vars
.get(ty
).map(|v
| *v
);
150 if let Some(opaque_ty
) = oty
{
152 "fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}",
155 self.demand_eqtype(span
, ty
, opaque_ty
);