|
1 | 1 | use std::path::PathBuf;
|
2 | 2 |
|
3 |
| -use rustc_data_structures::fx::FxHashSet; |
| 3 | +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; |
4 | 4 | use rustc_errors::codes::*;
|
5 | 5 | use rustc_errors::{
|
6 | 6 | Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic,
|
7 | 7 | EmissionGuarantee, IntoDiagArg, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic,
|
8 | 8 | };
|
9 | 9 | use rustc_hir as hir;
|
10 |
| -use rustc_hir::def_id::LocalDefId; |
| 10 | +use rustc_hir::def::DefKind; |
| 11 | +use rustc_hir::def_id::{DefId, LocalDefId}; |
11 | 12 | use rustc_hir::intravisit::{Visitor, walk_ty};
|
12 | 13 | use rustc_hir::{FnRetTy, GenericParamKind};
|
13 | 14 | use rustc_macros::{Diagnostic, Subdiagnostic};
|
@@ -1792,6 +1793,130 @@ impl Subdiagnostic for AddPreciseCapturingAndParams {
|
1792 | 1793 | self.suggs,
|
1793 | 1794 | Applicability::MaybeIncorrect,
|
1794 | 1795 | );
|
1795 |
| - diag.span_note(self.apit_spans, fluent::trait_selection_warn_removing_apit_params); |
| 1796 | + diag.span_note( |
| 1797 | + self.apit_spans, |
| 1798 | + fluent::trait_selection_warn_removing_apit_params_for_undercapture, |
| 1799 | + ); |
| 1800 | + } |
| 1801 | +} |
| 1802 | + |
| 1803 | +/// Given a set of captured `DefId` for an RPIT (opaque_def_id) and a given |
| 1804 | +/// function (fn_def_id), try to suggest adding `+ use<...>` to capture just |
| 1805 | +/// the specified parameters. If one of those parameters is an APIT, then try |
| 1806 | +/// to suggest turning it into a regular type parameter. |
| 1807 | +pub fn impl_trait_overcapture_suggestion<'tcx>( |
| 1808 | + tcx: TyCtxt<'tcx>, |
| 1809 | + opaque_def_id: LocalDefId, |
| 1810 | + fn_def_id: LocalDefId, |
| 1811 | + captured_args: FxIndexSet<DefId>, |
| 1812 | +) -> Option<AddPreciseCapturingForOvercapture> { |
| 1813 | + let generics = tcx.generics_of(fn_def_id); |
| 1814 | + |
| 1815 | + let mut captured_lifetimes = FxIndexSet::default(); |
| 1816 | + let mut captured_non_lifetimes = FxIndexSet::default(); |
| 1817 | + let mut synthetics = vec![]; |
| 1818 | + |
| 1819 | + for arg in captured_args { |
| 1820 | + if tcx.def_kind(arg) == DefKind::LifetimeParam { |
| 1821 | + captured_lifetimes.insert(tcx.item_name(arg)); |
| 1822 | + } else { |
| 1823 | + let idx = generics.param_def_id_to_index(tcx, arg).expect("expected arg in scope"); |
| 1824 | + let param = generics.param_at(idx as usize, tcx); |
| 1825 | + if param.kind.is_synthetic() { |
| 1826 | + synthetics.push((tcx.def_span(arg), param.name)); |
| 1827 | + } else { |
| 1828 | + captured_non_lifetimes.insert(tcx.item_name(arg)); |
| 1829 | + } |
| 1830 | + } |
| 1831 | + } |
| 1832 | + |
| 1833 | + let mut next_fresh_param = || { |
| 1834 | + ["T", "U", "V", "W", "X", "Y", "A", "B", "C"] |
| 1835 | + .into_iter() |
| 1836 | + .map(Symbol::intern) |
| 1837 | + .chain((0..).map(|i| Symbol::intern(&format!("T{i}")))) |
| 1838 | + .find(|s| captured_non_lifetimes.insert(*s)) |
| 1839 | + .unwrap() |
| 1840 | + }; |
| 1841 | + |
| 1842 | + let mut suggs = vec![]; |
| 1843 | + let mut apit_spans = vec![]; |
| 1844 | + |
| 1845 | + if !synthetics.is_empty() { |
| 1846 | + let mut new_params = String::new(); |
| 1847 | + for (i, (span, name)) in synthetics.into_iter().enumerate() { |
| 1848 | + apit_spans.push(span); |
| 1849 | + |
| 1850 | + let fresh_param = next_fresh_param(); |
| 1851 | + |
| 1852 | + // Suggest renaming. |
| 1853 | + suggs.push((span, fresh_param.to_string())); |
| 1854 | + |
| 1855 | + // Super jank. Turn `impl Trait` into `T: Trait`. |
| 1856 | + // |
| 1857 | + // This currently involves stripping the `impl` from the name of |
| 1858 | + // the parameter, since APITs are always named after how they are |
| 1859 | + // rendered in the AST. This sucks! But to recreate the bound list |
| 1860 | + // from the APIT itself would be miserable, so we're stuck with |
| 1861 | + // this for now! |
| 1862 | + if i > 0 { |
| 1863 | + new_params += ", "; |
| 1864 | + } |
| 1865 | + let name_as_bounds = name.as_str().trim_start_matches("impl").trim_start(); |
| 1866 | + new_params += fresh_param.as_str(); |
| 1867 | + new_params += ": "; |
| 1868 | + new_params += name_as_bounds; |
| 1869 | + } |
| 1870 | + |
| 1871 | + let Some(generics) = tcx.hir().get_generics(fn_def_id) else { |
| 1872 | + // This shouldn't happen, but don't ICE. |
| 1873 | + return None; |
| 1874 | + }; |
| 1875 | + |
| 1876 | + // Add generics or concatenate to the end of the list. |
| 1877 | + suggs.push(if let Some(params_span) = generics.span_for_param_suggestion() { |
| 1878 | + (params_span, format!(", {new_params}")) |
| 1879 | + } else { |
| 1880 | + (generics.span, format!("<{new_params}>")) |
| 1881 | + }); |
| 1882 | + } |
| 1883 | + |
| 1884 | + let concatenated_bounds = captured_lifetimes |
| 1885 | + .into_iter() |
| 1886 | + .chain(captured_non_lifetimes) |
| 1887 | + .map(|sym| sym.to_string()) |
| 1888 | + .collect::<Vec<_>>() |
| 1889 | + .join(", "); |
| 1890 | + |
| 1891 | + suggs.push(( |
| 1892 | + tcx.def_span(opaque_def_id).shrink_to_hi(), |
| 1893 | + format!(" + use<{concatenated_bounds}>"), |
| 1894 | + )); |
| 1895 | + |
| 1896 | + Some(AddPreciseCapturingForOvercapture { suggs, apit_spans }) |
| 1897 | +} |
| 1898 | + |
| 1899 | +pub struct AddPreciseCapturingForOvercapture { |
| 1900 | + pub suggs: Vec<(Span, String)>, |
| 1901 | + pub apit_spans: Vec<Span>, |
| 1902 | +} |
| 1903 | + |
| 1904 | +impl Subdiagnostic for AddPreciseCapturingForOvercapture { |
| 1905 | + fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( |
| 1906 | + self, |
| 1907 | + diag: &mut Diag<'_, G>, |
| 1908 | + _f: &F, |
| 1909 | + ) { |
| 1910 | + diag.multipart_suggestion_verbose( |
| 1911 | + fluent::trait_selection_precise_capturing_overcaptures, |
| 1912 | + self.suggs, |
| 1913 | + Applicability::MaybeIncorrect, |
| 1914 | + ); |
| 1915 | + if !self.apit_spans.is_empty() { |
| 1916 | + diag.span_note( |
| 1917 | + self.apit_spans, |
| 1918 | + fluent::trait_selection_warn_removing_apit_params_for_overcapture, |
| 1919 | + ); |
| 1920 | + } |
1796 | 1921 | }
|
1797 | 1922 | }
|
0 commit comments