diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index b1931ca459f61..974d9dcfae408 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -85,19 +85,20 @@ mod graphviz; #[cfg(test)] mod tests; -pub trait ForestObligation : Clone + Debug { - type Predicate : Clone + hash::Hash + Eq + Debug; +pub trait ForestObligation: Clone + Debug { + type Predicate: Clone + hash::Hash + Eq + Debug; fn as_predicate(&self) -> &Self::Predicate; } pub trait ObligationProcessor { - type Obligation : ForestObligation; - type Error : Debug; + type Obligation: ForestObligation; + type Error: Debug; - fn process_obligation(&mut self, - obligation: &mut Self::Obligation) - -> ProcessResult; + fn process_obligation( + &mut self, + obligation: &mut Self::Obligation, + ) -> ProcessResult; /// As we do the cycle check, we invoke this callback when we /// encounter an actual cycle. `cycle` is an iterator that starts @@ -107,10 +108,9 @@ pub trait ObligationProcessor { /// In other words, if we had O1 which required O2 which required /// O3 which required O1, we would give an iterator yielding O1, /// O2, O3 (O1 is not yielded twice). - fn process_backedge<'c, I>(&mut self, - cycle: I, - _marker: PhantomData<&'c Self::Obligation>) - where I: Clone + Iterator; + fn process_backedge<'c, I>(&mut self, cycle: I, _marker: PhantomData<&'c Self::Obligation>) + where + I: Clone + Iterator; } /// The result type used by `process_obligation`. @@ -129,7 +129,7 @@ type ObligationTreeIdGenerator = pub struct ObligationForest { /// The list of obligations. In between calls to `process_obligations`, - /// this list only contains nodes in the `Pending` or `Success` state. + /// this list only contains nodes in the `Pending` or `Waiting` state. /// /// `usize` indices are used here and throughout this module, rather than /// `rustc_index::newtype_index!` indices, because this code is hot enough @@ -137,10 +137,6 @@ pub struct ObligationForest { /// significant, and space considerations are not important. nodes: Vec>, - /// The process generation is 1 on the first call to `process_obligations`, - /// 2 on the second call, etc. - gen: u32, - /// A cache of predicates that have been successfully completed. done_cache: FxHashSet, @@ -185,29 +181,20 @@ struct Node { } impl Node { - fn new( - parent: Option, - obligation: O, - obligation_tree_id: ObligationTreeId - ) -> Node { + fn new(parent: Option, obligation: O, obligation_tree_id: ObligationTreeId) -> Node { Node { obligation, state: Cell::new(NodeState::Pending), - dependents: - if let Some(parent_index) = parent { - vec![parent_index] - } else { - vec![] - }, + dependents: if let Some(parent_index) = parent { vec![parent_index] } else { vec![] }, has_parent: parent.is_some(), obligation_tree_id, } } } -/// The state of one node in some tree within the forest. This -/// represents the current state of processing for the obligation (of -/// type `O`) associated with this node. +/// The state of one node in some tree within the forest. This represents the +/// current state of processing for the obligation (of type `O`) associated +/// with this node. /// /// The non-`Error` state transitions are as follows. /// ``` @@ -219,51 +206,47 @@ impl Node { /// | /// | process_obligations() /// v -/// Success(not_waiting()) -/// | | -/// | | mark_still_waiting_nodes() +/// Success +/// | ^ +/// | | mark_successes() /// | v -/// | Success(still_waiting()) -/// | | -/// | | compress() -/// v v +/// | Waiting +/// | +/// | process_cycles() +/// v +/// Done +/// | +/// | compress() +/// v /// (Removed) /// ``` /// The `Error` state can be introduced in several places, via `error_at()`. /// /// Outside of `ObligationForest` methods, nodes should be either `Pending` or -/// `Success`. +/// `Waiting`. #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum NodeState { /// This obligation has not yet been selected successfully. Cannot have /// subobligations. Pending, - /// This obligation was selected successfully, but it may be waiting on one - /// or more pending subobligations, as indicated by the `WaitingState`. - Success(WaitingState), + /// This obligation was selected successfully, but may or may not have + /// subobligations. + Success, + + /// This obligation was selected successfully, but it has a pending + /// subobligation. + Waiting, + + /// This obligation, along with its subobligations, are complete, and will + /// be removed in the next collection. + Done, /// This obligation was resolved to an error. It will be removed by the /// next compression step. Error, } -/// Indicates when a `Success` node was last (if ever) waiting on one or more -/// `Pending` nodes. The notion of "when" comes from `ObligationForest::gen`. -/// - 0: "Not waiting". This is a special value, set by `process_obligation`, -/// and usable because generation counting starts at 1. -/// - 1..ObligationForest::gen: "Was waiting" in a previous generation, but -/// waiting no longer. In other words, finished. -/// - ObligationForest::gen: "Still waiting" in this generation. -/// -/// Things to note about this encoding: -/// - Every time `ObligationForest::gen` is incremented, all the "still -/// waiting" nodes automatically become "was waiting". -/// - `ObligationForest::is_still_waiting` is very cheap. -/// -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd)] -struct WaitingState(u32); - #[derive(Debug)] pub struct Outcome { /// Obligations that were completely evaluated, including all @@ -300,7 +283,6 @@ impl ObligationForest { pub fn new() -> ObligationForest { ObligationForest { nodes: vec![], - gen: 0, done_cache: Default::default(), active_cache: Default::default(), node_rewrites: RefCell::new(vec![]), @@ -339,11 +321,7 @@ impl ObligationForest { node.dependents.push(parent_index); } } - if let NodeState::Error = node.state.get() { - Err(()) - } else { - Ok(()) - } + if let NodeState::Error = node.state.get() { Err(()) } else { Ok(()) } } Entry::Vacant(v) => { let obligation_tree_id = match parent { @@ -351,12 +329,12 @@ impl ObligationForest { None => self.obligation_tree_id_generator.next().unwrap(), }; - let already_failed = - parent.is_some() - && self.error_cache - .get(&obligation_tree_id) - .map(|errors| errors.contains(obligation.as_predicate())) - .unwrap_or(false); + let already_failed = parent.is_some() + && self + .error_cache + .get(&obligation_tree_id) + .map(|errors| errors.contains(obligation.as_predicate())) + .unwrap_or(false); if already_failed { Err(()) @@ -372,14 +350,12 @@ impl ObligationForest { /// Converts all remaining obligations to the given error. pub fn to_errors(&mut self, error: E) -> Vec> { - let errors = self.nodes.iter().enumerate() + let errors = self + .nodes + .iter() + .enumerate() .filter(|(_index, node)| node.state.get() == NodeState::Pending) - .map(|(index, _node)| { - Error { - error: error.clone(), - backtrace: self.error_at(index), - } - }) + .map(|(index, _node)| Error { error: error.clone(), backtrace: self.error_at(index) }) .collect(); let successful_obligations = self.compress(DoCompleted::Yes); @@ -389,9 +365,11 @@ impl ObligationForest { /// Returns the set of obligations that are in a pending state. pub fn map_pending_obligations(&self, f: F) -> Vec

- where F: Fn(&O) -> P + where + F: Fn(&O) -> P, { - self.nodes.iter() + self.nodes + .iter() .filter(|node| node.state.get() == NodeState::Pending) .map(|node| f(&node.obligation)) .collect() @@ -405,28 +383,18 @@ impl ObligationForest { .insert(node.obligation.as_predicate().clone()); } - fn not_waiting() -> WaitingState { - WaitingState(0) - } - - fn still_waiting(&self) -> WaitingState { - WaitingState(self.gen) - } - - fn is_still_waiting(&self, waiting: WaitingState) -> bool { - waiting.0 == self.gen - } - /// Performs a pass through the obligation list. This must /// be called in a loop until `outcome.stalled` is false. /// /// This _cannot_ be unrolled (presently, at least). - pub fn process_obligations

(&mut self, processor: &mut P, do_completed: DoCompleted) - -> Outcome - where P: ObligationProcessor + pub fn process_obligations

( + &mut self, + processor: &mut P, + do_completed: DoCompleted, + ) -> Outcome + where + P: ObligationProcessor, { - self.gen += 1; - let mut errors = vec![]; let mut stalled = true; @@ -459,13 +427,10 @@ impl ObligationForest { ProcessResult::Changed(children) => { // We are not (yet) stalled. stalled = false; - node.state.set(NodeState::Success(Self::not_waiting())); + node.state.set(NodeState::Success); for child in children { - let st = self.register_obligation_at( - child, - Some(index) - ); + let st = self.register_obligation_at(child, Some(index)); if let Err(()) = st { // Error already reported - propagate it // to our node. @@ -475,10 +440,7 @@ impl ObligationForest { } ProcessResult::Error(err) => { stalled = false; - errors.push(Error { - error: err, - backtrace: self.error_at(index), - }); + errors.push(Error { error: err, backtrace: self.error_at(index) }); } } index += 1; @@ -494,15 +456,11 @@ impl ObligationForest { }; } - self.mark_still_waiting_nodes(); + self.mark_successes(); self.process_cycles(processor); let completed = self.compress(do_completed); - Outcome { - completed, - errors, - stalled, - } + Outcome { completed, errors, stalled } } /// Returns a vector of obligations for `p` and all of its @@ -538,43 +496,53 @@ impl ObligationForest { trace } - /// Mark all `Success` nodes that depend on a pending node as still - /// waiting. Upon completion, any `Success` nodes that aren't still waiting - /// can be removed by `compress`. - fn mark_still_waiting_nodes(&self) { + /// Mark all `Waiting` nodes as `Success`, except those that depend on a + /// pending node. + fn mark_successes(&self) { + // Convert all `Waiting` nodes to `Success`. + for node in &self.nodes { + if node.state.get() == NodeState::Waiting { + node.state.set(NodeState::Success); + } + } + + // Convert `Success` nodes that depend on a pending node back to + // `Waiting`. for node in &self.nodes { if node.state.get() == NodeState::Pending { // This call site is hot. - self.inlined_mark_dependents_as_still_waiting(node); + self.inlined_mark_dependents_as_waiting(node); } } } // This always-inlined function is for the hot call site. #[inline(always)] - fn inlined_mark_dependents_as_still_waiting(&self, node: &Node) { + fn inlined_mark_dependents_as_waiting(&self, node: &Node) { for &index in node.dependents.iter() { let node = &self.nodes[index]; - if let NodeState::Success(waiting) = node.state.get() { - if !self.is_still_waiting(waiting) { - node.state.set(NodeState::Success(self.still_waiting())); - // This call site is cold. - self.uninlined_mark_dependents_as_still_waiting(node); - } + let state = node.state.get(); + if state == NodeState::Success { + node.state.set(NodeState::Waiting); + // This call site is cold. + self.uninlined_mark_dependents_as_waiting(node); + } else { + debug_assert!(state == NodeState::Waiting || state == NodeState::Error) } } } // This never-inlined function is for the cold call site. #[inline(never)] - fn uninlined_mark_dependents_as_still_waiting(&self, node: &Node) { - self.inlined_mark_dependents_as_still_waiting(node) + fn uninlined_mark_dependents_as_waiting(&self, node: &Node) { + self.inlined_mark_dependents_as_waiting(node) } - /// Report cycles between all `Success` nodes that aren't still waiting. - /// This must be called after `mark_still_waiting_nodes`. + /// Report cycles between all `Success` nodes, and convert all `Success` + /// nodes to `Done`. This must be called after `mark_successes`. fn process_cycles

(&self, processor: &mut P) - where P: ObligationProcessor + where + P: ObligationProcessor, { let mut stack = vec![]; @@ -582,41 +550,35 @@ impl ObligationForest { // For some benchmarks this state test is extremely hot. It's a win // to handle the no-op cases immediately to avoid the cost of the // function call. - if let NodeState::Success(waiting) = node.state.get() { - if !self.is_still_waiting(waiting) { - self.find_cycles_from_node(&mut stack, processor, index, index); - } + if node.state.get() == NodeState::Success { + self.find_cycles_from_node(&mut stack, processor, index); } } debug_assert!(stack.is_empty()); } - fn find_cycles_from_node

(&self, stack: &mut Vec, processor: &mut P, min_index: usize, - index: usize) - where P: ObligationProcessor + fn find_cycles_from_node

(&self, stack: &mut Vec, processor: &mut P, index: usize) + where + P: ObligationProcessor, { let node = &self.nodes[index]; - if let NodeState::Success(waiting) = node.state.get() { - if !self.is_still_waiting(waiting) { - match stack.iter().rposition(|&n| n == index) { - None => { - stack.push(index); - for &dep_index in node.dependents.iter() { - // The index check avoids re-considering a node. - if dep_index >= min_index { - self.find_cycles_from_node(stack, processor, min_index, dep_index); - } - } - stack.pop(); - } - Some(rpos) => { - // Cycle detected. - processor.process_backedge( - stack[rpos..].iter().map(GetObligation(&self.nodes)), - PhantomData - ); + if node.state.get() == NodeState::Success { + match stack.iter().rposition(|&n| n == index) { + None => { + stack.push(index); + for &dep_index in node.dependents.iter() { + self.find_cycles_from_node(stack, processor, dep_index); } + stack.pop(); + node.state.set(NodeState::Done); + } + Some(rpos) => { + // Cycle detected. + processor.process_backedge( + stack[rpos..].iter().map(GetObligation(&self.nodes)), + PhantomData, + ); } } } @@ -624,8 +586,7 @@ impl ObligationForest { /// Compresses the vector, removing all popped nodes. This adjusts the /// indices and hence invalidates any outstanding indices. `process_cycles` - /// must be run beforehand to remove any cycles on not-still-waiting - /// `Success` nodes. + /// must be run beforehand to remove any cycles on `Success` nodes. #[inline(never)] fn compress(&mut self, do_completed: DoCompleted) -> Option> { let orig_nodes_len = self.nodes.len(); @@ -633,7 +594,7 @@ impl ObligationForest { debug_assert!(node_rewrites.is_empty()); node_rewrites.extend(0..orig_nodes_len); let mut dead_nodes = 0; - let mut removed_success_obligations: Vec = vec![]; + let mut removed_done_obligations: Vec = vec![]; // Move removable nodes to the end, preserving the order of the // remaining nodes. @@ -645,19 +606,13 @@ impl ObligationForest { for index in 0..orig_nodes_len { let node = &self.nodes[index]; match node.state.get() { - NodeState::Pending => { - if dead_nodes > 0 { - self.nodes.swap(index, index - dead_nodes); - node_rewrites[index] -= dead_nodes; - } - } - NodeState::Success(waiting) if self.is_still_waiting(waiting) => { + NodeState::Pending | NodeState::Waiting => { if dead_nodes > 0 { self.nodes.swap(index, index - dead_nodes); node_rewrites[index] -= dead_nodes; } } - NodeState::Success(_) => { + NodeState::Done => { // This lookup can fail because the contents of // `self.active_cache` are not guaranteed to match those of // `self.nodes`. See the comment in `process_obligation` @@ -671,7 +626,7 @@ impl ObligationForest { } if do_completed == DoCompleted::Yes { // Extract the success stories. - removed_success_obligations.push(node.obligation.clone()); + removed_done_obligations.push(node.obligation.clone()); } node_rewrites[index] = orig_nodes_len; dead_nodes += 1; @@ -685,6 +640,7 @@ impl ObligationForest { node_rewrites[index] = orig_nodes_len; dead_nodes += 1; } + NodeState::Success => unreachable!(), } } @@ -697,11 +653,7 @@ impl ObligationForest { node_rewrites.truncate(0); self.node_rewrites.replace(node_rewrites); - if do_completed == DoCompleted::Yes { - Some(removed_success_obligations) - } else { - None - } + if do_completed == DoCompleted::Yes { Some(removed_done_obligations) } else { None } } fn apply_rewrites(&mut self, node_rewrites: &[usize]) { diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 451913757482a..779081993a16f 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -9,26 +9,25 @@ use Destination::*; -use syntax_pos::{SourceFile, Span, MultiSpan}; use syntax_pos::source_map::SourceMap; +use syntax_pos::{MultiSpan, SourceFile, Span}; +use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString}; +use crate::styled_buffer::StyledBuffer; +use crate::Level::Error; use crate::{ - Level, CodeSuggestion, Diagnostic, SubDiagnostic, pluralize, - SuggestionStyle, DiagnosticId, + pluralize, CodeSuggestion, Diagnostic, DiagnosticId, Level, SubDiagnostic, SuggestionStyle, }; -use crate::Level::Error; -use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style}; -use crate::styled_buffer::StyledBuffer; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use std::borrow::Cow; -use std::io::prelude::*; +use std::cmp::{max, min, Reverse}; use std::io; -use std::cmp::{min, max, Reverse}; +use std::io::prelude::*; use std::path::Path; -use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter, Ansi}; -use termcolor::{WriteColor, Color, Buffer}; +use termcolor::{Ansi, BufferWriter, ColorChoice, ColorSpec, StandardStream}; +use termcolor::{Buffer, Color, WriteColor}; /// Describes the way the content of the `rendered` field of the json output is generated #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -57,8 +56,15 @@ impl HumanReadableErrorType { ) -> EmitterWriter { let (short, color_config) = self.unzip(); let color = color_config.suggests_using_colors(); - EmitterWriter::new(dst, source_map, short, teach, color, terminal_width, - external_macro_backtrace) + EmitterWriter::new( + dst, + source_map, + short, + teach, + color, + terminal_width, + external_macro_backtrace, + ) } } @@ -117,15 +123,15 @@ impl Margin { } fn was_cut_right(&self, line_len: usize) -> bool { - let right = if self.computed_right == self.span_right || - self.computed_right == self.label_right - { - // Account for the "..." padding given above. Otherwise we end up with code lines that - // do fit but end in "..." as if they were trimmed. - self.computed_right - 6 - } else { - self.computed_right - }; + let right = + if self.computed_right == self.span_right || self.computed_right == self.label_right { + // Account for the "..." padding given above. Otherwise we end + // up with code lines that do fit but end in "..." as if they + // were trimmed. + self.computed_right - 6 + } else { + self.computed_right + }; right < line_len && self.computed_left + self.column_width < line_len } @@ -156,7 +162,8 @@ impl Margin { let padding_left = (self.column_width - (self.span_right - self.span_left)) / 5 * 2; self.computed_left = self.span_left.saturating_sub(padding_left); self.computed_right = self.computed_left + self.column_width; - } else { // Mostly give up but still don't show the full line. + } else { + // Mostly give up but still don't show the full line. self.computed_left = self.span_left; self.computed_right = self.span_right; } @@ -240,11 +247,15 @@ pub trait Emitter { format!( "help: {}{}: `{}`", sugg.msg, - if self.source_map().map(|sm| is_case_difference( - &**sm, - substitution, - sugg.substitutions[0].parts[0].span, - )).unwrap_or(false) { + if self + .source_map() + .map(|sm| is_case_difference( + &**sm, + substitution, + sugg.substitutions[0].parts[0].span, + )) + .unwrap_or(false) + { " (notice the capitalization)" } else { "" @@ -271,37 +282,35 @@ pub trait Emitter { // This does a small "fix" for multispans by looking to see if it can find any that // point directly at <*macros>. Since these are often difficult to read, this // will change the span to point at the use site. - fn fix_multispans_in_std_macros(&self, - source_map: &Option>, - span: &mut MultiSpan, - children: &mut Vec, - level: &Level, - backtrace: bool) { + fn fix_multispans_in_std_macros( + &self, + source_map: &Option>, + span: &mut MultiSpan, + children: &mut Vec, + level: &Level, + backtrace: bool, + ) { let mut spans_updated = self.fix_multispan_in_std_macros(source_map, span, backtrace); for child in children.iter_mut() { - spans_updated |= self.fix_multispan_in_std_macros( - source_map, - &mut child.span, - backtrace - ); + spans_updated |= + self.fix_multispan_in_std_macros(source_map, &mut child.span, backtrace); } let msg = if level == &Error { "this error originates in a macro outside of the current crate \ (in Nightly builds, run with -Z external-macro-backtrace \ - for more info)".to_string() + for more info)" + .to_string() } else { "this warning originates in a macro outside of the current crate \ (in Nightly builds, run with -Z external-macro-backtrace \ - for more info)".to_string() + for more info)" + .to_string() }; if spans_updated { children.push(SubDiagnostic { level: Level::Note, - message: vec![ - (msg, - Style::NoStyle), - ], + message: vec![(msg, Style::NoStyle)], span: MultiSpan::new(), render_span: None, }); @@ -311,10 +320,12 @@ pub trait Emitter { // This "fixes" MultiSpans that contain Spans that are pointing to locations inside of // <*macros>. Since these locations are often difficult to read, we move these Spans from // <*macros> to their corresponding use site. - fn fix_multispan_in_std_macros(&self, - source_map: &Option>, - span: &mut MultiSpan, - always_backtrace: bool) -> bool { + fn fix_multispan_in_std_macros( + &self, + source_map: &Option>, + span: &mut MultiSpan, + always_backtrace: bool, + ) -> bool { let sm = match source_map { Some(ref sm) => sm, None => return false, @@ -340,31 +351,40 @@ pub trait Emitter { continue; } if always_backtrace { - new_labels.push((trace.def_site_span, - format!("in this expansion of `{}`{}", - trace.macro_decl_name, - if backtrace_len > 2 { - // if backtrace_len == 1 it'll be pointed - // at by "in this macro invocation" - format!(" (#{})", i + 1) - } else { - String::new() - }))); + new_labels.push(( + trace.def_site_span, + format!( + "in this expansion of `{}`{}", + trace.macro_decl_name, + if backtrace_len > 2 { + // if backtrace_len == 1 it'll be pointed + // at by "in this macro invocation" + format!(" (#{})", i + 1) + } else { + String::new() + } + ), + )); } // Check to make sure we're not in any <*macros> - if !sm.span_to_filename(trace.def_site_span).is_macros() && - !trace.macro_decl_name.starts_with("desugaring of ") && - !trace.macro_decl_name.starts_with("#[") || - always_backtrace { - new_labels.push((trace.call_site, - format!("in this macro invocation{}", - if backtrace_len > 2 && always_backtrace { - // only specify order when the macro - // backtrace is multiple levels deep - format!(" (#{})", i + 1) - } else { - String::new() - }))); + if !sm.span_to_filename(trace.def_site_span).is_macros() + && !trace.macro_decl_name.starts_with("desugaring of ") + && !trace.macro_decl_name.starts_with("#[") + || always_backtrace + { + new_labels.push(( + trace.call_site, + format!( + "in this macro invocation{}", + if backtrace_len > 2 && always_backtrace { + // only specify order when the macro + // backtrace is multiple levels deep + format!(" (#{})", i + 1) + } else { + String::new() + } + ), + )); if !always_backtrace { break; } @@ -378,9 +398,7 @@ pub trait Emitter { if sp_label.span.is_dummy() { continue; } - if sm.span_to_filename(sp_label.span.clone()).is_macros() && - !always_backtrace - { + if sm.span_to_filename(sp_label.span.clone()).is_macros() && !always_backtrace { let v = sp_label.span.macro_backtrace(); if let Some(use_site) = v.last() { before_after.push((sp_label.span.clone(), use_site.call_site.clone())); @@ -406,18 +424,22 @@ impl Emitter for EmitterWriter { let mut children = diag.children.clone(); let (mut primary_span, suggestions) = self.primary_span_formatted(&diag); - self.fix_multispans_in_std_macros(&self.sm, - &mut primary_span, - &mut children, - &diag.level, - self.external_macro_backtrace); - - self.emit_messages_default(&diag.level, - &diag.styled_message(), - &diag.code, - &primary_span, - &children, - &suggestions); + self.fix_multispans_in_std_macros( + &self.sm, + &mut primary_span, + &mut children, + &diag.level, + self.external_macro_backtrace, + ); + + self.emit_messages_default( + &diag.level, + &diag.styled_message(), + &diag.code, + &primary_span, + &children, + &suggestions, + ); } fn should_show_explain(&self) -> bool { @@ -429,7 +451,9 @@ impl Emitter for EmitterWriter { pub struct SilentEmitter; impl Emitter for SilentEmitter { - fn source_map(&self) -> Option<&Lrc> { None } + fn source_map(&self) -> Option<&Lrc> { + None + } fn emit_diagnostic(&mut self, _: &Diagnostic) {} } @@ -458,17 +482,13 @@ impl ColorConfig { } } ColorConfig::Never => ColorChoice::Never, - ColorConfig::Auto if atty::is(atty::Stream::Stderr) => { - ColorChoice::Auto - } + ColorConfig::Auto if atty::is(atty::Stream::Stderr) => ColorChoice::Auto, ColorConfig::Auto => ColorChoice::Never, } } fn suggests_using_colors(self) -> bool { match self { - | ColorConfig::Always - | ColorConfig::Auto - => true, + ColorConfig::Always | ColorConfig::Auto => true, ColorConfig::Never => false, } } @@ -540,11 +560,7 @@ impl EmitterWriter { } fn maybe_anonymized(&self, line_num: usize) -> String { - if self.ui_testing { - ANONYMIZED_LINE_NUM.to_string() - } else { - line_num.to_string() - } + if self.ui_testing { ANONYMIZED_LINE_NUM.to_string() } else { line_num.to_string() } } fn draw_line( @@ -563,17 +579,22 @@ impl EmitterWriter { let right = margin.right(line_len); // On long lines, we strip the source line, accounting for unicode. let mut taken = 0; - let code: String = source_string.chars().skip(left).take_while(|ch| { - // Make sure that the trimming on the right will fall within the terminal width. - // FIXME: `unicode_width` sometimes disagrees with terminals on how wide a `char` is. - // For now, just accept that sometimes the code line will be longer than desired. - let next = unicode_width::UnicodeWidthChar::width(*ch).unwrap_or(1); - if taken + next > right - left { - return false; - } - taken += next; - true - }).collect(); + let code: String = source_string + .chars() + .skip(left) + .take_while(|ch| { + // Make sure that the trimming on the right will fall within the + // terminal width. FIXME: `unicode_width` sometimes disagrees + // with terminals on how wide a `char` is. For now, just accept + // that sometimes the code line will be longer than desired. + let next = unicode_width::UnicodeWidthChar::width(*ch).unwrap_or(1); + if taken + next > right - left { + return false; + } + taken += next; + true + }) + .collect(); buffer.puts(line_offset, code_offset, &code, Style::Quotation); if margin.was_cut_left() { // We have stripped some code/whitespace from the beginning, make it clear. @@ -624,7 +645,9 @@ impl EmitterWriter { let left = margin.left(source_string.len()); // Left trim // Account for unicode characters of width !=0 that were removed. - let left = source_string.chars().take(left) + let left = source_string + .chars() + .take(left) .map(|ch| unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1)) .sum(); @@ -773,13 +796,14 @@ impl EmitterWriter { if overlaps(next, annotation, 0) // This label overlaps with another one and both && annotation.has_label() // take space (they have text and are not && j > i // multiline lines). - && p == 0 // We're currently on the first line, move the label one line down + && p == 0 + // We're currently on the first line, move the label one line down { // If we're overlapping with an un-labelled annotation with the same span // we can just merge them in the output if next.start_col == annotation.start_col - && next.end_col == annotation.end_col - && !next.has_label() + && next.end_col == annotation.end_col + && !next.has_label() { continue; } @@ -791,7 +815,7 @@ impl EmitterWriter { } annotations_position.push((p, annotation)); for (j, next) in annotations.iter().enumerate() { - if j > i { + if j > i { let l = next.label.as_ref().map_or(0, |label| label.len() + 2); if (overlaps(next, annotation, l) // Do not allow two labels to be in the same // line if they overlap including padding, to @@ -814,7 +838,8 @@ impl EmitterWriter { || (overlaps(next, annotation, l) && next.end_col <= annotation.end_col && next.has_label() - && p == 0) // Avoid #42595. + && p == 0) + // Avoid #42595. { // This annotation needs a new line in the output. p += 1; @@ -848,10 +873,7 @@ impl EmitterWriter { // | for pos in 0..=line_len { draw_col_separator(buffer, line_offset + pos + 1, width_offset - 2); - buffer.putc(line_offset + pos + 1, - width_offset - 2, - '|', - Style::LineNumber); + buffer.putc(line_offset + pos + 1, width_offset - 2, '|', Style::LineNumber); } // Write the horizontal lines for multiline annotations @@ -874,8 +896,7 @@ impl EmitterWriter { }; let pos = pos + 1; match annotation.annotation_type { - AnnotationType::MultilineStart(depth) | - AnnotationType::MultilineEnd(depth) => { + AnnotationType::MultilineStart(depth) | AnnotationType::MultilineEnd(depth) => { draw_range( buffer, '_', @@ -919,27 +940,23 @@ impl EmitterWriter { if pos > 1 && (annotation.has_label() || annotation.takes_space()) { for p in line_offset + 1..=line_offset + pos { - buffer.putc(p, - (code_offset + annotation.start_col).saturating_sub(left), - '|', - style); + buffer.putc( + p, + (code_offset + annotation.start_col).saturating_sub(left), + '|', + style, + ); } } match annotation.annotation_type { AnnotationType::MultilineStart(depth) => { for p in line_offset + pos + 1..line_offset + line_len + 2 { - buffer.putc(p, - width_offset + depth - 1, - '|', - style); + buffer.putc(p, width_offset + depth - 1, '|', style); } } AnnotationType::MultilineEnd(depth) => { for p in line_offset..=line_offset + pos { - buffer.putc(p, - width_offset + depth - 1, - '|', - style); + buffer.putc(p, width_offset + depth - 1, '|', style); } } _ => (), @@ -958,11 +975,8 @@ impl EmitterWriter { // 4 | } // | _ test for &(pos, annotation) in &annotations_position { - let style = if annotation.is_primary { - Style::LabelPrimary - } else { - Style::LabelSecondary - }; + let style = + if annotation.is_primary { Style::LabelPrimary } else { Style::LabelSecondary }; let (pos, col) = if pos == 0 { (pos + 1, (annotation.end_col + 1).saturating_sub(left)) } else { @@ -1012,8 +1026,9 @@ impl EmitterWriter { ); } } - annotations_position.iter().filter_map(|&(_, annotation)| { - match annotation.annotation_type { + annotations_position + .iter() + .filter_map(|&(_, annotation)| match annotation.annotation_type { AnnotationType::MultilineStart(p) | AnnotationType::MultilineEnd(p) => { let style = if annotation.is_primary { Style::LabelPrimary @@ -1022,10 +1037,9 @@ impl EmitterWriter { }; Some((p, style)) } - _ => None - } - - }).collect::>() + _ => None, + }) + .collect::>() } fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize { @@ -1055,7 +1069,8 @@ impl EmitterWriter { fn get_max_line_num(&mut self, span: &MultiSpan, children: &[SubDiagnostic]) -> usize { let primary = self.get_multispan_max_line_num(span); - children.iter() + children + .iter() .map(|sub| self.get_multispan_max_line_num(&sub.span)) .max() .unwrap_or(0) @@ -1064,13 +1079,14 @@ impl EmitterWriter { /// Adds a left margin to every line but the first, given a padding length and the label being /// displayed, keeping the provided highlighting. - fn msg_to_buffer(&self, - buffer: &mut StyledBuffer, - msg: &[(String, Style)], - padding: usize, - label: &str, - override_style: Option