From 1053d41f8ce684ec1c02f572ed135aa081a87ca7 Mon Sep 17 00:00:00 2001 From: beetrees Date: Fri, 28 Mar 2025 20:09:07 +0000 Subject: [PATCH 1/3] Fallback `{float}` to `f32` when `f32: From<{float}>` --- Cargo.lock | 148 +++++++++++------- compiler/rustc_hir/src/lang_items.rs | 3 + compiler/rustc_hir_typeck/src/fallback.rs | 58 ++++++- .../src/fn_ctxt/inspect_obligations.rs | 101 +++++++++++- compiler/rustc_infer/src/infer/mod.rs | 4 + compiler/rustc_middle/src/ty/sty.rs | 8 + library/core/src/convert/mod.rs | 1 + tests/ui/float/f32-into-f32.rs | 9 ++ tests/ui/float/trait-f16-or-f32.rs | 13 ++ tests/ui/float/trait-f16-or-f32.stderr | 20 +++ 10 files changed, 301 insertions(+), 64 deletions(-) create mode 100644 tests/ui/float/f32-into-f32.rs create mode 100644 tests/ui/float/trait-f16-or-f32.rs create mode 100644 tests/ui/float/trait-f16-or-f32.stderr diff --git a/Cargo.lock b/Cargo.lock index bf0e6ec7f4575..32c09421cf086 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -226,9 +226,9 @@ dependencies = [ [[package]] name = "assert_cmd" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcbb6924530aa9e0432442af08bbcafdad182db80d2e560da42a6d442535bf85" +checksum = "9a686bbee5efb88a82df0621b236e74d925f470e5445d3220a5648b892ec99c9" dependencies = [ "anstyle", "bstr", @@ -472,11 +472,12 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122ec45a44b270afd1402f351b782c676b173e3c3fb28d86ff7ebfb4d86a4ee4" +checksum = "87a0c0e6148f11f01f32650a2ea02d532b2ad4e81d8bd41e6e565b5adc5e6082" dependencies = [ "serde", + "serde_core", ] [[package]] @@ -531,7 +532,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef987d17b0a113becdd19d3d0022d04d7ef41f9efe4f3fb63ac44ba61df3ade9" dependencies = [ "camino", - "cargo-platform 0.3.1", + "cargo-platform 0.3.2", "semver", "serde", "serde_json", @@ -669,7 +670,7 @@ dependencies = [ "serde_json", "tempfile", "termize", - "toml 0.9.8", + "toml 0.9.12+spec-1.1.0", "ui_test", "walkdir", ] @@ -712,7 +713,7 @@ dependencies = [ "regex-syntax", "semver", "serde", - "toml 0.9.8", + "toml 0.9.12+spec-1.1.0", "unicode-normalization", "unicode-script", "url", @@ -837,11 +838,11 @@ dependencies = [ [[package]] name = "colored" -version = "3.0.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" +checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -888,10 +889,21 @@ dependencies = [ "encode_unicode", "libc", "once_cell", - "unicode-width 0.2.2", "windows-sys 0.59.0", ] +[[package]] +name = "console" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" +dependencies = [ + "encode_unicode", + "libc", + "unicode-width 0.2.2", + "windows-sys 0.61.2", +] + [[package]] name = "constant_time_eq" version = "0.3.1" @@ -1022,9 +1034,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.188" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47ac4eaf7ebe29e92f1b091ceefec7710a53a6f6154b2460afda626c113b65b9" +checksum = "747d8437319e3a2f43d93b341c137927ca70c0f5dabeea7a005a73665e247c7e" dependencies = [ "cc", "cxx-build", @@ -1037,9 +1049,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.188" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2abd4c3021eefbac5149f994c117b426852bca3a0aad227698527bca6d4ea657" +checksum = "b0f4697d190a142477b16aef7da8a99bfdc41e7e8b1687583c0d23a79c7afc1e" dependencies = [ "cc", "codespan-reporting", @@ -1052,9 +1064,9 @@ dependencies = [ [[package]] name = "cxxbridge-cmd" -version = "1.0.188" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f12fbc5888b2311f23e52a601e11ad7790d8f0dbb903ec26e2513bf5373ed70" +checksum = "d0956799fa8678d4c50eed028f2de1c0552ae183c76e976cf7ca8c4e36a7c328" dependencies = [ "clap", "codespan-reporting", @@ -1066,15 +1078,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.188" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83d3dd7870af06e283f3f8ce0418019c96171c9ce122cfb9c8879de3d84388fd" +checksum = "23384a836ab4f0ad98ace7e3955ad2de39de42378ab487dc28d3990392cb283a" [[package]] name = "cxxbridge-macro" -version = "1.0.188" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26f0d82da663316786791c3d0e9f9edc7d1ee1f04bdad3d2643086a69d6256c" +checksum = "e6acc6b5822b9526adfb4fc377b67128fdd60aac757cc4a741a6278603f763cf" dependencies = [ "indexmap", "proc-macro2", @@ -1340,9 +1352,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" +checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" dependencies = [ "serde", "serde_core", @@ -1613,9 +1625,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.20.2" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" +checksum = "7b88256088d75a56f8ecfa070513a775dd9107f6530ef14919dac831af9cfe2b" dependencies = [ "bitflags", "libc", @@ -1968,10 +1980,22 @@ version = "0.17.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" dependencies = [ - "console", + "console 0.15.11", "number_prefix", "portable-atomic", + "web-time", +] + +[[package]] +name = "indicatif" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb" +dependencies = [ + "console 0.16.3", + "portable-atomic", "unicode-width 0.2.2", + "unit-prefix", "web-time", ] @@ -2175,9 +2199,9 @@ checksum = "9fa0e2a1fcbe2f6be6c42e342259976206b383122fc152e872795338b5a3f3a7" [[package]] name = "libc" -version = "0.2.177" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "libdbus-sys" @@ -2210,9 +2234,9 @@ dependencies = [ [[package]] name = "libgit2-sys" -version = "0.18.2+1.9.1" +version = "0.18.3+1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222" +checksum = "c9b3acc4b91781bb0b3386669d325163746af5f6e4f73e6d2d630e09a35f3487" dependencies = [ "cc", "libc", @@ -2454,9 +2478,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", "wasi 0.11.1+wasi-snapshot-preview1", @@ -2481,7 +2505,7 @@ dependencies = [ "capstone", "chrono", "chrono-tz", - "colored 3.0.0", + "colored 3.1.1", "directories", "genmc-sys", "getrandom 0.3.3", @@ -2997,9 +3021,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.11.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" @@ -3038,9 +3062,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "predicates" -version = "3.1.3" +version = "3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" +checksum = "ada8f2932f28a27ee7b70dd6c1c39ea0675c55a36879ab92f3a715eaa1e63cfe" dependencies = [ "anstyle", "difflib", @@ -3049,15 +3073,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" +checksum = "cad38746f3166b4031b1a0d39ad9f954dd291e7854fcc0eed52ee41a0b50d144" [[package]] name = "predicates-tree" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" +checksum = "d0de1b847b39c8131db0467e9df1ff60e6d0562ab8e9a16e568ad0fdb372e2f2" dependencies = [ "predicates-core", "termtree", @@ -4969,7 +4993,7 @@ dependencies = [ "tempfile", "term", "thiserror 1.0.69", - "toml 0.9.8", + "toml 0.9.12+spec-1.1.0", "tracing", "tracing-subscriber", "unicode-properties", @@ -5195,9 +5219,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" dependencies = [ "serde_core", ] @@ -5531,7 +5555,7 @@ checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" name = "test-float-parse" version = "0.1.0" dependencies = [ - "indicatif", + "indicatif 0.17.11", "num", "rand 0.9.2", "rand_chacha 0.9.0", @@ -5702,14 +5726,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.8" +version = "0.9.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" dependencies = [ "indexmap", "serde_core", - "serde_spanned 1.0.3", - "toml_datetime 0.7.3", + "serde_spanned 1.0.4", + "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", "toml_writer", "winnow 0.7.13", @@ -5726,9 +5750,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.3" +version = "0.7.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" dependencies = [ "serde_core", ] @@ -5762,9 +5786,9 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.4" +version = "1.0.9+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" dependencies = [ "winnow 0.7.13", ] @@ -5777,9 +5801,9 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "toml_writer" -version = "1.0.4" +version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" +checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" [[package]] name = "tracing" @@ -5933,9 +5957,9 @@ checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "ui_test" -version = "0.30.3" +version = "0.30.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44eb652e1a8799d4e47f20851370e86247cbc5270ce677ab1e9409a6d45a9649" +checksum = "ada249620d81f010b9a1472b63a5077ac7c722dd0f4bacf6528b313d0b8c15d8" dependencies = [ "annotate-snippets 0.11.5", "anyhow", @@ -5943,10 +5967,10 @@ dependencies = [ "cargo-platform 0.1.9", "cargo_metadata 0.18.1", "color-eyre", - "colored 3.0.0", + "colored 3.1.1", "comma", "crossbeam-channel", - "indicatif", + "indicatif 0.18.4", "levenshtein", "prettydiff", "regex", @@ -6083,6 +6107,12 @@ dependencies = [ "diff", ] +[[package]] +name = "unit-prefix" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" + [[package]] name = "unstable-book-gen" version = "0.1.0" diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 80f0af9d663cb..3a6fcf9d4f0fe 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -443,6 +443,9 @@ language_item_table! { FieldBase, sym::field_base, field_base, Target::AssocTy, GenericRequirement::Exact(0); FieldType, sym::field_type, field_type, Target::AssocTy, GenericRequirement::Exact(0); FieldOffset, sym::field_offset, field_offset, Target::AssocConst, GenericRequirement::Exact(0); + + // Used to fallback `{float}` to `f32` when `f32: From<{float}>` + From, sym::From, from_trait, Target::Trait, GenericRequirement::Exact(1); } /// The requirement imposed on the generics of a lang item diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index f7ecfb6cd09cb..704abb9c39d92 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -11,7 +11,7 @@ use rustc_hir::attrs::DivergingFallbackBehavior; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{InferKind, Visitor}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; +use rustc_middle::ty::{self, FloatVid, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::{DUMMY_SP, Span}; @@ -55,6 +55,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { let (diverging_fallback, diverging_fallback_ty) = self.calculate_diverging_fallback(&unresolved_variables); + let fallback_to_f32 = self.calculate_fallback_to_f32(&unresolved_variables); // We do fallback in two passes, to try to generate // better error messages. @@ -62,8 +63,12 @@ impl<'tcx> FnCtxt<'_, 'tcx> { let mut fallback_occurred = false; for ty in unresolved_variables { debug!("unsolved_variable = {:?}", ty); - fallback_occurred |= - self.fallback_if_possible(ty, &diverging_fallback, diverging_fallback_ty); + fallback_occurred |= self.fallback_if_possible( + ty, + &diverging_fallback, + diverging_fallback_ty, + &fallback_to_f32, + ); } fallback_occurred @@ -73,7 +78,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> { /// /// - Unconstrained ints are replaced with `i32`. /// - /// - Unconstrained floats are replaced with `f64`. + /// - Unconstrained floats are replaced with `f64`, except when there is a trait predicate + /// `f32: From<{float}>`, in which case `f32` is used as the fallback instead. /// /// - Non-numerics may get replaced with `()` or `!`, depending on how they /// were categorized by [`Self::calculate_diverging_fallback`], crate's @@ -89,6 +95,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { ty: Ty<'tcx>, diverging_fallback: &UnordSet>, diverging_fallback_ty: Ty<'tcx>, + fallback_to_f32: &UnordSet, ) -> bool { // Careful: we do NOT shallow-resolve `ty`. We know that `ty` // is an unsolved variable, and we determine its fallback @@ -111,6 +118,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { let fallback = match ty.kind() { _ if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx, e), ty::Infer(ty::IntVar(_)) => self.tcx.types.i32, + ty::Infer(ty::FloatVar(vid)) if fallback_to_f32.contains(vid) => self.tcx.types.f32, ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64, _ if diverging_fallback.contains(&ty) => { self.diverging_fallback_has_occurred.set(true); @@ -125,6 +133,38 @@ impl<'tcx> FnCtxt<'_, 'tcx> { true } + /// Existing code relies on `f32: From` (usually written as `T: Into`) resolving `T` to + /// `f32` when the type of `T` is inferred from an unsuffixed float literal. Using the default + /// fallback of `f64`, this would break when adding `impl From for f32`, as there are now + /// two float type which could be `T`, meaning that the fallback of `f64` would be used and + /// compilation error would occur as `f32` does not implement `From`. To avoid breaking + /// existing code, we instead fallback `T` to `f32` when there is a trait predicate + /// `f32: From`. This means code like the following will continue to compile: + /// + /// ```rust + /// fn foo>(_: T) {} + /// + /// foo(1.0); + /// ``` + fn calculate_fallback_to_f32(&self, unresolved_variables: &[Ty<'tcx>]) -> UnordSet { + let roots: UnordSet = self.from_float_for_f32_root_vids(); + if roots.is_empty() { + // Most functions have no `f32: From<{float}>` predicates, so short-circuit and return + // an empty set when this is the case. + return UnordSet::new(); + } + // Calculate all the unresolved variables that need to fallback to `f32` here. This ensures + // we don't need to find root variables in `fallback_if_possible`: see the comment at the + // top of that function for details. + let fallback_to_f32 = unresolved_variables + .iter() + .flat_map(|ty| ty.float_vid()) + .filter(|vid| roots.contains(&self.root_float_var(*vid))) + .collect(); + debug!("calculate_fallback_to_f32: fallback_to_f32={:?}", fallback_to_f32); + fallback_to_f32 + } + fn calculate_diverging_fallback( &self, unresolved_variables: &[Ty<'tcx>], @@ -357,6 +397,16 @@ impl<'tcx> FnCtxt<'_, 'tcx> { VecGraph::new(num_ty_vars, coercion_edges) } + /// If `ty` is an unresolved type variable, returns its root vid. + fn root_vid(&self, ty: Ty<'tcx>) -> Option { + Some(self.root_var(self.shallow_resolve(ty).ty_vid()?)) + } + + /// If `ty` is an unresolved float type variable, returns its root vid. + pub(crate) fn root_float_vid(&self, ty: Ty<'tcx>) -> Option { + Some(self.root_float_var(self.shallow_resolve(ty).float_vid()?)) + } + /// Given a set of diverging vids and coercions, walk the HIR to gather a /// set of suggestions which can be applied to preserve fallback to unit. fn try_to_suggest_annotations( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index 1ab7ac4c2e361..dcaace299adaa 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -1,5 +1,7 @@ //! A utility module to inspect currently ambiguous obligations in the current context. +use rustc_data_structures::unord::UnordSet; +use rustc_hir::def_id::DefId; use rustc_infer::traits::{self, ObligationCause, PredicateObligations}; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_span::Span; @@ -96,6 +98,69 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); obligations_for_self_ty } + + /// Only needed for the `From<{float}>` for `f32` type fallback. + #[instrument(skip(self), level = "debug")] + pub(crate) fn from_float_for_f32_root_vids(&self) -> UnordSet { + if self.next_trait_solver() { + self.from_float_for_f32_root_vids_next() + } else { + let Some(from_trait) = self.tcx.lang_items().from_trait() else { + return UnordSet::new(); + }; + self.fulfillment_cx + .borrow_mut() + .pending_obligations() + .into_iter() + .filter_map(|obligation| { + self.predicate_from_float_for_f32_root_vid(from_trait, obligation.predicate) + }) + .collect() + } + } + + fn predicate_from_float_for_f32_root_vid( + &self, + from_trait: DefId, + predicate: ty::Predicate<'tcx>, + ) -> Option { + // The predicates we are looking for look like + // `TraitPredicate(>, polarity:Positive)`. + // They will have no bound variables. + match predicate.kind().no_bound_vars() { + Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { + polarity: ty::PredicatePolarity::Positive, + trait_ref, + }))) if trait_ref.def_id == from_trait + && self.shallow_resolve(trait_ref.self_ty()).kind() + == &ty::Float(ty::FloatTy::F32) => + { + self.root_float_vid(trait_ref.args.type_at(1)) + } + _ => None, + } + } + + fn from_float_for_f32_root_vids_next(&self) -> UnordSet { + let Some(from_trait) = self.tcx.lang_items().from_trait() else { + return UnordSet::new(); + }; + let obligations = self.fulfillment_cx.borrow().pending_obligations(); + debug!(?obligations); + let mut vids = UnordSet::new(); + for obligation in obligations { + let mut visitor = FindFromFloatForF32RootVids { + fcx: self, + from_trait, + vids: &mut vids, + span: obligation.cause.span, + }; + + let goal = obligation.as_goal(); + self.visit_proof_tree(goal, &mut visitor); + } + vids + } } struct NestedObligationsForSelfTy<'a, 'tcx> { @@ -105,7 +170,7 @@ struct NestedObligationsForSelfTy<'a, 'tcx> { obligations_for_self_ty: &'a mut PredicateObligations<'tcx>, } -impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> { +impl<'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'_, 'tcx> { fn span(&self) -> Span { self.root_cause.span } @@ -144,3 +209,37 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> { } } } + +struct FindFromFloatForF32RootVids<'a, 'tcx> { + fcx: &'a FnCtxt<'a, 'tcx>, + from_trait: DefId, + vids: &'a mut UnordSet, + span: Span, +} + +impl<'tcx> ProofTreeVisitor<'tcx> for FindFromFloatForF32RootVids<'_, 'tcx> { + fn span(&self) -> Span { + self.span + } + + fn config(&self) -> InspectConfig { + // Avoid hang from exponentially growing proof trees (see `cycle-modulo-ambig-aliases.rs`). + // 3 is more than enough for all occurences in practice (a.k.a. `Into`). + InspectConfig { max_depth: 3 } + } + + fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'tcx>) { + if let Some(vid) = self + .fcx + .predicate_from_float_for_f32_root_vid(self.from_trait, inspect_goal.goal().predicate) + { + self.vids.insert(vid); + } else if let Some(candidate) = inspect_goal.unique_applicable_candidate() { + let start_len = self.vids.len(); + let _ = candidate.goal().infcx().commit_if_ok(|_| { + candidate.visit_nested_no_probe(self); + if self.vids.len() > start_len { Ok(()) } else { Err(()) } + }); + } + } +} diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index b573065362601..74e269118b1f1 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1199,6 +1199,10 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().type_variables().sub_unification_table_root_var(var) } + pub fn root_float_var(&self, var: ty::FloatVid) -> ty::FloatVid { + self.inner.borrow_mut().float_unification_table().find(var) + } + pub fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid { self.inner.borrow_mut().const_unification_table().find(var).vid } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 9c22d158154fb..1aba983ca58a9 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1183,6 +1183,14 @@ impl<'tcx> Ty<'tcx> { } } + #[inline] + pub fn float_vid(self) -> Option { + match self.kind() { + &Infer(FloatVar(vid)) => Some(vid), + _ => None, + } + } + #[inline] pub fn is_ty_or_numeric_infer(self) -> bool { matches!(self.kind(), Infer(_)) diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index ef4ab15f93c0b..4a4c7ee388f9e 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -577,6 +577,7 @@ pub const trait Into: Sized { /// [`from`]: From::from /// [book]: ../../book/ch09-00-error-handling.html #[rustc_diagnostic_item = "From"] +#[lang = "From"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(on( all(Self = "&str", T = "alloc::string::String"), diff --git a/tests/ui/float/f32-into-f32.rs b/tests/ui/float/f32-into-f32.rs new file mode 100644 index 0000000000000..1b3f0926bddec --- /dev/null +++ b/tests/ui/float/f32-into-f32.rs @@ -0,0 +1,9 @@ +//@ revisions: old-solver next-solver +//@[next-solver] compile-flags: -Znext-solver +//@ run-pass + +fn foo(_: impl Into) {} + +fn main() { + foo(1.0); +} diff --git a/tests/ui/float/trait-f16-or-f32.rs b/tests/ui/float/trait-f16-or-f32.rs new file mode 100644 index 0000000000000..72f0a4fbde477 --- /dev/null +++ b/tests/ui/float/trait-f16-or-f32.rs @@ -0,0 +1,13 @@ +//@ check-fail + +#![feature(f16)] + +trait Trait {} +impl Trait for f16 {} +impl Trait for f32 {} + +fn foo(_: impl Trait) {} + +fn main() { + foo(1.0); //~ ERROR the trait bound `f64: Trait` is not satisfied +} diff --git a/tests/ui/float/trait-f16-or-f32.stderr b/tests/ui/float/trait-f16-or-f32.stderr new file mode 100644 index 0000000000000..8af81231bd949 --- /dev/null +++ b/tests/ui/float/trait-f16-or-f32.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `f64: Trait` is not satisfied + --> $DIR/trait-f16-or-f32.rs:12:9 + | +LL | foo(1.0); + | --- ^^^ the trait `Trait` is not implemented for `f64` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `Trait`: + f16 + f32 +note: required by a bound in `foo` + --> $DIR/trait-f16-or-f32.rs:9:16 + | +LL | fn foo(_: impl Trait) {} + | ^^^^^ required by this bound in `foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From e7709ba5bff0e6e5660a5d4e9fe571306aa480cd Mon Sep 17 00:00:00 2001 From: beetrees Date: Fri, 28 Mar 2025 20:09:30 +0000 Subject: [PATCH 2/3] Add `impl From for f32` --- library/core/src/convert/num.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 40d61de50aaf2..c41fa36b3725f 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -176,6 +176,7 @@ impl_from!(u32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0 // float -> float // FIXME(f16,f128): adding additional `From<{float}>` impls to `f32` breaks inference. See // +impl_from!(f16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(f16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(f16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(f32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); From cacf239a0a8e570dad35619167713fb956aababa Mon Sep 17 00:00:00 2001 From: beetrees Date: Mon, 31 Mar 2025 23:18:09 +0100 Subject: [PATCH 3/3] Add FCW for unsuffixed float literal `f32` fallback --- compiler/rustc_hir_typeck/src/demand.rs | 2 +- compiler/rustc_hir_typeck/src/errors.rs | 12 +++++ compiler/rustc_hir_typeck/src/fallback.rs | 18 ++++++- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- .../rustc_infer/src/infer/canonical/mod.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 21 ++++++-- .../rustc_infer/src/infer/snapshot/fudge.rs | 26 +++++++--- compiler/rustc_lint_defs/src/builtin.rs | 49 +++++++++++++++++++ tests/ui/float/f32-into-f32.next-solver.fixed | 23 +++++++++ .../ui/float/f32-into-f32.next-solver.stderr | 39 +++++++++++++++ tests/ui/float/f32-into-f32.old-solver.fixed | 23 +++++++++ tests/ui/float/f32-into-f32.old-solver.stderr | 39 +++++++++++++++ tests/ui/float/f32-into-f32.rs | 14 ++++++ tests/ui/inference/untyped-primitives.rs | 2 + tests/ui/inference/untyped-primitives.stderr | 12 +++++ 15 files changed, 269 insertions(+), 15 deletions(-) create mode 100644 tests/ui/float/f32-into-f32.next-solver.fixed create mode 100644 tests/ui/float/f32-into-f32.next-solver.stderr create mode 100644 tests/ui/float/f32-into-f32.old-solver.fixed create mode 100644 tests/ui/float/f32-into-f32.old-solver.stderr create mode 100644 tests/ui/inference/untyped-primitives.stderr diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 0d49e06240532..6316e6b9d592a 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -346,7 +346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match infer { ty::TyVar(_) => self.next_ty_var(DUMMY_SP), ty::IntVar(_) => self.next_int_var(), - ty::FloatVar(_) => self.next_float_var(), + ty::FloatVar(_) => self.next_float_var(DUMMY_SP), ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => { bug!("unexpected fresh ty outside of the trait solver") } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 6eef156846972..b55e7933cc1e9 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -1384,3 +1384,15 @@ pub(crate) struct ProjectOnNonPinProjectType { )] pub sugg_span: Option, } + +#[derive(Diagnostic)] +#[diag("falling back to `f32` as the trait bound `f32: From` is not satisfied")] +pub(crate) struct FloatLiteralF32Fallback { + pub literal: String, + #[suggestion( + "explicitly specify the type as `f32`", + code = "{literal}_f32", + applicability = "machine-applicable" + )] + pub span: Option, +} diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 704abb9c39d92..cebf10e382ac9 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -5,12 +5,12 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph; use rustc_data_structures::graph::vec_graph::VecGraph; use rustc_data_structures::unord::{UnordMap, UnordSet}; -use rustc_hir as hir; -use rustc_hir::HirId; use rustc_hir::attrs::DivergingFallbackBehavior; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{InferKind, Visitor}; +use rustc_hir::{self as hir, CRATE_HIR_ID, HirId}; +use rustc_lint::builtin::FLOAT_LITERAL_F32_FALLBACK; use rustc_middle::ty::{self, FloatVid, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; @@ -160,6 +160,20 @@ impl<'tcx> FnCtxt<'_, 'tcx> { .iter() .flat_map(|ty| ty.float_vid()) .filter(|vid| roots.contains(&self.root_float_var(*vid))) + .inspect(|vid| { + let span = self.float_var_origin(*vid); + // Show the entire literal in the suggestion to make it clearer. + let literal = self.tcx.sess.source_map().span_to_snippet(span).ok(); + self.tcx.emit_node_span_lint( + FLOAT_LITERAL_F32_FALLBACK, + CRATE_HIR_ID, + span, + errors::FloatLiteralF32Fallback { + span: literal.as_ref().map(|_| span), + literal: literal.unwrap_or_default(), + }, + ); + }) .collect(); debug!("calculate_fallback_to_f32: fallback_to_f32={:?}", fallback_to_f32); fallback_to_f32 diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 9faa75e18480d..34ba3d6860a88 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -763,7 +763,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Float(_) => Some(ty), _ => None, }); - opt_ty.unwrap_or_else(|| self.next_float_var()) + opt_ty.unwrap_or_else(|| self.next_float_var(lit.span)) } ast::LitKind::Bool(_) => tcx.types.bool, ast::LitKind::CStr(_, _) => Ty::new_imm_ref( diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index c6826d774216f..321f2e43deef0 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -107,7 +107,7 @@ impl<'tcx> InferCtxt<'tcx> { CanonicalVarKind::Int => self.next_int_var().into(), - CanonicalVarKind::Float => self.next_float_var().into(), + CanonicalVarKind::Float => self.next_float_var(span).into(), CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, bound, .. }) => { let universe_mapped = universe_map(universe); diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 74e269118b1f1..1ef6c86b46d22 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -18,6 +18,7 @@ use rustc_data_structures::unify as ut; use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_index::IndexVec; use rustc_macros::extension; pub use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::bug; @@ -108,6 +109,10 @@ pub struct InferCtxtInner<'tcx> { /// Map from floating variable to the kind of float it represents. float_unification_storage: ut::UnificationTableStorage, + /// Map from floating variable to the origin span it came from. This is only used for the FCW + /// for the fallback to `f32`, so can be removed once the `f32` fallback is removed. + float_origin_span_storage: IndexVec, + /// Tracks the set of region variables and the constraints between them. /// /// This is initially `Some(_)` but when @@ -161,6 +166,7 @@ impl<'tcx> InferCtxtInner<'tcx> { const_unification_storage: Default::default(), int_unification_storage: Default::default(), float_unification_storage: Default::default(), + float_origin_span_storage: Default::default(), region_constraint_storage: Some(Default::default()), region_obligations: Default::default(), region_assumptions: Default::default(), @@ -644,6 +650,13 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().type_variables().var_origin(vid) } + /// Returns the origin of the float type variable identified by `vid`. + /// + /// No attempt is made to resolve `vid` to its root variable. + pub fn float_var_origin(&self, vid: FloatVid) -> Span { + self.inner.borrow_mut().float_origin_span_storage[vid] + } + /// Returns the origin of the const variable identified by `vid` // FIXME: We should store origins separately from the unification table // so this doesn't need to be optional. @@ -821,9 +834,11 @@ impl<'tcx> InferCtxt<'tcx> { Ty::new_int_var(self.tcx, next_int_var_id) } - pub fn next_float_var(&self) -> Ty<'tcx> { - let next_float_var_id = - self.inner.borrow_mut().float_unification_table().new_key(ty::FloatVarValue::Unknown); + pub fn next_float_var(&self, span: Span) -> Ty<'tcx> { + let mut inner = self.inner.borrow_mut(); + let next_float_var_id = inner.float_unification_table().new_key(ty::FloatVarValue::Unknown); + let span_index = inner.float_origin_span_storage.push(span); + debug_assert_eq!(next_float_var_id, span_index); Ty::new_float_var(self.tcx, next_float_var_id) } diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs index 6709c822dc7b1..48af711c31771 100644 --- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs +++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs @@ -6,13 +6,16 @@ use rustc_middle::ty::{ self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; +use rustc_span::Span; use tracing::instrument; use ut::UnifyKey; use super::VariableLengths; use crate::infer::type_variable::TypeVariableOrigin; use crate::infer::unify_key::{ConstVariableValue, ConstVidKey}; -use crate::infer::{ConstVariableOrigin, InferCtxt, RegionVariableOrigin, UnificationTable}; +use crate::infer::{ + ConstVariableOrigin, InferCtxt, InferCtxtInner, RegionVariableOrigin, UnificationTable, +}; fn vars_since_snapshot<'tcx, T>( table: &UnificationTable<'_, 'tcx, T>, @@ -25,6 +28,14 @@ where T::from_index(snapshot_var_len as u32)..T::from_index(table.len() as u32) } +fn float_vars_since_snapshot( + inner: &mut InferCtxtInner<'_>, + snapshot_var_len: usize, +) -> (Range, Vec) { + let range = vars_since_snapshot(&inner.float_unification_table(), snapshot_var_len); + (range.clone(), range.map(|index| inner.float_origin_span_storage[index]).collect()) +} + fn const_vars_since_snapshot<'tcx>( table: &mut UnificationTable<'_, 'tcx, ConstVidKey<'tcx>>, snapshot_var_len: usize, @@ -130,7 +141,7 @@ struct SnapshotVarData<'tcx> { region_vars: (Range, Vec>), type_vars: (Range, Vec), int_vars: Range, - float_vars: Range, + float_vars: (Range, Vec), const_vars: (Range, Vec), } @@ -143,8 +154,7 @@ impl<'tcx> SnapshotVarData<'tcx> { let type_vars = inner.type_variables().vars_since_snapshot(vars_pre_snapshot.type_var_len); let int_vars = vars_since_snapshot(&inner.int_unification_table(), vars_pre_snapshot.int_var_len); - let float_vars = - vars_since_snapshot(&inner.float_unification_table(), vars_pre_snapshot.float_var_len); + let float_vars = float_vars_since_snapshot(&mut inner, vars_pre_snapshot.float_var_len); let const_vars = const_vars_since_snapshot( &mut inner.const_unification_table(), @@ -158,7 +168,7 @@ impl<'tcx> SnapshotVarData<'tcx> { region_vars.0.is_empty() && type_vars.0.is_empty() && int_vars.is_empty() - && float_vars.is_empty() + && float_vars.0.is_empty() && const_vars.0.is_empty() } } @@ -203,8 +213,10 @@ impl<'a, 'tcx> TypeFolder> for InferenceFudger<'a, 'tcx> { } } ty::FloatVar(vid) => { - if self.snapshot_vars.float_vars.contains(&vid) { - self.infcx.next_float_var() + if self.snapshot_vars.float_vars.0.contains(&vid) { + let idx = vid.as_usize() - self.snapshot_vars.float_vars.0.start.as_usize(); + let span = self.snapshot_vars.float_vars.1[idx]; + self.infcx.next_float_var(span) } else { ty } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index fc8455dff9258..09c89220bb574 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -5612,3 +5612,52 @@ declare_lint! { report_in_deps: false, }; } + +declare_lint! { + /// The `float_literal_f32_fallback` lint detects situations where the type of an unsuffixed + /// float literal falls back to `f32` instead of `f64` to avoid a compilation error. This occurs + /// when there is a trait bound `f32: From` (or equivalent, such as `T: Into`) and the + /// literal is inferred to have the same type as `T`. + /// + /// ### Example + /// + /// ```rust + /// fn foo(x: impl Into) -> f32 { + /// x.into() + /// } + /// + /// fn main() { + /// dbg!(foo(2.5)); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Rust allows traits that are only implemented for a single floating point type to guide type + /// inferrence for floating point literals. This used to apply in the case of `f32: From` + /// (where `T` was inferred to be the same type as a floating point literal), as the only + /// floating point type impl was `f32: From`. However, as Rust is in the process of adding + /// support for `f16`, there are now two implementations for floating point types: + /// `f32: From` and `f32: From`. This means that the trait bound `f32: From` can no + /// longer guide inferrence for the type of the floating point literal. The default fallback for + /// unsuffixed floating point literals is `f64`. As `f32` does not implement `From`, + /// falling back to `f64` would cause a compilation error; therefore, the float type fallback + /// has been tempoarily adjusted to fallback to `f32` in this scenario. + /// + /// The lint will automatically provide a machine-applicable suggestion to add a `_f32` suffix + /// to the literal, which will fix the problem. + /// + /// This is a [future-incompatible] lint to transition this to a hard error in the future. See + /// [issue #FIXME] for more details. + /// + /// [issue #FIXME]: https://github.com/rust-lang/rust/issues/FIXME + pub FLOAT_LITERAL_F32_FALLBACK, + Warn, + "detects unsuffixed floating point literals whose type fallback to `f32`", + @future_incompatible = FutureIncompatibleInfo { + reason: fcw!(FutureReleaseError #0), + report_in_deps: false, + }; +} diff --git a/tests/ui/float/f32-into-f32.next-solver.fixed b/tests/ui/float/f32-into-f32.next-solver.fixed new file mode 100644 index 0000000000000..a8d56f4428b91 --- /dev/null +++ b/tests/ui/float/f32-into-f32.next-solver.fixed @@ -0,0 +1,23 @@ +//@ revisions: old-solver next-solver +//@[next-solver] compile-flags: -Znext-solver +//@ run-pass +//@ run-rustfix + +fn foo(_: impl Into) {} + +fn main() { + foo(1.0_f32); + //~^ WARN falling back to `f32` + //~| WARN this was previously accepted + foo(-(2.5_f32)); + //~^ WARN falling back to `f32` + //~| WARN this was previously accepted + foo(1e5_f32); + //~^ WARN falling back to `f32` + //~| WARN this was previously accepted + foo(4f32); // no warning + let x = -4.0_f32; + //~^ WARN falling back to `f32` + //~| WARN this was previously accepted + foo(x); +} diff --git a/tests/ui/float/f32-into-f32.next-solver.stderr b/tests/ui/float/f32-into-f32.next-solver.stderr new file mode 100644 index 0000000000000..ea71e3652384f --- /dev/null +++ b/tests/ui/float/f32-into-f32.next-solver.stderr @@ -0,0 +1,39 @@ +warning: falling back to `f32` as the trait bound `f32: From` is not satisfied + --> $DIR/f32-into-f32.rs:9:9 + | +LL | foo(1.0); + | ^^^ help: explicitly specify the type as `f32`: `1.0_f32` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #0 + = note: `#[warn(float_literal_f32_fallback)]` on by default + +warning: falling back to `f32` as the trait bound `f32: From` is not satisfied + --> $DIR/f32-into-f32.rs:12:11 + | +LL | foo(-(2.5)); + | ^^^ help: explicitly specify the type as `f32`: `2.5_f32` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #0 + +warning: falling back to `f32` as the trait bound `f32: From` is not satisfied + --> $DIR/f32-into-f32.rs:15:9 + | +LL | foo(1e5); + | ^^^ help: explicitly specify the type as `f32`: `1e5_f32` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #0 + +warning: falling back to `f32` as the trait bound `f32: From` is not satisfied + --> $DIR/f32-into-f32.rs:19:14 + | +LL | let x = -4.0; + | ^^^ help: explicitly specify the type as `f32`: `4.0_f32` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #0 + +warning: 4 warnings emitted + diff --git a/tests/ui/float/f32-into-f32.old-solver.fixed b/tests/ui/float/f32-into-f32.old-solver.fixed new file mode 100644 index 0000000000000..a8d56f4428b91 --- /dev/null +++ b/tests/ui/float/f32-into-f32.old-solver.fixed @@ -0,0 +1,23 @@ +//@ revisions: old-solver next-solver +//@[next-solver] compile-flags: -Znext-solver +//@ run-pass +//@ run-rustfix + +fn foo(_: impl Into) {} + +fn main() { + foo(1.0_f32); + //~^ WARN falling back to `f32` + //~| WARN this was previously accepted + foo(-(2.5_f32)); + //~^ WARN falling back to `f32` + //~| WARN this was previously accepted + foo(1e5_f32); + //~^ WARN falling back to `f32` + //~| WARN this was previously accepted + foo(4f32); // no warning + let x = -4.0_f32; + //~^ WARN falling back to `f32` + //~| WARN this was previously accepted + foo(x); +} diff --git a/tests/ui/float/f32-into-f32.old-solver.stderr b/tests/ui/float/f32-into-f32.old-solver.stderr new file mode 100644 index 0000000000000..ea71e3652384f --- /dev/null +++ b/tests/ui/float/f32-into-f32.old-solver.stderr @@ -0,0 +1,39 @@ +warning: falling back to `f32` as the trait bound `f32: From` is not satisfied + --> $DIR/f32-into-f32.rs:9:9 + | +LL | foo(1.0); + | ^^^ help: explicitly specify the type as `f32`: `1.0_f32` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #0 + = note: `#[warn(float_literal_f32_fallback)]` on by default + +warning: falling back to `f32` as the trait bound `f32: From` is not satisfied + --> $DIR/f32-into-f32.rs:12:11 + | +LL | foo(-(2.5)); + | ^^^ help: explicitly specify the type as `f32`: `2.5_f32` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #0 + +warning: falling back to `f32` as the trait bound `f32: From` is not satisfied + --> $DIR/f32-into-f32.rs:15:9 + | +LL | foo(1e5); + | ^^^ help: explicitly specify the type as `f32`: `1e5_f32` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #0 + +warning: falling back to `f32` as the trait bound `f32: From` is not satisfied + --> $DIR/f32-into-f32.rs:19:14 + | +LL | let x = -4.0; + | ^^^ help: explicitly specify the type as `f32`: `4.0_f32` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #0 + +warning: 4 warnings emitted + diff --git a/tests/ui/float/f32-into-f32.rs b/tests/ui/float/f32-into-f32.rs index 1b3f0926bddec..b55023453b7e0 100644 --- a/tests/ui/float/f32-into-f32.rs +++ b/tests/ui/float/f32-into-f32.rs @@ -1,9 +1,23 @@ //@ revisions: old-solver next-solver //@[next-solver] compile-flags: -Znext-solver //@ run-pass +//@ run-rustfix fn foo(_: impl Into) {} fn main() { foo(1.0); + //~^ WARN falling back to `f32` + //~| WARN this was previously accepted + foo(-(2.5)); + //~^ WARN falling back to `f32` + //~| WARN this was previously accepted + foo(1e5); + //~^ WARN falling back to `f32` + //~| WARN this was previously accepted + foo(4f32); // no warning + let x = -4.0; + //~^ WARN falling back to `f32` + //~| WARN this was previously accepted + foo(x); } diff --git a/tests/ui/inference/untyped-primitives.rs b/tests/ui/inference/untyped-primitives.rs index 8515ca79903fc..d04ccb4ff7bbd 100644 --- a/tests/ui/inference/untyped-primitives.rs +++ b/tests/ui/inference/untyped-primitives.rs @@ -5,5 +5,7 @@ fn main() { let x = f32::from(3.14); + //~^ WARN falling back to `f32` + //~| WARN this was previously accepted let y = f64::from(3.14); } diff --git a/tests/ui/inference/untyped-primitives.stderr b/tests/ui/inference/untyped-primitives.stderr new file mode 100644 index 0000000000000..48d62963221cb --- /dev/null +++ b/tests/ui/inference/untyped-primitives.stderr @@ -0,0 +1,12 @@ +warning: falling back to `f32` as the trait bound `f32: From` is not satisfied + --> $DIR/untyped-primitives.rs:7:23 + | +LL | let x = f32::from(3.14); + | ^^^^ help: explicitly specify the type as `f32`: `3.14_f32` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #FIXME + = note: `#[warn(float_literal_f32_fallback)]` on by default + +warning: 1 warning emitted +