Repository: rust-analyzer/rust-analyzer
Pull request #8038 (2021-03-15 17:59:25)

Fix unification logic

flodiebold: bors r+
bors[bot]: Build failed:
  * [Rust (macos-latest)](https://github.com/rust-analyzer/rust-analyzer/runs/2115197240)

Patch:
diff --git a/Cargo.lock b/Cargo.lock
index b2d009e38f..b1fef2e80a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -486,7 +486,6 @@ dependencies = [
  "log",
  "profile",
  "rustc-hash",
- "smallvec",
  "stdx",
  "syntax",
  "tt",
diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml
index 55e9c3f0cf..d4ea7327eb 100644
--- a/crates/hir/Cargo.toml
+++ b/crates/hir/Cargo.toml
@@ -15,7 +15,6 @@ rustc-hash = "1.1.0"
 either = "1.5.3"
 arrayvec = "0.5.1"
 itertools = "0.10.0"
-smallvec = "1.4.0"
 
 stdx = { path = "../stdx", version = "0.0.0" }
 syntax = { path = "../syntax", version = "0.0.0" }
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 519339c0c8..945638cc56 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -259,10 +259,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
     }
 
     pub fn to_module_def(&self, file: FileId) -> Option<Module> {
-        self.imp.to_module_def(file).next()
-    }
-
-    pub fn to_module_defs(&self, file: FileId) -> impl Iterator<Item = Module> {
         self.imp.to_module_def(file)
     }
 
@@ -541,8 +537,8 @@ impl<'db> SemanticsImpl<'db> {
         f(&mut ctx)
     }
 
-    fn to_module_def(&self, file: FileId) -> impl Iterator<Item = Module> {
-        self.with_ctx(|ctx| ctx.file_to_def(file)).into_iter().map(Module::from)
+    fn to_module_def(&self, file: FileId) -> Option<Module> {
+        self.with_ctx(|ctx| ctx.file_to_def(file)).map(Module::from)
     }
 
     fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> {
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index e9d8201403..6c612ee863 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -12,7 +12,6 @@ use hir_def::{
 };
 use hir_expand::{name::AsName, AstId, MacroDefKind};
 use rustc_hash::FxHashMap;
-use smallvec::SmallVec;
 use stdx::impl_from;
 use syntax::{
     ast::{self, NameOwner},
@@ -29,19 +28,14 @@ pub(super) struct SourceToDefCtx<'a, 'b> {
 }
 
 impl SourceToDefCtx<'_, '_> {
-    pub(super) fn file_to_def(&mut self, file: FileId) -> SmallVec<[ModuleId; 1]> {
+    pub(super) fn file_to_def(&mut self, file: FileId) -> Option<ModuleId> {
         let _p = profile::span("SourceBinder::to_module_def");
-        let mut mods = SmallVec::new();
-        for &crate_id in self.db.relevant_crates(file).iter() {
+        self.db.relevant_crates(file).iter().find_map(|&crate_id| {
             // FIXME: inner items
             let crate_def_map = self.db.crate_def_map(crate_id);
-            mods.extend(
-                crate_def_map
-                    .modules_for_file(file)
-                    .map(|local_id| crate_def_map.module_id(local_id)),
-            )
-        }
-        mods
+            let local_id = crate_def_map.modules_for_file(file).next()?;
+            Some(crate_def_map.module_id(local_id))
+        })
     }
 
     pub(super) fn module_to_def(&mut self, src: InFile<ast::Module>) -> Option<ModuleId> {
@@ -61,7 +55,7 @@ impl SourceToDefCtx<'_, '_> {
             Some(parent_declaration) => self.module_to_def(parent_declaration),
             None => {
                 let file_id = src.file_id.original_file(self.db.upcast());
-                self.file_to_def(file_id).get(0).copied()
+                self.file_to_def(file_id)
             }
         }?;
 
@@ -191,7 +185,7 @@ impl SourceToDefCtx<'_, '_> {
     ) -> Option<MacroDefId> {
         let kind = MacroDefKind::Declarative;
         let file_id = src.file_id.original_file(self.db.upcast());
-        let krate = self.file_to_def(file_id).get(0).copied()?.krate();
+        let krate = self.file_to_def(file_id)?.krate();
         let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value);
         let ast_id = Some(AstId::new(src.file_id, file_ast_id.upcast()));
         Some(MacroDefId { krate, ast_id, kind, local_inner: false })
@@ -251,7 +245,7 @@ impl SourceToDefCtx<'_, '_> {
             return Some(res);
         }
 
-        let def = self.file_to_def(src.file_id.original_file(self.db.upcast())).get(0).copied()?;
+        let def = self.file_to_def(src.file_id.original_file(self.db.upcast()))?;
         Some(def.into())
     }
 
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index 66f8fe8a32..7795f446f5 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -300,7 +300,7 @@ impl InferenceTable {
                 | (TyKind::Raw(_, ty1), TyKind::Raw(_, ty2))
                 | (TyKind::Array(ty1), TyKind::Array(ty2))
                 | (TyKind::Slice(ty1), TyKind::Slice(ty2)) => self.unify_inner(ty1, ty2, depth + 1),
-                _ => false,
+                _ => true, /* we checked equals_ctor already */
             }
         } else {
             self.unify_inner_trivial(&ty1, &ty2, depth)
diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs
index 22b0d6ecbe..03d71b3807 100644
--- a/crates/ide/src/parent_module.rs
+++ b/crates/ide/src/parent_module.rs
@@ -1,7 +1,6 @@
 use hir::Semantics;
 use ide_db::base_db::{CrateId, FileId, FilePosition};
 use ide_db::RootDatabase;
-use itertools::Itertools;
 use syntax::{
     algo::find_node_at_offset,
     ast::{self, AstNode},
@@ -19,7 +18,8 @@ use crate::NavigationTarget;
 // | VS Code | **Rust Analyzer: Locate parent module**
 // |===
 
-/// This returns `Vec` because a module may be included from several places.
+/// This returns `Vec` because a module may be included from several places. We
+/// don't handle this case yet though, so the Vec has length at most one.
 pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> {
     let sema = Semantics::new(db);
     let source_file = sema.parse(position.file_id);
@@ -37,23 +37,27 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<Na
         }
     }
 
-    match module {
-        Some(module) => sema
-            .to_def(&module)
-            .into_iter()
-            .map(|module| NavigationTarget::from_module_to_decl(db, module))
-            .collect(),
-        None => sema
-            .to_module_defs(position.file_id)
-            .map(|module| NavigationTarget::from_module_to_decl(db, module))
-            .collect(),
-    }
+    let module = match module {
+        Some(module) => sema.to_def(&module),
+        None => sema.to_module_def(position.file_id),
+    };
+    let module = match module {
+        None => return Vec::new(),
+        Some(it) => it,
+    };
+    let nav = NavigationTarget::from_module_to_decl(db, module);
+    vec![nav]
 }
 
 /// Returns `Vec` for the same reason as `parent_module`
 pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> {
     let sema = Semantics::new(db);
-    sema.to_module_defs(file_id).map(|module| module.krate().into()).unique().collect()
+    let module = match sema.to_module_def(file_id) {
+        Some(it) => it,
+        None => return Vec::new(),
+    };
+    let krate = module.krate();
+    vec![krate.into()]
 }
 
 #[cfg(test)]
@@ -63,13 +67,11 @@ mod tests {
     use crate::fixture;
 
     fn check(ra_fixture: &str) {
-        let (analysis, position, expected) = fixture::annotations(ra_fixture);
-        let navs = analysis.parent_module(position).unwrap();
-        let navs = navs
-            .iter()
-            .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
-            .collect::<Vec<_>>();
-        assert_eq!(expected.into_iter().map(|(fr, _)| fr).collect::<Vec<_>>(), navs);
+        let (analysis, position, expected) = fixture::nav_target_annotation(ra_fixture);
+        let mut navs = analysis.parent_module(position).unwrap();
+        assert_eq!(navs.len(), 1);
+        let nav = navs.pop().unwrap();
+        assert_eq!(expected, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() });
     }
 
     #[test]
@@ -117,47 +119,16 @@ mod foo {
         );
     }
 
-    #[test]
-    fn test_resolve_multi_parent_module() {
-        check(
-            r#"
-//- /main.rs
-mod foo;
-  //^^^
-#[path = "foo.rs"]
-mod bar;
-  //^^^
-//- /foo.rs
-$0
-"#,
-        );
-    }
-
     #[test]
     fn test_resolve_crate_root() {
         let (analysis, file_id) = fixture::file(
             r#"
-//- /foo.rs
-$0
 //- /main.rs
 mod foo;
-"#,
-        );
-        assert_eq!(analysis.crate_for(file_id).unwrap().len(), 1);
-    }
-
-    #[test]
-    fn test_resolve_multi_parent_crate() {
-        let (analysis, file_id) = fixture::file(
-            r#"
-//- /baz.rs
+//- /foo.rs
 $0
-//- /foo.rs crate:foo
-mod baz;
-//- /bar.rs crate:bar
-mod baz;
 "#,
         );
-        assert_eq!(analysis.crate_for(file_id).unwrap().len(), 2);
+        assert_eq!(analysis.crate_for(file_id).unwrap().len(), 1);
     }
 }
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index bed1f01169..694f445bc3 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -170,28 +170,22 @@ export function parentModule(ctx: Ctx): Cmd {
         const client = ctx.client;
         if (!editor || !client) return;
 
-        const locations = await client.sendRequest(ra.parentModule, {
+        const response = await client.sendRequest(ra.parentModule, {
             textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
             position: client.code2ProtocolConverter.asPosition(
                 editor.selection.active,
             ),
         });
+        const loc = response[0];
+        if (!loc) return;
 
-        if (locations.length === 1) {
-            const loc = locations[0];
+        const uri = client.protocol2CodeConverter.asUri(loc.targetUri);
+        const range = client.protocol2CodeConverter.asRange(loc.targetRange);
 
-            const uri = client.protocol2CodeConverter.asUri(loc.targetUri);
-            const range = client.protocol2CodeConverter.asRange(loc.targetRange);
-
-            const doc = await vscode.workspace.openTextDocument(uri);
-            const e = await vscode.window.showTextDocument(doc);
-            e.selection = new vscode.Selection(range.start, range.start);
-            e.revealRange(range, vscode.TextEditorRevealType.InCenter);
-        } else {
-            const uri = editor.document.uri.toString();
-            const position = client.code2ProtocolConverter.asPosition(editor.selection.active);
-            await showReferencesImpl(client, uri, position, locations.map(loc => lc.Location.create(loc.targetUri, loc.targetRange)));
-        }
+        const doc = await vscode.workspace.openTextDocument(uri);
+        const e = await vscode.window.showTextDocument(doc);
+        e.selection = new vscode.Selection(range.start, range.start);
+        e.revealRange(range, vscode.TextEditorRevealType.InCenter);
     };
 }
 


Test patch:
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index e185b1c0a1..93d3ad020a 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -1699,7 +1699,7 @@ fn super_trait_assoc_type_bounds() {
 
 #[test]
 fn fn_trait() {
-    check_infer(
+    check_infer_with_mismatches(
         r#"
         trait FnOnce<Args> {
             type Output;
@@ -1727,7 +1727,7 @@ fn fn_trait() {
 
 #[test]
 fn fn_ptr_and_item() {
-    check_infer(
+    check_infer_with_mismatches(
         r#"
         #[lang="fn_once"]
         trait FnOnce<Args> {
@@ -1743,12 +1743,12 @@ fn fn_ptr_and_item() {
         struct Bar<T>(T);
 
         impl<A1, R, F: FnOnce(A1) -> R> Foo<(A1, R)> for Bar<F> {
-            fn foo(&self) -> (A1, R) {}
+            fn foo(&self) -> (A1, R) { loop {} }
         }
 
         enum Opt<T> { None, Some(T) }
         impl<T> Opt<T> {
-            fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Opt<U> {}
+            fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Opt<U> { loop {} }
         }
 
         fn test() {
@@ -1765,19 +1765,23 @@ fn fn_ptr_and_item() {
             80..84 'args': Args
             139..143 'self': &Self
             243..247 'self': &Bar<F>
-            260..262 '{}': ()
-            346..350 'self': Opt<T>
-            352..353 'f': F
-            368..370 '{}': ()
-            384..500 '{     ...(f); }': ()
-            394..397 'bar': Bar<fn(u8) -> u32>
-            423..426 'bar': Bar<fn(u8) -> u32>
-            423..432 'bar.foo()': (u8, u32)
-            443..446 'opt': Opt<u8>
-            465..466 'f': fn(u8) -> u32
-            487..490 'opt': Opt<u8>
-            487..497 'opt.map(f)': Opt<u32>
-            495..496 'f': fn(u8) -> u32
+            260..271 '{ loop {} }': (A1, R)
+            262..269 'loop {}': !
+            267..269 '{}': ()
+            355..359 'self': Opt<T>
+            361..362 'f': F
+            377..388 '{ loop {} }': Opt<U>
+            379..386 'loop {}': !
+            384..386 '{}': ()
+            402..518 '{     ...(f); }': ()
+            412..415 'bar': Bar<fn(u8) -> u32>
+            441..444 'bar': Bar<fn(u8) -> u32>
+            441..450 'bar.foo()': (u8, u32)
+            461..464 'opt': Opt<u8>
+            483..484 'f': fn(u8) -> u32
+            505..508 'opt': Opt<u8>
+            505..515 'opt.map(f)': Opt<u32>
+            513..514 'f': fn(u8) -> u32
         "#]],
     );
 }
@@ -1859,7 +1863,7 @@ fn fn_trait_deref_with_ty_default() {
 
 #[test]
 fn closure_1() {
-    check_infer(
+    check_infer_with_mismatches(
         r#"
         #[lang = "fn_once"]
         trait FnOnce<Args> {
@@ -1868,7 +1872,7 @@ fn closure_1() {
 
         enum Option<T> { Some(T), None }
         impl<T> Option<T> {
-            fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {}
+            fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> { loop {} }
         }
 
         fn test() {
@@ -1881,37 +1885,39 @@ fn closure_1() {
         expect![[r#"
             147..151 'self': Option<T>
             153..154 'f': F
-            172..174 '{}': ()
-            188..307 '{     ... 1); }': ()
-            198..199 'x': Option<u32>
-            202..214 'Option::Some': Some<u32>(u32) -> Option<u32>
-            202..220 'Option...(1u32)': Option<u32>
-            215..219 '1u32': u32
-            226..227 'x': Option<u32>
-            226..242 'x.map(...v + 1)': Option<u32>
-            232..241 '|v| v + 1': |u32| -> u32
-            233..234 'v': u32
-            236..237 'v': u32
-            236..241 'v + 1': u32
-            240..241 '1': u32
-            248..249 'x': Option<u32>
-            248..264 'x.map(... 1u64)': Option<u64>
-            254..263 '|_v| 1u64': |u32| -> u64
-            255..257 '_v': u32
-            259..263 '1u64': u64
-            274..275 'y': Option<i64>
-            291..292 'x': Option<u32>
-            291..304 'x.map(|_v| 1)': Option<i64>
-            297..303 '|_v| 1': |u32| -> i64
-            298..300 '_v': u32
-            302..303 '1': i64
+            172..183 '{ loop {} }': Option<U>
+            174..181 'loop {}': !
+            179..181 '{}': ()
+            197..316 '{     ... 1); }': ()
+            207..208 'x': Option<u32>
+            211..223 'Option::Some': Some<u32>(u32) -> Option<u32>
+            211..229 'Option...(1u32)': Option<u32>
+            224..228 '1u32': u32
+            235..236 'x': Option<u32>
+            235..251 'x.map(...v + 1)': Option<u32>
+            241..250 '|v| v + 1': |u32| -> u32
+            242..243 'v': u32
+            245..246 'v': u32
+            245..250 'v + 1': u32
+            249..250 '1': u32
+            257..258 'x': Option<u32>
+            257..273 'x.map(... 1u64)': Option<u64>
+            263..272 '|_v| 1u64': |u32| -> u64
+            264..266 '_v': u32
+            268..272 '1u64': u64
+            283..284 'y': Option<i64>
+            300..301 'x': Option<u32>
+            300..313 'x.map(|_v| 1)': Option<i64>
+            306..312 '|_v| 1': |u32| -> i64
+            307..309 '_v': u32
+            311..312 '1': i64
         "#]],
     );
 }
 
 #[test]
 fn closure_2() {
-    check_infer(
+    check_infer_with_mismatches(
         r#"
         trait FnOnce<Args> {
             type Output;
@@ -1951,22 +1957,22 @@ fn closure_2() {
 
 #[test]
 fn closure_as_argument_inference_order() {
-    check_infer(
+    check_infer_with_mismatches(
         r#"
         #[lang = "fn_once"]
         trait FnOnce<Args> {
             type Output;
         }
 
-        fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U {}
-        fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U {}
+        fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U { loop {} }
+        fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U { loop {} }
 
         struct S;
         impl S {
             fn method(self) -> u64;
 
-            fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U {}
-            fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U {}
+            fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U { loop {} }
+            fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U { loop {} }
         }
 
         fn test() {
@@ -1979,52 +1985,60 @@ fn closure_as_argument_inference_order() {
         expect![[r#"
             94..95 'x': T
             100..101 'f': F
-            111..113 '{}': ()
-            147..148 'f': F
-            153..154 'x': T
-            164..166 '{}': ()
-            201..205 'self': S
-            253..257 'self': S
-            259..260 'x': T
-            265..266 'f': F
-            276..278 '{}': ()
-            316..320 'self': S
-            322..323 'f': F
-            328..329 'x': T
-            339..341 '{}': ()
-            355..514 '{     ... S); }': ()
-            365..367 'x1': u64
-            370..374 'foo1': fn foo1<S, u64, |S| -> u64>(S, |S| -> u64) -> u64
-            370..393 'foo1(S...hod())': u64
-            375..376 'S': S
-            378..392 '|s| s.method()': |S| -> u64
-            379..380 's': S
-            382..383 's': S
-            382..392 's.method()': u64
-            403..405 'x2': u64
-            408..412 'foo2': fn foo2<S, u64, |S| -> u64>(|S| -> u64, S) -> u64
-            408..431 'foo2(|...(), S)': u64
-            413..427 '|s| s.method()': |S| -> u64
-            414..415 's': S
-            417..418 's': S
-            417..427 's.method()': u64
-            429..430 'S': S
-            441..443 'x3': u64
-            446..447 'S': S
-            446..471 'S.foo1...hod())': u64
-            453..454 'S': S
-            456..470 '|s| s.method()': |S| -> u64
-            457..458 's': S
-            460..461 's': S
-            460..470 's.method()': u64
-            481..483 'x4': u64
-            486..487 'S': S
-            486..511 'S.foo2...(), S)': u64
-            493..507 '|s| s.method()': |S| -> u64
-            494..495 's': S
-            497..498 's': S
-            497..507 's.method()': u64
-            509..510 'S': S
+            111..122 '{ loop {} }': U
+            113..120 'loop {}': !
+            118..120 '{}': ()
+            156..157 'f': F
+            162..163 'x': T
+            173..184 '{ loop {} }': U
+            175..182 'loop {}': !
+            180..182 '{}': ()
+            219..223 'self': S
+            271..275 'self': S
+            277..278 'x': T
+            283..284 'f': F
+            294..305 '{ loop {} }': U
+            296..303 'loop {}': !
+            301..303 '{}': ()
+            343..347 'self': S
+            349..350 'f': F
+            355..356 'x': T
+            366..377 '{ loop {} }': U
+            368..375 'loop {}': !
+            373..375 '{}': ()
+            391..550 '{     ... S); }': ()
+            401..403 'x1': u64
+            406..410 'foo1': fn foo1<S, u64, |S| -> u64>(S, |S| -> u64) -> u64
+            406..429 'foo1(S...hod())': u64
+            411..412 'S': S
+            414..428 '|s| s.method()': |S| -> u64
+            415..416 's': S
+            418..419 's': S
+            418..428 's.method()': u64
+            439..441 'x2': u64
+            444..448 'foo2': fn foo2<S, u64, |S| -> u64>(|S| -> u64, S) -> u64
+            444..467 'foo2(|...(), S)': u64
+            449..463 '|s| s.method()': |S| -> u64
+            450..451 's': S
+            453..454 's': S
+            453..463 's.method()': u64
+            465..466 'S': S
+            477..479 'x3': u64
+            482..483 'S': S
+            482..507 'S.foo1...hod())': u64
+            489..490 'S': S
+            492..506 '|s| s.method()': |S| -> u64
+            493..494 's': S
+            496..497 's': S
+            496..506 's.method()': u64
+            517..519 'x4': u64
+            522..523 'S': S
+            522..547 'S.foo2...(), S)': u64
+            529..543 '|s| s.method()': |S| -> u64
+            530..531 's': S
+            533..534 's': S
+            533..543 's.method()': u64
+            545..546 'S': S
         "#]],
     );
 }
@@ -2536,7 +2550,7 @@ fn test() {
 
 #[test]
 fn iterator_chain() {
-    check_infer(
+    check_infer_with_mismatches(
         r#"
         //- /main.rs
         #[lang = "fn_once"]
@@ -2939,7 +2953,7 @@ fn infer_closure_arg() {
 
 #[test]
 fn infer_fn_trait_arg() {
-    check_infer(
+    check_infer_with_mismatches(
         r#"
         //- /lib.rs deps:std
 
@@ -2986,7 +3000,8 @@ fn infer_fn_trait_arg() {
 
 #[test]
 fn infer_box_fn_arg() {
-    check_infer(
+    // The type mismatch is a bug
+    check_infer_with_mismatches(
         r#"
         //- /lib.rs deps:std
 
@@ -3025,7 +3040,7 @@ fn infer_box_fn_arg() {
         fn foo() {
             let s = Option::None;
             let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {});
-            f(&s)
+            f(&s);
         }
         "#,
         expect![[r#"
@@ -3037,7 +3052,7 @@ fn infer_box_fn_arg() {
             406..417 '&self.inner': &*mut T
             407..411 'self': &Box<T>
             407..417 'self.inner': *mut T
-            478..575 '{     ...(&s) }': FnOnce::Output<dyn FnOnce(&Option<i32>), (&Option<i32>,)>
+            478..576 '{     ...&s); }': ()
             488..489 's': Option<i32>
             492..504 'Option::None': Option<i32>
             514..515 'f': Box<dyn FnOnce(&Option<i32>)>
@@ -3049,6 +3064,7 @@ fn infer_box_fn_arg() {
             568..573 'f(&s)': FnOnce::Output<dyn FnOnce(&Option<i32>), (&Option<i32>,)>
             570..572 '&s': &Option<i32>
             571..572 's': Option<i32>
+            549..562: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|_| -> ()>
         "#]],
     );
 }