|
1 | 1 | use super::{
|
2 | 2 | EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
|
| 3 | + SelectionContext, |
3 | 4 | };
|
4 | 5 |
|
5 | 6 | use crate::infer::InferCtxt;
|
| 7 | +use crate::traits::normalize_projection_type; |
6 | 8 |
|
7 | 9 | use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder, Style};
|
8 | 10 | use rustc_hir as hir;
|
9 | 11 | use rustc_hir::def::DefKind;
|
10 | 12 | use rustc_hir::def_id::DefId;
|
11 | 13 | use rustc_hir::intravisit::Visitor;
|
| 14 | +use rustc_hir::lang_items; |
12 | 15 | use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
|
13 | 16 | use rustc_middle::ty::TypeckTables;
|
14 | 17 | use rustc_middle::ty::{
|
@@ -150,6 +153,15 @@ pub trait InferCtxtExt<'tcx> {
|
150 | 153 | T: fmt::Display;
|
151 | 154 |
|
152 | 155 | fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>);
|
| 156 | + |
| 157 | + /// Suggest to await before try: future? => future.await? |
| 158 | + fn suggest_await_before_try( |
| 159 | + &self, |
| 160 | + err: &mut DiagnosticBuilder<'_>, |
| 161 | + obligation: &PredicateObligation<'tcx>, |
| 162 | + trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, |
| 163 | + span: Span, |
| 164 | + ); |
153 | 165 | }
|
154 | 166 |
|
155 | 167 | fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) {
|
@@ -1822,6 +1834,95 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
1822 | 1834 | suggested_limit, self.tcx.crate_name,
|
1823 | 1835 | ));
|
1824 | 1836 | }
|
| 1837 | + |
| 1838 | + fn suggest_await_before_try( |
| 1839 | + &self, |
| 1840 | + err: &mut DiagnosticBuilder<'_>, |
| 1841 | + obligation: &PredicateObligation<'tcx>, |
| 1842 | + trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, |
| 1843 | + span: Span, |
| 1844 | + ) { |
| 1845 | + debug!( |
| 1846 | + "suggest_await_befor_try: obligation={:?}, span={:?}, trait_ref={:?}, trait_ref_self_ty={:?}", |
| 1847 | + obligation, |
| 1848 | + span, |
| 1849 | + trait_ref, |
| 1850 | + trait_ref.self_ty() |
| 1851 | + ); |
| 1852 | + let body_hir_id = obligation.cause.body_id; |
| 1853 | + let item_id = self.tcx.hir().get_parent_node(body_hir_id); |
| 1854 | + |
| 1855 | + if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(item_id) { |
| 1856 | + let body = self.tcx.hir().body(body_id); |
| 1857 | + if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { |
| 1858 | + let future_trait = |
| 1859 | + self.tcx.require_lang_item(lang_items::FutureTraitLangItem, None); |
| 1860 | + |
| 1861 | + let self_ty = self.resolve_vars_if_possible(&trait_ref.self_ty()); |
| 1862 | + |
| 1863 | + let impls_future = self.tcx.type_implements_trait(( |
| 1864 | + future_trait, |
| 1865 | + self_ty, |
| 1866 | + ty::List::empty(), |
| 1867 | + obligation.param_env, |
| 1868 | + )); |
| 1869 | + |
| 1870 | + let item_def_id = self |
| 1871 | + .tcx |
| 1872 | + .associated_items(future_trait) |
| 1873 | + .in_definition_order() |
| 1874 | + .next() |
| 1875 | + .unwrap() |
| 1876 | + .def_id; |
| 1877 | + // `<T as Future>::Output` |
| 1878 | + let projection_ty = ty::ProjectionTy { |
| 1879 | + // `T` |
| 1880 | + substs: self.tcx.mk_substs_trait( |
| 1881 | + trait_ref.self_ty(), |
| 1882 | + self.fresh_substs_for_item(span, item_def_id), |
| 1883 | + ), |
| 1884 | + // `Future::Output` |
| 1885 | + item_def_id, |
| 1886 | + }; |
| 1887 | + |
| 1888 | + let mut selcx = SelectionContext::new(self); |
| 1889 | + |
| 1890 | + let mut obligations = vec![]; |
| 1891 | + let normalized_ty = normalize_projection_type( |
| 1892 | + &mut selcx, |
| 1893 | + obligation.param_env, |
| 1894 | + projection_ty, |
| 1895 | + obligation.cause.clone(), |
| 1896 | + 0, |
| 1897 | + &mut obligations, |
| 1898 | + ); |
| 1899 | + |
| 1900 | + debug!( |
| 1901 | + "suggest_await_befor_try: normalized_projection_type {:?}", |
| 1902 | + self.resolve_vars_if_possible(&normalized_ty) |
| 1903 | + ); |
| 1904 | + let try_obligation = self.mk_obligation_for_def_id( |
| 1905 | + trait_ref.def_id(), |
| 1906 | + normalized_ty, |
| 1907 | + obligation.cause.clone(), |
| 1908 | + obligation.param_env, |
| 1909 | + ); |
| 1910 | + debug!("suggest_await_befor_try: try_trait_obligation {:?}", try_obligation); |
| 1911 | + if self.predicate_may_hold(&try_obligation) && impls_future { |
| 1912 | + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { |
| 1913 | + if snippet.ends_with('?') { |
| 1914 | + err.span_suggestion( |
| 1915 | + span, |
| 1916 | + "consider using `.await` here", |
| 1917 | + format!("{}.await?", snippet.trim_end_matches('?')), |
| 1918 | + Applicability::MaybeIncorrect, |
| 1919 | + ); |
| 1920 | + } |
| 1921 | + } |
| 1922 | + } |
| 1923 | + } |
| 1924 | + } |
| 1925 | + } |
1825 | 1926 | }
|
1826 | 1927 |
|
1827 | 1928 | /// Collect all the returned expressions within the input expression.
|
|
0 commit comments