This mapping has 1 multi-map group: several pairings are equally correct there. The code view shows one arbitrary valid pairing, not the only one.

Code view:

A painting is a person's account of this edit as text, recorded independently of the node mapping - a rendering often has several equally defensible answers where the mapping has one. Deletions and insertions carry no position on the opposite side in a painting, so that panel draws no caret for them.

Before

1use std::fmt::Debug;
2use std::hash::Hash;
3use std::num::NonZero;
4use std::sync::Arc;
5
6use parking_lot::{Condvar, Mutex};
7use rustc_span::Span;
8
9use crate::query::plumbing::CycleError;
10use crate::query::stack::{QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra};
11use crate::ty::TyCtxt;
12
13/// Represents a span and a query key.
14#[derive(Clone, Debug)]
15pub struct QueryInfo<I> {
16 /// The span corresponding to the reason for which this query was required.
17 pub span: Span,
18 pub frame: QueryStackFrame<I>,
19}
20
21impl<'tcx> QueryInfo<QueryStackDeferred<'tcx>> {
22 pub(crate) fn lift(&self) -> QueryInfo<QueryStackFrameExtra> {
23 QueryInfo { span: self.span, frame: self.frame.lift() }
24 }
25}
26
27/// A value uniquely identifying an active query job.
28#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
29pub struct QueryJobId(pub NonZero<u64>);
30
31/// Represents an active query job.
…lines 32–70 unchanged (39 lines)
71
72#[derive(Debug)]
73pub struct QueryWaiter<'tcx> {
74 pub query: Option<QueryJobId>,
75 pub condvar: Condvar,
76 pub span: Span,
77 pub cycle: Mutex<Option<CycleError<QueryStackDeferred<'tcx>>>>,
78}
79
80#[derive(Clone, Debug)]
81pub struct QueryLatch<'tcx> {
82 /// The `Option` is `Some(..)` when the job is active, and `None` once completed.
83 pub waiters: Arc<Mutex<Option<Vec<Arc<QueryWaiter<'tcx>>>>>>,
…lines 84–90 unchanged (7 lines)
91 /// Awaits for the query job to complete.
92 pub fn wait_on(
93 &self,
94 tcx: TyCtxt<'tcx>,
95 query: Option<QueryJobId>,
96 span: Span,
97 ) -> Result<(), CycleError<QueryStackDeferred<'tcx>>> {
98 let mut waiters_guard = self.waiters.lock();
99 let Some(waiters) = &mut *waiters_guard else {
100 return Ok(()); // already complete
101 };
102
103 let waiter =
104 Arc::new(QueryWaiter { query, span, cycle: Mutex::new(None), condvar: Condvar::new() });
105
106 // We push the waiter on to the `waiters` list. It can be accessed inside
107 // the `wait` call below, by 1) the `set` method or 2) by deadlock detection.
108 // Both of these will remove it from the `waiters` list before resuming
109 // this thread.
110 waiters.push(Arc::clone(&waiter));
111
112 // Awaits the caller on this latch by blocking the current thread.
113 // If this detects a deadlock and the deadlock handler wants to resume this thread
114 // we have to be in the `wait` call. This is ensured by the deadlock handler
115 // getting the self.info lock.
116 rustc_thread_pool::mark_blocked();
117 tcx.jobserver_proxy.release_thread();
118 waiter.condvar.wait(&mut waiters_guard);
119 // Release the lock before we potentially block in `acquire_thread`
120 drop(waiters_guard);
121 tcx.jobserver_proxy.acquire_thread();
122
123 // FIXME: Get rid of this lock. We have ownership of the QueryWaiter
124 // although another thread may still have a Arc reference so we cannot
125 // use Arc::get_mut
126 let mut cycle = waiter.cycle.lock();
127 match cycle.take() {
128 None => Ok(()),
129 Some(cycle) => Err(cycle),
130 }
131 }
132
133 /// Sets the latch and resumes all waiters on it
134 fn set(&self) {
135 let mut waiters_guard = self.waiters.lock();
136 let waiters = waiters_guard.take().unwrap(); // mark the latch as complete
137 let registry = rustc_thread_pool::Registry::current();
…lines 138–153 unchanged (16 lines)

After

1use std::fmt::Debug;
2use std::hash::Hash;
3use std::num::NonZero;
4use std::sync::Arc;
5
6use parking_lot::{Condvar, Mutex};
7use rustc_span::Span;
8
9use crate::query::plumbing::CycleError;
10use crate::query::stack::QueryStackFrame;
11use crate::ty::TyCtxt;
12
13/// Represents a span and a query key.
14#[derive(Clone, Debug)]
15pub struct QueryInfo<'tcx> {
16 /// The span corresponding to the reason for which this query was required.
17 pub span: Span,
18 pub frame: QueryStackFrame<'tcx>,
19}
20
21/// A value uniquely identifying an active query job.
22#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
23pub struct QueryJobId(pub NonZero<u64>);
24
25/// Represents an active query job.
26#[derive(Clone, Debug)]
…lines 27–64 unchanged (38 lines)
65
66#[derive(Debug)]
67pub struct QueryWaiter<'tcx> {
68 pub query: Option<QueryJobId>,
69 pub condvar: Condvar,
70 pub span: Span,
71 pub cycle: Mutex<Option<CycleError<'tcx>>>,
72}
73
74#[derive(Clone, Debug)]
75pub struct QueryLatch<'tcx> {
76 /// The `Option` is `Some(..)` when the job is active, and `None` once completed.
77 pub waiters: Arc<Mutex<Option<Vec<Arc<QueryWaiter<'tcx>>>>>>,
…lines 78–84 unchanged (7 lines)
85 /// Awaits for the query job to complete.
86 pub fn wait_on(
87 &self,
88 tcx: TyCtxt<'tcx>,
89 query: Option<QueryJobId>,
90 span: Span,
91 ) -> Result<(), CycleError<'tcx>> {
92 let mut waiters_guard = self.waiters.lock();
93 let Some(waiters) = &mut *waiters_guard else {
94 return Ok(()); // already complete
95 };
96
97 let waiter =
98 Arc::new(QueryWaiter { query, span, cycle: Mutex::new(None), condvar: Condvar::new() });
99
100 // We push the waiter on to the `waiters` list. It can be accessed inside
101 // the `wait` call below, by 1) the `set` method or 2) by deadlock detection.
102 // Both of these will remove it from the `waiters` list before resuming
103 // this thread.
104 waiters.push(Arc::clone(&waiter));
105
106 // Awaits the caller on this latch by blocking the current thread.
107 // If this detects a deadlock and the deadlock handler wants to resume this thread
108 // we have to be in the `wait` call. This is ensured by the deadlock handler
109 // getting the self.info lock.
110 rustc_thread_pool::mark_blocked();
111 tcx.jobserver_proxy.release_thread();
112 waiter.condvar.wait(&mut waiters_guard);
113 // Release the lock before we potentially block in `acquire_thread`
114 drop(waiters_guard);
115 tcx.jobserver_proxy.acquire_thread();
116
117 // FIXME: Get rid of this lock. We have ownership of the QueryWaiter
118 // although another thread may still have a Arc reference so we cannot
119 // use Arc::get_mut
120 let mut cycle = waiter.cycle.lock();
121 match cycle.take() {
122 None => Ok(()),
123 Some(cycle) => Err(cycle),
124 }
125 }
126
127 /// Sets the latch and resumes all waiters on it
128 fn set(&self) {
129 let mut waiters_guard = self.waiters.lock();
130 let waiters = waiters_guard.take().unwrap(); // mark the latch as complete
131 let registry = rustc_thread_pool::Registry::current();
…lines 132–147 unchanged (16 lines)

Before

source_file
use_declaration
use "use"
scoped_identifier
scoped_identifier
identifier "std"
:: "::"
identifier "fmt"
:: "::"
identifier "Debug"
; ";"
use_declaration
use "use"
scoped_identifier
scoped_identifier
identifier "std"
:: "::"
identifier "hash"
:: "::"
identifier "Hash"
; ";"
use_declaration
use "use"
scoped_identifier
scoped_identifier
identifier "std"
:: "::"
identifier "num"
:: "::"
identifier "NonZero"
; ";"
use_declaration
use "use"
scoped_identifier
scoped_identifier
identifier "std"
:: "::"
identifier "sync"
:: "::"
identifier "Arc"
; ";"
use_declaration
use "use"
scoped_use_list
identifier "parking_lot"
:: "::"
use_list
{ "{"
identifier "Condvar"
, ","
identifier "Mutex"
} "}"
; ";"
use_declaration
use "use"
scoped_identifier
identifier "rustc_span"
:: "::"
identifier "Span"
; ";"
use_declaration
use "use"
scoped_identifier
scoped_identifier
scoped_identifier
crate "crate"
:: "::"
identifier "query"
:: "::"
identifier "plumbing"
:: "::"
identifier "CycleError"
; ";"
use_declaration
use "use"
scoped_use_list
scoped_identifier any 2:3
scoped_identifier any 2:3
crate "crate"
:: "::"
identifier "query"
:: "::"
identifier "stack"
:: "::"
use_list
{ "{"
identifier "QueryStackDeferred"
, ","
identifier "QueryStackFrame"
, ","
identifier "QueryStackFrameExtra"
} "}"
; ";"
use_declaration
use "use"
scoped_identifier
scoped_identifier
crate "crate"
:: "::"
identifier "ty"
:: "::"
identifier "TyCtxt"
; ";"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Represents a span and a query key.\n"
attribute_item
# "#"
[ "["
attribute
identifier "derive"
token_tree
( "("
identifier "Clone"
, ","
identifier "Debug"
) ")"
] "]"
struct_item
visibility_modifier
pub "pub"
struct "struct"
type_identifier "QueryInfo"
type_parameters
< "<"
type_parameter
type_identifier "I"
> ">"
field_declaration_list
{ "{"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " The span corresponding to the reason for which this query w"...
field_declaration
visibility_modifier
pub "pub"
field_identifier "span"
: ":"
type_identifier "Span"
, ","
field_declaration
visibility_modifier
pub "pub"
field_identifier "frame"
: ":"
generic_type
type_identifier "QueryStackFrame"
type_arguments
< "<"
type_identifier "I"
> ">"
, ","
} "}"
impl_item
impl "impl"
type_parameters
< "<"
lifetime_parameter
lifetime
' "'"
identifier "tcx"
> ">"
generic_type
type_identifier "QueryInfo"
type_arguments
< "<"
generic_type
type_identifier "QueryStackDeferred"
type_arguments
< "<"
lifetime
' "'"
identifier "tcx"
> ">"
> ">"
declaration_list
{ "{"
function_item
visibility_modifier
pub "pub"
( "("
crate "crate"
) ")"
fn "fn"
identifier "lift"
parameters
( "("
self_parameter
& "&"
self "self"
) ")"
-> "->"
generic_type
type_identifier "QueryInfo"
type_arguments
< "<"
type_identifier "QueryStackFrameExtra"
> ">"
block
{ "{"
struct_expression
type_identifier "QueryInfo"
field_initializer_list
{ "{"
field_initializer
field_identifier "span"
: ":"
field_expression
self "self"
. "."
field_identifier "span"
, ","
field_initializer
field_identifier "frame"
: ":"
call_expression
field_expression
field_expression
self "self"
. "."
field_identifier "frame"
. "."
field_identifier "lift"
arguments
( "("
) ")"
} "}"
} "}"
} "}"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " A value uniquely identifying an active query job.\n"
attribute_item
# "#"
[ "["
attribute
identifier "derive"
token_tree
( "("
identifier "Copy"
, ","
identifier "Clone"
, ","
identifier "Eq"
, ","
identifier "PartialEq"
, ","
identifier "Hash"
, ","
identifier "Debug"
) ")"
] "]"
struct_item
visibility_modifier
pub "pub"
struct "struct"
type_identifier "QueryJobId"
ordered_field_declaration_list
( "("
visibility_modifier
pub "pub"
generic_type
type_identifier "NonZero"
type_arguments
< "<"
primitive_type "u64"
> ">"
) ")"
; ";"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Represents an active query job.\n"
attribute_item
# "#"
[ "["
attribute
identifier "derive"
token_tree
( "("
identifier "Clone"
, ","
identifier "Debug"
) ")"
] "]"
struct_item (+75 nodes collapsed)
impl_item (+235 nodes collapsed)
attribute_item
# "#"
[ "["
attribute
identifier "derive"
token_tree
( "("
identifier "Debug"
) ")"
] "]"
struct_item
visibility_modifier
pub "pub"
struct "struct"
type_identifier "QueryWaiter"
type_parameters
< "<"
lifetime_parameter
lifetime
' "'"
identifier "tcx"
> ">"
field_declaration_list
{ "{"
field_declaration
visibility_modifier
pub "pub"
field_identifier "query"
: ":"
generic_type
type_identifier "Option"
type_arguments
< "<"
type_identifier "QueryJobId"
> ">"
, ","
field_declaration
visibility_modifier
pub "pub"
field_identifier "condvar"
: ":"
type_identifier "Condvar"
, ","
field_declaration
visibility_modifier
pub "pub"
field_identifier "span"
: ":"
type_identifier "Span"
, ","
field_declaration
visibility_modifier
pub "pub"
field_identifier "cycle"
: ":"
generic_type
type_identifier "Mutex"
type_arguments
< "<"
generic_type
type_identifier "Option"
type_arguments
< "<"
generic_type
type_identifier "CycleError"
type_arguments
< "<"
generic_type
type_identifier "QueryStackDeferred"
type_arguments
< "<"
lifetime
' "'"
identifier "tcx"
> ">"
> ">"
> ">"
> ">"
, ","
} "}"
attribute_item
# "#"
[ "["
attribute
identifier "derive"
token_tree
( "("
identifier "Clone"
, ","
identifier "Debug"
) ")"
] "]"
struct_item (+59 nodes collapsed)
impl_item
impl "impl"
type_parameters
< "<"
lifetime_parameter
lifetime
' "'"
identifier "tcx"
> ">"
generic_type
type_identifier "QueryLatch"
type_arguments
< "<"
lifetime
' "'"
identifier "tcx"
> ">"
declaration_list
{ "{"
function_item (+48 nodes collapsed)
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Awaits for the query job to complete.\n"
function_item
visibility_modifier
pub "pub"
fn "fn"
identifier "wait_on"
parameters (+34 nodes collapsed)
-> "->"
generic_type
type_identifier "Result"
type_arguments
< "<"
unit_type
( "("
) ")"
, ","
generic_type
type_identifier "CycleError"
type_arguments
< "<"
generic_type
type_identifier "QueryStackDeferred"
type_arguments
< "<"
lifetime
' "'"
identifier "tcx"
> ">"
> ">"
> ">"
block (+266 nodes collapsed)
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Sets the latch and resumes all waiters on it\n"
function_item (+102 nodes collapsed)
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Removes a single waiter from the list of waiters.\n"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " This is used to break query cycles.\n"
function_item (+85 nodes collapsed)
} "}"

After

source_file
use_declaration
use "use"
scoped_identifier
scoped_identifier
identifier "std"
:: "::"
identifier "fmt"
:: "::"
identifier "Debug"
; ";"
use_declaration
use "use"
scoped_identifier
scoped_identifier
identifier "std"
:: "::"
identifier "hash"
:: "::"
identifier "Hash"
; ";"
use_declaration
use "use"
scoped_identifier
scoped_identifier
identifier "std"
:: "::"
identifier "num"
:: "::"
identifier "NonZero"
; ";"
use_declaration
use "use"
scoped_identifier
scoped_identifier
identifier "std"
:: "::"
identifier "sync"
:: "::"
identifier "Arc"
; ";"
use_declaration
use "use"
scoped_use_list
identifier "parking_lot"
:: "::"
use_list
{ "{"
identifier "Condvar"
, ","
identifier "Mutex"
} "}"
; ";"
use_declaration
use "use"
scoped_identifier
identifier "rustc_span"
:: "::"
identifier "Span"
; ";"
use_declaration
use "use"
scoped_identifier
scoped_identifier
scoped_identifier
crate "crate"
:: "::"
identifier "query"
:: "::"
identifier "plumbing"
:: "::"
identifier "CycleError"
; ";"
use_declaration
use "use"
scoped_identifier any 2:3
scoped_identifier any 2:3
scoped_identifier any 2:3
crate "crate"
:: "::"
identifier "query"
:: "::"
identifier "stack"
:: "::"
identifier "QueryStackFrame"
; ";"
use_declaration
use "use"
scoped_identifier
scoped_identifier
crate "crate"
:: "::"
identifier "ty"
:: "::"
identifier "TyCtxt"
; ";"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Represents a span and a query key.\n"
attribute_item
# "#"
[ "["
attribute
identifier "derive"
token_tree
( "("
identifier "Clone"
, ","
identifier "Debug"
) ")"
] "]"
struct_item
visibility_modifier
pub "pub"
struct "struct"
type_identifier "QueryInfo"
type_parameters
< "<"
lifetime_parameter
lifetime
' "'"
identifier "tcx"
> ">"
field_declaration_list
{ "{"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " The span corresponding to the reason for which this query w"...
field_declaration
visibility_modifier
pub "pub"
field_identifier "span"
: ":"
type_identifier "Span"
, ","
field_declaration
visibility_modifier
pub "pub"
field_identifier "frame"
: ":"
generic_type
type_identifier "QueryStackFrame"
type_arguments
< "<"
lifetime
' "'"
identifier "tcx"
> ">"
, ","
} "}"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " A value uniquely identifying an active query job.\n"
attribute_item
# "#"
[ "["
attribute
identifier "derive"
token_tree
( "("
identifier "Copy"
, ","
identifier "Clone"
, ","
identifier "Eq"
, ","
identifier "PartialEq"
, ","
identifier "Hash"
, ","
identifier "Debug"
) ")"
] "]"
struct_item
visibility_modifier
pub "pub"
struct "struct"
type_identifier "QueryJobId"
ordered_field_declaration_list
( "("
visibility_modifier
pub "pub"
generic_type
type_identifier "NonZero"
type_arguments
< "<"
primitive_type "u64"
> ">"
) ")"
; ";"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Represents an active query job.\n"
attribute_item
# "#"
[ "["
attribute
identifier "derive"
token_tree
( "("
identifier "Clone"
, ","
identifier "Debug"
) ")"
] "]"
struct_item (+75 nodes collapsed)
impl_item (+235 nodes collapsed)
attribute_item
# "#"
[ "["
attribute
identifier "derive"
token_tree
( "("
identifier "Debug"
) ")"
] "]"
struct_item
visibility_modifier
pub "pub"
struct "struct"
type_identifier "QueryWaiter"
type_parameters
< "<"
lifetime_parameter
lifetime
' "'"
identifier "tcx"
> ">"
field_declaration_list
{ "{"
field_declaration
visibility_modifier
pub "pub"
field_identifier "query"
: ":"
generic_type
type_identifier "Option"
type_arguments
< "<"
type_identifier "QueryJobId"
> ">"
, ","
field_declaration
visibility_modifier
pub "pub"
field_identifier "condvar"
: ":"
type_identifier "Condvar"
, ","
field_declaration
visibility_modifier
pub "pub"
field_identifier "span"
: ":"
type_identifier "Span"
, ","
field_declaration
visibility_modifier
pub "pub"
field_identifier "cycle"
: ":"
generic_type
type_identifier "Mutex"
type_arguments
< "<"
generic_type
type_identifier "Option"
type_arguments
< "<"
generic_type
type_identifier "CycleError"
type_arguments
< "<"
lifetime
' "'"
identifier "tcx"
> ">"
> ">"
> ">"
, ","
} "}"
attribute_item
# "#"
[ "["
attribute
identifier "derive"
token_tree
( "("
identifier "Clone"
, ","
identifier "Debug"
) ")"
] "]"
struct_item (+59 nodes collapsed)
impl_item
impl "impl"
type_parameters
< "<"
lifetime_parameter
lifetime
' "'"
identifier "tcx"
> ">"
generic_type
type_identifier "QueryLatch"
type_arguments
< "<"
lifetime
' "'"
identifier "tcx"
> ">"
declaration_list
{ "{"
function_item (+48 nodes collapsed)
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Awaits for the query job to complete.\n"
function_item
visibility_modifier
pub "pub"
fn "fn"
identifier "wait_on"
parameters (+34 nodes collapsed)
-> "->"
generic_type
type_identifier "Result"
type_arguments
< "<"
unit_type
( "("
) ")"
, ","
generic_type
type_identifier "CycleError"
type_arguments
< "<"
lifetime
' "'"
identifier "tcx"
> ">"
> ">"
block (+266 nodes collapsed)
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Sets the latch and resumes all waiters on it\n"
function_item (+102 nodes collapsed)
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Removes a single waiter from the list of waiters.\n"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " This is used to break query cycles.\n"
function_item (+85 nodes collapsed)
} "}"