1- use crate :: check:: FallbackMode ;
21use crate :: check:: FnCtxt ;
2+ use rustc_infer:: infer:: type_variable:: Diverging ;
3+ use rustc_middle:: ty:: { self , Ty } ;
34
45impl < ' 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,113 @@ 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+ let oty = self . inner . borrow ( ) . opaque_types_vars . get ( ty) . map ( |v| * v) ;
146+ if let Some ( opaque_ty) = oty {
147+ debug ! (
148+ "fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}" ,
149+ ty, opaque_ty
150+ ) ;
151+ self . demand_eqtype ( span, ty, opaque_ty) ;
152+ true
153+ } else {
154+ return false ;
155+ }
156+ }
52157}
0 commit comments