@@ -11,7 +11,7 @@ use rustc_hir::attrs::DivergingFallbackBehavior;
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 } ;
@@ -55,15 +55,20 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
5555
5656 let ( diverging_fallback, diverging_fallback_ty) =
5757 self . calculate_diverging_fallback ( & unresolved_variables) ;
58+ let fallback_to_f32 = self . calculate_fallback_to_f32 ( & unresolved_variables) ;
5859
5960 // We do fallback in two passes, to try to generate
6061 // better error messages.
6162 // The first time, we do *not* replace opaque types.
6263 let mut fallback_occurred = false ;
6364 for ty in unresolved_variables {
6465 debug ! ( "unsolved_variable = {:?}" , ty) ;
65- fallback_occurred |=
66- self . fallback_if_possible ( ty, & diverging_fallback, diverging_fallback_ty) ;
66+ fallback_occurred |= self . fallback_if_possible (
67+ ty,
68+ & diverging_fallback,
69+ diverging_fallback_ty,
70+ & fallback_to_f32,
71+ ) ;
6772 }
6873
6974 fallback_occurred
@@ -73,7 +78,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
7378 ///
7479 /// - Unconstrained ints are replaced with `i32`.
7580 ///
76- /// - Unconstrained floats are replaced with `f64`.
81+ /// - Unconstrained floats are replaced with `f64`, except when there is a trait predicate
82+ /// `f32: From<{float}>`, in which case `f32` is used as the fallback instead.
7783 ///
7884 /// - Non-numerics may get replaced with `()` or `!`, depending on how they
7985 /// were categorized by [`Self::calculate_diverging_fallback`], crate's
@@ -89,6 +95,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
8995 ty : Ty < ' tcx > ,
9096 diverging_fallback : & UnordSet < Ty < ' tcx > > ,
9197 diverging_fallback_ty : Ty < ' tcx > ,
98+ fallback_to_f32 : & UnordSet < FloatVid > ,
9299 ) -> bool {
93100 // Careful: we do NOT shallow-resolve `ty`. We know that `ty`
94101 // is an unsolved variable, and we determine its fallback
@@ -111,6 +118,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
111118 let fallback = match ty. kind ( ) {
112119 _ if let Some ( e) = self . tainted_by_errors ( ) => Ty :: new_error ( self . tcx , e) ,
113120 ty:: Infer ( ty:: IntVar ( _) ) => self . tcx . types . i32 ,
121+ ty:: Infer ( ty:: FloatVar ( vid) ) if fallback_to_f32. contains ( vid) => self . tcx . types . f32 ,
114122 ty:: Infer ( ty:: FloatVar ( _) ) => self . tcx . types . f64 ,
115123 _ if diverging_fallback. contains ( & ty) => {
116124 self . diverging_fallback_has_occurred . set ( true ) ;
@@ -125,6 +133,38 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
125133 true
126134 }
127135
136+ /// Existing code relies on `f32: From<T>` (usually written as `T: Into<f32>`) resolving `T` to
137+ /// `f32` when the type of `T` is inferred from an unsuffixed float literal. Using the default
138+ /// fallback of `f64`, this would break when adding `impl From<f16> for f32`, as there are now
139+ /// two float type which could be `T`, meaning that the fallback of `f64` would be used and
140+ /// compilation error would occur as `f32` does not implement `From<f64>`. To avoid breaking
141+ /// existing code, we instead fallback `T` to `f32` when there is a trait predicate
142+ /// `f32: From<T>`. This means code like the following will continue to compile:
143+ ///
144+ /// ```rust
145+ /// fn foo<T: Into<f32>>(_: T) {}
146+ ///
147+ /// foo(1.0);
148+ /// ```
149+ fn calculate_fallback_to_f32 ( & self , unresolved_variables : & [ Ty < ' tcx > ] ) -> UnordSet < FloatVid > {
150+ let roots: UnordSet < ty:: FloatVid > = self . from_float_for_f32_root_vids ( ) ;
151+ if roots. is_empty ( ) {
152+ // Most functions have no `f32: From<{float}>` predicates, so short-circuit and return
153+ // an empty set when this is the case.
154+ return UnordSet :: new ( ) ;
155+ }
156+ // Calculate all the unresolved variables that need to fallback to `f32` here. This ensures
157+ // we don't need to find root variables in `fallback_if_possible`: see the comment at the
158+ // top of that function for details.
159+ let fallback_to_f32 = unresolved_variables
160+ . iter ( )
161+ . flat_map ( |ty| ty. float_vid ( ) )
162+ . filter ( |vid| roots. contains ( & self . root_float_var ( * vid) ) )
163+ . collect ( ) ;
164+ debug ! ( "calculate_fallback_to_f32: fallback_to_f32={:?}" , fallback_to_f32) ;
165+ fallback_to_f32
166+ }
167+
128168 fn calculate_diverging_fallback (
129169 & self ,
130170 unresolved_variables : & [ Ty < ' tcx > ] ,
@@ -362,6 +402,11 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
362402 Some ( self . root_var ( self . shallow_resolve ( ty) . ty_vid ( ) ?) )
363403 }
364404
405+ /// If `ty` is an unresolved float type variable, returns its root vid.
406+ pub ( crate ) fn root_float_vid ( & self , ty : Ty < ' tcx > ) -> Option < ty:: FloatVid > {
407+ Some ( self . root_float_var ( self . shallow_resolve ( ty) . float_vid ( ) ?) )
408+ }
409+
365410 /// Given a set of diverging vids and coercions, walk the HIR to gather a
366411 /// set of suggestions which can be applied to preserve fallback to unit.
367412 fn try_to_suggest_annotations (
0 commit comments