Rollup merge of #84529 - richkadel:issue-84180, r=tmandry
Improve coverage spans for chained function calls Fixes: #84180 For chained function calls separated by the `?` try operator, the function call following the try operator produced a MIR `Call` span that matched the span of the first call. The `?` try operator started a new span, so the second call got no span. It turns out the MIR `Call` terminator has a `func` `Operand` for the `Constant` representing the function name, and the function name's Span can be used to reset the starting position of the span. r? `@tmandry` cc: `@wesleywiser`
This commit is contained in:
commit
3f89ca1a32
3 changed files with 182 additions and 3 deletions
|
@ -717,11 +717,21 @@ pub(super) fn filtered_terminator_span(
|
||||||
| TerminatorKind::FalseEdge { .. }
|
| TerminatorKind::FalseEdge { .. }
|
||||||
| TerminatorKind::Goto { .. } => None,
|
| TerminatorKind::Goto { .. } => None,
|
||||||
|
|
||||||
|
// Call `func` operand can have a more specific span when part of a chain of calls
|
||||||
|
| TerminatorKind::Call { ref func, .. } => {
|
||||||
|
let mut span = terminator.source_info.span;
|
||||||
|
if let mir::Operand::Constant(box constant) = func {
|
||||||
|
if constant.span.lo() > span.lo() {
|
||||||
|
span = span.with_lo(constant.span.lo());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(function_source_span(span, body_span))
|
||||||
|
}
|
||||||
|
|
||||||
// Retain spans from all other terminators
|
// Retain spans from all other terminators
|
||||||
TerminatorKind::Resume
|
TerminatorKind::Resume
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Abort
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Call { .. }
|
|
||||||
| TerminatorKind::Yield { .. }
|
| TerminatorKind::Yield { .. }
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
| TerminatorKind::FalseUnwind { .. }
|
| TerminatorKind::FalseUnwind { .. }
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
9| | }
|
9| | }
|
||||||
10| 6|}
|
10| 6|}
|
||||||
11| |
|
11| |
|
||||||
12| 1|fn main() -> Result<(),()> {
|
12| 1|fn test1() -> Result<(),()> {
|
||||||
13| 1| let mut
|
13| 1| let mut
|
||||||
14| 1| countdown = 10
|
14| 1| countdown = 10
|
||||||
15| | ;
|
15| | ;
|
||||||
|
@ -35,4 +35,91 @@
|
||||||
34| | }
|
34| | }
|
||||||
35| 0| Ok(())
|
35| 0| Ok(())
|
||||||
36| 1|}
|
36| 1|}
|
||||||
|
37| |
|
||||||
|
38| |struct Thing1;
|
||||||
|
39| |impl Thing1 {
|
||||||
|
40| 18| fn get_thing_2(&self, return_error: bool) -> Result<Thing2,()> {
|
||||||
|
41| 18| if return_error {
|
||||||
|
42| 1| Err(())
|
||||||
|
43| | } else {
|
||||||
|
44| 17| Ok(Thing2{})
|
||||||
|
45| | }
|
||||||
|
46| 18| }
|
||||||
|
47| |}
|
||||||
|
48| |
|
||||||
|
49| |struct Thing2;
|
||||||
|
50| |impl Thing2 {
|
||||||
|
51| 17| fn call(&self, return_error: bool) -> Result<u32,()> {
|
||||||
|
52| 17| if return_error {
|
||||||
|
53| 2| Err(())
|
||||||
|
54| | } else {
|
||||||
|
55| 15| Ok(57)
|
||||||
|
56| | }
|
||||||
|
57| 17| }
|
||||||
|
58| |}
|
||||||
|
59| |
|
||||||
|
60| 1|fn test2() -> Result<(),()> {
|
||||||
|
61| 1| let thing1 = Thing1{};
|
||||||
|
62| 1| let mut
|
||||||
|
63| 1| countdown = 10
|
||||||
|
64| | ;
|
||||||
|
65| | for
|
||||||
|
66| 6| _
|
||||||
|
67| | in
|
||||||
|
68| 6| 0..10
|
||||||
|
69| | {
|
||||||
|
70| 6| countdown
|
||||||
|
71| 6| -= 1
|
||||||
|
72| 6| ;
|
||||||
|
73| 6| if
|
||||||
|
74| 6| countdown < 5
|
||||||
|
75| | {
|
||||||
|
76| 1| thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail");
|
||||||
|
^0
|
||||||
|
77| 1| thing1
|
||||||
|
78| 1| .
|
||||||
|
79| 1| get_thing_2(/*return_error=*/ false)
|
||||||
|
80| 0| ?
|
||||||
|
81| | .
|
||||||
|
82| 1| call(/*return_error=*/ true)
|
||||||
|
83| 1| .
|
||||||
|
84| 1| expect_err(
|
||||||
|
85| 1| "call should fail"
|
||||||
|
86| 1| );
|
||||||
|
87| 1| let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?;
|
||||||
|
^0 ^0 ^0
|
||||||
|
88| 0| assert_eq!(val, 57);
|
||||||
|
89| 0| let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ false)?;
|
||||||
|
90| 0| assert_eq!(val, 57);
|
||||||
|
91| | }
|
||||||
|
92| | else
|
||||||
|
93| | {
|
||||||
|
94| 5| let val = thing1.get_thing_2(/*return_error=*/ false)?.call(/*return_error=*/ false)?;
|
||||||
|
^0 ^0
|
||||||
|
95| 5| assert_eq!(val, 57);
|
||||||
|
96| 5| let val = thing1
|
||||||
|
97| 5| .get_thing_2(/*return_error=*/ false)?
|
||||||
|
^0
|
||||||
|
98| 5| .call(/*return_error=*/ false)?;
|
||||||
|
^0
|
||||||
|
99| 5| assert_eq!(val, 57);
|
||||||
|
100| 5| let val = thing1
|
||||||
|
101| 5| .get_thing_2(/*return_error=*/ false)
|
||||||
|
102| 0| ?
|
||||||
|
103| 5| .call(/*return_error=*/ false)
|
||||||
|
104| 0| ?
|
||||||
|
105| | ;
|
||||||
|
106| 5| assert_eq!(val, 57);
|
||||||
|
107| | }
|
||||||
|
108| | }
|
||||||
|
109| 0| Ok(())
|
||||||
|
110| 1|}
|
||||||
|
111| |
|
||||||
|
112| 1|fn main() -> Result<(),()> {
|
||||||
|
113| 1| test1().expect_err("test1 should fail");
|
||||||
|
114| 1| test2()
|
||||||
|
115| 1| ?
|
||||||
|
116| | ;
|
||||||
|
117| 0| Ok(())
|
||||||
|
118| 1|}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ fn call(return_error: bool) -> Result<(),()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(),()> {
|
fn test1() -> Result<(),()> {
|
||||||
let mut
|
let mut
|
||||||
countdown = 10
|
countdown = 10
|
||||||
;
|
;
|
||||||
|
@ -34,3 +34,85 @@ fn main() -> Result<(),()> {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Thing1;
|
||||||
|
impl Thing1 {
|
||||||
|
fn get_thing_2(&self, return_error: bool) -> Result<Thing2,()> {
|
||||||
|
if return_error {
|
||||||
|
Err(())
|
||||||
|
} else {
|
||||||
|
Ok(Thing2{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Thing2;
|
||||||
|
impl Thing2 {
|
||||||
|
fn call(&self, return_error: bool) -> Result<u32,()> {
|
||||||
|
if return_error {
|
||||||
|
Err(())
|
||||||
|
} else {
|
||||||
|
Ok(57)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test2() -> Result<(),()> {
|
||||||
|
let thing1 = Thing1{};
|
||||||
|
let mut
|
||||||
|
countdown = 10
|
||||||
|
;
|
||||||
|
for
|
||||||
|
_
|
||||||
|
in
|
||||||
|
0..10
|
||||||
|
{
|
||||||
|
countdown
|
||||||
|
-= 1
|
||||||
|
;
|
||||||
|
if
|
||||||
|
countdown < 5
|
||||||
|
{
|
||||||
|
thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail");
|
||||||
|
thing1
|
||||||
|
.
|
||||||
|
get_thing_2(/*return_error=*/ false)
|
||||||
|
?
|
||||||
|
.
|
||||||
|
call(/*return_error=*/ true)
|
||||||
|
.
|
||||||
|
expect_err(
|
||||||
|
"call should fail"
|
||||||
|
);
|
||||||
|
let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?;
|
||||||
|
assert_eq!(val, 57);
|
||||||
|
let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ false)?;
|
||||||
|
assert_eq!(val, 57);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
let val = thing1.get_thing_2(/*return_error=*/ false)?.call(/*return_error=*/ false)?;
|
||||||
|
assert_eq!(val, 57);
|
||||||
|
let val = thing1
|
||||||
|
.get_thing_2(/*return_error=*/ false)?
|
||||||
|
.call(/*return_error=*/ false)?;
|
||||||
|
assert_eq!(val, 57);
|
||||||
|
let val = thing1
|
||||||
|
.get_thing_2(/*return_error=*/ false)
|
||||||
|
?
|
||||||
|
.call(/*return_error=*/ false)
|
||||||
|
?
|
||||||
|
;
|
||||||
|
assert_eq!(val, 57);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(),()> {
|
||||||
|
test1().expect_err("test1 should fail");
|
||||||
|
test2()
|
||||||
|
?
|
||||||
|
;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue