@@ -11,7 +11,7 @@ use rustc_hir::HirId;
1111use rustc_hir:: def:: { DefKind , Res } ;
1212use rustc_hir:: def_id:: DefId ;
1313use rustc_hir:: intravisit:: { InferKind , Visitor } ;
14- use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable } ;
14+ use rustc_middle:: ty:: { self , FloatVid , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable } ;
1515use rustc_session:: lint;
1616use rustc_span:: def_id:: LocalDefId ;
1717use rustc_span:: { DUMMY_SP , Span } ;
@@ -92,14 +92,16 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
9292
9393 let diverging_fallback = self
9494 . calculate_diverging_fallback ( & unresolved_variables, self . diverging_fallback_behavior ) ;
95+ let fallback_to_f32 = self . calculate_fallback_to_f32 ( & unresolved_variables) ;
9596
9697 // We do fallback in two passes, to try to generate
9798 // better error messages.
9899 // The first time, we do *not* replace opaque types.
99100 let mut fallback_occurred = false ;
100101 for ty in unresolved_variables {
101102 debug ! ( "unsolved_variable = {:?}" , ty) ;
102- fallback_occurred |= self . fallback_if_possible ( ty, & diverging_fallback) ;
103+ fallback_occurred |=
104+ self . fallback_if_possible ( ty, & diverging_fallback, & fallback_to_f32) ;
103105 }
104106
105107 fallback_occurred
@@ -109,7 +111,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
109111 //
110112 // - Unconstrained ints are replaced with `i32`.
111113 //
112- // - Unconstrained floats are replaced with `f64`.
114+ // - Unconstrained floats are replaced with `f64`, except when there is a trait predicate
115+ // `f32: From<{float}>`, in which case `f32` is used as the fallback instead.
113116 //
114117 // - Non-numerics may get replaced with `()` or `!`, depending on
115118 // how they were categorized by `calculate_diverging_fallback`
@@ -124,6 +127,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
124127 & self ,
125128 ty : Ty < ' tcx > ,
126129 diverging_fallback : & UnordMap < Ty < ' tcx > , Ty < ' tcx > > ,
130+ fallback_to_f32 : & UnordSet < FloatVid > ,
127131 ) -> bool {
128132 // Careful: we do NOT shallow-resolve `ty`. We know that `ty`
129133 // is an unsolved variable, and we determine its fallback
@@ -146,6 +150,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
146150 let fallback = match ty. kind ( ) {
147151 _ if let Some ( e) = self . tainted_by_errors ( ) => Ty :: new_error ( self . tcx , e) ,
148152 ty:: Infer ( ty:: IntVar ( _) ) => self . tcx . types . i32 ,
153+ ty:: Infer ( ty:: FloatVar ( vid) ) if fallback_to_f32. contains ( vid) => self . tcx . types . f32 ,
149154 ty:: Infer ( ty:: FloatVar ( _) ) => self . tcx . types . f64 ,
150155 _ => match diverging_fallback. get ( & ty) {
151156 Some ( & fallback_ty) => fallback_ty,
@@ -160,6 +165,38 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
160165 true
161166 }
162167
168+ /// Existing code relies on `f32: From<T>` (usually written as `T: Into<f32>`) resolving `T` to
169+ /// `f32` when the type of `T` is inferred from an unsuffixed float literal. Using the default
170+ /// fallback of `f64`, this would break when adding `impl From<f16> for f32`, as there are now
171+ /// two float type which could be `T`, meaning that the fallback of `f64` would be used and
172+ /// compilation error would occur as `f32` does not implement `From<f64>`. To avoid breaking
173+ /// existing code, we instead fallback `T` to `f32` when there is a trait predicate
174+ /// `f32: From<T>`. This means code like the following will continue to compile:
175+ ///
176+ /// ```rust
177+ /// fn foo<T: Into<f32>>(_: T) {}
178+ ///
179+ /// foo(1.0);
180+ /// ```
181+ fn calculate_fallback_to_f32 ( & self , unresolved_variables : & [ Ty < ' tcx > ] ) -> UnordSet < FloatVid > {
182+ let roots: UnordSet < ty:: FloatVid > = self . from_float_for_f32_root_vids ( ) ;
183+ if roots. is_empty ( ) {
184+ // Most functions have no `f32: From<{float}>` predicates, so short-circuit and return
185+ // an empty set when this is the case.
186+ return UnordSet :: new ( ) ;
187+ }
188+ // Calculate all the unresolved variables that need to fallback to `f32` here. This ensures
189+ // we don't need to find root variables in `fallback_if_possible`: see the comment at the
190+ // top of that function for details.
191+ let fallback_to_f32 = unresolved_variables
192+ . iter ( )
193+ . flat_map ( |ty| ty. float_vid ( ) )
194+ . filter ( |vid| roots. contains ( & self . root_float_var ( * vid) ) )
195+ . collect ( ) ;
196+ debug ! ( "calculate_fallback_to_f32: fallback_to_f32={:?}" , fallback_to_f32) ;
197+ fallback_to_f32
198+ }
199+
163200 /// The "diverging fallback" system is rather complicated. This is
164201 /// a result of our need to balance 'do the right thing' with
165202 /// backwards compatibility.
@@ -565,6 +602,11 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
565602 Some ( self . root_var ( self . shallow_resolve ( ty) . ty_vid ( ) ?) )
566603 }
567604
605+ /// If `ty` is an unresolved float type variable, returns its root vid.
606+ pub ( crate ) fn root_float_vid ( & self , ty : Ty < ' tcx > ) -> Option < ty:: FloatVid > {
607+ Some ( self . root_float_var ( self . shallow_resolve ( ty) . float_vid ( ) ?) )
608+ }
609+
568610 /// Given a set of diverging vids and coercions, walk the HIR to gather a
569611 /// set of suggestions which can be applied to preserve fallback to unit.
570612 fn try_to_suggest_annotations (
0 commit comments