]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_typeck/src/check/fallback.rs
Rollup merge of #89021 - WaffleLapkin:separate_error_for_dyn_trait_in_const_fn, r...
[rust.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 }