]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_typeck/src/check/fallback.rs
New upstream version 1.56.0~beta.4+dfsg1
[rustc.git] / 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};
4
5 impl<'tcx> FnCtxt<'_, 'tcx> {
6 /// Performs type inference fallback, returning true if any fallback
7 /// occurs.
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;
12
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);
19 }
20
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.
27 //
28 // In code like this:
29 //
30 // ```rust
31 // type MyType = impl Copy;
32 // fn produce() -> MyType { true }
33 // fn bad_produce() -> MyType { panic!() }
34 // ```
35 //
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`.
40 //
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, |_| {});
45
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);
51 }
52
53 // See if we can make any more progress.
54 self.select_obligations_where_possible(fallback_has_occurred, |_| {});
55
56 fallback_has_occurred
57 }
58
59 // Tries to apply a fallback to `ty` if it is an unsolved variable.
60 //
61 // - Unconstrained ints are replaced with `i32`.
62 //
63 // - Unconstrained floats are replaced with with `f64`.
64 //
65 // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
66 // is enabled. Otherwise, they are replaced with `()`.
67 //
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.
76 //
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.)
83 //
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,
95 },
96 };
97 debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback);
98
99 let span = self
100 .infcx
101 .type_var_origin(ty)
102 .map(|origin| origin.span)
103 .unwrap_or(rustc_span::DUMMY_SP);
104 self.demand_eqtype(span, ty, fallback);
105 true
106 }
107
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.
113 ///
114 /// For example, in this code:
115 ///
116 ///```
117 /// type MyType = impl Copy;
118 /// fn defining_use() -> MyType { true }
119 /// fn other_use() -> MyType { defining_use() }
120 /// ```
121 ///
122 /// `defining_use` will constrain the instantiated inference
123 /// variable to `bool`, while `other_use` will constrain
124 /// the instantiated inference variable to `MyType`.
125 ///
126 /// When we process opaque types during writeback, we
127 /// will handle cases like `other_use`, and not count
128 /// them as defining usages
129 ///
130 /// However, we also need to handle cases like this:
131 ///
132 /// ```rust
133 /// pub type Foo = impl Copy;
134 /// fn produce() -> Option<Foo> {
135 /// None
136 /// }
137 /// ```
138 ///
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 {
144 let span = self
145 .infcx
146 .type_var_origin(ty)
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 {
151 debug!(
152 "fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}",
153 ty, opaque_ty
154 );
155 self.demand_eqtype(span, ty, opaque_ty);
156 true
157 } else {
158 return false;
159 }
160 }
161 }