<commit_before>use crate::{Applicability, Handler, Level, StashKey};
use crate::{Diagnostic, DiagnosticId, DiagnosticStyledString};

use log::debug;
use rustc_span::{MultiSpan, Span};
use std::fmt::{self, Debug};
use std::ops::{Deref, DerefMut};
use std::thread::panicking;

/// Used for emitting structured error messages and other diagnostic information.
///
/// If there is some state in a downstream crate you would like to
/// access in the methods of `DiagnosticBuilder` here, consider
/// extending `HandlerFlags`, accessed via `self.handler.flags`.
#[must_use]
#[derive(Clone)]
pub struct DiagnosticBuilder<'a>(Box<DiagnosticBuilderInner<'a>>);

/// This is a large type, and often used as a return value, especially within
/// the frequently-used `PResult` type. In theory, return value optimization
/// (RVO) should avoid unnecessary copying. In practice, it does not (at the
/// time of writing). The split between `DiagnosticBuilder` and
/// `DiagnosticBuilderInner` exists to avoid many `memcpy` calls.
#[must_use]
#[derive(Clone)]
struct DiagnosticBuilderInner<'a> {
    handler: &'a Handler,
    diagnostic: Diagnostic,
    allow_suggestions: bool,
}

/// In general, the `DiagnosticBuilder` uses deref to allow access to
/// the fields and methods of the embedded `diagnostic` in a
/// transparent way. *However,* many of the methods are intended to
/// be used in a chained way, and hence ought to return `self`. In
/// that case, we can't just naively forward to the method on the
/// `diagnostic`, because the return type would be a `&Diagnostic`
/// instead of a `&DiagnosticBuilder<'a>`. This `forward!` macro makes
/// it easy to declare such methods on the builder.
macro_rules! forward {
    // Forward pattern for &self -> &Self
    (
        $(#[$attrs:meta])*
        pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)?) -> &Self
    ) => {
        $(#[$attrs])*
        pub fn $n(&self, $($name: $ty),*) -> &Self {
            self.diagnostic.$n($($name),*);
            self
        }
    };

    // Forward pattern for &mut self -> &mut Self
    (
        $(#[$attrs:meta])*
        pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)?) -> &mut Self
    ) => {
        $(#[$attrs])*
        pub fn $n(&mut self, $($name: $ty),*) -> &mut Self {
            self.0.diagnostic.$n($($name),*);
            self
        }
    };

    // Forward pattern for &mut self -> &mut Self, with S: Into<MultiSpan>
    // type parameter. No obvious way to make this more generic.
    (
        $(#[$attrs:meta])*
        pub fn $n:ident<S: Into<MultiSpan>>(
            &mut self,
            $($name:ident: $ty:ty),*
            $(,)?
        ) -> &mut Self
    ) => {
        $(#[$attrs])*
        pub fn $n<S: Into<MultiSpan>>(&mut self, $($name: $ty),*) -> &mut Self {
            self.0.diagnostic.$n($($name),*);
            self
        }
    };
}

impl<'a> Deref for DiagnosticBuilder<'a> {
    type Target = Diagnostic;

    fn deref(&self) -> &Diagnostic {
        &self.0.diagnostic
    }
}

impl<'a> DerefMut for DiagnosticBuilder<'a> {
    fn deref_mut(&mut self) -> &mut Diagnostic {
        &mut self.0.diagnostic
    }
}

impl<'a> DiagnosticBuilder<'a> {
    /// Emit the diagnostic.
    pub fn emit(&mut self) {
        self.0.handler.emit_diagnostic(&self);
        self.cancel();
    }

    /// Emit the diagnostic unless `delay` is true,
    /// in which case the emission will be delayed as a bug.
    ///
    /// See `emit` and `delay_as_bug` for details.
    pub fn emit_unless(&mut self, delay: bool) {
        if delay {
            self.delay_as_bug();
        } else {
            self.emit();
        }
    }

    /// Stashes diagnostic for possible later improvement in a different,
    /// later stage of the compiler. The diagnostic can be accessed with
    /// the provided `span` and `key` through `.steal_diagnostic` on `Handler`.
    ///
    /// As with `buffer`, this is unless the handler has disabled such buffering.
    pub fn stash(self, span: Span, key: StashKey) {
        if let Some((diag, handler)) = self.into_diagnostic() {
            handler.stash_diagnostic(span, key, diag);
        }
    }

    /// Converts the builder to a `Diagnostic` for later emission,
    /// unless handler has disabled such buffering.
    pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a Handler)> {
        if self.0.handler.flags.dont_buffer_diagnostics
            || self.0.handler.flags.treat_err_as_bug.is_some()
        {
            self.emit();
            return None;
        }

        let handler = self.0.handler;

        // We need to use `ptr::read` because `DiagnosticBuilder` implements `Drop`.
        let diagnostic;
        unsafe {
            diagnostic = std::ptr::read(&self.0.diagnostic);
            std::mem::forget(self);
        };
        // Logging here is useful to help track down where in logs an error was
        // actually emitted.
        debug!("buffer: diagnostic={:?}", diagnostic);

        Some((diagnostic, handler))
    }

    /// Buffers the diagnostic for later emission,
    /// unless handler has disabled such buffering.
    pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {
        buffered_diagnostics.extend(self.into_diagnostic().map(|(diag, _)| diag));
    }

    /// Convenience function for internal use, clients should use one of the
    /// span_* methods instead.
    pub fn sub<S: Into<MultiSpan>>(
        &mut self,
        level: Level,
        message: &str,
        span: Option<S>,
    ) -> &mut Self {
        let span = span.map(|s| s.into()).unwrap_or_else(|| MultiSpan::new());
        self.0.diagnostic.sub(level, message, span, None);
        self
    }

    /// Delay emission of this diagnostic as a bug.
    ///
    /// This can be useful in contexts where an error indicates a bug but
    /// typically this only happens when other compilation errors have already
    /// happened. In those cases this can be used to defer emission of this
    /// diagnostic as a bug in the compiler only if no other errors have been
    /// emitted.
    ///
    /// In the meantime, though, callsites are required to deal with the "bug"
    /// locally in whichever way makes the most sense.
    pub fn delay_as_bug(&mut self) {
        self.level = Level::Bug;
        self.0.handler.delay_as_bug(self.0.diagnostic.clone());
        self.cancel();
    }

    /// Adds a span/label to be included in the resulting snippet.
    /// This is pushed onto the `MultiSpan` that was created when the
    /// diagnostic was first built. If you don't call this function at
    /// all, and you just supplied a `Span` to create the diagnostic,
    /// then the snippet will just include that `Span`, which is
    /// called the primary span.
    pub fn span_label(&mut self, span: Span, label: impl Into<String>) -> &mut Self {
        self.0.diagnostic.span_label(span, label);
        self
    }

    /// Labels all the given spans with the provided label.
    /// See `span_label` for more information.
    pub fn span_labels(
        &mut self,
        spans: impl IntoIterator<Item = Span>,
        label: impl AsRef<str>,
    ) -> &mut Self {
        let label = label.as_ref();
        for span in spans {
            self.0.diagnostic.span_label(span, label);
        }
        self
    }

    forward!(pub fn note_expected_found(
        &mut self,
        expected_label: &dyn fmt::Display,
        expected: DiagnosticStyledString,
        found_label: &dyn fmt::Display,
        found: DiagnosticStyledString,
    ) -> &mut Self);

    forward!(pub fn note_expected_found_extra(
        &mut self,
        expected_label: &dyn fmt::Display,
        expected: DiagnosticStyledString,
        found_label: &dyn fmt::Display,
        found: DiagnosticStyledString,
        expected_extra: &dyn fmt::Display,
        found_extra: &dyn fmt::Display,
    ) -> &mut Self);

    forward!(pub fn note_unsuccessfull_coercion(
        &mut self,
        expected: DiagnosticStyledString,
        found: DiagnosticStyledString,
    ) -> &mut Self);

    forward!(pub fn note(&mut self, msg: &str) -> &mut Self);
    forward!(pub fn span_note<S: Into<MultiSpan>>(
        &mut self,
        sp: S,
        msg: &str,
    ) -> &mut Self);
    forward!(pub fn warn(&mut self, msg: &str) -> &mut Self);
    forward!(pub fn span_warn<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self);
    forward!(pub fn help(&mut self, msg: &str) -> &mut Self);
    forward!(pub fn span_help<S: Into<MultiSpan>>(
        &mut self,
        sp: S,
        msg: &str,
    ) -> &mut Self);

    pub fn multipart_suggestion(
        &mut self,
        msg: &str,
        suggestion: Vec<(Span, String)>,
        applicability: Applicability,
    ) -> &mut Self {
        if !self.0.allow_suggestions {
            return self;
        }
        self.0.diagnostic.multipart_suggestion(msg, suggestion, applicability);
        self
    }

    pub fn tool_only_multipart_suggestion(
        &mut self,
        msg: &str,
        suggestion: Vec<(Span, String)>,
        applicability: Applicability,
    ) -> &mut Self {
        if !self.0.allow_suggestions {
            return self;
        }
        self.0.diagnostic.tool_only_multipart_suggestion(msg, suggestion, applicability);
        self
    }

    pub fn span_suggestion(
        &mut self,
        sp: Span,
        msg: &str,
        suggestion: String,
        applicability: Applicability,
    ) -> &mut Self {
        if !self.0.allow_suggestions {
            return self;
        }
        self.0.diagnostic.span_suggestion(sp, msg, suggestion, applicability);
        self
    }

    pub fn span_suggestions(
        &mut self,
        sp: Span,
        msg: &str,
        suggestions: impl Iterator<Item = String>,
        applicability: Applicability,
    ) -> &mut Self {
        if !self.0.allow_suggestions {
            return self;
        }
        self.0.diagnostic.span_suggestions(sp, msg, suggestions, applicability);
        self
    }

    pub fn span_suggestion_short(
        &mut self,
        sp: Span,
        msg: &str,
        suggestion: String,
        applicability: Applicability,
    ) -> &mut Self {
        if !self.0.allow_suggestions {
            return self;
        }
        self.0.diagnostic.span_suggestion_short(sp, msg, suggestion, applicability);
        self
    }

    pub fn span_suggestion_hidden(
        &mut self,
        sp: Span,
        msg: &str,
        suggestion: String,
        applicability: Applicability,
    ) -> &mut Self {
        if !self.0.allow_suggestions {
            return self;
        }
        self.0.diagnostic.span_suggestion_hidden(sp, msg, suggestion, applicability);
        self
    }

    pub fn tool_only_span_suggestion(
        &mut self,
        sp: Span,
        msg: &str,
        suggestion: String,
        applicability: Applicability,
    ) -> &mut Self {
        if !self.0.allow_suggestions {
            return self;
        }
        self.0.diagnostic.tool_only_span_suggestion(sp, msg, suggestion, applicability);
        self
    }

    forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
    forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);

    pub fn allow_suggestions(&mut self, allow: bool) -> &mut Self {
        self.0.allow_suggestions = allow;
        self
    }

    /// Convenience function for internal use, clients should use one of the
    /// struct_* methods on Handler.
    crate fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> {
        DiagnosticBuilder::new_with_code(handler, level, None, message)
    }

    /// Convenience function for internal use, clients should use one of the
    /// struct_* methods on Handler.
    crate fn new_with_code(
        handler: &'a Handler,
        level: Level,
        code: Option<DiagnosticId>,
        message: &str,
    ) -> DiagnosticBuilder<'a> {
        let diagnostic = Diagnostic::new_with_code(level, code, message);
        DiagnosticBuilder::new_diagnostic(handler, diagnostic)
    }

    /// Creates a new `DiagnosticBuilder` with an already constructed
    /// diagnostic.
    crate fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> DiagnosticBuilder<'a> {
        debug!("Created new diagnostic");
        DiagnosticBuilder(Box::new(DiagnosticBuilderInner {
            handler,
            diagnostic,
            allow_suggestions: true,
        }))
    }
}

impl<'a> Debug for DiagnosticBuilder<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.diagnostic.fmt(f)
    }
}

/// Destructor bomb - a `DiagnosticBuilder` must be either emitted or canceled
/// or we emit a bug.
impl<'a> Drop for DiagnosticBuilder<'a> {
    fn drop(&mut self) {
        if !panicking() && !self.cancelled() {
            let mut db = DiagnosticBuilder::new(
                self.0.handler,
                Level::Bug,
                "the following error was constructed but not emitted",
            );
            db.emit();
            self.emit();
            panic!();
        }
    }
}

#[macro_export]
macro_rules! struct_span_err {
    ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
        $session.struct_span_err_with_code(
            $span,
            &format!($($message)*),
            $crate::error_code!($code),
        )
    })
}

#[macro_export]
macro_rules! error_code {
    ($code:ident) => {{ $crate::DiagnosticId::Error(stringify!($code).to_owned()) }};
}
<commit_msg>Rollup merge of #69628 - nnethercote:fix-DiagnosticBuilder-into_diagnostic-leak, r=Centril<commit_after>use crate::{Applicability, Handler, Level, StashKey};
use crate::{Diagnostic, DiagnosticId, DiagnosticStyledString};

use log::debug;
use rustc_span::{MultiSpan, Span};
use std::fmt::{self, Debug};
use std::ops::{Deref, DerefMut};
use std::thread::panicking;

/// Used for emitting structured error messages and other diagnostic information.
///
/// If there is some state in a downstream crate you would like to
/// access in the methods of `DiagnosticBuilder` here, consider
/// extending `HandlerFlags`, accessed via `self.handler.flags`.
#[must_use]
#[derive(Clone)]
pub struct DiagnosticBuilder<'a>(Box<DiagnosticBuilderInner<'a>>);

/// This is a large type, and often used as a return value, especially within
/// the frequently-used `PResult` type. In theory, return value optimization
/// (RVO) should avoid unnecessary copying. In practice, it does not (at the
/// time of writing). The split between `DiagnosticBuilder` and
/// `DiagnosticBuilderInner` exists to avoid many `memcpy` calls.
#[must_use]
#[derive(Clone)]
struct DiagnosticBuilderInner<'a> {
    handler: &'a Handler,
    diagnostic: Diagnostic,
    allow_suggestions: bool,
}

/// In general, the `DiagnosticBuilder` uses deref to allow access to
/// the fields and methods of the embedded `diagnostic` in a
/// transparent way. *However,* many of the methods are intended to
/// be used in a chained way, and hence ought to return `self`. In
/// that case, we can't just naively forward to the method on the
/// `diagnostic`, because the return type would be a `&Diagnostic`
/// instead of a `&DiagnosticBuilder<'a>`. This `forward!` macro makes
/// it easy to declare such methods on the builder.
macro_rules! forward {
    // Forward pattern for &self -> &Self
    (
        $(#[$attrs:meta])*
        pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)?) -> &Self
    ) => {
        $(#[$attrs])*
        pub fn $n(&self, $($name: $ty),*) -> &Self {
            self.diagnostic.$n($($name),*);
            self
        }
    };

    // Forward pattern for &mut self -> &mut Self
    (
        $(#[$attrs:meta])*
        pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)?) -> &mut Self
    ) => {
        $(#[$attrs])*
        pub fn $n(&mut self, $($name: $ty),*) -> &mut Self {
            self.0.diagnostic.$n($($name),*);
            self
        }
    };

    // Forward pattern for &mut self -> &mut Self, with S: Into<MultiSpan>
    // type parameter. No obvious way to make this more generic.
    (
        $(#[$attrs:meta])*
        pub fn $n:ident<S: Into<MultiSpan>>(
            &mut self,
            $($name:ident: $ty:ty),*
            $(,)?
        ) -> &mut Self
    ) => {
        $(#[$attrs])*
        pub fn $n<S: Into<MultiSpan>>(&mut self, $($name: $ty),*) -> &mut Self {
            self.0.diagnostic.$n($($name),*);
            self
        }
    };
}

impl<'a> Deref for DiagnosticBuilder<'a> {
    type Target = Diagnostic;

    fn deref(&self) -> &Diagnostic {
        &self.0.diagnostic
    }
}

impl<'a> DerefMut for DiagnosticBuilder<'a> {
    fn deref_mut(&mut self) -> &mut Diagnostic {
        &mut self.0.diagnostic
    }
}

impl<'a> DiagnosticBuilder<'a> {
    /// Emit the diagnostic.
    pub fn emit(&mut self) {
        self.0.handler.emit_diagnostic(&self);
        self.cancel();
    }

    /// Emit the diagnostic unless `delay` is true,
    /// in which case the emission will be delayed as a bug.
    ///
    /// See `emit` and `delay_as_bug` for details.
    pub fn emit_unless(&mut self, delay: bool) {
        if delay {
            self.delay_as_bug();
        } else {
            self.emit();
        }
    }

    /// Stashes diagnostic for possible later improvement in a different,
    /// later stage of the compiler. The diagnostic can be accessed with
    /// the provided `span` and `key` through `.steal_diagnostic` on `Handler`.
    ///
    /// As with `buffer`, this is unless the handler has disabled such buffering.
    pub fn stash(self, span: Span, key: StashKey) {
        if let Some((diag, handler)) = self.into_diagnostic() {
            handler.stash_diagnostic(span, key, diag);
        }
    }

    /// Converts the builder to a `Diagnostic` for later emission,
    /// unless handler has disabled such buffering.
    pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a Handler)> {
        if self.0.handler.flags.dont_buffer_diagnostics
            || self.0.handler.flags.treat_err_as_bug.is_some()
        {
            self.emit();
            return None;
        }

        let handler = self.0.handler;

        // We must use `Level::Cancelled` for `dummy` to avoid an ICE about an
        // unused diagnostic.
        let dummy = Diagnostic::new(Level::Cancelled, "");
        let diagnostic = std::mem::replace(&mut self.0.diagnostic, dummy);

        // Logging here is useful to help track down where in logs an error was
        // actually emitted.
        debug!("buffer: diagnostic={:?}", diagnostic);

        Some((diagnostic, handler))
    }

    /// Buffers the diagnostic for later emission,
    /// unless handler has disabled such buffering.
    pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {
        buffered_diagnostics.extend(self.into_diagnostic().map(|(diag, _)| diag));
    }

    /// Convenience function for internal use, clients should use one of the
    /// span_* methods instead.
    pub fn sub<S: Into<MultiSpan>>(
        &mut self,
        level: Level,
        message: &str,
        span: Option<S>,
    ) -> &mut Self {
        let span = span.map(|s| s.into()).unwrap_or_else(|| MultiSpan::new());
        self.0.diagnostic.sub(level, message, span, None);
        self
    }

    /// Delay emission of this diagnostic as a bug.
    ///
    /// This can be useful in contexts where an error indicates a bug but
    /// typically this only happens when other compilation errors have already
    /// happened. In those cases this can be used to defer emission of this
    /// diagnostic as a bug in the compiler only if no other errors have been
    /// emitted.
    ///
    /// In the meantime, though, callsites are required to deal with the "bug"
    /// locally in whichever way makes the most sense.
    pub fn delay_as_bug(&mut self) {
        self.level = Level::Bug;
        self.0.handler.delay_as_bug(self.0.diagnostic.clone());
        self.cancel();
    }

    /// Adds a span/label to be included in the resulting snippet.
    /// This is pushed onto the `MultiSpan` that was created when the
    /// diagnostic was first built. If you don't call this function at
    /// all, and you just supplied a `Span` to create the diagnostic,
    /// then the snippet will just include that `Span`, which is
    /// called the primary span.
    pub fn span_label(&mut self, span: Span, label: impl Into<String>) -> &mut Self {
        self.0.diagnostic.span_label(span, label);
        self
    }

    /// Labels all the given spans with the provided label.
    /// See `span_label` for more information.
    pub fn span_labels(
        &mut self,
        spans: impl IntoIterator<Item = Span>,
        label: impl AsRef<str>,
    ) -> &mut Self {
        let label = label.as_ref();
        for span in spans {
            self.0.diagnostic.span_label(span, label);
        }
        self
    }

    forward!(pub fn note_expected_found(
        &mut self,
        expected_label: &dyn fmt::Display,
        expected: DiagnosticStyledString,
        found_label: &dyn fmt::Display,
        found: DiagnosticStyledString,
    ) -> &mut Self);

    forward!(pub fn note_expected_found_extra(
        &mut self,
        expected_label: &dyn fmt::Display,
        expected: DiagnosticStyledString,
        found_label: &dyn fmt::Display,
        found: DiagnosticStyledString,
        expected_extra: &dyn fmt::Display,
        found_extra: &dyn fmt::Display,
    ) -> &mut Self);

    forward!(pub fn note_unsuccessfull_coercion(
        &mut self,
        expected: DiagnosticStyledString,
        found: DiagnosticStyledString,
    ) -> &mut Self);

    forward!(pub fn note(&mut self, msg: &str) -> &mut Self);
    forward!(pub fn span_note<S: Into<MultiSpan>>(
        &mut self,
        sp: S,
        msg: &str,
    ) -> &mut Self);
    forward!(pub fn warn(&mut self, msg: &str) -> &mut Self);
    forward!(pub fn span_warn<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self);
    forward!(pub fn help(&mut self, msg: &str) -> &mut Self);
    forward!(pub fn span_help<S: Into<MultiSpan>>(
        &mut self,
        sp: S,
        msg: &str,
    ) -> &mut Self);

    pub fn multipart_suggestion(
        &mut self,
        msg: &str,
        suggestion: Vec<(Span, String)>,
        applicability: Applicability,
    ) -> &mut Self {
        if !self.0.allow_suggestions {
            return self;
        }
        self.0.diagnostic.multipart_suggestion(msg, suggestion, applicability);
        self
    }

    pub fn tool_only_multipart_suggestion(
        &mut self,
        msg: &str,
        suggestion: Vec<(Span, String)>,
        applicability: Applicability,
    ) -> &mut Self {
        if !self.0.allow_suggestions {
            return self;
        }
        self.0.diagnostic.tool_only_multipart_suggestion(msg, suggestion, applicability);
        self
    }

    pub fn span_suggestion(
        &mut self,
        sp: Span,
        msg: &str,
        suggestion: String,
        applicability: Applicability,
    ) -> &mut Self {
        if !self.0.allow_suggestions {
            return self;
        }
        self.0.diagnostic.span_suggestion(sp, msg, suggestion, applicability);
        self
    }

    pub fn span_suggestions(
        &mut self,
        sp: Span,
        msg: &str,
        suggestions: impl Iterator<Item = String>,
        applicability: Applicability,
    ) -> &mut Self {
        if !self.0.allow_suggestions {
            return self;
        }
        self.0.diagnostic.span_suggestions(sp, msg, suggestions, applicability);
        self
    }

    pub fn span_suggestion_short(
        &mut self,
        sp: Span,
        msg: &str,
        suggestion: String,
        applicability: Applicability,
    ) -> &mut Self {
        if !self.0.allow_suggestions {
            return self;
        }
        self.0.diagnostic.span_suggestion_short(sp, msg, suggestion, applicability);
        self
    }

    pub fn span_suggestion_hidden(
        &mut self,
        sp: Span,
        msg: &str,
        suggestion: String,
        applicability: Applicability,
    ) -> &mut Self {
        if !self.0.allow_suggestions {
            return self;
        }
        self.0.diagnostic.span_suggestion_hidden(sp, msg, suggestion, applicability);
        self
    }

    pub fn tool_only_span_suggestion(
        &mut self,
        sp: Span,
        msg: &str,
        suggestion: String,
        applicability: Applicability,
    ) -> &mut Self {
        if !self.0.allow_suggestions {
            return self;
        }
        self.0.diagnostic.tool_only_span_suggestion(sp, msg, suggestion, applicability);
        self
    }

    forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
    forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);

    pub fn allow_suggestions(&mut self, allow: bool) -> &mut Self {
        self.0.allow_suggestions = allow;
        self
    }

    /// Convenience function for internal use, clients should use one of the
    /// struct_* methods on Handler.
    crate fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> {
        DiagnosticBuilder::new_with_code(handler, level, None, message)
    }

    /// Convenience function for internal use, clients should use one of the
    /// struct_* methods on Handler.
    crate fn new_with_code(
        handler: &'a Handler,
        level: Level,
        code: Option<DiagnosticId>,
        message: &str,
    ) -> DiagnosticBuilder<'a> {
        let diagnostic = Diagnostic::new_with_code(level, code, message);
        DiagnosticBuilder::new_diagnostic(handler, diagnostic)
    }

    /// Creates a new `DiagnosticBuilder` with an already constructed
    /// diagnostic.
    crate fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> DiagnosticBuilder<'a> {
        debug!("Created new diagnostic");
        DiagnosticBuilder(Box::new(DiagnosticBuilderInner {
            handler,
            diagnostic,
            allow_suggestions: true,
        }))
    }
}

impl<'a> Debug for DiagnosticBuilder<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.diagnostic.fmt(f)
    }
}

/// Destructor bomb - a `DiagnosticBuilder` must be either emitted or canceled
/// or we emit a bug.
impl<'a> Drop for DiagnosticBuilder<'a> {
    fn drop(&mut self) {
        if !panicking() && !self.cancelled() {
            let mut db = DiagnosticBuilder::new(
                self.0.handler,
                Level::Bug,
                "the following error was constructed but not emitted",
            );
            db.emit();
            self.emit();
            panic!();
        }
    }
}

#[macro_export]
macro_rules! struct_span_err {
    ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
        $session.struct_span_err_with_code(
            $span,
            &format!($($message)*),
            $crate::error_code!($code),
        )
    })
}

#[macro_export]
macro_rules! error_code {
    ($code:ident) => {{ $crate::DiagnosticId::Error(stringify!($code).to_owned()) }};
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;

struct History {
    h: Vec<(usize, usize)>
}

struct Board {
        board: [usize; 8],
}

impl Board{
    fn new() -> Board {
        Board{
            board: [8,8,8,8,8,8,8,8]
        }
    }

    fn set(&mut self, x: usize, y: usize){
        self.board[x] = y;
    }

    fn get(&self, x: usize) -> usize {
        self.board[x]
    }

    fn pos_set(&self, x: usize, y: usize) -> bool {
        self.get(x) == y
    }

    fn done(&self) -> bool {
        for i in 0..self.board.len() {
            if self.board[i] == 8 {
                return false;
            }
        }
        return true;
    }

    fn print(&self){
        println!("\n---------------------------------");
        for i in 0..8 {
            print!("|");
            for j in 0..8 {
                match self.get(j).cmp(&i) {
                    Ordering::Equal     => print!(" {} |", "X"),
                    Ordering::Greater   => print!(" {} |", " "),
                    Ordering::Less      => print!(" {} |", " "),
                }
            }
            println!("\n---------------------------------");
        }
    }

    fn collision(&self, x: usize, y: usize) -> bool {
        // col
        if self.get(x) != 8 {
            //println!("column true");
            return true;
        }

        for i in 0..8 {
            if self.pos_set(i, y) {
                //println!("row true");
                return true;
            }
        }

        let mut x_pos;
        let mut y_pos;
        if x < (7 - y) {
            x_pos = 0;
            y_pos = y + x;
        } else {
            x_pos = x - (7 - y);
            y_pos = 7;
        }

        loop {
            if self.pos_set(x_pos, y_pos){
                //println!("diag 1 found");
                return true;
            }
            if y_pos == 0 {
                break;
            }
            if x_pos == 7 {
                break;
            }
            x_pos = x_pos + 1;
            y_pos = y_pos - 1;
        }

        let mut x_pos;
        let mut y_pos;
        if y < x {
            x_pos = x - y;
            y_pos = 0;
        } else {
            x_pos = 0;
            y_pos = y - x;
        }

        loop {
            if self.pos_set(x_pos, y_pos){
                //println!("diag 1 found");
                return true;
            }
            if y_pos == 7 {
                break;
            }
            if x_pos == 7 {
                break;
            }
            x_pos = x_pos + 1;
            y_pos = y_pos + 1;
        }

        return false;
    }
}

fn find_my_queens(board: &mut Board, history: &mut History, row: usize, col: usize){
    if board.done() {
        board.print();
        return;
    }

    let r = row % 8;
    let mut c = 0;
    let mut found = false;
    for i in col..8 {
        if !board.collision(i, r){
            c = i;
            found = true;
            break;
        }
    }

    if found {
        board.set(c, r);
        history.h.push((c, r));
        find_my_queens(board, history, r + 1, 0);
    } else {
        match history.h.pop() {
            Some((x,_)) => {
                board.set(x, 8);
                if r == 0 {
                    find_my_queens(board, history, r, x + 1)
                } else {
                    find_my_queens(board, history, r - 1, x + 1)
                }
            }
            None => {}
        }
    }
}

fn main() {

    for i in 0..8 {
        for j in 0..8 {
            let mut board = Board::new();
            let mut history = History { h: vec![] };
            find_my_queens(&mut board, &mut history, j, i);
        }
    }
}
<commit_msg>fix index<commit_after>use std::cmp::Ordering;

struct History {
    h: Vec<(usize, usize)>
}

struct Board {
        board: [usize; 8],
}

impl Board{
    fn new() -> Board {
        Board{
            board: [8,8,8,8,8,8,8,8]
        }
    }

    fn set(&mut self, x: usize, y: usize){
        self.board[x] = y;
    }

    fn get(&self, x: usize) -> usize {
        self.board[x]
    }

    fn pos_set(&self, x: usize, y: usize) -> bool {
        self.get(x) == y
    }

    fn done(&self) -> bool {
        for i in 0..self.board.len() {
            if self.board[i] == 8 {
                return false;
            }
        }
        return true;
    }

    fn print(&self){
        println!("\n---------------------------------");
        for i in 0..8 {
            print!("|");
            for j in 0..8 {
                match self.get(j).cmp(&i) {
                    Ordering::Equal     => print!(" {} |", "X"),
                    Ordering::Greater   => print!(" {} |", " "),
                    Ordering::Less      => print!(" {} |", " "),
                }
            }
            println!("\n---------------------------------");
        }
    }

    fn collision(&self, x: usize, y: usize) -> bool {
        // col
        if self.get(x) != 8 {
            //println!("column true");
            return true;
        }

        for i in 0..8 {
            if self.pos_set(i, y) {
                //println!("row true");
                return true;
            }
        }

        let mut x_pos;
        let mut y_pos;
        if x < (7 - y) {
            x_pos = 0;
            y_pos = y + x;
        } else {
            x_pos = x - (7 - y);
            y_pos = 7;
        }

        loop {
            if self.pos_set(x_pos, y_pos){
                //println!("diag 1 found");
                return true;
            }
            if y_pos == 0 {
                break;
            }
            if x_pos == 7 {
                break;
            }
            x_pos = x_pos + 1;
            y_pos = y_pos - 1;
        }

        let mut x_pos;
        let mut y_pos;
        if y < x {
            x_pos = x - y;
            y_pos = 0;
        } else {
            x_pos = 0;
            y_pos = y - x;
        }

        loop {
            if self.pos_set(x_pos, y_pos){
                //println!("diag 1 found");
                return true;
            }
            if y_pos == 7 {
                break;
            }
            if x_pos == 7 {
                break;
            }
            x_pos = x_pos + 1;
            y_pos = y_pos + 1;
        }

        return false;
    }
}

fn find_my_queens(board: &mut Board, history: &mut History, row: usize, col: usize){
    if board.done() {
        board.print();
        return;
    }

    let r = row % 8;
    let mut c = 0;
    let mut found = false;
    for i in col..8 {
        if !board.collision(i, r){
            c = i;
            found = true;
            break;
        }
    }

    if found {
        board.set(c, r);
        history.h.push((c, r));
        find_my_queens(board, history, r + 1, 0);
    } else {
        match history.h.pop() {
            Some((x,_)) => {
                board.set(x, 8);
                if r == 0 {
                    find_my_queens(board, history, r, x + 1)
                } else {
                    find_my_queens(board, history, r - 1, x + 1)
                }
            }
            None => {}
        }
    }
}

fn main() {

    for i in 0..8 {
        for j in 0..8 {
            let mut board = Board::new();
            let mut history = History { h: vec![] };
            find_my_queens(&mut board, &mut history, i, j);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use futures::{Future, Stream, Sink, IntoFuture};
use futures::future::Either;
use futures::sync::mpsc;
use tokio_core::net::{TcpListener, TcpStream};
use tokio_core::reactor::{Core, Timeout};
use tokio_io::AsyncRead;

use std::net::SocketAddr;
use std::time::Duration;
use std::collections::hash_map::{HashMap, Entry};

use messages::{Any, Connect, RawMessage};
use node::{ExternalMessage, NodeTimeout};

use super::error::{other_error, result_ok, forget_result, into_other, log_error};
use super::codec::MessagesCodec;
use super::handler::{EventsAggregator, EventHandler};

#[derive(Debug)]
pub enum NetworkEvent {
    MessageReceived(SocketAddr, RawMessage),
    PeerConnected(SocketAddr, Connect),
    PeerDisconnected(SocketAddr),
}

#[derive(Debug, Clone)]
pub enum NetworkRequest {
    SendMessage(SocketAddr, RawMessage),
    DisconnectWithPeer(SocketAddr),
}

#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct NetworkConfiguration {
    // TODO: think more about config parameters
    pub max_incoming_connections: usize,
    pub max_outgoing_connections: usize,
    pub tcp_nodelay: bool,
    pub tcp_keep_alive: Option<u32>,
    pub tcp_reconnect_timeout: u64,
    pub tcp_reconnect_timeout_max: u64,
}

impl Default for NetworkConfiguration {
    fn default() -> NetworkConfiguration {
        NetworkConfiguration {
            max_incoming_connections: 128,
            max_outgoing_connections: 128,
            tcp_keep_alive: None,
            tcp_nodelay: false,
            tcp_reconnect_timeout: 500,
            tcp_reconnect_timeout_max: 600000,
        }
    }
}

#[derive(Debug)]
pub struct HandlerPart<H: EventHandler> {
    pub core: Core,
    pub handler: H,
    pub timeout_rx: mpsc::Receiver<NodeTimeout>,
    pub network_rx: mpsc::Receiver<NetworkEvent>,
    pub api_rx: mpsc::Receiver<ExternalMessage>,
}

#[derive(Debug)]
pub struct NetworkPart {
    pub listen_address: SocketAddr,
    pub network_requests: (mpsc::Sender<NetworkRequest>, mpsc::Receiver<NetworkRequest>),
    pub network_tx: mpsc::Sender<NetworkEvent>,
}

impl<H: EventHandler> HandlerPart<H> {
    pub fn run(self) -> Result<(), ()> {
        let mut core = self.core;
        let mut handler = self.handler;

        let events_handle = EventsAggregator::new(self.timeout_rx, self.network_rx, self.api_rx)
            .for_each(move |event| {
                handler.handle_event(event);
                Ok(())
            });
        core.run(events_handle)
    }
}

impl NetworkPart {
    pub fn run(self) -> Result<(), ()> {
       let mut core = Core::new().unwrap();

        // Outgoing connections handler
        let mut outgoing_connections: HashMap<SocketAddr, mpsc::Sender<RawMessage>> =
            HashMap::new();

        // Requests handler
        let handle = core.handle();
        let network_tx = self.network_tx.clone();
        let requests_tx = self.network_requests.0.clone();
        let requests_handle = self.network_requests.1.for_each(|request| {
            match request {
                NetworkRequest::SendMessage(peer, msg) => {
                    let conn_tx = match outgoing_connections.entry(peer) {
                        Entry::Occupied(entry) => entry.get().clone(),
                        Entry::Vacant(entry) => {
                            let (conn_tx, conn_rx) = mpsc::channel(10);
                            let socket = TcpStream::connect(&peer, &handle);

                            let requests_tx = requests_tx.clone();
                            let connect_handle = socket
                                .and_then(move |sock| {
                                    info!("Tokio: Established connection with peer={}", peer);

                                    let stream = sock.framed(MessagesCodec);
                                    let (sink, stream) = stream.split();

                                    let writer = conn_rx
                                        .map_err(|_| other_error("Can't send data into socket"))
                                        .forward(sink);
                                    let reader = stream.for_each(result_ok).map_err(into_other);

                                    reader
                                        .select2(writer)
                                        .map_err(|_| other_error("Socket error"))
                                        .and_then(|res| match res {
                                            Either::A((_, _reader)) => Ok(()).into_future(),
                                            Either::B((_, _writer)) => Ok(()).into_future(),
                                        })
                                })
                                .map_err(log_error)
                                .then(move |_| {
                                    info!("Tokio: Connection with peer={} closed", peer);
                                    let request = NetworkRequest::DisconnectWithPeer(peer);
                                    requests_tx
                                        .clone()
                                        .send(request)
                                        .map(forget_result)
                                        .map_err(into_other)
                                })
                                .map_err(log_error);
                            handle.spawn(connect_handle);

                            entry.insert(conn_tx.clone());
                            conn_tx
                        }
                    };

                    let duration = Duration::from_secs(5);
                    let send_timeout = Timeout::new(duration, &handle)
                        .unwrap()
                        .and_then(result_ok)
                        .map_err(|_| other_error("Can't timeout"));

                    let send_handle = conn_tx.send(msg).map(forget_result).map_err(log_error);

                    let timeouted_connect = send_handle
                        .select2(send_timeout)
                        .map_err(|_| other_error("Unable to send message"))
                        .and_then(move |either| match either {
                            Either::A((send, _timeout_fut)) => Ok(send),
                            Either::B((_, _connect_fut)) => Err(other_error("Send timeout")),
                        })
                        .map_err(log_error);

                    handle.spawn(timeouted_connect);
                }
                NetworkRequest::DisconnectWithPeer(peer) => {
                    outgoing_connections.remove(&peer);

                    let event = NetworkEvent::PeerDisconnected(peer);
                    let event_handle = network_tx.clone().send(event).map(forget_result).map_err(
                        log_error,
                    );
                    handle.spawn(event_handle);
                }
            }

            Ok(())
        });

        // Incoming connections handler
        let listener = TcpListener::bind(&self.listen_address, &core.handle()).unwrap();
        let network_tx = network_tx.clone();
        let server = listener
            .incoming()
            .fold(network_tx, move |network_tx, (sock, addr)| {
                info!("Tokio: Accepted incoming connection with peer={}", addr);

                let stream = sock.framed(MessagesCodec);
                let (_, stream) = stream.split();
                let network_tx = network_tx.clone();
                stream
                    .into_future()
                    .map_err(|e| e.0)
                    .and_then(move |(raw, stream)| {
                        let msg = raw.map(Any::from_raw);
                        if let Some(Ok(Any::Connect(msg))) = msg {
                            Ok((msg, stream))
                        } else {
                            Err(other_error("First message is not Connect"))
                        }
                    })
                    .and_then(move |(connect, stream)| {
                        info!("Tokio: Received handshake message={:?}", connect);

                        let event = NetworkEvent::PeerConnected(addr, connect);
                        let connect_event = network_tx.clone().send(event).map_err(into_other);

                        let network_tx = network_tx.clone();
                        let messages_stream = stream.for_each(move |raw| {
                            let event = NetworkEvent::MessageReceived(addr, raw);
                            network_tx.clone().send(event).map(forget_result).map_err(
                                into_other,
                            )
                        });

                        messages_stream
                            .join(connect_event)
                            .map(move |(_, stream)| stream)
                            .map_err(into_other)
                    })
                    .map_err(into_other)
            })
            .map(forget_result)
            .map_err(log_error);
        core.handle().spawn(server);

        core.run(requests_handle)
    }
}<commit_msg>Remove HashMap::entry<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use futures::{Future, Stream, Sink, IntoFuture};
use futures::future::Either;
use futures::sync::mpsc;
use tokio_core::net::{TcpListener, TcpStream};
use tokio_core::reactor::{Core, Timeout};
use tokio_io::AsyncRead;

use std::net::SocketAddr;
use std::time::Duration;
use std::collections::HashMap;
use std::rc::Rc;

use messages::{Any, Connect, RawMessage};
use node::{ExternalMessage, NodeTimeout};

use super::error::{other_error, result_ok, forget_result, into_other, log_error};
use super::codec::MessagesCodec;
use super::handler::{EventsAggregator, EventHandler};

#[derive(Debug)]
pub enum NetworkEvent {
    MessageReceived(SocketAddr, RawMessage),
    PeerConnected(SocketAddr, Connect),
    PeerDisconnected(SocketAddr),
}

#[derive(Debug, Clone)]
pub enum NetworkRequest {
    SendMessage(SocketAddr, RawMessage),
    DisconnectWithPeer(SocketAddr),
}

#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct NetworkConfiguration {
    // TODO: think more about config parameters
    pub max_incoming_connections: usize,
    pub max_outgoing_connections: usize,
    pub tcp_nodelay: bool,
    pub tcp_keep_alive: Option<u32>,
    pub tcp_reconnect_timeout: u64,
    pub tcp_reconnect_timeout_max: u64,
}

impl Default for NetworkConfiguration {
    fn default() -> NetworkConfiguration {
        NetworkConfiguration {
            max_incoming_connections: 128,
            max_outgoing_connections: 128,
            tcp_keep_alive: None,
            tcp_nodelay: false,
            tcp_reconnect_timeout: 500,
            tcp_reconnect_timeout_max: 600000,
        }
    }
}

#[derive(Debug)]
pub struct HandlerPart<H: EventHandler> {
    pub core: Core,
    pub handler: H,
    pub timeout_rx: mpsc::Receiver<NodeTimeout>,
    pub network_rx: mpsc::Receiver<NetworkEvent>,
    pub api_rx: mpsc::Receiver<ExternalMessage>,
}

#[derive(Debug)]
pub struct NetworkPart {
    pub listen_address: SocketAddr,
    pub network_requests: (mpsc::Sender<NetworkRequest>, mpsc::Receiver<NetworkRequest>),
    pub network_tx: mpsc::Sender<NetworkEvent>,
}

impl<H: EventHandler> HandlerPart<H> {
    pub fn run(self) -> Result<(), ()> {
        let mut core = self.core;
        let mut handler = self.handler;

        let events_handle = EventsAggregator::new(self.timeout_rx, self.network_rx, self.api_rx)
            .for_each(move |event| {
                handler.handle_event(event);
                Ok(())
            });
        core.run(events_handle)
    }
}

impl NetworkPart {
    pub fn run(self) -> Result<(), ()> {
        let mut core = Core::new().unwrap();

        // Outgoing connections handler
        let mut outgoing_connections: HashMap<SocketAddr, mpsc::Sender<RawMessage>> =
            HashMap::new();

        // Requests handler
        let handle = core.handle();
        let network_tx = self.network_tx.clone();
        let requests_tx = self.network_requests.0.clone();
        let requests_handle = self.network_requests.1.for_each(|request| {
            match request {
                NetworkRequest::SendMessage(peer, msg) => {
                    let conn_tx = if let Some(conn_tx) = outgoing_connections.get(&peer).cloned() {
                        conn_tx
                    } else {
                        let (conn_tx, conn_rx) = mpsc::channel(10);
                        outgoing_connections.insert(peer, conn_tx.clone());

                        let requests_tx = requests_tx.clone();
                        let connect_handle = TcpStream::connect(&peer, &handle)
                            .and_then(move |sock| {
                                info!("Established connection with peer={}", peer);

                                let stream = sock.framed(MessagesCodec);
                                let (sink, stream) = stream.split();

                                let writer = conn_rx
                                    .map_err(|_| other_error("Can't send data into socket"))
                                    .forward(sink);
                                let reader = stream.for_each(result_ok).map_err(into_other);

                                reader
                                    .select2(writer)
                                    .map_err(|_| other_error("Socket error"))
                                    .and_then(|res| match res {
                                        Either::A((_, _reader)) => Ok(()).into_future(),
                                        Either::B((_, _writer)) => Ok(()).into_future(),
                                    })
                            })
                            .then(move |res| {
                                info!("Connection with peer={} closed, reason={:?}", peer, res);
                                // outgoing_connections.remove(&peer);

                                let request = NetworkRequest::DisconnectWithPeer(peer);
                                requests_tx
                                    .clone()
                                    .send(request)
                                    .map(forget_result)
                                    .map_err(into_other)
                            }).map_err(log_error);
                        handle.spawn(connect_handle);
                        conn_tx
                    };

                    let duration = Duration::from_secs(5);
                    let send_timeout = Timeout::new(duration, &handle)
                        .unwrap()
                        .and_then(result_ok)
                        .map_err(|_| other_error("Can't timeout"));

                    let send_handle = conn_tx.send(msg).map(forget_result).map_err(log_error);

                    let timeouted_connect = send_handle
                        .select2(send_timeout)
                        .map_err(|_| other_error("Unable to send message"))
                        .and_then(move |either| match either {
                            Either::A((send, _timeout_fut)) => Ok(send),
                            Either::B((_, _connect_fut)) => Err(other_error("Send timeout")),
                        })
                        .map_err(log_error);

                    handle.spawn(timeouted_connect);
                }
                NetworkRequest::DisconnectWithPeer(peer) => {
                    outgoing_connections.remove(&peer);

                    let event = NetworkEvent::PeerDisconnected(peer);
                    let event_handle = network_tx.clone().send(event).map(forget_result).map_err(
                        log_error,
                    );
                    handle.spawn(event_handle);
                }
            }

            Ok(())
        });

        // Incoming connections handler
        let listener = TcpListener::bind(&self.listen_address, &core.handle()).unwrap();
        let network_tx = network_tx.clone();
        let server = listener
            .incoming()
            .fold(network_tx, move |network_tx, (sock, addr)| {
                info!("Accepted incoming connection with peer={}", addr);

                let stream = sock.framed(MessagesCodec);
                let (_, stream) = stream.split();
                let network_tx = network_tx.clone();
                stream
                    .into_future()
                    .map_err(|e| e.0)
                    .and_then(move |(raw, stream)| {
                        let msg = raw.map(Any::from_raw);
                        if let Some(Ok(Any::Connect(msg))) = msg {
                            Ok((msg, stream))
                        } else {
                            Err(other_error("First message is not Connect"))
                        }
                    })
                    .and_then(move |(connect, stream)| {
                        info!("Received handshake message={:?}", connect);

                        let event = NetworkEvent::PeerConnected(addr, connect);
                        let connect_event = network_tx.clone().send(event).map_err(into_other);

                        let network_tx = network_tx.clone();
                        let messages_stream = stream.for_each(move |raw| {
                            let event = NetworkEvent::MessageReceived(addr, raw);
                            network_tx.clone().send(event).map(forget_result).map_err(
                                into_other,
                            )
                        });

                        messages_stream
                            .join(connect_event)
                            .map(move |(_, stream)| stream)
                            .map_err(into_other)
                    })
                    .map_err(into_other)
            })
            .map(forget_result)
            .map_err(log_error);
        core.handle().spawn(server);

        core.run(requests_handle)
    }
}<|endoftext|>


<commit_before>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::str::FromStr;
use std::io::prelude::*;
use std::path::Path;

use clap::ArgMatches;
use failure::SyncFailure;
use handlebars::Handlebars;
use hcore::package::{PackageArchive, PackageIdent};
use common::ui::UI;
use rand;
use rand::Rng;

use export_docker::Result;

use topology::Topology;
use error::Error;

// Kubernetes manifest template
const MANIFESTFILE: &'static str = include_str!("../defaults/KubernetesManifest.hbs");
const BINDFILE: &'static str = include_str!("../defaults/KubernetesBind.hbs");

#[derive(Debug, Clone)]
pub struct Manifest {
    metadata_name: String,
    habitat_name: String,
    image: String,
    count: u64,
    service_topology: Topology,
    service_group: Option<String>,
    config_secret_name: Option<String>,
    ring_secret_name: Option<String>,
    // TODO: Represent binds with a struct
    binds: Vec<String>,
}

impl Manifest {
    pub fn new_from_cli_matches(_ui: &mut UI, matches: &ArgMatches) -> Result<Self> {
        let count = matches.value_of("COUNT").unwrap_or("1").parse()?;
        let topology: Topology = FromStr::from_str(
            matches.value_of("TOPOLOGY").unwrap_or("standalone"),
        ).unwrap_or(Topology::Standalone);
        let group = matches.value_of("GROUP").map(|s| s.to_string());
        let config_secret_name = matches.value_of("CONFIG_SECRET_NAME").map(
            |s| s.to_string(),
        );
        let ring_secret_name = matches.value_of("RING_SECRET_NAME").map(|s| s.to_string());
        // clap ensures that we do have the mandatory args so unwrap() is fine here
        let pkg_ident_str = matches.value_of("PKG_IDENT_OR_ARTIFACT").expect(
            "No package specified",
        );
        let pkg_ident = if Path::new(pkg_ident_str).is_file() {
            // We're going to use the `$pkg_origin/$pkg_name`, fuzzy form of a package
            // identifier to ensure that update strategies will work if desired
            PackageArchive::new(pkg_ident_str).ident()?
        } else {
            PackageIdent::from_str(pkg_ident_str)?
        };

        // To allow multiple instances of Habitat application in Kubernetes,
        // random suffix in metadata_name is needed.
        let metadata_name = format!(
            "{}-{}{}",
            pkg_ident.name,
            rand::thread_rng()
                .gen_ascii_chars()
                .filter(|c| c.is_lowercase() || c.is_numeric())
                .take(4)
                .collect::<String>(),
            rand::thread_rng()
                .gen_ascii_chars()
                .filter(|c| c.is_lowercase() && !c.is_numeric())
                .take(1)
                .collect::<String>()
        );

        let image = match matches.value_of("IMAGE_NAME") {
            Some(i) => i.to_string(),
            None => pkg_ident.origin + "/" + &pkg_ident.name,
        };

        let binds: Vec<String> = match matches.values_of("BIND") {
            Some(binds) => binds.map(|s| s.to_string()).collect(),
            None => Vec::new(),
        };

        Ok(Manifest {
            metadata_name: metadata_name,
            habitat_name: pkg_ident.name,
            image: image,
            count: count,
            service_topology: topology,
            service_group: group,
            config_secret_name: config_secret_name,
            ring_secret_name: ring_secret_name,
            binds: binds,
        })
    }

    pub fn generate(&mut self, write: &mut Write) -> Result<()> {
        let json = json!({
            "metadata_name": self.metadata_name,
            "habitat_name": self.habitat_name,
            "image": self.image,
            "count": self.count,
            "service_topology": self.service_topology.to_string(),
            "service_group": self.service_group,
            "config_secret_name": self.config_secret_name,
            "ring_secret_name": self.ring_secret_name,
            "bind": self.binds,
        });

        let r = Handlebars::new()
            .template_render(MANIFESTFILE, &json)
            .map_err(SyncFailure::new)?;
        let mut out = r.lines().filter(|l| *l != "").collect::<Vec<_>>().join(
            "\n",
        ) + "\n";

        for bind in &self.binds {
            let split: Vec<&str> = bind.split(":").collect();
            if split.len() < 3 {
                return Err(Error::InvalidBindSpec(bind.to_string()).into());
            }

            let json = json!({
                "name": split[0],
                "service": split[1],
                "group": split[2],
            });

            out += &Handlebars::new().template_render(BINDFILE, &json).map_err(
                SyncFailure::new,
            )?;
        }

        write.write(out.as_bytes())?;

        Ok(())
    }
}
<commit_msg>pkg-export-k8s: Simplify random str generation a bit<commit_after>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::str::FromStr;
use std::io::prelude::*;
use std::path::Path;

use clap::ArgMatches;
use failure::SyncFailure;
use handlebars::Handlebars;
use hcore::package::{PackageArchive, PackageIdent};
use common::ui::UI;
use rand;
use rand::Rng;

use export_docker::Result;

use topology::Topology;
use error::Error;

// Kubernetes manifest template
const MANIFESTFILE: &'static str = include_str!("../defaults/KubernetesManifest.hbs");
const BINDFILE: &'static str = include_str!("../defaults/KubernetesBind.hbs");

#[derive(Debug, Clone)]
pub struct Manifest {
    metadata_name: String,
    habitat_name: String,
    image: String,
    count: u64,
    service_topology: Topology,
    service_group: Option<String>,
    config_secret_name: Option<String>,
    ring_secret_name: Option<String>,
    // TODO: Represent binds with a struct
    binds: Vec<String>,
}

impl Manifest {
    pub fn new_from_cli_matches(_ui: &mut UI, matches: &ArgMatches) -> Result<Self> {
        let count = matches.value_of("COUNT").unwrap_or("1").parse()?;
        let topology: Topology = FromStr::from_str(
            matches.value_of("TOPOLOGY").unwrap_or("standalone"),
        ).unwrap_or(Topology::Standalone);
        let group = matches.value_of("GROUP").map(|s| s.to_string());
        let config_secret_name = matches.value_of("CONFIG_SECRET_NAME").map(
            |s| s.to_string(),
        );
        let ring_secret_name = matches.value_of("RING_SECRET_NAME").map(|s| s.to_string());
        // clap ensures that we do have the mandatory args so unwrap() is fine here
        let pkg_ident_str = matches.value_of("PKG_IDENT_OR_ARTIFACT").expect(
            "No package specified",
        );
        let pkg_ident = if Path::new(pkg_ident_str).is_file() {
            // We're going to use the `$pkg_origin/$pkg_name`, fuzzy form of a package
            // identifier to ensure that update strategies will work if desired
            PackageArchive::new(pkg_ident_str).ident()?
        } else {
            PackageIdent::from_str(pkg_ident_str)?
        };

        // To allow multiple instances of Habitat application in Kubernetes,
        // random suffix in metadata_name is needed.
        let metadata_name =
            format!(
            "{}-{}",
            pkg_ident.name,
            rand::thread_rng()
                .gen_ascii_chars()
                .filter(|c| c.is_lowercase() || c.is_numeric())
                .take(5)
                .collect::<String>(),
        );

        let image = match matches.value_of("IMAGE_NAME") {
            Some(i) => i.to_string(),
            None => pkg_ident.origin + "/" + &pkg_ident.name,
        };

        let binds: Vec<String> = match matches.values_of("BIND") {
            Some(binds) => binds.map(|s| s.to_string()).collect(),
            None => Vec::new(),
        };

        Ok(Manifest {
            metadata_name: metadata_name,
            habitat_name: pkg_ident.name,
            image: image,
            count: count,
            service_topology: topology,
            service_group: group,
            config_secret_name: config_secret_name,
            ring_secret_name: ring_secret_name,
            binds: binds,
        })
    }

    pub fn generate(&mut self, write: &mut Write) -> Result<()> {
        let json = json!({
            "metadata_name": self.metadata_name,
            "habitat_name": self.habitat_name,
            "image": self.image,
            "count": self.count,
            "service_topology": self.service_topology.to_string(),
            "service_group": self.service_group,
            "config_secret_name": self.config_secret_name,
            "ring_secret_name": self.ring_secret_name,
            "bind": self.binds,
        });

        let r = Handlebars::new()
            .template_render(MANIFESTFILE, &json)
            .map_err(SyncFailure::new)?;
        let mut out = r.lines().filter(|l| *l != "").collect::<Vec<_>>().join(
            "\n",
        ) + "\n";

        for bind in &self.binds {
            let split: Vec<&str> = bind.split(":").collect();
            if split.len() < 3 {
                return Err(Error::InvalidBindSpec(bind.to_string()).into());
            }

            let json = json!({
                "name": split[0],
                "service": split[1],
                "group": split[2],
            });

            out += &Handlebars::new().template_render(BINDFILE, &json).map_err(
                SyncFailure::new,
            )?;
        }

        write.write(out.as_bytes())?;

        Ok(())
    }
}
<|endoftext|>


<commit_before><commit_msg>Suppress cast_lossless lint<commit_after><|endoftext|>


<commit_before>//! Diagnostics related methods for `TyS`.

use crate::ty::TyKind::*;
use crate::ty::{InferTy, TyCtxt, TyS};
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate};

impl<'tcx> TyS<'tcx> {
    /// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive.
    pub fn is_primitive_ty(&self) -> bool {
        matches!(
            self.kind(),
            Bool | Char
                | Str
                | Int(_)
                | Uint(_)
                | Float(_)
                | Infer(
                    InferTy::IntVar(_)
                        | InferTy::FloatVar(_)
                        | InferTy::FreshIntTy(_)
                        | InferTy::FreshFloatTy(_)
                )
        )
    }

    /// Whether the type is succinctly representable as a type instead of just referred to with a
    /// description in error messages. This is used in the main error message.
    pub fn is_simple_ty(&self) -> bool {
        match self.kind() {
            Bool
            | Char
            | Str
            | Int(_)
            | Uint(_)
            | Float(_)
            | Infer(
                InferTy::IntVar(_)
                | InferTy::FloatVar(_)
                | InferTy::FreshIntTy(_)
                | InferTy::FreshFloatTy(_),
            ) => true,
            Ref(_, x, _) | Array(x, _) | Slice(x) => x.peel_refs().is_simple_ty(),
            Tuple(tys) if tys.is_empty() => true,
            _ => false,
        }
    }

    /// Whether the type is succinctly representable as a type instead of just referred to with a
    /// description in error messages. This is used in the primary span label. Beyond what
    /// `is_simple_ty` includes, it also accepts ADTs with no type arguments and references to
    /// ADTs with no type arguments.
    pub fn is_simple_text(&self) -> bool {
        match self.kind() {
            Adt(_, substs) => substs.types().next().is_none() && substs.consts().next().is_none(),
            Ref(_, ty, _) => ty.is_simple_text(),
            _ => self.is_simple_ty(),
        }
    }

    /// Whether the type can be safely suggested during error recovery.
    pub fn is_suggestable(&self) -> bool {
        !matches!(
            self.kind(),
            Opaque(..)
                | FnDef(..)
                | FnPtr(..)
                | Dynamic(..)
                | Closure(..)
                | Infer(..)
                | Projection(..)
        )
    }
}

pub fn suggest_arbitrary_trait_bound(
    generics: &hir::Generics<'_>,
    err: &mut DiagnosticBuilder<'_>,
    param_name: &str,
    constraint: &str,
) -> bool {
    let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
    match (param, param_name) {
        (Some(_), "Self") => return false,
        _ => {}
    }
    // Suggest a where clause bound for a non-type paremeter.
    let (action, prefix) = if generics.where_clause.predicates.is_empty() {
        ("introducing a", " where ")
    } else {
        ("extending the", ", ")
    };
    err.span_suggestion_verbose(
        generics.where_clause.tail_span_for_suggestion(),
        &format!(
            "consider {} `where` bound, but there might be an alternative better way to express \
             this requirement",
            action,
        ),
        format!("{}{}: {}", prefix, param_name, constraint),
        Applicability::MaybeIncorrect,
    );
    true
}

/// Suggest restricting a type param with a new bound.
pub fn suggest_constraining_type_param(
    tcx: TyCtxt<'_>,
    generics: &hir::Generics<'_>,
    err: &mut DiagnosticBuilder<'_>,
    param_name: &str,
    constraint: &str,
    def_id: Option<DefId>,
) -> bool {
    let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);

    let param = if let Some(param) = param {
        param
    } else {
        return false;
    };

    const MSG_RESTRICT_BOUND_FURTHER: &str = "consider further restricting this bound";
    let msg_restrict_type = format!("consider restricting type parameter `{}`", param_name);
    let msg_restrict_type_further =
        format!("consider further restricting type parameter `{}`", param_name);

    if def_id == tcx.lang_items().sized_trait() {
        // Type parameters are already `Sized` by default.
        err.span_label(param.span, &format!("this type parameter needs to be `{}`", constraint));
        return true;
    }
    let mut suggest_restrict = |span| {
        err.span_suggestion_verbose(
            span,
            MSG_RESTRICT_BOUND_FURTHER,
            format!(" + {}", constraint),
            Applicability::MachineApplicable,
        );
    };

    if param_name.starts_with("impl ") {
        // If there's an `impl Trait` used in argument position, suggest
        // restricting it:
        //
        //   fn foo(t: impl Foo) { ... }
        //             --------
        //             |
        //             help: consider further restricting this bound with `+ Bar`
        //
        // Suggestion for tools in this case is:
        //
        //   fn foo(t: impl Foo) { ... }
        //             --------
        //             |
        //             replace with: `impl Foo + Bar`

        suggest_restrict(param.span.shrink_to_hi());
        return true;
    }

    if generics.where_clause.predicates.is_empty()
        // Given `trait Base<T = String>: Super<T>` where `T: Copy`, suggest restricting in the
        // `where` clause instead of `trait Base<T: Copy = String>: Super<T>`.
        && !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
    {
        if let Some(bounds_span) = param.bounds_span() {
            // If user has provided some bounds, suggest restricting them:
            //
            //   fn foo<T: Foo>(t: T) { ... }
            //             ---
            //             |
            //             help: consider further restricting this bound with `+ Bar`
            //
            // Suggestion for tools in this case is:
            //
            //   fn foo<T: Foo>(t: T) { ... }
            //          --
            //          |
            //          replace with: `T: Bar +`
            suggest_restrict(bounds_span.shrink_to_hi());
        } else {
            // If user hasn't provided any bounds, suggest adding a new one:
            //
            //   fn foo<T>(t: T) { ... }
            //          - help: consider restricting this type parameter with `T: Foo`
            err.span_suggestion_verbose(
                param.span.shrink_to_hi(),
                &msg_restrict_type,
                format!(": {}", constraint),
                Applicability::MachineApplicable,
            );
        }

        true
    } else {
        // This part is a bit tricky, because using the `where` clause user can
        // provide zero, one or many bounds for the same type parameter, so we
        // have following cases to consider:
        //
        // 1) When the type parameter has been provided zero bounds
        //
        //    Message:
        //      fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
        //             - help: consider restricting this type parameter with `where X: Bar`
        //
        //    Suggestion:
        //      fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
        //                                           - insert: `, X: Bar`
        //
        //
        // 2) When the type parameter has been provided one bound
        //
        //    Message:
        //      fn foo<T>(t: T) where T: Foo { ... }
        //                            ^^^^^^
        //                            |
        //                            help: consider further restricting this bound with `+ Bar`
        //
        //    Suggestion:
        //      fn foo<T>(t: T) where T: Foo { ... }
        //                            ^^
        //                            |
        //                            replace with: `T: Bar +`
        //
        //
        // 3) When the type parameter has been provided many bounds
        //
        //    Message:
        //      fn foo<T>(t: T) where T: Foo, T: Bar {... }
        //             - help: consider further restricting this type parameter with `where T: Zar`
        //
        //    Suggestion:
        //      fn foo<T>(t: T) where T: Foo, T: Bar {... }
        //                                          - insert: `, T: Zar`
        //
        // Additionally, there may be no `where` clause whatsoever in the case that this was
        // reached because the generic parameter has a default:
        //
        //    Message:
        //      trait Foo<T=()> {... }
        //             - help: consider further restricting this type parameter with `where T: Zar`
        //
        //    Suggestion:
        //      trait Foo<T=()> where T: Zar {... }
        //                     - insert: `where T: Zar`

        if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
            && generics.where_clause.predicates.len() == 0
        {
            // Suggest a bound, but there is no existing `where` clause *and* the type param has a
            // default (`<T=Foo>`), so we suggest adding `where T: Bar`.
            err.span_suggestion_verbose(
                generics.where_clause.tail_span_for_suggestion(),
                &msg_restrict_type_further,
                format!(" where {}: {}", param_name, constraint),
                Applicability::MachineApplicable,
            );
        } else {
            let mut param_spans = Vec::new();

            for predicate in generics.where_clause.predicates {
                if let WherePredicate::BoundPredicate(WhereBoundPredicate {
                    span,
                    bounded_ty,
                    ..
                }) = predicate
                {
                    if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind {
                        if let Some(segment) = path.segments.first() {
                            if segment.ident.to_string() == param_name {
                                param_spans.push(span);
                            }
                        }
                    }
                }
            }

            match param_spans[..] {
                [&param_span] => suggest_restrict(param_span.shrink_to_hi()),
                _ => {
                    err.span_suggestion_verbose(
                        generics.where_clause.tail_span_for_suggestion(),
                        &msg_restrict_type_further,
                        format!(", {}: {}", param_name, constraint),
                        Applicability::MachineApplicable,
                    );
                }
            }
        }

        true
    }
}

/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>);

impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
    type Map = rustc_hir::intravisit::ErasedMap<'v>;

    fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
        hir::intravisit::NestedVisitorMap::None
    }

    fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
        match ty.kind {
            hir::TyKind::TraitObject(
                _,
                hir::Lifetime {
                    name:
                        hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
                    ..
                },
                _,
            ) => {
                self.0.push(ty);
            }
            hir::TyKind::OpaqueDef(item_id, _) => {
                self.0.push(ty);
                let item = self.1.item(item_id);
                hir::intravisit::walk_item(self, item);
            }
            _ => {}
        }
        hir::intravisit::walk_ty(self, ty);
    }
}
<commit_msg>use non_erasable_generics<commit_after>//! Diagnostics related methods for `TyS`.

use crate::ty::TyKind::*;
use crate::ty::{InferTy, TyCtxt, TyS};
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate};

impl<'tcx> TyS<'tcx> {
    /// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive.
    pub fn is_primitive_ty(&self) -> bool {
        matches!(
            self.kind(),
            Bool | Char
                | Str
                | Int(_)
                | Uint(_)
                | Float(_)
                | Infer(
                    InferTy::IntVar(_)
                        | InferTy::FloatVar(_)
                        | InferTy::FreshIntTy(_)
                        | InferTy::FreshFloatTy(_)
                )
        )
    }

    /// Whether the type is succinctly representable as a type instead of just referred to with a
    /// description in error messages. This is used in the main error message.
    pub fn is_simple_ty(&self) -> bool {
        match self.kind() {
            Bool
            | Char
            | Str
            | Int(_)
            | Uint(_)
            | Float(_)
            | Infer(
                InferTy::IntVar(_)
                | InferTy::FloatVar(_)
                | InferTy::FreshIntTy(_)
                | InferTy::FreshFloatTy(_),
            ) => true,
            Ref(_, x, _) | Array(x, _) | Slice(x) => x.peel_refs().is_simple_ty(),
            Tuple(tys) if tys.is_empty() => true,
            _ => false,
        }
    }

    /// Whether the type is succinctly representable as a type instead of just referred to with a
    /// description in error messages. This is used in the primary span label. Beyond what
    /// `is_simple_ty` includes, it also accepts ADTs with no type arguments and references to
    /// ADTs with no type arguments.
    pub fn is_simple_text(&self) -> bool {
        match self.kind() {
            Adt(_, substs) => substs.non_erasable_generics().next().is_none(),
            Ref(_, ty, _) => ty.is_simple_text(),
            _ => self.is_simple_ty(),
        }
    }

    /// Whether the type can be safely suggested during error recovery.
    pub fn is_suggestable(&self) -> bool {
        !matches!(
            self.kind(),
            Opaque(..)
                | FnDef(..)
                | FnPtr(..)
                | Dynamic(..)
                | Closure(..)
                | Infer(..)
                | Projection(..)
        )
    }
}

pub fn suggest_arbitrary_trait_bound(
    generics: &hir::Generics<'_>,
    err: &mut DiagnosticBuilder<'_>,
    param_name: &str,
    constraint: &str,
) -> bool {
    let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
    match (param, param_name) {
        (Some(_), "Self") => return false,
        _ => {}
    }
    // Suggest a where clause bound for a non-type paremeter.
    let (action, prefix) = if generics.where_clause.predicates.is_empty() {
        ("introducing a", " where ")
    } else {
        ("extending the", ", ")
    };
    err.span_suggestion_verbose(
        generics.where_clause.tail_span_for_suggestion(),
        &format!(
            "consider {} `where` bound, but there might be an alternative better way to express \
             this requirement",
            action,
        ),
        format!("{}{}: {}", prefix, param_name, constraint),
        Applicability::MaybeIncorrect,
    );
    true
}

/// Suggest restricting a type param with a new bound.
pub fn suggest_constraining_type_param(
    tcx: TyCtxt<'_>,
    generics: &hir::Generics<'_>,
    err: &mut DiagnosticBuilder<'_>,
    param_name: &str,
    constraint: &str,
    def_id: Option<DefId>,
) -> bool {
    let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);

    let param = if let Some(param) = param {
        param
    } else {
        return false;
    };

    const MSG_RESTRICT_BOUND_FURTHER: &str = "consider further restricting this bound";
    let msg_restrict_type = format!("consider restricting type parameter `{}`", param_name);
    let msg_restrict_type_further =
        format!("consider further restricting type parameter `{}`", param_name);

    if def_id == tcx.lang_items().sized_trait() {
        // Type parameters are already `Sized` by default.
        err.span_label(param.span, &format!("this type parameter needs to be `{}`", constraint));
        return true;
    }
    let mut suggest_restrict = |span| {
        err.span_suggestion_verbose(
            span,
            MSG_RESTRICT_BOUND_FURTHER,
            format!(" + {}", constraint),
            Applicability::MachineApplicable,
        );
    };

    if param_name.starts_with("impl ") {
        // If there's an `impl Trait` used in argument position, suggest
        // restricting it:
        //
        //   fn foo(t: impl Foo) { ... }
        //             --------
        //             |
        //             help: consider further restricting this bound with `+ Bar`
        //
        // Suggestion for tools in this case is:
        //
        //   fn foo(t: impl Foo) { ... }
        //             --------
        //             |
        //             replace with: `impl Foo + Bar`

        suggest_restrict(param.span.shrink_to_hi());
        return true;
    }

    if generics.where_clause.predicates.is_empty()
        // Given `trait Base<T = String>: Super<T>` where `T: Copy`, suggest restricting in the
        // `where` clause instead of `trait Base<T: Copy = String>: Super<T>`.
        && !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
    {
        if let Some(bounds_span) = param.bounds_span() {
            // If user has provided some bounds, suggest restricting them:
            //
            //   fn foo<T: Foo>(t: T) { ... }
            //             ---
            //             |
            //             help: consider further restricting this bound with `+ Bar`
            //
            // Suggestion for tools in this case is:
            //
            //   fn foo<T: Foo>(t: T) { ... }
            //          --
            //          |
            //          replace with: `T: Bar +`
            suggest_restrict(bounds_span.shrink_to_hi());
        } else {
            // If user hasn't provided any bounds, suggest adding a new one:
            //
            //   fn foo<T>(t: T) { ... }
            //          - help: consider restricting this type parameter with `T: Foo`
            err.span_suggestion_verbose(
                param.span.shrink_to_hi(),
                &msg_restrict_type,
                format!(": {}", constraint),
                Applicability::MachineApplicable,
            );
        }

        true
    } else {
        // This part is a bit tricky, because using the `where` clause user can
        // provide zero, one or many bounds for the same type parameter, so we
        // have following cases to consider:
        //
        // 1) When the type parameter has been provided zero bounds
        //
        //    Message:
        //      fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
        //             - help: consider restricting this type parameter with `where X: Bar`
        //
        //    Suggestion:
        //      fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
        //                                           - insert: `, X: Bar`
        //
        //
        // 2) When the type parameter has been provided one bound
        //
        //    Message:
        //      fn foo<T>(t: T) where T: Foo { ... }
        //                            ^^^^^^
        //                            |
        //                            help: consider further restricting this bound with `+ Bar`
        //
        //    Suggestion:
        //      fn foo<T>(t: T) where T: Foo { ... }
        //                            ^^
        //                            |
        //                            replace with: `T: Bar +`
        //
        //
        // 3) When the type parameter has been provided many bounds
        //
        //    Message:
        //      fn foo<T>(t: T) where T: Foo, T: Bar {... }
        //             - help: consider further restricting this type parameter with `where T: Zar`
        //
        //    Suggestion:
        //      fn foo<T>(t: T) where T: Foo, T: Bar {... }
        //                                          - insert: `, T: Zar`
        //
        // Additionally, there may be no `where` clause whatsoever in the case that this was
        // reached because the generic parameter has a default:
        //
        //    Message:
        //      trait Foo<T=()> {... }
        //             - help: consider further restricting this type parameter with `where T: Zar`
        //
        //    Suggestion:
        //      trait Foo<T=()> where T: Zar {... }
        //                     - insert: `where T: Zar`

        if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
            && generics.where_clause.predicates.len() == 0
        {
            // Suggest a bound, but there is no existing `where` clause *and* the type param has a
            // default (`<T=Foo>`), so we suggest adding `where T: Bar`.
            err.span_suggestion_verbose(
                generics.where_clause.tail_span_for_suggestion(),
                &msg_restrict_type_further,
                format!(" where {}: {}", param_name, constraint),
                Applicability::MachineApplicable,
            );
        } else {
            let mut param_spans = Vec::new();

            for predicate in generics.where_clause.predicates {
                if let WherePredicate::BoundPredicate(WhereBoundPredicate {
                    span,
                    bounded_ty,
                    ..
                }) = predicate
                {
                    if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind {
                        if let Some(segment) = path.segments.first() {
                            if segment.ident.to_string() == param_name {
                                param_spans.push(span);
                            }
                        }
                    }
                }
            }

            match param_spans[..] {
                [&param_span] => suggest_restrict(param_span.shrink_to_hi()),
                _ => {
                    err.span_suggestion_verbose(
                        generics.where_clause.tail_span_for_suggestion(),
                        &msg_restrict_type_further,
                        format!(", {}: {}", param_name, constraint),
                        Applicability::MachineApplicable,
                    );
                }
            }
        }

        true
    }
}

/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>);

impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
    type Map = rustc_hir::intravisit::ErasedMap<'v>;

    fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
        hir::intravisit::NestedVisitorMap::None
    }

    fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
        match ty.kind {
            hir::TyKind::TraitObject(
                _,
                hir::Lifetime {
                    name:
                        hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
                    ..
                },
                _,
            ) => {
                self.0.push(ty);
            }
            hir::TyKind::OpaqueDef(item_id, _) => {
                self.0.push(ty);
                let item = self.1.item(item_id);
                hir::intravisit::walk_item(self, item);
            }
            _ => {}
        }
        hir::intravisit::walk_ty(self, ty);
    }
}
<|endoftext|>


<commit_before>use crate::{api_client::Client,
            common::ui::{Status,
                         UIWriter,
                         UI}};

use crate::{error::{Error,
                    Result},
            PRODUCT,
            VERSION};

pub fn start(ui: &mut UI, bldr_url: &str, token: &str, origin: &str) -> Result<()> {
    let api_client = Client::new(bldr_url, PRODUCT, VERSION, None).map_err(Error::APIClient)?;

    ui.status(Status::Deleting, format!("origin {}.", origin))?;

    api_client.delete_origin(origin, token)
              .map_err(Error::APIClient)?;

    ui.status(Status::Deleted, format!("origin {}.", origin))
      .map_err(Into::into)
}
<commit_msg>Update error handling for origin deletion<commit_after>use crate::{api_client::{self,
                         Client},
            common::ui::{Status,
                         UIWriter,
                         UI},
            error::{Error,
                    Result},
            PRODUCT,
            VERSION};
use hyper::status::StatusCode;

pub fn start(ui: &mut UI, bldr_url: &str, token: &str, origin: &str) -> Result<()> {
    let api_client = Client::new(bldr_url, PRODUCT, VERSION, None).map_err(Error::APIClient)?;

    ui.status(Status::Deleting, format!("origin {}.", origin))?;

    match api_client.delete_origin(origin, token) {
        Ok(_) => {
            ui.status(Status::Deleted, format!("origin {}.", origin))
              .map_err(Into::into)
        }
        Err(api_client::Error::APIError(StatusCode::Conflict, msg)) => {
            ui.fatal(format!("Unable to delete origin {}", origin))?;
            ui.fatal(format!("Origins may only be deleted if they have no packages, linked \
                              projects"))?;
            ui.fatal("or other dependencies. Please check your origin and try again.")?;
            Err(Error::APIClient(api_client::Error::APIError(StatusCode::Conflict, msg)))
        }
        Err(e) => {
            ui.fatal(format!("Failed to delete origin {}, {:?}", origin, e))?;
            Err(Error::from(e))
        }
    }
}
<|endoftext|>