From 0b20ce97f7cc1360190cb9c2b102cdee4f487de2 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 8 Feb 2020 16:02:20 -0800 Subject: [PATCH 01/14] Make `num::NonZeroX::new` an unstable `const fn` --- src/libcore/num/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index ed37b48b3e855..3ae8f0f7870c1 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -69,8 +69,9 @@ assert_eq!(size_of::>(), size_of::<", s /// Creates a non-zero if the given value is not zero. #[$stability] + #[rustc_const_unstable(feature = "const_nonzero_int_methods", issue = "53718")] #[inline] - pub fn new(n: $Int) -> Option { + pub const fn new(n: $Int) -> Option { if n != 0 { // SAFETY: we just checked that there's no `0` Some(unsafe { Self(n) }) From 0755c41ae26af20c940a80b3c1f686ab5916e655 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 8 Feb 2020 16:02:37 -0800 Subject: [PATCH 02/14] Test `NonZeroU8::new` in a const context --- src/test/ui/consts/const-nonzero.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/test/ui/consts/const-nonzero.rs b/src/test/ui/consts/const-nonzero.rs index 6db3d1b3331fa..2160bad48074d 100644 --- a/src/test/ui/consts/const-nonzero.rs +++ b/src/test/ui/consts/const-nonzero.rs @@ -1,9 +1,18 @@ -// build-pass (FIXME(62277): could be check-pass?) +// run-pass + +#![feature(const_nonzero_int_methods)] use std::num::NonZeroU8; const X: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(5) }; const Y: u8 = X.get(); +const ZERO: Option = NonZeroU8::new(0); +const ONE: Option = NonZeroU8::new(1); + fn main() { + assert_eq!(Y, 5); + + assert!(ZERO.is_none()); + assert_eq!(ONE.unwrap().get(), 1); } From fa5a3c35dcda3c82d0c10837cdcbf747e833eabd Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 9 Feb 2020 13:19:06 +0000 Subject: [PATCH 03/14] Don't parse `mut a @ b` as `mut a @ mut b` --- src/librustc_parse/parser/pat.rs | 11 ++++++---- .../nested-binding-mode-lint.rs | 13 ++++++++++++ .../nested-binding-modes-mut.rs | 13 ++++++++++++ .../nested-binding-modes-mut.stderr | 21 +++++++++++++++++++ .../nested-binding-modes-ref.rs | 13 ++++++++++++ .../nested-binding-modes-ref.stderr | 15 +++++++++++++ 6 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/pattern/bindings-after-at/nested-binding-mode-lint.rs create mode 100644 src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.rs create mode 100644 src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr create mode 100644 src/test/ui/pattern/bindings-after-at/nested-binding-modes-ref.rs create mode 100644 src/test/ui/pattern/bindings-after-at/nested-binding-modes-ref.stderr diff --git a/src/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs index e07b0733739d1..985185230f26a 100644 --- a/src/librustc_parse/parser/pat.rs +++ b/src/librustc_parse/parser/pat.rs @@ -542,11 +542,14 @@ impl<'a> Parser<'a> { } fn visit_pat(&mut self, pat: &mut P) { - if let PatKind::Ident(BindingMode::ByValue(ref mut m @ Mutability::Not), ..) = - pat.kind - { - *m = Mutability::Mut; + if let PatKind::Ident(ref mut bm, ..) = pat.kind { + if let BindingMode::ByValue(ref mut m @ Mutability::Not) = bm { + *m = Mutability::Mut; + } self.0 = true; + // Don't recurse into the subpattern, mut on the outer + // binding doesn't affect the inner bindings. + return; } noop_visit_pat(pat, self); } diff --git a/src/test/ui/pattern/bindings-after-at/nested-binding-mode-lint.rs b/src/test/ui/pattern/bindings-after-at/nested-binding-mode-lint.rs new file mode 100644 index 0000000000000..497d94a3db0d9 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/nested-binding-mode-lint.rs @@ -0,0 +1,13 @@ +// check-pass + +#![feature(bindings_after_at)] +#![deny(unused_mut)] + +fn main() { + let mut is_mut @ not_mut = 42; + &mut is_mut; + ¬_mut; + let not_mut @ mut is_mut = 42; + &mut is_mut; + ¬_mut; +} diff --git a/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.rs b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.rs new file mode 100644 index 0000000000000..54f04117f7def --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.rs @@ -0,0 +1,13 @@ +#![feature(bindings_after_at)] + +fn main() { + let mut is_mut @ not_mut = 42; + &mut is_mut; + &mut not_mut; + //~^ ERROR cannot borrow + + let not_mut @ mut is_mut = 42; + &mut is_mut; + &mut not_mut; + //~^ ERROR cannot borrow +} diff --git a/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr new file mode 100644 index 0000000000000..a8d5e4c4c69cc --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr @@ -0,0 +1,21 @@ +error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutable + --> $DIR/nested-binding-modes-mut.rs:6:5 + | +LL | let mut is_mut @ not_mut = 42; + | ------- help: consider changing this to be mutable: `mut not_mut` +LL | &mut is_mut; +LL | &mut not_mut; + | ^^^^^^^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutable + --> $DIR/nested-binding-modes-mut.rs:11:5 + | +LL | let not_mut @ mut is_mut = 42; + | -------------------- help: consider changing this to be mutable: `mut not_mut` +LL | &mut is_mut; +LL | &mut not_mut; + | ^^^^^^^^^^^^ cannot borrow as mutable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/pattern/bindings-after-at/nested-binding-modes-ref.rs b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-ref.rs new file mode 100644 index 0000000000000..d5086aec93ec3 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-ref.rs @@ -0,0 +1,13 @@ +#![feature(bindings_after_at)] + +fn main() { + let ref is_ref @ is_val = 42; + *is_ref; + *is_val; + //~^ ERROR cannot be dereferenced + + let is_val @ ref is_ref = 42; + *is_ref; + *is_val; + //~^ ERROR cannot be dereferenced +} diff --git a/src/test/ui/pattern/bindings-after-at/nested-binding-modes-ref.stderr b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-ref.stderr new file mode 100644 index 0000000000000..9cc928d214993 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-ref.stderr @@ -0,0 +1,15 @@ +error[E0614]: type `{integer}` cannot be dereferenced + --> $DIR/nested-binding-modes-ref.rs:6:5 + | +LL | *is_val; + | ^^^^^^^ + +error[E0614]: type `{integer}` cannot be dereferenced + --> $DIR/nested-binding-modes-ref.rs:11:5 + | +LL | *is_val; + | ^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0614`. From effd52078c55c4e585010f6d1a322414c4979da6 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 20 Jan 2020 18:36:54 -0800 Subject: [PATCH 04/14] Print `after` effect in default graphviz formatter Now the line for each statement will show the diff resulting from the combination of `before_statement_effect` and `statement_effect`. It's still possible to observe each in isolation via `borrowck_graphviz_format = "two_phase"`. --- src/librustc_mir/dataflow/generic/graphviz.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/dataflow/generic/graphviz.rs b/src/librustc_mir/dataflow/generic/graphviz.rs index fdf86e7b53f60..2917807482cc8 100644 --- a/src/librustc_mir/dataflow/generic/graphviz.rs +++ b/src/librustc_mir/dataflow/generic/graphviz.rs @@ -418,7 +418,7 @@ where self.prev_loc = location; write!(w, r#""#, fmt = fmt)?; - results.seek_before(location); + results.seek_after(location); let curr_state = results.get(); write_diff(&mut w, results.analysis(), &self.prev_state, curr_state)?; self.prev_state.overwrite(curr_state); @@ -445,7 +445,7 @@ where A: Analysis<'tcx>, { fn column_names(&self) -> &[&str] { - &["ENTRY", " EXIT"] + &["BEFORE", " AFTER"] } fn write_state_for_location( @@ -465,7 +465,7 @@ where self.prev_loc = location; - // Entry + // Before write!(w, r#""#, fmt = fmt)?; results.seek_before(location); @@ -474,7 +474,7 @@ where self.prev_state.overwrite(curr_state); write!(w, "")?; - // Exit + // After write!(w, r#""#, fmt = fmt)?; results.seek_after(location); From 852afa2e88db4db01d6454c3150c975f9f897420 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 21 Jan 2020 13:35:17 -0800 Subject: [PATCH 05/14] Add option to `dot::render` for monospace font --- src/libgraphviz/lib.rs | 10 ++++++++++ src/librustc_mir/dataflow/generic/engine.rs | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index d04f5c1d4ee77..a53e0012ca221 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -597,6 +597,8 @@ pub enum RenderOption { NoNodeLabels, NoEdgeStyles, NoNodeStyles, + + Monospace, } /// Returns vec holding all the default render options. @@ -626,6 +628,14 @@ where W: Write, { writeln!(w, "digraph {} {{", g.graph_id().as_slice())?; + + // Global graph properties + if options.contains(&RenderOption::Monospace) { + writeln!(w, r#" graph[fontname="monospace"];"#)?; + writeln!(w, r#" node[fontname="monospace"];"#)?; + writeln!(w, r#" edge[fontname="monospace"];"#)?; + } + for n in g.nodes().iter() { write!(w, " ")?; let id = g.node_id(n); diff --git a/src/librustc_mir/dataflow/generic/engine.rs b/src/librustc_mir/dataflow/generic/engine.rs index c0152b0c7d504..718c1e9ae2043 100644 --- a/src/librustc_mir/dataflow/generic/engine.rs +++ b/src/librustc_mir/dataflow/generic/engine.rs @@ -331,7 +331,7 @@ where let mut buf = Vec::new(); let graphviz = graphviz::Formatter::new(body, def_id, results, &mut *formatter); - dot::render(&graphviz, &mut buf)?; + dot::render_opts(&graphviz, &mut buf, &[dot::RenderOption::Monospace])?; fs::write(&path, buf)?; Ok(()) } From fb14386de355c2bf437515f20975612cda04ef70 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 21 Jan 2020 13:36:34 -0800 Subject: [PATCH 06/14] Remove unnecessary allows --- src/librustc_mir/dataflow/generic/graphviz.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/librustc_mir/dataflow/generic/graphviz.rs b/src/librustc_mir/dataflow/generic/graphviz.rs index 2917807482cc8..8bf5852f003f1 100644 --- a/src/librustc_mir/dataflow/generic/graphviz.rs +++ b/src/librustc_mir/dataflow/generic/graphviz.rs @@ -387,7 +387,6 @@ pub struct SimpleDiff { } impl SimpleDiff { - #![allow(unused)] pub fn new(bits_per_block: usize) -> Self { SimpleDiff { prev_state: BitSet::new_empty(bits_per_block), prev_loc: Location::START } } @@ -434,7 +433,6 @@ pub struct TwoPhaseDiff { } impl TwoPhaseDiff { - #![allow(unused)] pub fn new(bits_per_block: usize) -> Self { TwoPhaseDiff { prev_state: BitSet::new_empty(bits_per_block), prev_loc: Location::START } } @@ -492,7 +490,6 @@ pub struct BlockTransferFunc<'a, 'tcx, T: Idx> { } impl BlockTransferFunc<'mir, 'tcx, T> { - #![allow(unused)] pub fn new( body: &'mir mir::Body<'tcx>, trans_for_block: IndexVec>, From 83dfb422fe71979914d3db67db135e160ab29dcd Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 21 Jan 2020 13:37:02 -0800 Subject: [PATCH 07/14] Don't break first line --- src/librustc_mir/dataflow/generic/graphviz.rs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/librustc_mir/dataflow/generic/graphviz.rs b/src/librustc_mir/dataflow/generic/graphviz.rs index 8bf5852f003f1..f70564d401913 100644 --- a/src/librustc_mir/dataflow/generic/graphviz.rs +++ b/src/librustc_mir/dataflow/generic/graphviz.rs @@ -610,13 +610,6 @@ where let mut line_break_inserted = false; for idx in elems { - if first { - first = false; - } else { - write!(w, "{}", sep)?; - curr_line_width += sep_width; - } - buf.clear(); analysis.pretty_print_idx(&mut buf, idx)?; let idx_str = @@ -624,11 +617,18 @@ where let escaped = dot::escape_html(idx_str); let escaped_width = escaped.chars().count(); - if let Some(line_break) = &line_break { - if curr_line_width + sep_width + escaped_width > line_break.limit { - write!(w, "{}", line_break.sequence)?; - line_break_inserted = true; - curr_line_width = 0; + if first { + first = false; + } else { + write!(w, "{}", sep)?; + curr_line_width += sep_width; + + if let Some(line_break) = &line_break { + if curr_line_width + sep_width + escaped_width > line_break.limit { + write!(w, "{}", line_break.sequence)?; + line_break_inserted = true; + curr_line_width = 0; + } } } From 8d6208c39b5aa63c7bbda30e325fdffefc7b81b8 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 21 Jan 2020 13:37:59 -0800 Subject: [PATCH 08/14] Use nicer alignment when printing state vectors --- src/librustc_mir/dataflow/generic/graphviz.rs | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/src/librustc_mir/dataflow/generic/graphviz.rs b/src/librustc_mir/dataflow/generic/graphviz.rs index f70564d401913..b805b13592f89 100644 --- a/src/librustc_mir/dataflow/generic/graphviz.rs +++ b/src/librustc_mir/dataflow/generic/graphviz.rs @@ -171,10 +171,19 @@ where // | | (on successful return) | +_4 | // +-+----------------------------------+------------+ - write!( - w, - r#""#, - )?; + // N.B., Some attributes (`align`, `balign`) are repeated on parent elements and their + // children. This is because `xdot` seemed to have a hard time correctly propagating + // attributes. Make sure to test the output before trying to remove the redundancy. + // Notably, `align` was found to have no effect when applied only to
. + + let table_fmt = concat!( + " border=\"1\"", + " cellborder=\"1\"", + " cellspacing=\"0\"", + " cellpadding=\"3\"", + " sides=\"rb\"", + ); + write!(w, r#""#, fmt = table_fmt)?; // A + B: Block header if self.state_formatter.column_names().is_empty() { @@ -186,7 +195,7 @@ where // C: Entry state self.bg = Background::Light; self.results.seek_to_block_start(block); - self.write_row_with_full_state(w, "", "(on_entry)")?; + self.write_row_with_full_state(w, "", "(on entry)")?; // D: Statement transfer functions for (i, statement) in body[block].statements.iter().enumerate() { @@ -212,7 +221,7 @@ where self.write_row(w, "", "(on successful return)", |this, w, fmt| { write!( w, - r#"") }) } @@ -416,7 +427,7 @@ where } self.prev_loc = location; - write!(w, r#"")?; } @@ -561,25 +572,28 @@ fn write_diff>( if !set.is_empty() { write!(w, r#"+"#)?; - pretty_print_state_elems(w, analysis, set.iter(), ",", LIMIT_40_ALIGN_1)?; + pretty_print_state_elems(w, analysis, set.iter(), ", ", LIMIT_30_ALIGN_1)?; write!(w, r#""#)?; } if !set.is_empty() && !clear.is_empty() { - write!(w, "
")?; + write!(w, "{}", BR_LEFT)?; } if !clear.is_empty() { write!(w, r#"-"#)?; - pretty_print_state_elems(w, analysis, clear.iter(), ",", LIMIT_40_ALIGN_1)?; + pretty_print_state_elems(w, analysis, clear.iter(), ", ", LIMIT_30_ALIGN_1)?; write!(w, r#""#)?; } Ok(()) } +const BR_LEFT: &'static str = r#"
"#; +const BR_LEFT_SPACE: &'static str = r#"
"#; + /// Line break policy that breaks at 40 characters and starts the next line with a single space. -const LIMIT_40_ALIGN_1: Option = Some(LineBreak { sequence: "
", limit: 40 }); +const LIMIT_30_ALIGN_1: Option = Some(LineBreak { sequence: BR_LEFT_SPACE, limit: 30 }); struct LineBreak { sequence: &'static str, From cd7a428b5e5508d43deabdd1a1d3a6e776f54929 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 9 Feb 2020 17:54:38 +0300 Subject: [PATCH 09/14] parser: Keep current and previous tokens precisely including their unnormalized forms. Add more documentation for them. --- src/librustc_parse/parser/mod.rs | 74 +++++++++++++------ src/librustc_parse/parser/path.rs | 2 +- .../ui/parser/mbe_missing_right_paren.stderr | 4 +- 3 files changed, 54 insertions(+), 26 deletions(-) diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 825607a234859..7131eb1144e06 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -95,8 +95,6 @@ enum PrevTokenKind { Other, } -// NOTE: `Ident`s are handled by `common.rs`. - #[derive(Clone)] pub struct Parser<'a> { pub sess: &'a ParseSess, @@ -104,14 +102,25 @@ pub struct Parser<'a> { /// "Normalized" means that some interpolated tokens /// (`$i: ident` and `$l: lifetime` meta-variables) are replaced /// with non-interpolated identifier and lifetime tokens they refer to. - /// Perhaps the normalized / non-normalized setup can be simplified somehow. + /// Use span from this token if you need an isolated span. pub token: Token, - /// The span of the current non-normalized token. - meta_var_span: Option, - /// The span of the previous non-normalized token. - pub prev_span: Span, - /// The kind of the previous normalized token (in simplified form). + /// The current non-normalized token if it's different from `token`. + /// Preferable use is through the `unnormalized_token()` getter. + /// Use span from this token if you need to concatenate it with some neighbouring spans. + unnormalized_token: Option, + /// The previous normalized token. + /// Use span from this token if you need an isolated span. + prev_token: Token, + /// The previous non-normalized token if it's different from `prev_token`. + /// Preferable use is through the `unnormalized_prev_token()` getter. + /// Use span from this token if you need to concatenate it with some neighbouring spans. + unnormalized_prev_token: Option, + /// Equivalent to `prev_token.kind` in simplified form. + /// FIXME: Remove in favor of `(unnormalized_)prev_token().kind`. prev_token_kind: PrevTokenKind, + /// Equivalent to `unnormalized_prev_token().span`. + /// FIXME: Remove in favor of `(unnormalized_)prev_token().span`. + pub prev_span: Span, restrictions: Restrictions, /// Used to determine the path to externally loaded source files. pub(super) directory: Directory<'a>, @@ -384,9 +393,11 @@ impl<'a> Parser<'a> { let mut parser = Parser { sess, token: Token::dummy(), - prev_span: DUMMY_SP, - meta_var_span: None, + unnormalized_token: None, + prev_token: Token::dummy(), + unnormalized_prev_token: None, prev_token_kind: PrevTokenKind::Other, + prev_span: DUMMY_SP, restrictions: Restrictions::empty(), recurse_into_file_modules, directory: Directory { @@ -427,6 +438,14 @@ impl<'a> Parser<'a> { parser } + fn unnormalized_token(&self) -> &Token { + self.unnormalized_token.as_ref().unwrap_or(&self.token) + } + + fn unnormalized_prev_token(&self) -> &Token { + self.unnormalized_prev_token.as_ref().unwrap_or(&self.prev_token) + } + fn next_tok(&mut self) -> Token { let mut next = if self.desugar_doc_comments { self.token_cursor.next_desugared() @@ -435,7 +454,7 @@ impl<'a> Parser<'a> { }; if next.span.is_dummy() { // Tweak the location for better diagnostics, but keep syntactic context intact. - next.span = self.prev_span.with_ctxt(next.span.ctxt()); + next.span = self.unnormalized_token().span.with_ctxt(next.span.ctxt()); } next } @@ -895,10 +914,13 @@ impl<'a> Parser<'a> { self.span_bug(self.token.span, msg); } - self.prev_span = self.meta_var_span.take().unwrap_or(self.token.span); + // Update the current and previous tokens. + let next_token = self.next_tok(); + self.prev_token = mem::replace(&mut self.token, next_token); + self.unnormalized_prev_token = self.unnormalized_token.take(); - // Record last token kind for possible error recovery. - self.prev_token_kind = match self.token.kind { + // Update fields derived from the previous token. + self.prev_token_kind = match self.prev_token.kind { token::DocComment(..) => PrevTokenKind::DocComment, token::Comma => PrevTokenKind::Comma, token::BinOp(token::Plus) => PrevTokenKind::Plus, @@ -908,8 +930,8 @@ impl<'a> Parser<'a> { token::Ident(..) => PrevTokenKind::Ident, _ => PrevTokenKind::Other, }; + self.prev_span = self.unnormalized_prev_token().span; - self.token = self.next_tok(); self.expected_tokens.clear(); // Check after each token. self.process_potential_macro_variable(); @@ -917,13 +939,19 @@ impl<'a> Parser<'a> { /// Advances the parser using provided token as a next one. Use this when /// consuming a part of a token. For example a single `<` from `<<`. + /// FIXME: this function sets the previous token data to some semi-nonsensical values + /// which kind of work because they are currently used in very limited ways in practice. + /// Correct token kinds and spans need to be calculated instead. fn bump_with(&mut self, next: TokenKind, span: Span) { - self.prev_span = self.token.span.with_hi(span.lo()); - // It would be incorrect to record the kind of the current token, but - // fortunately for tokens currently using `bump_with`, the - // `prev_token_kind` will be of no use anyway. + // Update the current and previous tokens. + let next_token = Token::new(next, span); + self.prev_token = mem::replace(&mut self.token, next_token); + self.unnormalized_prev_token = self.unnormalized_token.take(); + + // Update fields derived from the previous token. self.prev_token_kind = PrevTokenKind::Other; - self.token = Token::new(next, span); + self.prev_span = self.unnormalized_prev_token().span.with_hi(span.lo()); + self.expected_tokens.clear(); } @@ -1054,7 +1082,7 @@ impl<'a> Parser<'a> { } pub fn process_potential_macro_variable(&mut self) { - self.token = match self.token.kind { + let normalized_token = match self.token.kind { token::Dollar if self.token.span.from_expansion() && self.look_ahead(1, |t| t.is_ident()) => { @@ -1071,7 +1099,6 @@ impl<'a> Parser<'a> { return; } token::Interpolated(ref nt) => { - self.meta_var_span = Some(self.token.span); // Interpolated identifier and lifetime tokens are replaced with usual identifier // and lifetime tokens, so the former are never encountered during normal parsing. match **nt { @@ -1084,6 +1111,7 @@ impl<'a> Parser<'a> { } _ => return, }; + self.unnormalized_token = Some(mem::replace(&mut self.token, normalized_token)); } /// Parses a single token tree from the input. @@ -1100,7 +1128,7 @@ impl<'a> Parser<'a> { } token::CloseDelim(_) | token::Eof => unreachable!(), _ => { - let token = self.token.take(); + let token = self.token.clone(); self.bump(); TokenTree::Token(token) } diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index cb14ffb4bd028..761c06b70ee8b 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -134,7 +134,7 @@ impl<'a> Parser<'a> { path }); - let lo = self.meta_var_span.unwrap_or(self.token.span); + let lo = self.unnormalized_token().span; let mut segments = Vec::new(); let mod_sep_ctxt = self.token.span.ctxt(); if self.eat(&token::ModSep) { diff --git a/src/test/ui/parser/mbe_missing_right_paren.stderr b/src/test/ui/parser/mbe_missing_right_paren.stderr index 4ce39de886649..ec04b937b9ace 100644 --- a/src/test/ui/parser/mbe_missing_right_paren.stderr +++ b/src/test/ui/parser/mbe_missing_right_paren.stderr @@ -22,10 +22,10 @@ LL | macro_rules! abc(ؼ; | ^ error: unexpected end of macro invocation - --> $DIR/mbe_missing_right_paren.rs:3:1 + --> $DIR/mbe_missing_right_paren.rs:3:19 | LL | macro_rules! abc(ؼ - | ^^^^^^^^^^^^^^^^^^ missing tokens in macro arguments + | ^ missing tokens in macro arguments error: aborting due to 3 previous errors From 7426853ba255940b880f2e7f8026d60b94b42404 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 31 Jan 2020 08:45:57 +1100 Subject: [PATCH 10/14] Reduce the number of `RefCell`s in `InferCtxt`. `InferCtxt` contains six structures within `RefCell`s. Every time we create and dispose of (commit or rollback) a snapshot we have to `borrow_mut` each one of them. This commit moves the six structures under a single `RefCell`, which gives significant speed-ups by reducing the number of `borrow_mut` calls. To avoid runtime errors I had to reduce the lifetimes of dynamic borrows in a couple of places. --- src/librustc/infer/canonical/canonicalizer.rs | 6 +- src/librustc/infer/combine.rs | 50 +-- src/librustc/infer/equate.rs | 13 +- .../infer/error_reporting/need_type_info.rs | 13 +- src/librustc/infer/freshen.rs | 18 +- src/librustc/infer/fudge.rs | 32 +- src/librustc/infer/glb.rs | 7 +- src/librustc/infer/higher_ranked/mod.rs | 2 +- src/librustc/infer/lattice.rs | 4 +- src/librustc/infer/lub.rs | 7 +- src/librustc/infer/mod.rs | 336 ++++++++++-------- src/librustc/infer/nll_relate/mod.rs | 10 +- src/librustc/infer/outlives/obligations.rs | 4 +- src/librustc/infer/resolve.rs | 11 +- src/librustc/infer/sub.rs | 13 +- src/librustc/infer/unify_key.rs | 3 +- src/librustc/traits/auto_trait.rs | 16 +- src/librustc/traits/project.rs | 12 +- src/librustc/traits/select.rs | 2 +- .../chalk_context/resolvent_ops.rs | 4 +- 20 files changed, 321 insertions(+), 242 deletions(-) diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index 48a6c6d7413d1..85fafa349151e 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -317,7 +317,9 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { let r = self .infcx .unwrap() - .borrow_region_constraints() + .inner + .borrow_mut() + .unwrap_region_constraints() .opportunistic_resolve_var(self.tcx, vid); debug!( "canonical: region var found with vid {:?}, \ @@ -621,7 +623,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { /// Returns the universe in which `vid` is defined. fn region_var_universe(&self, vid: ty::RegionVid) -> ty::UniverseIndex { - self.infcx.unwrap().borrow_region_constraints().var_universe(vid) + self.infcx.unwrap().inner.borrow_mut().unwrap_region_constraints().var_universe(vid) } /// Creates a canonical variable (with the given `info`) diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 2518805a1ecfc..9eb961255c295 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -74,8 +74,9 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { match (&a.kind, &b.kind) { // Relate integral variables to other types (&ty::Infer(ty::IntVar(a_id)), &ty::Infer(ty::IntVar(b_id))) => { - self.int_unification_table + self.inner .borrow_mut() + .int_unification_table .unify_var_var(a_id, b_id) .map_err(|e| int_unification_error(a_is_expected, e))?; Ok(a) @@ -95,8 +96,9 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { // Relate floating-point variables to other types (&ty::Infer(ty::FloatVar(a_id)), &ty::Infer(ty::FloatVar(b_id))) => { - self.float_unification_table + self.inner .borrow_mut() + .float_unification_table .unify_var_var(a_id, b_id) .map_err(|e| float_unification_error(relation.a_is_expected(), e))?; Ok(a) @@ -131,8 +133,8 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { return Ok(a); } - let a = replace_if_possible(self.const_unification_table.borrow_mut(), a); - let b = replace_if_possible(self.const_unification_table.borrow_mut(), b); + let a = replace_if_possible(&mut self.inner.borrow_mut().const_unification_table, a); + let b = replace_if_possible(&mut self.inner.borrow_mut().const_unification_table, b); let a_is_expected = relation.a_is_expected(); @@ -141,8 +143,9 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { ty::ConstKind::Infer(InferConst::Var(a_vid)), ty::ConstKind::Infer(InferConst::Var(b_vid)), ) => { - self.const_unification_table + self.inner .borrow_mut() + .const_unification_table .unify_var_var(a_vid, b_vid) .map_err(|e| const_unification_error(a_is_expected, e))?; return Ok(a); @@ -174,8 +177,9 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { vid: ty::ConstVid<'tcx>, value: &'tcx ty::Const<'tcx>, ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - self.const_unification_table + self.inner .borrow_mut() + .const_unification_table .unify_var_value( vid, ConstVarValue { @@ -196,8 +200,9 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { vid: ty::IntVid, val: ty::IntVarValue, ) -> RelateResult<'tcx, Ty<'tcx>> { - self.int_unification_table + self.inner .borrow_mut() + .int_unification_table .unify_var_value(vid, Some(val)) .map_err(|e| int_unification_error(vid_is_expected, e))?; match val { @@ -212,8 +217,9 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { vid: ty::FloatVid, val: ast::FloatTy, ) -> RelateResult<'tcx, Ty<'tcx>> { - self.float_unification_table + self.inner .borrow_mut() + .float_unification_table .unify_var_value(vid, Some(ty::FloatVarValue(val))) .map_err(|e| float_unification_error(vid_is_expected, e))?; Ok(self.tcx.mk_mach_float(val)) @@ -260,7 +266,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { use self::RelationDir::*; // Get the actual variable that b_vid has been inferred to - debug_assert!(self.infcx.type_variables.borrow_mut().probe(b_vid).is_unknown()); + debug_assert!(self.infcx.inner.borrow_mut().type_variables.probe(b_vid).is_unknown()); debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", a_ty, dir, b_vid); @@ -280,7 +286,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { "instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})", a_ty, dir, b_vid, b_ty ); - self.infcx.type_variables.borrow_mut().instantiate(b_vid, b_ty); + self.infcx.inner.borrow_mut().type_variables.instantiate(b_vid, b_ty); if needs_wf { self.obligations.push(Obligation::new( @@ -338,7 +344,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { debug!("generalize: ambient_variance = {:?}", ambient_variance); - let for_universe = match self.infcx.type_variables.borrow_mut().probe(for_vid) { + let for_universe = match self.infcx.inner.borrow_mut().type_variables.probe(for_vid) { v @ TypeVariableValue::Known { .. } => { panic!("instantiating {:?} which has a known value {:?}", for_vid, v,) } @@ -350,7 +356,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { let mut generalize = Generalizer { infcx: self.infcx, span: self.trace.cause.span, - for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid), + for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables.sub_root_var(for_vid), for_universe, ambient_variance, needs_wf: false, @@ -502,17 +508,16 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { // us from creating infinitely sized types. match t.kind { ty::Infer(ty::TyVar(vid)) => { - let mut variables = self.infcx.type_variables.borrow_mut(); - let vid = variables.root_var(vid); - let sub_vid = variables.sub_root_var(vid); + let vid = self.infcx.inner.borrow_mut().type_variables.root_var(vid); + let sub_vid = self.infcx.inner.borrow_mut().type_variables.sub_root_var(vid); if sub_vid == self.for_vid_sub_root { // If sub-roots are equal, then `for_vid` and // `vid` are related via subtyping. Err(TypeError::CyclicTy(self.root_ty)) } else { - match variables.probe(vid) { + let probe = self.infcx.inner.borrow_mut().type_variables.probe(vid); + match probe { TypeVariableValue::Known { value: u } => { - drop(variables); debug!("generalize: known value {:?}", u); self.relate(&u, &u) } @@ -536,8 +541,13 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { ty::Covariant | ty::Contravariant => (), } - let origin = *variables.var_origin(vid); - let new_var_id = variables.new_var(self.for_universe, false, origin); + let origin = + *self.infcx.inner.borrow_mut().type_variables.var_origin(vid); + let new_var_id = self.infcx.inner.borrow_mut().type_variables.new_var( + self.for_universe, + false, + origin, + ); let u = self.tcx().mk_ty_var(new_var_id); debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); Ok(u) @@ -612,7 +622,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { match c.val { ty::ConstKind::Infer(InferConst::Var(vid)) => { - let mut variable_table = self.infcx.const_unification_table.borrow_mut(); + let variable_table = &mut self.infcx.inner.borrow_mut().const_unification_table; let var_value = variable_table.probe_value(vid); match var_value.val { ConstVariableValue::Known { value: u } => self.relate(&u, &u), diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index f192295c1aa07..018bbe035431e 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -72,14 +72,14 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> { } let infcx = self.fields.infcx; - let a = infcx.type_variables.borrow_mut().replace_if_possible(a); - let b = infcx.type_variables.borrow_mut().replace_if_possible(b); + let a = infcx.inner.borrow_mut().type_variables.replace_if_possible(a); + let b = infcx.inner.borrow_mut().type_variables.replace_if_possible(b); debug!("{}.tys: replacements ({:?}, {:?})", self.tag(), a, b); match (&a.kind, &b.kind) { (&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => { - infcx.type_variables.borrow_mut().equate(a_id, b_id); + infcx.inner.borrow_mut().type_variables.equate(a_id, b_id); } (&ty::Infer(TyVar(a_id)), _) => { @@ -105,7 +105,12 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> { ) -> RelateResult<'tcx, ty::Region<'tcx>> { debug!("{}.regions({:?}, {:?})", self.tag(), a, b); let origin = Subtype(box self.fields.trace.clone()); - self.fields.infcx.borrow_region_constraints().make_eqregion(origin, a, b); + self.fields + .infcx + .inner + .borrow_mut() + .unwrap_region_constraints() + .make_eqregion(origin, a, b); Ok(a) } diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 9947dea234096..0d7fce7eac6c5 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -47,9 +47,12 @@ impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> { if ty.walk().any(|inner_ty| { inner_ty == self.target_ty || match (&inner_ty.kind, &self.target_ty.kind) { - (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => { - self.infcx.type_variables.borrow_mut().sub_unified(a_vid, b_vid) - } + (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => self + .infcx + .inner + .borrow_mut() + .type_variables + .sub_unified(a_vid, b_vid), _ => false, } }) { @@ -166,7 +169,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { highlight: Option, ) -> (String, Option, Cow<'static, str>, Option, Option<&'static str>) { if let ty::Infer(ty::TyVar(ty_vid)) = ty.kind { - let ty_vars = self.type_variables.borrow(); + let ty_vars = &self.inner.borrow().type_variables; let var_origin = ty_vars.var_origin(ty_vid); if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind { let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id)); @@ -224,7 +227,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let ty_to_string = |ty: Ty<'tcx>| -> String { let mut s = String::new(); let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); - let ty_vars = self.type_variables.borrow(); + let ty_vars = &self.inner.borrow().type_variables; let getter = move |ty_vid| { let var_origin = ty_vars.var_origin(ty_vid); if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind { diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index cf61cac0ac4bb..0190989267bb4 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -154,14 +154,15 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { match t.kind { ty::Infer(ty::TyVar(v)) => { - let opt_ty = self.infcx.type_variables.borrow_mut().probe(v).known(); + let opt_ty = self.infcx.inner.borrow_mut().type_variables.probe(v).known(); self.freshen_ty(opt_ty, ty::TyVar(v), ty::FreshTy) } ty::Infer(ty::IntVar(v)) => self.freshen_ty( self.infcx - .int_unification_table + .inner .borrow_mut() + .int_unification_table .probe_value(v) .map(|v| v.to_type(tcx)), ty::IntVar(v), @@ -170,8 +171,9 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { ty::Infer(ty::FloatVar(v)) => self.freshen_ty( self.infcx - .float_unification_table + .inner .borrow_mut() + .float_unification_table .probe_value(v) .map(|v| v.to_type(tcx)), ty::FloatVar(v), @@ -225,8 +227,14 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { match ct.val { ty::ConstKind::Infer(ty::InferConst::Var(v)) => { - let opt_ct = - self.infcx.const_unification_table.borrow_mut().probe_value(v).val.known(); + let opt_ct = self + .infcx + .inner + .borrow_mut() + .const_unification_table + .probe_value(v) + .val + .known(); return self.freshen_const( opt_ct, ty::InferConst::Var(v), diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index 265e45635cf53..d0b7bb32b9815 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -8,11 +8,10 @@ use super::{ConstVariableOrigin, RegionVariableOrigin}; use rustc_data_structures::unify as ut; use ut::UnifyKey; -use std::cell::RefMut; use std::ops::Range; fn const_vars_since_snapshot<'tcx>( - mut table: RefMut<'_, ut::UnificationTable>>>, + table: &mut ut::UnificationTable>>, snapshot: &ut::Snapshot>>, ) -> (Range>, Vec) { let range = table.vars_since_snapshot(snapshot); @@ -82,23 +81,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // going to be popped, so we will have to // eliminate any references to them. - let type_vars = self - .type_variables - .borrow_mut() - .vars_since_snapshot(&snapshot.type_snapshot); - let int_vars = self - .int_unification_table - .borrow_mut() - .vars_since_snapshot(&snapshot.int_snapshot); - let float_vars = self - .float_unification_table - .borrow_mut() - .vars_since_snapshot(&snapshot.float_snapshot); - let region_vars = self - .borrow_region_constraints() + let mut inner = self.inner.borrow_mut(); + let type_vars = + inner.type_variables.vars_since_snapshot(&snapshot.type_snapshot); + let int_vars = + inner.int_unification_table.vars_since_snapshot(&snapshot.int_snapshot); + let float_vars = + inner.float_unification_table.vars_since_snapshot(&snapshot.float_snapshot); + let region_vars = inner + .unwrap_region_constraints() .vars_since_snapshot(&snapshot.region_constraints_snapshot); let const_vars = const_vars_since_snapshot( - self.const_unification_table.borrow_mut(), + &mut inner.const_unification_table, &snapshot.const_snapshot, ); @@ -166,7 +160,9 @@ impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> { // variables to their binding anyhow, we know // that it is unbound, so we can just return // it. - debug_assert!(self.infcx.type_variables.borrow_mut().probe(vid).is_unknown()); + debug_assert!( + self.infcx.inner.borrow_mut().type_variables.probe(vid).is_unknown() + ); ty } } diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index 293dc80d983a9..6ef92132bc703 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -66,7 +66,12 @@ impl TypeRelation<'tcx> for Glb<'combine, 'infcx, 'tcx> { debug!("{}.regions({:?}, {:?})", self.tag(), a, b); let origin = Subtype(box self.fields.trace.clone()); - Ok(self.fields.infcx.borrow_region_constraints().glb_regions(self.tcx(), origin, a, b)) + Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions( + self.tcx(), + origin, + a, + b, + )) } fn consts( diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index d25d186f4d74e..1b0f399ca3392 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -138,7 +138,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { return Ok(()); } - self.borrow_region_constraints().leak_check( + self.inner.borrow_mut().unwrap_region_constraints().leak_check( self.tcx, overly_polymorphic, placeholder_map, diff --git a/src/librustc/infer/lattice.rs b/src/librustc/infer/lattice.rs index 3e0aa4727ae1a..df475af1151aa 100644 --- a/src/librustc/infer/lattice.rs +++ b/src/librustc/infer/lattice.rs @@ -56,8 +56,8 @@ where } let infcx = this.infcx(); - let a = infcx.type_variables.borrow_mut().replace_if_possible(a); - let b = infcx.type_variables.borrow_mut().replace_if_possible(b); + let a = infcx.inner.borrow_mut().type_variables.replace_if_possible(a); + let b = infcx.inner.borrow_mut().type_variables.replace_if_possible(b); match (&a.kind, &b.kind) { // If one side is known to be a variable and one is not, // create a variable (`v`) to represent the LUB. Make sure to diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index b512d3df3e8df..6a699f803c7b8 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -66,7 +66,12 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> { debug!("{}.regions({:?}, {:?})", self.tag(), a, b); let origin = Subtype(box self.fields.trace.clone()); - Ok(self.fields.infcx.borrow_region_constraints().lub_regions(self.tcx(), origin, a, b)) + Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions( + self.tcx(), + origin, + a, + b, + )) } fn consts( diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index b93f4408cdc46..be58de996a5de 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -29,7 +29,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_span::symbol::Symbol; use rustc_span::Span; -use std::cell::{Cell, Ref, RefCell, RefMut}; +use std::cell::{Cell, Ref, RefCell}; use std::collections::BTreeMap; use std::fmt; use syntax::ast; @@ -105,6 +105,89 @@ impl SuppressRegionErrors { } } +/// This type contains all the things within `InferCtxt` that sit within a +/// `RefCell` and are involved with taking/rolling back snapshots. Snapshot +/// operations are hot enough that we want only one call to `borrow_mut` per +/// call to `start_snapshot` and `rollback_to`. +pub struct InferCtxtInner<'tcx> { + /// Cache for projections. This cache is snapshotted along with the infcx. + /// + /// Public so that `traits::project` can use it. + pub projection_cache: traits::ProjectionCache<'tcx>, + + /// We instantiate `UnificationTable` with `bounds` because the types + /// that might instantiate a general type variable have an order, + /// represented by its upper and lower bounds. + type_variables: type_variable::TypeVariableTable<'tcx>, + + /// Map from const parameter variable to the kind of const it represents. + const_unification_table: ut::UnificationTable>>, + + /// Map from integral variable to the kind of integer it represents. + int_unification_table: ut::UnificationTable>, + + /// Map from floating variable to the kind of float it represents. + float_unification_table: ut::UnificationTable>, + + /// Tracks the set of region variables and the constraints between them. + /// This is initially `Some(_)` but when + /// `resolve_regions_and_report_errors` is invoked, this gets set to `None` + /// -- further attempts to perform unification, etc., may fail if new + /// region constraints would've been added. + region_constraints: Option>, + + /// A set of constraints that regionck must validate. Each + /// constraint has the form `T:'a`, meaning "some type `T` must + /// outlive the lifetime 'a". These constraints derive from + /// instantiated type parameters. So if you had a struct defined + /// like + /// + /// struct Foo { ... } + /// + /// then in some expression `let x = Foo { ... }` it will + /// instantiate the type parameter `T` with a fresh type `$0`. At + /// the same time, it will record a region obligation of + /// `$0:'static`. This will get checked later by regionck. (We + /// can't generally check these things right away because we have + /// to wait until types are resolved.) + /// + /// These are stored in a map keyed to the id of the innermost + /// enclosing fn body / static initializer expression. This is + /// because the location where the obligation was incurred can be + /// relevant with respect to which sublifetime assumptions are in + /// place. The reason that we store under the fn-id, and not + /// something more fine-grained, is so that it is easier for + /// regionck to be sure that it has found *all* the region + /// obligations (otherwise, it's easy to fail to walk to a + /// particular node-id). + /// + /// Before running `resolve_regions_and_report_errors`, the creator + /// of the inference context is expected to invoke + /// `process_region_obligations` (defined in `self::region_obligations`) + /// for each body-id in this map, which will process the + /// obligations within. This is expected to be done 'late enough' + /// that all type inference variables have been bound and so forth. + pub region_obligations: Vec<(hir::HirId, RegionObligation<'tcx>)>, +} + +impl<'tcx> InferCtxtInner<'tcx> { + fn new() -> InferCtxtInner<'tcx> { + InferCtxtInner { + projection_cache: Default::default(), + type_variables: type_variable::TypeVariableTable::new(), + const_unification_table: ut::UnificationTable::new(), + int_unification_table: ut::UnificationTable::new(), + float_unification_table: ut::UnificationTable::new(), + region_constraints: Some(RegionConstraintCollector::new()), + region_obligations: vec![], + } + } + + pub fn unwrap_region_constraints(&mut self) -> &mut RegionConstraintCollector<'tcx> { + self.region_constraints.as_mut().expect("region constraints already solved") + } +} + pub struct InferCtxt<'a, 'tcx> { pub tcx: TyCtxt<'tcx>, @@ -114,16 +197,7 @@ pub struct InferCtxt<'a, 'tcx> { /// and for error reporting logic to read arbitrary node types. pub in_progress_tables: Option<&'a RefCell>>, - /// Cache for projections. This cache is snapshotted along with the - /// infcx. - /// - /// Public so that `traits::project` can use it. - pub projection_cache: RefCell>, - - /// We instantiate `UnificationTable` with `bounds` because the - /// types that might instantiate a general type variable have an - /// order, represented by its upper and lower bounds. - pub type_variables: RefCell>, + pub inner: RefCell>, /// If set, this flag causes us to skip the 'leak check' during /// higher-ranked subtyping operations. This flag is a temporary one used @@ -132,22 +206,6 @@ pub struct InferCtxt<'a, 'tcx> { /// when entering a snapshot. skip_leak_check: Cell, - /// Map from const parameter variable to the kind of const it represents. - const_unification_table: RefCell>>>, - - /// Map from integral variable to the kind of integer it represents. - int_unification_table: RefCell>>, - - /// Map from floating variable to the kind of float it represents - float_unification_table: RefCell>>, - - /// Tracks the set of region variables and the constraints between - /// them. This is initially `Some(_)` but when - /// `resolve_regions_and_report_errors` is invoked, this gets set - /// to `None` -- further attempts to perform unification etc may - /// fail if new region constraints would've been added. - region_constraints: RefCell>>, - /// Once region inference is done, the values for each variable. lexical_region_resolutions: RefCell>>, @@ -189,39 +247,6 @@ pub struct InferCtxt<'a, 'tcx> { /// This flag is true while there is an active snapshot. in_snapshot: Cell, - /// A set of constraints that regionck must validate. Each - /// constraint has the form `T:'a`, meaning "some type `T` must - /// outlive the lifetime 'a". These constraints derive from - /// instantiated type parameters. So if you had a struct defined - /// like - /// - /// struct Foo { ... } - /// - /// then in some expression `let x = Foo { ... }` it will - /// instantiate the type parameter `T` with a fresh type `$0`. At - /// the same time, it will record a region obligation of - /// `$0:'static`. This will get checked later by regionck. (We - /// can't generally check these things right away because we have - /// to wait until types are resolved.) - /// - /// These are stored in a map keyed to the id of the innermost - /// enclosing fn body / static initializer expression. This is - /// because the location where the obligation was incurred can be - /// relevant with respect to which sublifetime assumptions are in - /// place. The reason that we store under the fn-id, and not - /// something more fine-grained, is so that it is easier for - /// regionck to be sure that it has found *all* the region - /// obligations (otherwise, it's easy to fail to walk to a - /// particular node-id). - /// - /// Before running `resolve_regions_and_report_errors`, the creator - /// of the inference context is expected to invoke - /// `process_region_obligations` (defined in `self::region_obligations`) - /// for each body-id in this map, which will process the - /// obligations within. This is expected to be done 'late enough' - /// that all type inference variables have been bound and so forth. - pub region_obligations: RefCell)>>, - /// What is the innermost universe we have created? Starts out as /// `UniverseIndex::root()` but grows from there as we enter /// universal quantifiers. @@ -543,12 +568,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { f(InferCtxt { tcx, in_progress_tables, - projection_cache: Default::default(), - type_variables: RefCell::new(type_variable::TypeVariableTable::new()), - const_unification_table: RefCell::new(ut::UnificationTable::new()), - int_unification_table: RefCell::new(ut::UnificationTable::new()), - float_unification_table: RefCell::new(ut::UnificationTable::new()), - region_constraints: RefCell::new(Some(RegionConstraintCollector::new())), + inner: RefCell::new(InferCtxtInner::new()), lexical_region_resolutions: RefCell::new(None), selection_cache: Default::default(), evaluation_cache: Default::default(), @@ -558,7 +578,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> { err_count_on_creation: tcx.sess.err_count(), in_snapshot: Cell::new(false), skip_leak_check: Cell::new(false), - region_obligations: RefCell::new(vec![]), universe: Cell::new(ty::UniverseIndex::ROOT), }) }) @@ -616,7 +635,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> bool { match ty.kind { - ty::Infer(ty::TyVar(vid)) => self.type_variables.borrow().var_diverges(vid), + ty::Infer(ty::TyVar(vid)) => self.inner.borrow().type_variables.var_diverges(vid), _ => false, } } @@ -630,14 +649,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { use crate::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt}; match ty.kind { ty::Infer(ty::IntVar(vid)) => { - if self.int_unification_table.borrow_mut().probe_value(vid).is_some() { + if self.inner.borrow_mut().int_unification_table.probe_value(vid).is_some() { Neither } else { UnconstrainedInt } } ty::Infer(ty::FloatVar(vid)) => { - if self.float_unification_table.borrow_mut().probe_value(vid).is_some() { + if self.inner.borrow_mut().float_unification_table.probe_value(vid).is_some() { Neither } else { UnconstrainedFloat @@ -648,28 +667,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn unsolved_variables(&self) -> Vec> { - let mut type_variables = self.type_variables.borrow_mut(); - let mut int_unification_table = self.int_unification_table.borrow_mut(); - let mut float_unification_table = self.float_unification_table.borrow_mut(); + let mut inner = self.inner.borrow_mut(); // FIXME(const_generics): should there be an equivalent function for const variables? - type_variables + let mut vars: Vec> = inner + .type_variables .unsolved_variables() .into_iter() .map(|t| self.tcx.mk_ty_var(t)) - .chain( - (0..int_unification_table.len()) - .map(|i| ty::IntVid { index: i as u32 }) - .filter(|&vid| int_unification_table.probe_value(vid).is_none()) - .map(|v| self.tcx.mk_int_var(v)), - ) - .chain( - (0..float_unification_table.len()) - .map(|i| ty::FloatVid { index: i as u32 }) - .filter(|&vid| float_unification_table.probe_value(vid).is_none()) - .map(|v| self.tcx.mk_float_var(v)), - ) - .collect() + .collect(); + vars.extend( + (0..inner.int_unification_table.len()) + .map(|i| ty::IntVid { index: i as u32 }) + .filter(|&vid| inner.int_unification_table.probe_value(vid).is_none()) + .map(|v| self.tcx.mk_int_var(v)), + ); + vars.extend( + (0..inner.float_unification_table.len()) + .map(|i| ty::FloatVid { index: i as u32 }) + .filter(|&vid| inner.float_unification_table.probe_value(vid).is_none()) + .map(|v| self.tcx.mk_float_var(v)), + ); + vars } fn combine_fields( @@ -719,14 +738,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let in_snapshot = self.in_snapshot.get(); self.in_snapshot.set(true); + let mut inner = self.inner.borrow_mut(); CombinedSnapshot { - projection_cache_snapshot: self.projection_cache.borrow_mut().snapshot(), - type_snapshot: self.type_variables.borrow_mut().snapshot(), - const_snapshot: self.const_unification_table.borrow_mut().snapshot(), - int_snapshot: self.int_unification_table.borrow_mut().snapshot(), - float_snapshot: self.float_unification_table.borrow_mut().snapshot(), - region_constraints_snapshot: self.borrow_region_constraints().start_snapshot(), - region_obligations_snapshot: self.region_obligations.borrow().len(), + projection_cache_snapshot: inner.projection_cache.snapshot(), + type_snapshot: inner.type_variables.snapshot(), + const_snapshot: inner.const_unification_table.snapshot(), + int_snapshot: inner.int_unification_table.snapshot(), + float_snapshot: inner.float_unification_table.snapshot(), + region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(), + region_obligations_snapshot: inner.region_obligations.len(), universe: self.universe(), was_in_snapshot: in_snapshot, was_skip_leak_check: self.skip_leak_check.get(), @@ -756,13 +776,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.universe.set(universe); self.skip_leak_check.set(was_skip_leak_check); - self.projection_cache.borrow_mut().rollback_to(projection_cache_snapshot); - self.type_variables.borrow_mut().rollback_to(type_snapshot); - self.const_unification_table.borrow_mut().rollback_to(const_snapshot); - self.int_unification_table.borrow_mut().rollback_to(int_snapshot); - self.float_unification_table.borrow_mut().rollback_to(float_snapshot); - self.region_obligations.borrow_mut().truncate(region_obligations_snapshot); - self.borrow_region_constraints().rollback_to(region_constraints_snapshot); + let mut inner = self.inner.borrow_mut(); + inner.projection_cache.rollback_to(projection_cache_snapshot); + inner.type_variables.rollback_to(type_snapshot); + inner.const_unification_table.rollback_to(const_snapshot); + inner.int_unification_table.rollback_to(int_snapshot); + inner.float_unification_table.rollback_to(float_snapshot); + inner.unwrap_region_constraints().rollback_to(region_constraints_snapshot); + inner.region_obligations.truncate(region_obligations_snapshot); } fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) { @@ -784,12 +805,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.in_snapshot.set(was_in_snapshot); self.skip_leak_check.set(was_skip_leak_check); - self.projection_cache.borrow_mut().commit(projection_cache_snapshot); - self.type_variables.borrow_mut().commit(type_snapshot); - self.const_unification_table.borrow_mut().commit(const_snapshot); - self.int_unification_table.borrow_mut().commit(int_snapshot); - self.float_unification_table.borrow_mut().commit(float_snapshot); - self.borrow_region_constraints().commit(region_constraints_snapshot); + let mut inner = self.inner.borrow_mut(); + inner.projection_cache.commit(projection_cache_snapshot); + inner.type_variables.commit(type_snapshot); + inner.const_unification_table.commit(const_snapshot); + inner.int_unification_table.commit(int_snapshot); + inner.float_unification_table.commit(float_snapshot); + inner.unwrap_region_constraints().commit(region_constraints_snapshot); } /// Executes `f` and commit the bindings. @@ -859,12 +881,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, snapshot: &CombinedSnapshot<'a, 'tcx>, ) -> Option { - self.borrow_region_constraints() + self.inner + .borrow_mut() + .unwrap_region_constraints() .region_constraints_added_in_snapshot(&snapshot.region_constraints_snapshot) } pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) { - self.borrow_region_constraints().add_given(sub, sup); + self.inner.borrow_mut().unwrap_region_constraints().add_given(sub, sup); } pub fn can_sub(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> UnitResult<'tcx> @@ -900,7 +924,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { b: ty::Region<'tcx>, ) { debug!("sub_regions({:?} <: {:?})", a, b); - self.borrow_region_constraints().make_subregion(origin, a, b); + self.inner.borrow_mut().unwrap_region_constraints().make_subregion(origin, a, b); } /// Require that the region `r` be equal to one of the regions in @@ -914,7 +938,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { in_regions: &Lrc>>, ) { debug!("member_constraint({:?} <: {:?})", region, in_regions); - self.borrow_region_constraints().member_constraint( + self.inner.borrow_mut().unwrap_region_constraints().member_constraint( opaque_type_def_id, definition_span, hidden_ty, @@ -978,7 +1002,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid { - self.type_variables.borrow_mut().new_var(self.universe(), diverging, origin) + self.inner.borrow_mut().type_variables.new_var(self.universe(), diverging, origin) } pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { @@ -990,7 +1014,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeVariableOrigin, universe: ty::UniverseIndex, ) -> Ty<'tcx> { - let vid = self.type_variables.borrow_mut().new_var(universe, false, origin); + let vid = self.inner.borrow_mut().type_variables.new_var(universe, false, origin); self.tcx.mk_ty_var(vid) } @@ -1013,21 +1037,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { universe: ty::UniverseIndex, ) -> &'tcx ty::Const<'tcx> { let vid = self - .const_unification_table + .inner .borrow_mut() + .const_unification_table .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } }); self.tcx.mk_const_var(vid, ty) } pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid<'tcx> { - self.const_unification_table.borrow_mut().new_key(ConstVarValue { + self.inner.borrow_mut().const_unification_table.new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe: self.universe() }, }) } fn next_int_var_id(&self) -> IntVid { - self.int_unification_table.borrow_mut().new_key(None) + self.inner.borrow_mut().int_unification_table.new_key(None) } pub fn next_int_var(&self) -> Ty<'tcx> { @@ -1035,7 +1060,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } fn next_float_var_id(&self) -> FloatVid { - self.float_unification_table.borrow_mut().new_key(None) + self.inner.borrow_mut().float_unification_table.new_key(None) } pub fn next_float_var(&self) -> Ty<'tcx> { @@ -1057,7 +1082,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: RegionVariableOrigin, universe: ty::UniverseIndex, ) -> ty::Region<'tcx> { - let region_var = self.borrow_region_constraints().new_region_var(universe, origin); + let region_var = + self.inner.borrow_mut().unwrap_region_constraints().new_region_var(universe, origin); self.tcx.mk_region(ty::ReVar(region_var)) } @@ -1067,12 +1093,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// placeholders, however, it will return the universe which which /// they are associated. fn universe_of_region(&self, r: ty::Region<'tcx>) -> ty::UniverseIndex { - self.borrow_region_constraints().universe(r) + self.inner.borrow_mut().unwrap_region_constraints().universe(r) } /// Number of region variables created so far. pub fn num_region_vars(&self) -> usize { - self.borrow_region_constraints().num_region_vars() + self.inner.borrow_mut().unwrap_region_constraints().num_region_vars() } /// Just a convenient wrapper of `next_region_var` for using during NLL. @@ -1105,7 +1131,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // used in a path such as `Foo::::new()` will // use an inference variable for `C` with `[T, U]` // as the substitutions for the default, `(T, U)`. - let ty_var_id = self.type_variables.borrow_mut().new_var( + let ty_var_id = self.inner.borrow_mut().type_variables.new_var( self.universe(), false, TypeVariableOrigin { @@ -1125,7 +1151,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span, }; let const_var_id = - self.const_unification_table.borrow_mut().new_key(ConstVarValue { + self.inner.borrow_mut().const_unification_table.new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe: self.universe() }, }); @@ -1179,9 +1205,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { suppress: SuppressRegionErrors, ) { assert!( - self.is_tainted_by_errors() || self.region_obligations.borrow().is_empty(), + self.is_tainted_by_errors() || self.inner.borrow().region_obligations.is_empty(), "region_obligations not empty: {:#?}", - self.region_obligations.borrow() + self.inner.borrow().region_obligations ); let region_rels = &RegionRelations::new( @@ -1191,8 +1217,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { outlives_env.free_region_map(), ); let (var_infos, data) = self - .region_constraints + .inner .borrow_mut() + .region_constraints .take() .expect("regions already resolved") .into_infos_and_data(); @@ -1224,12 +1251,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// understands. See the NLL module for mode details. pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> { assert!( - self.region_obligations.borrow().is_empty(), + self.inner.borrow().region_obligations.is_empty(), "region_obligations not empty: {:#?}", - self.region_obligations.borrow() + self.inner.borrow().region_obligations ); - self.borrow_region_constraints().take_and_reset_data() + self.inner.borrow_mut().unwrap_region_constraints().take_and_reset_data() } /// Gives temporary access to the region constraint data. @@ -1238,8 +1265,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, op: impl FnOnce(&RegionConstraintData<'tcx>) -> R, ) -> R { - let region_constraints = self.borrow_region_constraints(); - op(region_constraints.data()) + let mut inner = self.inner.borrow_mut(); + op(inner.unwrap_region_constraints().data()) } /// Takes ownership of the list of variable regions. This implies @@ -1249,8 +1276,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// of the set of region variables into the NLL region context. pub fn take_region_var_origins(&self) -> VarInfos { let (var_infos, data) = self - .region_constraints + .inner .borrow_mut() + .region_constraints .take() .expect("regions already resolved") .into_infos_and_data(); @@ -1276,7 +1304,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn probe_ty_var(&self, vid: TyVid) -> Result, ty::UniverseIndex> { use self::type_variable::TypeVariableValue; - match self.type_variables.borrow_mut().probe(vid) { + match self.inner.borrow_mut().type_variables.probe(vid) { TypeVariableValue::Known { value } => Ok(value), TypeVariableValue::Unknown { universe } => Err(universe), } @@ -1299,7 +1327,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid { - self.type_variables.borrow_mut().root_var(var) + self.inner.borrow_mut().type_variables.root_var(var) } /// Where possible, replaces type/const variables in @@ -1337,7 +1365,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, vid: ty::ConstVid<'tcx>, ) -> Result<&'tcx ty::Const<'tcx>, ty::UniverseIndex> { - match self.const_unification_table.borrow_mut().probe_value(vid).val { + match self.inner.borrow_mut().const_unification_table.probe_value(vid).val { ConstVariableValue::Known { value } => Ok(value), ConstVariableValue::Unknown { universe } => Err(universe), } @@ -1434,7 +1462,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) { debug!("verify_generic_bound({:?}, {:?} <: {:?})", kind, a, bound); - self.borrow_region_constraints().verify_generic_bound(origin, kind, a, bound); + self.inner + .borrow_mut() + .unwrap_region_constraints() + .verify_generic_bound(origin, kind, a, bound); } pub fn type_is_copy_modulo_regions( @@ -1509,19 +1540,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { InferOk { value, obligations } } - pub fn borrow_region_constraints(&self) -> RefMut<'_, RegionConstraintCollector<'tcx>> { - RefMut::map(self.region_constraints.borrow_mut(), |c| { - c.as_mut().expect("region constraints already solved") - }) - } - /// Clears the selection, evaluation, and projection caches. This is useful when /// repeatedly attempting to select an `Obligation` while changing only /// its `ParamEnv`, since `FulfillmentContext` doesn't use probing. pub fn clear_caches(&self) { self.selection_cache.clear(); self.evaluation_cache.clear(); - self.projection_cache.borrow_mut().clear(); + self.inner.borrow_mut().projection_cache.clear(); } fn universe(&self) -> ty::UniverseIndex { @@ -1562,27 +1587,27 @@ impl<'a, 'tcx> ShallowResolver<'a, 'tcx> { // structurally), and we prevent cycles in any case, // so this recursion should always be of very limited // depth. - self.infcx - .type_variables - .borrow_mut() - .probe(v) - .known() - .map(|t| self.fold_ty(t)) - .unwrap_or(typ) + // + // Note: if these two lines are combined into one we get + // dynamic borrow errors on `self.infcx.inner`. + let known = self.infcx.inner.borrow_mut().type_variables.probe(v).known(); + known.map(|t| self.fold_ty(t)).unwrap_or(typ) } ty::Infer(ty::IntVar(v)) => self .infcx - .int_unification_table + .inner .borrow_mut() + .int_unification_table .probe_value(v) .map(|v| v.to_type(self.infcx.tcx)) .unwrap_or(typ), ty::Infer(ty::FloatVar(v)) => self .infcx - .float_unification_table + .inner .borrow_mut() + .float_unification_table .probe_value(v) .map(|v| v.to_type(self.infcx.tcx)) .unwrap_or(typ), @@ -1603,7 +1628,7 @@ impl<'a, 'tcx> ShallowResolver<'a, 'tcx> { // If `inlined_probe` returns a `Known` value its `kind` never // matches `infer`. - match self.infcx.type_variables.borrow_mut().inlined_probe(v) { + match self.infcx.inner.borrow_mut().type_variables.inlined_probe(v) { TypeVariableValue::Unknown { .. } => false, TypeVariableValue::Known { .. } => true, } @@ -1613,7 +1638,7 @@ impl<'a, 'tcx> ShallowResolver<'a, 'tcx> { // If inlined_probe_value returns a value it's always a // `ty::Int(_)` or `ty::UInt(_)`, which nevers matches a // `ty::Infer(_)`. - self.infcx.int_unification_table.borrow_mut().inlined_probe_value(v).is_some() + self.infcx.inner.borrow_mut().int_unification_table.inlined_probe_value(v).is_some() } ty::FloatVar(v) => { @@ -1621,7 +1646,7 @@ impl<'a, 'tcx> ShallowResolver<'a, 'tcx> { // `ty::Float(_)`, which nevers matches a `ty::Infer(_)`. // // Not `inlined_probe_value(v)` because this call site is colder. - self.infcx.float_unification_table.borrow_mut().probe_value(v).is_some() + self.infcx.inner.borrow_mut().float_unification_table.probe_value(v).is_some() } _ => unreachable!(), @@ -1641,8 +1666,9 @@ impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> { fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = ct { self.infcx - .const_unification_table + .inner .borrow_mut() + .const_unification_table .probe_value(*vid) .val .known() diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs index 6af004f7776a1..77e20e6ad8ff2 100644 --- a/src/librustc/infer/nll_relate/mod.rs +++ b/src/librustc/infer/nll_relate/mod.rs @@ -322,7 +322,7 @@ where match value_ty.kind { ty::Infer(ty::TyVar(value_vid)) => { // Two type variables: just equate them. - self.infcx.type_variables.borrow_mut().equate(vid, value_vid); + self.infcx.inner.borrow_mut().type_variables.equate(vid, value_vid); return Ok(value_ty); } @@ -343,7 +343,7 @@ where assert!(!generalized_ty.has_infer_types()); } - self.infcx.type_variables.borrow_mut().instantiate(vid, generalized_ty); + self.infcx.inner.borrow_mut().type_variables.instantiate(vid, generalized_ty); // The generalized values we extract from `canonical_var_values` have // been fully instantiated and hence the set of scopes we have @@ -373,7 +373,7 @@ where delegate: &mut self.delegate, first_free_index: ty::INNERMOST, ambient_variance: self.ambient_variance, - for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid), + for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables.sub_root_var(for_vid), universe, }; @@ -870,7 +870,7 @@ where } ty::Infer(ty::TyVar(vid)) => { - let mut variables = self.infcx.type_variables.borrow_mut(); + let variables = &mut self.infcx.inner.borrow_mut().type_variables; let vid = variables.root_var(vid); let sub_vid = variables.sub_root_var(vid); if sub_vid == self.for_vid_sub_root { @@ -972,7 +972,7 @@ where bug!("unexpected inference variable encountered in NLL generalization: {:?}", a); } ty::ConstKind::Infer(InferConst::Var(vid)) => { - let mut variable_table = self.infcx.const_unification_table.borrow_mut(); + let variable_table = &mut self.infcx.inner.borrow_mut().const_unification_table; let var_value = variable_table.probe_value(vid); match var_value.val.known() { Some(u) => self.relate(&u, &u), diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs index 45e4a84589eb5..17153ef97241b 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc/infer/outlives/obligations.rs @@ -82,7 +82,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { ) { debug!("register_region_obligation(body_id={:?}, obligation={:?})", body_id, obligation); - self.region_obligations.borrow_mut().push((body_id, obligation)); + self.inner.borrow_mut().region_obligations.push((body_id, obligation)); } pub fn register_region_obligation_with_cause( @@ -103,7 +103,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// Trait queries just want to pass back type obligations "as is" pub fn take_registered_region_obligations(&self) -> Vec<(hir::HirId, RegionObligation<'tcx>)> { - ::std::mem::take(&mut *self.region_obligations.borrow_mut()) + ::std::mem::take(&mut self.inner.borrow_mut().region_obligations) } /// Process the region obligations that must be proven (during diff --git a/src/librustc/infer/resolve.rs b/src/librustc/infer/resolve.rs index d7dc607044222..c9acd1cf4a1b3 100644 --- a/src/librustc/infer/resolve.rs +++ b/src/librustc/infer/resolve.rs @@ -75,9 +75,12 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticTypeAndRegionResolver<'a, 'tcx> fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { - ty::ReVar(rid) => { - self.infcx.borrow_region_constraints().opportunistic_resolve_var(self.tcx(), rid) - } + ty::ReVar(rid) => self + .infcx + .inner + .borrow_mut() + .unwrap_region_constraints() + .opportunistic_resolve_var(self.tcx(), rid), _ => r, } } @@ -120,7 +123,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { // Since we called `shallow_resolve` above, this must // be an (as yet...) unresolved inference variable. let ty_var_span = if let ty::TyVar(ty_vid) = infer_ty { - let ty_vars = self.infcx.type_variables.borrow(); + let ty_vars = &self.infcx.inner.borrow().type_variables; if let TypeVariableOrigin { kind: TypeVariableOriginKind::TypeParameterDefinition(_, _), span, diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index f355ffe196202..ef4903358d5c9 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -80,8 +80,8 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { } let infcx = self.fields.infcx; - let a = infcx.type_variables.borrow_mut().replace_if_possible(a); - let b = infcx.type_variables.borrow_mut().replace_if_possible(b); + let a = infcx.inner.borrow_mut().type_variables.replace_if_possible(a); + let b = infcx.inner.borrow_mut().type_variables.replace_if_possible(b); match (&a.kind, &b.kind) { (&ty::Infer(TyVar(a_vid)), &ty::Infer(TyVar(b_vid))) => { // Shouldn't have any LBR here, so we can safely put @@ -95,7 +95,7 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { // have to record in the `type_variables` tracker that // the two variables are equal modulo subtyping, which // is important to the occurs check later on. - infcx.type_variables.borrow_mut().sub(a_vid, b_vid); + infcx.inner.borrow_mut().type_variables.sub(a_vid, b_vid); self.fields.obligations.push(Obligation::new( self.fields.trace.cause.clone(), self.fields.param_env, @@ -140,7 +140,12 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { // from the "cause" field, we could perhaps give more tailored // error messages. let origin = SubregionOrigin::Subtype(box self.fields.trace.clone()); - self.fields.infcx.borrow_region_constraints().make_subregion(origin, a, b); + self.fields + .infcx + .inner + .borrow_mut() + .unwrap_region_constraints() + .make_subregion(origin, a, b); Ok(a) } diff --git a/src/librustc/infer/unify_key.rs b/src/librustc/infer/unify_key.rs index d88188538fccb..e205453a48c53 100644 --- a/src/librustc/infer/unify_key.rs +++ b/src/librustc/infer/unify_key.rs @@ -4,7 +4,6 @@ use rustc_data_structures::unify::{EqUnifyValue, NoError, UnificationTable, Unif use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; -use std::cell::RefMut; use std::cmp; use std::marker::PhantomData; @@ -214,7 +213,7 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> { impl<'tcx> EqUnifyValue for &'tcx ty::Const<'tcx> {} pub fn replace_if_possible( - mut table: RefMut<'_, UnificationTable>>>, + table: &mut UnificationTable>>, c: &'tcx ty::Const<'tcx>, ) -> &'tcx ty::Const<'tcx> { if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = c { diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index d775393a808f7..1255728de37b1 100644 --- a/src/librustc/traits/auto_trait.rs +++ b/src/librustc/traits/auto_trait.rs @@ -199,12 +199,22 @@ impl<'tcx> AutoTraitFinder<'tcx> { panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, e) }); - let body_id_map: FxHashMap<_, _> = - infcx.region_obligations.borrow().iter().map(|&(id, _)| (id, vec![])).collect(); + let body_id_map: FxHashMap<_, _> = infcx + .inner + .borrow() + .region_obligations + .iter() + .map(|&(id, _)| (id, vec![])) + .collect(); infcx.process_registered_region_obligations(&body_id_map, None, full_env); - let region_data = infcx.borrow_region_constraints().region_constraint_data().clone(); + let region_data = infcx + .inner + .borrow_mut() + .unwrap_region_constraints() + .region_constraint_data() + .clone(); let vid_to_region = self.map_vid_to_region(®ion_data); diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index fffcf66075f93..6c058455b98bd 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -454,7 +454,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // bounds. It might be the case that we want two distinct caches, // or else another kind of cache entry. - let cache_result = infcx.projection_cache.borrow_mut().try_start(cache_key); + let cache_result = infcx.inner.borrow_mut().projection_cache.try_start(cache_key); match cache_result { Ok(()) => {} Err(ProjectionCacheEntry::Ambiguous) => { @@ -528,7 +528,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // Once we have inferred everything we need to know, we // can ignore the `obligations` from that point on. if infcx.unresolved_type_vars(&ty.value).is_none() { - infcx.projection_cache.borrow_mut().complete_normalized(cache_key, &ty); + infcx.inner.borrow_mut().projection_cache.complete_normalized(cache_key, &ty); // No need to extend `obligations`. } else { obligations.extend(ty.obligations); @@ -590,7 +590,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( }; let cache_value = prune_cache_value_obligations(infcx, &result); - infcx.projection_cache.borrow_mut().insert_ty(cache_key, cache_value); + infcx.inner.borrow_mut().projection_cache.insert_ty(cache_key, cache_value); obligations.extend(result.obligations); Some(result.value) } @@ -601,7 +601,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( projected_ty ); let result = Normalized { value: projected_ty, obligations: vec![] }; - infcx.projection_cache.borrow_mut().insert_ty(cache_key, result.clone()); + infcx.inner.borrow_mut().projection_cache.insert_ty(cache_key, result.clone()); // No need to extend `obligations`. Some(result.value) } @@ -610,7 +610,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( "opt_normalize_projection_type: \ too many candidates" ); - infcx.projection_cache.borrow_mut().ambiguous(cache_key); + infcx.inner.borrow_mut().projection_cache.ambiguous(cache_key); None } Err(ProjectionTyError::TraitSelectionError(_)) => { @@ -620,7 +620,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // Trait`, which when processed will cause the error to be // reported later - infcx.projection_cache.borrow_mut().error(cache_key); + infcx.inner.borrow_mut().projection_cache.error(cache_key); let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); obligations.extend(result.obligations); Some(result.value) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index e4ef68c167f94..c56cde4f4ce44 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -511,7 +511,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let Some(key) = ProjectionCacheKey::from_poly_projection_predicate(self, data) { - self.infcx.projection_cache.borrow_mut().complete(key); + self.infcx.inner.borrow_mut().projection_cache.complete(key); } result } diff --git a/src/librustc_traits/chalk_context/resolvent_ops.rs b/src/librustc_traits/chalk_context/resolvent_ops.rs index 301ebf8adc5c7..dc6018e80ea7e 100644 --- a/src/librustc_traits/chalk_context/resolvent_ops.rs +++ b/src/librustc_traits/chalk_context/resolvent_ops.rs @@ -226,7 +226,9 @@ impl TypeRelation<'tcx> for AnswerSubstitutor<'cx, 'tcx> { let b = match b { &ty::ReVar(vid) => self .infcx - .borrow_region_constraints() + .inner + .borrow_mut() + .unwrap_region_constraints() .opportunistic_resolve_var(self.infcx.tcx, vid), other => other, From 5ab1ab4959c3a5bb55123a7f48934684fd62bc51 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 8 Feb 2020 00:27:07 +0100 Subject: [PATCH 11/14] Reduce queries/map lookups done by coherence This has negligible perf impact, but it does improve the code a bit. * Only query the specialization graph of any trait once instead of once per impl * Loop over impls only once, precomputing impl DefId and TraitRef --- src/librustc_typeck/coherence/builtin.rs | 12 ++-- src/librustc_typeck/coherence/mod.rs | 67 +++++++++---------- ...erence-inherited-assoc-ty-cycle-err.stderr | 4 +- 3 files changed, 37 insertions(+), 46 deletions(-) diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 79a006a898a89..1970b1e5c5deb 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -18,14 +18,12 @@ use rustc_hir::def_id::DefId; use rustc_hir::ItemKind; pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) { + let lang_items = tcx.lang_items(); Checker { tcx, trait_def_id } - .check(tcx.lang_items().drop_trait(), visit_implementation_of_drop) - .check(tcx.lang_items().copy_trait(), visit_implementation_of_copy) - .check(tcx.lang_items().coerce_unsized_trait(), visit_implementation_of_coerce_unsized) - .check( - tcx.lang_items().dispatch_from_dyn_trait(), - visit_implementation_of_dispatch_from_dyn, - ); + .check(lang_items.drop_trait(), visit_implementation_of_drop) + .check(lang_items.copy_trait(), visit_implementation_of_copy) + .check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized) + .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn); } struct Checker<'tcx> { diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 5583e3418b2a8..012cdb7b8aed7 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -10,7 +10,6 @@ use rustc::ty::query::Providers; use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc_errors::struct_span_err; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_hir::HirId; mod builtin; mod inherent_impls; @@ -18,28 +17,21 @@ mod inherent_impls_overlap; mod orphan; mod unsafety; -fn check_impl(tcx: TyCtxt<'_>, hir_id: HirId) { - let impl_def_id = tcx.hir().local_def_id(hir_id); +fn check_impl(tcx: TyCtxt<'_>, impl_def_id: DefId, trait_ref: ty::TraitRef<'_>) { + debug!( + "(checking implementation) adding impl for trait '{:?}', item '{}'", + trait_ref, + tcx.def_path_str(impl_def_id) + ); - // If there are no traits, then this implementation must have a - // base type. - - if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) { - debug!( - "(checking implementation) adding impl for trait '{:?}', item '{}'", - trait_ref, - tcx.def_path_str(impl_def_id) - ); - - // Skip impls where one of the self type is an error type. - // This occurs with e.g., resolve failures (#30589). - if trait_ref.references_error() { - return; - } - - enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id); - enforce_empty_impls_for_marker_traits(tcx, impl_def_id, trait_ref.def_id); + // Skip impls where one of the self type is an error type. + // This occurs with e.g., resolve failures (#30589). + if trait_ref.references_error() { + return; } + + enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id); + enforce_empty_impls_for_marker_traits(tcx, impl_def_id, trait_ref.def_id); } fn enforce_trait_manually_implementable(tcx: TyCtxt<'_>, impl_def_id: DefId, trait_def_id: DefId) { @@ -129,12 +121,17 @@ pub fn provide(providers: &mut Providers<'_>) { } fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) { + // Trigger building the specialization graph for the trait. This will detect and report any + // overlap errors. + tcx.specialization_graph_of(def_id); + let impls = tcx.hir().trait_impls(def_id); - for &impl_id in impls { - check_impl(tcx, impl_id); - } - for &impl_id in impls { - check_impl_overlap(tcx, impl_id); + for &hir_id in impls { + let impl_def_id = tcx.hir().local_def_id(hir_id); + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); + + check_impl(tcx, impl_def_id, trait_ref); + check_object_overlap(tcx, impl_def_id, trait_ref); } builtin::check_trait(tcx, def_id); } @@ -152,12 +149,12 @@ pub fn check_coherence(tcx: TyCtxt<'_>) { tcx.ensure().crate_inherent_impls_overlap_check(LOCAL_CRATE); } -/// Overlap: no two impls for the same trait are implemented for the -/// same type. Likewise, no two inherent impls for a given type -/// constructor provide a method with the same name. -fn check_impl_overlap<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId) { - let impl_def_id = tcx.hir().local_def_id(hir_id); - let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); +/// Checks whether an impl overlaps with the automatic `impl Trait for dyn Trait`. +fn check_object_overlap<'tcx>( + tcx: TyCtxt<'tcx>, + impl_def_id: DefId, + trait_ref: ty::TraitRef<'tcx>, +) { let trait_def_id = trait_ref.def_id; if trait_ref.references_error() { @@ -165,11 +162,7 @@ fn check_impl_overlap<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId) { return; } - // Trigger building the specialization graph for the trait of this impl. - // This will detect any overlap errors. - tcx.specialization_graph_of(trait_def_id); - - // check for overlap with the automatic `impl Trait for Trait` + // check for overlap with the automatic `impl Trait for dyn Trait` if let ty::Dynamic(ref data, ..) = trait_ref.self_ty().kind { // This is something like impl Trait1 for Trait2. Illegal // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe. diff --git a/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr b/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr index e5cc298a4355d..71f997c54c6f2 100644 --- a/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr +++ b/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr @@ -1,10 +1,10 @@ -error[E0391]: cycle detected when processing `Trait` +error[E0391]: cycle detected when building specialization graph of trait `Trait` --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:8:1 | LL | trait Trait { type Assoc; } | ^^^^^^^^^^^^^^ | - = note: ...which again requires processing `Trait`, completing the cycle + = note: ...which again requires building specialization graph of trait `Trait`, completing the cycle note: cycle used when coherence checking all impls of trait `Trait` --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:8:1 | From 82d6e79cfe857abd70e45210e86f58b6eeef4d35 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 8 Feb 2020 00:27:24 +0100 Subject: [PATCH 12/14] Add desc to `specialization_graph_of` query --- src/librustc/query/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 7cb1f3aa0e851..425f14a5740d4 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -647,7 +647,8 @@ rustc_queries! { query trait_impls_of(key: DefId) -> &'tcx ty::trait_def::TraitImpls { desc { |tcx| "trait impls of `{}`", tcx.def_path_str(key) } } - query specialization_graph_of(_: DefId) -> &'tcx specialization_graph::Graph { + query specialization_graph_of(key: DefId) -> &'tcx specialization_graph::Graph { + desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(key) } cache_on_disk_if { true } } query is_object_safe(key: DefId) -> bool { From 8f468ee11471dbc6eaec753f540b007014badf1b Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 8 Feb 2020 00:45:03 +0100 Subject: [PATCH 13/14] Defer error span calculation until needed This was showing up in profiles. Also deduplicates the code to get just the impl header span. --- src/librustc_typeck/coherence/mod.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 012cdb7b8aed7..1526182576c31 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -10,6 +10,7 @@ use rustc::ty::query::Providers; use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc_errors::struct_span_err; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_span::Span; mod builtin; mod inherent_impls; @@ -17,6 +18,11 @@ mod inherent_impls_overlap; mod orphan; mod unsafety; +/// Obtains the span of just the impl header of `impl_def_id`. +fn impl_header_span(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Span { + tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap()) +} + fn check_impl(tcx: TyCtxt<'_>, impl_def_id: DefId, trait_ref: ty::TraitRef<'_>) { debug!( "(checking implementation) adding impl for trait '{:?}', item '{}'", @@ -37,10 +43,10 @@ fn check_impl(tcx: TyCtxt<'_>, impl_def_id: DefId, trait_ref: ty::TraitRef<'_>) fn enforce_trait_manually_implementable(tcx: TyCtxt<'_>, impl_def_id: DefId, trait_def_id: DefId) { let did = Some(trait_def_id); let li = tcx.lang_items(); - let span = tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap()); // Disallow *all* explicit impls of `Sized` and `Unsize` for now. if did == li.sized_trait() { + let span = impl_header_span(tcx, impl_def_id); struct_span_err!( tcx.sess, span, @@ -53,6 +59,7 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt<'_>, impl_def_id: DefId, tra } if did == li.unsize_trait() { + let span = impl_header_span(tcx, impl_def_id); struct_span_err!( tcx.sess, span, @@ -78,6 +85,8 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt<'_>, impl_def_id: DefId, tra } else { return; // everything OK }; + + let span = impl_header_span(tcx, impl_def_id); struct_span_err!( tcx.sess, span, @@ -101,7 +110,7 @@ fn enforce_empty_impls_for_marker_traits(tcx: TyCtxt<'_>, impl_def_id: DefId, tr return; } - let span = tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap()); + let span = impl_header_span(tcx, impl_def_id); struct_span_err!(tcx.sess, span, E0715, "impls for marker traits cannot contain items").emit(); } @@ -187,17 +196,17 @@ fn check_object_overlap<'tcx>( } else { let mut supertrait_def_ids = traits::supertrait_def_ids(tcx, component_def_id); if supertrait_def_ids.any(|d| d == trait_def_id) { - let sp = tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap()); + let span = impl_header_span(tcx, impl_def_id); struct_span_err!( tcx.sess, - sp, + span, E0371, "the object type `{}` automatically implements the trait `{}`", trait_ref.self_ty(), tcx.def_path_str(trait_def_id) ) .span_label( - sp, + span, format!( "`{}` automatically implements trait `{}`", trait_ref.self_ty(), From 23095928a7e51e84f2e58a28ea0b76db6599d9d7 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 8 Feb 2020 19:14:50 +0100 Subject: [PATCH 14/14] Remove vestigial #43355-compat code This was previously a future-compat warning that has since been turned into hard error, but without actually removing all the code. Avoids a call to `traits::overlapping_impls`, which is expensive. --- src/librustc/traits/coherence.rs | 23 +++------- src/librustc/traits/mod.rs | 7 --- src/librustc/traits/select.rs | 44 +++++++------------ src/librustc/traits/specialize/mod.rs | 7 +-- .../traits/specialize/specialization_graph.rs | 30 +++---------- .../coherence/inherent_impls_overlap.rs | 3 +- 6 files changed, 29 insertions(+), 85 deletions(-) diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 855da0367de06..2a667b535508b 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -6,7 +6,6 @@ use crate::infer::{CombinedSnapshot, InferOk}; use crate::traits::select::IntercrateAmbiguityCause; -use crate::traits::IntercrateMode; use crate::traits::SkipLeakCheck; use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionContext}; use crate::ty::fold::TypeFoldable; @@ -27,7 +26,7 @@ enum InCrate { #[derive(Debug, Copy, Clone)] pub enum Conflict { Upstream, - Downstream { used_to_be_broken: bool }, + Downstream, } pub struct OverlapResult<'tcx> { @@ -53,7 +52,6 @@ pub fn overlapping_impls( tcx: TyCtxt<'_>, impl1_def_id: DefId, impl2_def_id: DefId, - intercrate_mode: IntercrateMode, skip_leak_check: SkipLeakCheck, on_overlap: F1, no_overlap: F2, @@ -65,13 +63,12 @@ where debug!( "overlapping_impls(\ impl1_def_id={:?}, \ - impl2_def_id={:?}, - intercrate_mode={:?})", - impl1_def_id, impl2_def_id, intercrate_mode + impl2_def_id={:?})", + impl1_def_id, impl2_def_id, ); let overlaps = tcx.infer_ctxt().enter(|infcx| { - let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode); + let selcx = &mut SelectionContext::intercrate(&infcx); overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).is_some() }); @@ -83,7 +80,7 @@ where // this time tracking intercrate ambuiguity causes for better // diagnostics. (These take time and can lead to false errors.) tcx.infer_ctxt().enter(|infcx| { - let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode); + let selcx = &mut SelectionContext::intercrate(&infcx); selcx.enable_tracking_intercrate_ambiguity_causes(); on_overlap(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).unwrap()) }) @@ -202,15 +199,7 @@ pub fn trait_ref_is_knowable<'tcx>( if orphan_check_trait_ref(tcx, trait_ref, InCrate::Remote).is_ok() { // A downstream or cousin crate is allowed to implement some // substitution of this trait-ref. - - // A trait can be implementable for a trait ref by both the current - // crate and crates downstream of it. Older versions of rustc - // were not aware of this, causing incoherence (issue #43355). - let used_to_be_broken = orphan_check_trait_ref(tcx, trait_ref, InCrate::Local).is_ok(); - if used_to_be_broken { - debug!("trait_ref_is_knowable({:?}) - USED TO BE BROKEN", trait_ref); - } - return Some(Conflict::Downstream { used_to_be_broken }); + return Some(Conflict::Downstream); } if trait_ref_is_local_or_fundamental(tcx, trait_ref) { diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 783807b5c3b59..417b52c38a74d 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -78,13 +78,6 @@ pub use self::chalk_fulfill::{ pub use self::types::*; -/// Whether to enable bug compatibility with issue #43355. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum IntercrateMode { - Issue43355, - Fixed, -} - /// Whether to skip the leak check, as part of a future compatibility warning step. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum SkipLeakCheck { diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 26f2a4ddb385a..1cbcbc4aaa7ce 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -19,8 +19,8 @@ use super::DerivedObligationCause; use super::Selection; use super::SelectionResult; use super::TraitNotObjectSafe; +use super::TraitQueryMode; use super::{BuiltinDerivedObligation, ImplDerivedObligation, ObligationCauseCode}; -use super::{IntercrateMode, TraitQueryMode}; use super::{ObjectCastObligation, Obligation}; use super::{ObligationCause, PredicateObligation, TraitObligation}; use super::{OutputTypeParameterMismatch, Overflow, SelectionError, Unimplemented}; @@ -80,7 +80,7 @@ pub struct SelectionContext<'cx, 'tcx> { /// other words, we consider `$0: Bar` to be unimplemented if /// there is no type that the user could *actually name* that /// would satisfy it. This avoids crippling inference, basically. - intercrate: Option, + intercrate: bool, intercrate_ambiguity_causes: Option>, @@ -218,22 +218,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { SelectionContext { infcx, freshener: infcx.freshener(), - intercrate: None, + intercrate: false, intercrate_ambiguity_causes: None, allow_negative_impls: false, query_mode: TraitQueryMode::Standard, } } - pub fn intercrate( - infcx: &'cx InferCtxt<'cx, 'tcx>, - mode: IntercrateMode, - ) -> SelectionContext<'cx, 'tcx> { - debug!("intercrate({:?})", mode); + pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { SelectionContext { infcx, freshener: infcx.freshener(), - intercrate: Some(mode), + intercrate: true, intercrate_ambiguity_causes: None, allow_negative_impls: false, query_mode: TraitQueryMode::Standard, @@ -248,7 +244,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { SelectionContext { infcx, freshener: infcx.freshener(), - intercrate: None, + intercrate: false, intercrate_ambiguity_causes: None, allow_negative_impls, query_mode: TraitQueryMode::Standard, @@ -263,7 +259,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { SelectionContext { infcx, freshener: infcx.freshener(), - intercrate: None, + intercrate: false, intercrate_ambiguity_causes: None, allow_negative_impls: false, query_mode, @@ -276,7 +272,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// false overflow results (#47139) and because it costs /// computation time. pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) { - assert!(self.intercrate.is_some()); + assert!(self.intercrate); assert!(self.intercrate_ambiguity_causes.is_none()); self.intercrate_ambiguity_causes = Some(vec![]); debug!("selcx: enable_tracking_intercrate_ambiguity_causes"); @@ -286,7 +282,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// was enabled and disables tracking at the same time. If /// tracking is not enabled, just returns an empty vector. pub fn take_intercrate_ambiguity_causes(&mut self) -> Vec { - assert!(self.intercrate.is_some()); + assert!(self.intercrate); self.intercrate_ambiguity_causes.take().unwrap_or(vec![]) } @@ -562,7 +558,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result { debug!("evaluate_trait_predicate_recursively({:?})", obligation); - if self.intercrate.is_none() + if !self.intercrate && obligation.is_global() && obligation.param_env.caller_bounds.iter().all(|bound| bound.needs_subst()) { @@ -727,7 +723,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { stack.fresh_trait_ref.skip_binder().input_types().any(|ty| ty.is_fresh()); // This check was an imperfect workaround for a bug in the old // intercrate mode; it should be removed when that goes away. - if unbound_input_types && self.intercrate == Some(IntercrateMode::Issue43355) { + if unbound_input_types && self.intercrate { debug!( "evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous", stack.fresh_trait_ref @@ -1206,7 +1202,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option { debug!("is_knowable(intercrate={:?})", self.intercrate); - if !self.intercrate.is_some() { + if !self.intercrate { return None; } @@ -1218,17 +1214,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // bound regions. let trait_ref = predicate.skip_binder().trait_ref; - let result = coherence::trait_ref_is_knowable(self.tcx(), trait_ref); - if let ( - Some(Conflict::Downstream { used_to_be_broken: true }), - Some(IntercrateMode::Issue43355), - ) = (result, self.intercrate) - { - debug!("is_knowable: IGNORING conflict to be bug-compatible with #43355"); - None - } else { - result - } + coherence::trait_ref_is_knowable(self.tcx(), trait_ref) } /// Returns `true` if the global caches can be used. @@ -1249,7 +1235,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // the master cache. Since coherence executes pretty quickly, // it's not worth going to more trouble to increase the // hit-rate, I don't think. - if self.intercrate.is_some() { + if self.intercrate { return false; } @@ -3305,7 +3291,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(()); } - if self.intercrate.is_none() + if !self.intercrate && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation { debug!("match_impl: reservation impls only apply in intercrate mode"); diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 8b68d6f260399..071b5277dd95d 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -332,14 +332,9 @@ pub(super) fn specialization_graph_provider( let impl_span = tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap()); let mut err = match used_to_be_allowed { - Some(FutureCompatOverlapErrorKind::Issue43355) | None => { - struct_span_err!(tcx.sess, impl_span, E0119, "{}", msg) - } + None => struct_span_err!(tcx.sess, impl_span, E0119, "{}", msg), Some(kind) => { let lint = match kind { - FutureCompatOverlapErrorKind::Issue43355 => { - unreachable!("converted to hard error above") - } FutureCompatOverlapErrorKind::Issue33140 => { ORDER_DEPENDENT_TRAIT_OBJECTS } diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index 98908e672f0aa..ca7740199ec7d 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -9,7 +9,6 @@ pub use rustc::traits::types::specialization_graph::*; #[derive(Copy, Clone, Debug)] pub enum FutureCompatOverlapErrorKind { - Issue43355, Issue33140, LeakCheck, } @@ -107,16 +106,16 @@ impl<'tcx> Children { } }; + let allowed_to_overlap = + tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling); + let (le, ge) = traits::overlapping_impls( tcx, possible_sibling, impl_def_id, - traits::IntercrateMode::Issue43355, traits::SkipLeakCheck::default(), |overlap| { - if let Some(overlap_kind) = - tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) - { + if let Some(overlap_kind) = &allowed_to_overlap { match overlap_kind { ty::ImplOverlapKind::Permitted { marker: _ } => {} ty::ImplOverlapKind::Issue33140 => { @@ -154,31 +153,14 @@ impl<'tcx> Children { replace_children.push(possible_sibling); } else { - if let None = tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) { - // do future-compat checks for overlap. Have issue #33140 - // errors overwrite issue #43355 errors when both are present. - - traits::overlapping_impls( - tcx, - possible_sibling, - impl_def_id, - traits::IntercrateMode::Fixed, - traits::SkipLeakCheck::default(), - |overlap| { - last_lint = Some(FutureCompatOverlapError { - error: overlap_error(overlap), - kind: FutureCompatOverlapErrorKind::Issue43355, - }); - }, - || (), - ); + if let None = allowed_to_overlap { + // Do future-compat checks for overlap. if last_lint.is_none() { traits::overlapping_impls( tcx, possible_sibling, impl_def_id, - traits::IntercrateMode::Fixed, traits::SkipLeakCheck::Yes, |overlap| { last_lint = Some(FutureCompatOverlapError { diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index fb9c173f52000..ffea849c4f209 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -1,5 +1,5 @@ use crate::namespace::Namespace; -use rustc::traits::{self, IntercrateMode, SkipLeakCheck}; +use rustc::traits::{self, SkipLeakCheck}; use rustc::ty::{AssocItem, TyCtxt}; use rustc_errors::struct_span_err; use rustc_hir as hir; @@ -93,7 +93,6 @@ impl InherentOverlapChecker<'tcx> { self.tcx, impl1_def_id, impl2_def_id, - IntercrateMode::Issue43355, // We go ahead and just skip the leak check for // inherent impls without warning. SkipLeakCheck::Yes,
"#, + r#""#, colspan = num_state_columns, fmt = fmt, )?; @@ -311,7 +320,9 @@ where f: impl FnOnce(&mut Self, &mut W, &str) -> io::Result<()>, ) -> io::Result<()> { let bg = self.toggle_background(); - let fmt = format!("sides=\"tl\" {}", bg.attr()); + let valign = if mir.starts_with("(on ") && mir != "(on entry)" { "bottom" } else { "top" }; + + let fmt = format!("valign=\"{}\" sides=\"tl\" {}", valign, bg.attr()); write!( w, @@ -345,7 +356,7 @@ where colspan = this.num_state_columns(), fmt = fmt, )?; - pretty_print_state_elems(w, analysis, state.iter(), ",", LIMIT_40_ALIGN_1)?; + pretty_print_state_elems(w, analysis, state.iter(), ", ", LIMIT_30_ALIGN_1)?; write!(w, "}}"#, fmt = fmt)?; + write!(w, r#""#, fmt = fmt)?; results.seek_after(location); let curr_state = results.get(); write_diff(&mut w, results.analysis(), &self.prev_state, curr_state)?; @@ -524,12 +535,12 @@ where for set in &[&block_trans.gen, &block_trans.kill] { write!( w, - r#""#, + r#""#, fmt = fmt, rowspan = rowspan )?; - pretty_print_state_elems(&mut w, results.analysis(), set.iter(), "\n", None)?; + pretty_print_state_elems(&mut w, results.analysis(), set.iter(), BR_LEFT, None)?; write!(w, "