Repository: rust-analyzer/rust-analyzer
Pull request #11806 (2022-03-23 22:43:26)

fix: Fix async block type inference using containing function return type
Fixes https://github.com/rust-analyzer/rust-analyzer/issues/11804
Should fix https://github.com/rust-analyzer/rust-analyzer/issues/11798#issuecomment-1076880521


Patch:
diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs
index 22cb856535..dffb36b5de 100644
--- a/crates/hir_ty/src/autoderef.rs
+++ b/crates/hir_ty/src/autoderef.rs
@@ -108,13 +108,8 @@ fn builtin_deref(ty: &Ty) -> Option<&Ty> {
 }
 
 fn deref_by_trait(table: &mut InferenceTable, ty: Ty) -> Option<Ty> {
-    let _p = profile::span("deref_by_trait");
-    if table.resolve_ty_shallow(&ty).inference_var(Interner).is_some() {
-        // don't try to deref unknown variables
-        return None;
-    }
-
     let db = table.db;
+    let _p = profile::span("deref_by_trait");
     let deref_trait = db
         .lang_item(table.trait_env.krate, SmolStr::new_inline("deref"))
         .and_then(|l| l.as_trait())?;
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index c91cdec183..e78d3f267f 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -364,7 +364,7 @@ pub(crate) struct InferenceContext<'a> {
     table: unify::InferenceTable<'a>,
     trait_env: Arc<TraitEnvironment>,
     result: InferenceResult,
-    /// The return type of the function being inferred, or the closure if we're
+    /// The return type of the function being inferred, the closure or async block if we're
     /// currently within one.
     ///
     /// We might consider using a nested inference context for checking
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 43cff92f23..01b11861cd 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -157,9 +157,17 @@ impl<'a> InferenceContext<'a> {
                 self.err_ty()
             }
             Expr::Async { body } => {
+                let ret_ty = self.table.new_type_var();
+                let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
+                let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
+
+                let inner_ty = self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
+
+                self.diverges = prev_diverges;
+                self.return_ty = prev_ret_ty;
+
                 // Use the first type parameter as the output type of future.
                 // existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
-                let inner_ty = self.infer_expr(*body, &Expectation::none());
                 let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body);
                 let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
                 TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty))
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 768772d5c3..1c939f3d8a 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -681,11 +681,6 @@ fn iterate_method_candidates_with_autoref(
     name: Option<&Name>,
     mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 ) -> ControlFlow<()> {
-    if receiver_ty.value.is_general_var(Interner, &receiver_ty.binders) {
-        // don't try to resolve methods on unknown types
-        return ControlFlow::Continue(());
-    }
-
     iterate_method_candidates_by_receiver(
         receiver_ty,
         first_adjustment.clone(),
diff --git a/crates/proc_macro_srv/src/abis/abi_1_58/rustc_server.rs b/crates/proc_macro_srv/src/abis/abi_1_58/rustc_server.rs
index 5c596bc0e6..6c57ac92dc 100644
--- a/crates/proc_macro_srv/src/abis/abi_1_58/rustc_server.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_58/rustc_server.rs
@@ -97,13 +97,9 @@ impl Extend<TokenStream> for TokenStream {
     }
 }
 
-#[derive(Clone)]
-pub struct SourceFile {
-    // FIXME stub
-}
-
 type Level = super::proc_macro::Level;
 type LineColumn = super::proc_macro::LineColumn;
+type SourceFile = super::proc_macro::SourceFile;
 
 /// A structure representing a diagnostic message and associated children
 /// messages.
@@ -598,15 +594,16 @@ impl server::Literal for Rustc {
 }
 
 impl server::SourceFile for Rustc {
-    // FIXME these are all stubs
-    fn eq(&mut self, _file1: &Self::SourceFile, _file2: &Self::SourceFile) -> bool {
-        true
+    fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
+        file1.eq(file2)
     }
-    fn path(&mut self, _file: &Self::SourceFile) -> String {
-        String::new()
+    fn path(&mut self, file: &Self::SourceFile) -> String {
+        String::from(
+            file.path().to_str().expect("non-UTF8 file path in `proc_macro::SourceFile::path`"),
+        )
     }
-    fn is_real(&mut self, _file: &Self::SourceFile) -> bool {
-        true
+    fn is_real(&mut self, file: &Self::SourceFile) -> bool {
+        file.is_real()
     }
 }
 
@@ -649,7 +646,8 @@ impl server::Span for Rustc {
         tt::TokenId::unspecified()
     }
     fn source_file(&mut self, _span: Self::Span) -> Self::SourceFile {
-        SourceFile {}
+        // let MySpanData(span) = self.span_interner.get(span.0);
+        unimplemented!()
     }
     fn save_span(&mut self, _span: Self::Span) -> usize {
         // FIXME stub


Test patch:
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index 011347e5c4..56b8db1319 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -2,7 +2,7 @@ use expect_test::expect;
 
 use crate::tests::check;
 
-use super::{check_infer, check_no_mismatches, check_types};
+use super::{check_infer, check_types};
 
 #[test]
 fn infer_slice_method() {
@@ -1697,68 +1697,3 @@ fn test() {
 "#,
     );
 }
-
-#[test]
-fn bad_inferred_reference_1() {
-    check_no_mismatches(
-        r#"
-//- minicore: sized
-pub trait Into<T>: Sized {
-    fn into(self) -> T;
-}
-impl<T> Into<T> for T {
-    fn into(self) -> T { self }
-}
-
-trait ExactSizeIterator {
-    fn len(&self) -> usize;
-}
-
-pub struct Foo;
-impl Foo {
-    fn len(&self) -> usize { 0 }
-}
-
-pub fn test(generic_args: impl Into<Foo>) {
-    let generic_args = generic_args.into();
-    generic_args.len();
-    let _: Foo = generic_args;
-}
-"#,
-    );
-}
-
-#[test]
-fn bad_inferred_reference_2() {
-    check_no_mismatches(
-        r#"
-//- minicore: deref
-trait ExactSizeIterator {
-    fn len(&self) -> usize;
-}
-
-pub struct Foo;
-impl Foo {
-    fn len(&self) -> usize { 0 }
-}
-
-pub fn test() {
-    let generic_args;
-    generic_args.len();
-    let _: Foo = generic_args;
-}
-"#,
-    );
-}
-
-#[test]
-fn resolve_minicore_iterator() {
-    check_types(
-        r#"
-//- minicore: iterators, sized
-fn foo() {
-    let m = core::iter::repeat(()).filter_map(|()| Some(92)).next();
-}         //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Option<i32>
-"#,
-    );
-}
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index de27c294f6..31045c193c 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -1952,6 +1952,52 @@ async fn main() {
         "#]],
     )
 }
+#[test]
+fn async_block_early_return() {
+    check_infer(
+        r#"
+//- minicore: future, result, fn
+fn test<I, E, F: FnMut() -> Fut, Fut: core::future::Future<Output = Result<I, E>>>(f: F) {}
+
+fn main() {
+    async {
+        return Err(());
+        Ok(())
+    };
+    test(|| async {
+        return Err(());
+        Ok(())
+    });
+}
+        "#,
+        expect![[r#"
+            83..84 'f': F
+            89..91 '{}': ()
+            103..231 '{     ... }); }': ()
+            109..161 'async ...     }': Result<(), ()>
+            109..161 'async ...     }': impl Future<Output = Result<(), ()>>
+            125..139 'return Err(())': !
+            132..135 'Err': Err<(), ()>(()) -> Result<(), ()>
+            132..139 'Err(())': Result<(), ()>
+            136..138 '()': ()
+            149..151 'Ok': Ok<(), ()>(()) -> Result<(), ()>
+            149..155 'Ok(())': Result<(), ()>
+            152..154 '()': ()
+            167..171 'test': fn test<(), (), || -> impl Future<Output = Result<(), ()>>, impl Future<Output = Result<(), ()>>>(|| -> impl Future<Output = Result<(), ()>>)
+            167..228 'test(|...    })': ()
+            172..227 '|| asy...     }': || -> impl Future<Output = Result<(), ()>>
+            175..227 'async ...     }': Result<(), ()>
+            175..227 'async ...     }': impl Future<Output = Result<(), ()>>
+            191..205 'return Err(())': !
+            198..201 'Err': Err<(), ()>(()) -> Result<(), ()>
+            198..205 'Err(())': Result<(), ()>
+            202..204 '()': ()
+            215..217 'Ok': Ok<(), ()>(()) -> Result<(), ()>
+            215..221 'Ok(())': Result<(), ()>
+            218..220 '()': ()
+        "#]],
+    )
+}
 
 #[test]
 fn infer_generic_from_later_assignment() {
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 2cd4fa809a..f8ca5c269c 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -1018,5 +1018,5 @@ fn benchmark_syntax_highlighting_parser() {
             .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Function))
             .count()
     };
-    assert_eq!(hash, 1609);
+    assert_eq!(hash, 1616);
 }
diff --git a/crates/test_utils/src/minicore.rs b/crates/test_utils/src/minicore.rs
index 8474014a2c..5c63e27879 100644
--- a/crates/test_utils/src/minicore.rs
+++ b/crates/test_utils/src/minicore.rs
@@ -518,7 +518,7 @@ pub mod iter {
             }
         }
     }
-    pub use self::adapters::{Take, FilterMap};
+    pub use self::adapters::Take;
 
     mod sources {
         mod repeat {