]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_typeck/src/check/fallback.rs
15788f410f1951bf92733bd0ad8bfdc8df2fdb49
[rust.git] / compiler / rustc_typeck / src / check / fallback.rs
1 use crate::check::FnCtxt;
2 use rustc_data_structures::{
3     fx::FxHashMap,
4     graph::WithSuccessors,
5     graph::{iterate::DepthFirstSearch, vec_graph::VecGraph},
6     stable_set::FxHashSet,
7 };
8 use rustc_middle::ty::{self, Ty};
9
10 impl<'tcx> FnCtxt<'_, 'tcx> {
11     /// Performs type inference fallback, returning true if any fallback
12     /// occurs.
13     pub(super) fn type_inference_fallback(&self) -> bool {
14         debug!(
15             "type-inference-fallback start obligations: {:#?}",
16             self.fulfillment_cx.borrow_mut().pending_obligations()
17         );
18
19         // All type checking constraints were added, try to fallback unsolved variables.
20         self.select_obligations_where_possible(false, |_| {});
21
22         debug!(
23             "type-inference-fallback post selection obligations: {:#?}",
24             self.fulfillment_cx.borrow_mut().pending_obligations()
25         );
26
27         // Check if we have any unsolved variables. If not, no need for fallback.
28         let unsolved_variables = self.unsolved_variables();
29         if unsolved_variables.is_empty() {
30             return false;
31         }
32
33         let diverging_fallback = self.calculate_diverging_fallback(&unsolved_variables);
34
35         let mut fallback_has_occurred = false;
36         // We do fallback in two passes, to try to generate
37         // better error messages.
38         // The first time, we do *not* replace opaque types.
39         for ty in unsolved_variables {
40             debug!("unsolved_variable = {:?}", ty);
41             fallback_has_occurred |= self.fallback_if_possible(ty, &diverging_fallback);
42         }
43
44         // We now see if we can make progress. This might cause us to
45         // unify inference variables for opaque types, since we may
46         // have unified some other type variables during the first
47         // phase of fallback.  This means that we only replace
48         // inference variables with their underlying opaque types as a
49         // last resort.
50         //
51         // In code like this:
52         //
53         // ```rust
54         // type MyType = impl Copy;
55         // fn produce() -> MyType { true }
56         // fn bad_produce() -> MyType { panic!() }
57         // ```
58         //
59         // we want to unify the opaque inference variable in `bad_produce`
60         // with the diverging fallback for `panic!` (e.g. `()` or `!`).
61         // This will produce a nice error message about conflicting concrete
62         // types for `MyType`.
63         //
64         // If we had tried to fallback the opaque inference variable to `MyType`,
65         // we will generate a confusing type-check error that does not explicitly
66         // refer to opaque types.
67         self.select_obligations_where_possible(fallback_has_occurred, |_| {});
68
69         fallback_has_occurred
70     }
71
72     // Tries to apply a fallback to `ty` if it is an unsolved variable.
73     //
74     // - Unconstrained ints are replaced with `i32`.
75     //
76     // - Unconstrained floats are replaced with with `f64`.
77     //
78     // - Non-numerics may get replaced with `()` or `!`, depending on
79     //   how they were categorized by `calculate_diverging_fallback`
80     //   (and the setting of `#![feature(never_type_fallback)]`).
81     //
82     // Fallback becomes very dubious if we have encountered
83     // type-checking errors.  In that case, fallback to Error.
84     //
85     // The return value indicates whether fallback has occurred.
86     fn fallback_if_possible(
87         &self,
88         ty: Ty<'tcx>,
89         diverging_fallback: &FxHashMap<Ty<'tcx>, Ty<'tcx>>,
90     ) -> bool {
91         // Careful: we do NOT shallow-resolve `ty`. We know that `ty`
92         // is an unsolved variable, and we determine its fallback
93         // based solely on how it was created, not what other type
94         // variables it may have been unified with since then.
95         //
96         // The reason this matters is that other attempts at fallback
97         // may (in principle) conflict with this fallback, and we wish
98         // to generate a type error in that case. (However, this
99         // actually isn't true right now, because we're only using the
100         // builtin fallback rules. This would be true if we were using
101         // user-supplied fallbacks. But it's still useful to write the
102         // code to detect bugs.)
103         //
104         // (Note though that if we have a general type variable `?T`
105         // that is then unified with an integer type variable `?I`
106         // that ultimately never gets resolved to a special integral
107         // type, `?T` is not considered unsolved, but `?I` is. The
108         // same is true for float variables.)
109         let fallback = match ty.kind() {
110             _ if self.is_tainted_by_errors() => self.tcx.ty_error(),
111             ty::Infer(ty::IntVar(_)) => self.tcx.types.i32,
112             ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64,
113             _ => match diverging_fallback.get(&ty) {
114                 Some(&fallback_ty) => fallback_ty,
115                 None => return false,
116             },
117         };
118         debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback);
119
120         let span = self
121             .infcx
122             .type_var_origin(ty)
123             .map(|origin| origin.span)
124             .unwrap_or(rustc_span::DUMMY_SP);
125         self.demand_eqtype(span, ty, fallback);
126         true
127     }
128
129     /// The "diverging fallback" system is rather complicated. This is
130     /// a result of our need to balance 'do the right thing' with
131     /// backwards compatibility.
132     ///
133     /// "Diverging" type variables are variables created when we
134     /// coerce a `!` type into an unbound type variable `?X`. If they
135     /// never wind up being constrained, the "right and natural" thing
136     /// is that `?X` should "fallback" to `!`. This means that e.g. an
137     /// expression like `Some(return)` will ultimately wind up with a
138     /// type like `Option<!>` (presuming it is not assigned or
139     /// constrained to have some other type).
140     ///
141     /// However, the fallback used to be `()` (before the `!` type was
142     /// added).  Moreover, there are cases where the `!` type 'leaks
143     /// out' from dead code into type variables that affect live
144     /// code. The most common case is something like this:
145     ///
146     /// ```rust
147     /// # fn foo() -> i32 { 4 }
148     /// match foo() {
149     ///     22 => Default::default(), // call this type `?D`
150     ///     _ => return, // return has type `!`
151     /// } // call the type of this match `?M`
152     /// ```
153     ///
154     /// Here, coercing the type `!` into `?M` will create a diverging
155     /// type variable `?X` where `?X <: ?M`.  We also have that `?D <:
156     /// ?M`. If `?M` winds up unconstrained, then `?X` will
157     /// fallback. If it falls back to `!`, then all the type variables
158     /// will wind up equal to `!` -- this includes the type `?D`
159     /// (since `!` doesn't implement `Default`, we wind up a "trait
160     /// not implemented" error in code like this). But since the
161     /// original fallback was `()`, this code used to compile with `?D
162     /// = ()`. This is somewhat surprising, since `Default::default()`
163     /// on its own would give an error because the types are
164     /// insufficiently constrained.
165     ///
166     /// Our solution to this dilemma is to modify diverging variables
167     /// so that they can *either* fallback to `!` (the default) or to
168     /// `()` (the backwards compatibility case). We decide which
169     /// fallback to use based on whether there is a coercion pattern
170     /// like this:
171     ///
172     /// ```ignore (not-rust)
173     /// ?Diverging -> ?V
174     /// ?NonDiverging -> ?V
175     /// ?V != ?NonDiverging
176     /// ```
177     ///
178     /// Here `?Diverging` represents some diverging type variable and
179     /// `?NonDiverging` represents some non-diverging type
180     /// variable. `?V` can be any type variable (diverging or not), so
181     /// long as it is not equal to `?NonDiverging`.
182     ///
183     /// Intuitively, what we are looking for is a case where a
184     /// "non-diverging" type variable (like `?M` in our example above)
185     /// is coerced *into* some variable `?V` that would otherwise
186     /// fallback to `!`. In that case, we make `?V` fallback to `!`,
187     /// along with anything that would flow into `?V`.
188     ///
189     /// The algorithm we use:
190     /// * Identify all variables that are coerced *into* by a
191     ///   diverging variable.  Do this by iterating over each
192     ///   diverging, unsolved variable and finding all variables
193     ///   reachable from there. Call that set `D`.
194     /// * Walk over all unsolved, non-diverging variables, and find
195     ///   any variable that has an edge into `D`.
196     fn calculate_diverging_fallback(
197         &self,
198         unsolved_variables: &[Ty<'tcx>],
199     ) -> FxHashMap<Ty<'tcx>, Ty<'tcx>> {
200         debug!("calculate_diverging_fallback({:?})", unsolved_variables);
201
202         let relationships = self.fulfillment_cx.borrow_mut().relationships().clone();
203
204         // Construct a coercion graph where an edge `A -> B` indicates
205         // a type variable is that is coerced
206         let coercion_graph = self.create_coercion_graph();
207
208         // Extract the unsolved type inference variable vids; note that some
209         // unsolved variables are integer/float variables and are excluded.
210         let unsolved_vids = unsolved_variables.iter().filter_map(|ty| ty.ty_vid());
211
212         // Compute the diverging root vids D -- that is, the root vid of
213         // those type variables that (a) are the target of a coercion from
214         // a `!` type and (b) have not yet been solved.
215         //
216         // These variables are the ones that are targets for fallback to
217         // either `!` or `()`.
218         let diverging_roots: FxHashSet<ty::TyVid> = self
219             .diverging_type_vars
220             .borrow()
221             .iter()
222             .map(|&ty| self.infcx.shallow_resolve(ty))
223             .filter_map(|ty| ty.ty_vid())
224             .map(|vid| self.infcx.root_var(vid))
225             .collect();
226         debug!(
227             "calculate_diverging_fallback: diverging_type_vars={:?}",
228             self.diverging_type_vars.borrow()
229         );
230         debug!("calculate_diverging_fallback: diverging_roots={:?}", diverging_roots);
231
232         // Find all type variables that are reachable from a diverging
233         // type variable. These will typically default to `!`, unless
234         // we find later that they are *also* reachable from some
235         // other type variable outside this set.
236         let mut roots_reachable_from_diverging = DepthFirstSearch::new(&coercion_graph);
237         let mut diverging_vids = vec![];
238         let mut non_diverging_vids = vec![];
239         for unsolved_vid in unsolved_vids {
240             let root_vid = self.infcx.root_var(unsolved_vid);
241             debug!(
242                 "calculate_diverging_fallback: unsolved_vid={:?} root_vid={:?} diverges={:?}",
243                 unsolved_vid,
244                 root_vid,
245                 diverging_roots.contains(&root_vid),
246             );
247             if diverging_roots.contains(&root_vid) {
248                 diverging_vids.push(unsolved_vid);
249                 roots_reachable_from_diverging.push_start_node(root_vid);
250
251                 debug!(
252                     "calculate_diverging_fallback: root_vid={:?} reaches {:?}",
253                     root_vid,
254                     coercion_graph.depth_first_search(root_vid).collect::<Vec<_>>()
255                 );
256
257                 // drain the iterator to visit all nodes reachable from this node
258                 roots_reachable_from_diverging.complete_search();
259             } else {
260                 non_diverging_vids.push(unsolved_vid);
261             }
262         }
263
264         debug!(
265             "calculate_diverging_fallback: roots_reachable_from_diverging={:?}",
266             roots_reachable_from_diverging,
267         );
268
269         // Find all type variables N0 that are not reachable from a
270         // diverging variable, and then compute the set reachable from
271         // N0, which we call N. These are the *non-diverging* type
272         // variables. (Note that this set consists of "root variables".)
273         let mut roots_reachable_from_non_diverging = DepthFirstSearch::new(&coercion_graph);
274         for &non_diverging_vid in &non_diverging_vids {
275             let root_vid = self.infcx.root_var(non_diverging_vid);
276             if roots_reachable_from_diverging.visited(root_vid) {
277                 continue;
278             }
279             roots_reachable_from_non_diverging.push_start_node(root_vid);
280             roots_reachable_from_non_diverging.complete_search();
281         }
282         debug!(
283             "calculate_diverging_fallback: roots_reachable_from_non_diverging={:?}",
284             roots_reachable_from_non_diverging,
285         );
286
287         debug!("inherited: {:#?}", self.inh.fulfillment_cx.borrow_mut().pending_obligations());
288         debug!("obligations: {:#?}", self.fulfillment_cx.borrow_mut().pending_obligations());
289         debug!("relationships: {:#?}", relationships);
290
291         // For each diverging variable, figure out whether it can
292         // reach a member of N. If so, it falls back to `()`. Else
293         // `!`.
294         let mut diverging_fallback = FxHashMap::default();
295         diverging_fallback.reserve(diverging_vids.len());
296         for &diverging_vid in &diverging_vids {
297             let diverging_ty = self.tcx.mk_ty_var(diverging_vid);
298             let root_vid = self.infcx.root_var(diverging_vid);
299             let can_reach_non_diverging = coercion_graph
300                 .depth_first_search(root_vid)
301                 .any(|n| roots_reachable_from_non_diverging.visited(n));
302
303             let mut relationship = ty::FoundRelationships { self_in_trait: false, output: false };
304
305             for (vid, rel) in relationships.iter() {
306                 if self.infcx.root_var(*vid) == root_vid {
307                     relationship.self_in_trait |= rel.self_in_trait;
308                     relationship.output |= rel.output;
309                 }
310             }
311
312             if relationship.self_in_trait && relationship.output {
313                 // This case falls back to () to ensure that the code pattern in
314                 // src/test/ui/never_type/fallback-closure-ret.rs continues to
315                 // compile when never_type_fallback is enabled.
316                 //
317                 // This rule is not readily explainable from first principles,
318                 // but is rather intended as a patchwork fix to ensure code
319                 // which compiles before the stabilization of never type
320                 // fallback continues to work.
321                 //
322                 // Typically this pattern is encountered in a function taking a
323                 // closure as a parameter, where the return type of that closure
324                 // (checked by `relationship.output`) is expected to implement
325                 // some trait (checked by `relationship.self_in_trait`). This
326                 // can come up in non-closure cases too, so we do not limit this
327                 // rule to specifically `FnOnce`.
328                 //
329                 // When the closure's body is something like `panic!()`, the
330                 // return type would normally be inferred to `!`. However, it
331                 // needs to fall back to `()` in order to still compile, as the
332                 // trait is specifically implemented for `()` but not `!`.
333                 //
334                 // For details on the requirements for these relationships to be
335                 // set, see the relationship finding module in
336                 // compiler/rustc_trait_selection/src/traits/relationships.rs.
337                 debug!("fallback to () - found trait and projection: {:?}", diverging_vid);
338                 diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
339             } else if can_reach_non_diverging {
340                 debug!("fallback to () - reached non-diverging: {:?}", diverging_vid);
341                 diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
342             } else {
343                 debug!("fallback to ! - all diverging: {:?}", diverging_vid);
344                 diverging_fallback.insert(diverging_ty, self.tcx.mk_diverging_default());
345             }
346         }
347
348         diverging_fallback
349     }
350
351     /// Returns a graph whose nodes are (unresolved) inference variables and where
352     /// an edge `?A -> ?B` indicates that the variable `?A` is coerced to `?B`.
353     fn create_coercion_graph(&self) -> VecGraph<ty::TyVid> {
354         let pending_obligations = self.fulfillment_cx.borrow_mut().pending_obligations();
355         debug!("create_coercion_graph: pending_obligations={:?}", pending_obligations);
356         let coercion_edges: Vec<(ty::TyVid, ty::TyVid)> = pending_obligations
357             .into_iter()
358             .filter_map(|obligation| {
359                 // The predicates we are looking for look like `Coerce(?A -> ?B)`.
360                 // They will have no bound variables.
361                 obligation.predicate.kind().no_bound_vars()
362             })
363             .filter_map(|atom| {
364                 // We consider both subtyping and coercion to imply 'flow' from
365                 // some position in the code `a` to a different position `b`.
366                 // This is then used to determine which variables interact with
367                 // live code, and as such must fall back to `()` to preserve
368                 // soundness.
369                 //
370                 // In practice currently the two ways that this happens is
371                 // coercion and subtyping.
372                 let (a, b) = if let ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) = atom {
373                     (a, b)
374                 } else if let ty::PredicateKind::Subtype(ty::SubtypePredicate {
375                     a_is_expected: _,
376                     a,
377                     b,
378                 }) = atom
379                 {
380                     (a, b)
381                 } else {
382                     return None;
383                 };
384
385                 let a_vid = self.root_vid(a)?;
386                 let b_vid = self.root_vid(b)?;
387                 Some((a_vid, b_vid))
388             })
389             .collect();
390         debug!("create_coercion_graph: coercion_edges={:?}", coercion_edges);
391         let num_ty_vars = self.infcx.num_ty_vars();
392         VecGraph::new(num_ty_vars, coercion_edges)
393     }
394
395     /// If `ty` is an unresolved type variable, returns its root vid.
396     fn root_vid(&self, ty: Ty<'tcx>) -> Option<ty::TyVid> {
397         Some(self.infcx.root_var(self.infcx.shallow_resolve(ty).ty_vid()?))
398     }
399 }