use crate::ast::{
    self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind,
    Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, VariantData,
};
use crate::feature_gate::{feature_err, UnstableFeatures};
use crate::parse::{SeqSep, PResult, Parser, ParseSess};
use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType};
use crate::parse::token::{self, TokenKind};
use crate::print::pprust;
use crate::ptr::P;
use crate::symbol::{kw, sym};
use crate::ThinVec;
use crate::util::parser::AssocOp;
use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
use rustc_data_structures::fx::FxHashSet;
use syntax_pos::{Span, DUMMY_SP, MultiSpan, SpanSnippetError};
use log::{debug, trace};
use std::mem;
crate fn dummy_arg(ident: Ident) -> Param {
    let pat = P(Pat {
        id: ast::DUMMY_NODE_ID,
        node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None),
        span: ident.span,
    });
    let ty = Ty {
        node: TyKind::Err,
        span: ident.span,
        id: ast::DUMMY_NODE_ID
    };
    Param { attrs: ThinVec::default(), id: ast::DUMMY_NODE_ID, pat, span: ident.span, ty: P(ty) }
}
pub enum Error {
    FileNotFoundForModule {
        mod_name: String,
        default_path: String,
        secondary_path: String,
        dir_path: String,
    },
    DuplicatePaths {
        mod_name: String,
        default_path: String,
        secondary_path: String,
    },
    UselessDocComment,
    InclusiveRangeWithNoEnd,
}
impl Error {
    fn span_err<S: Into<MultiSpan>>(
        self,
        sp: S,
        handler: &errors::Handler,
    ) -> DiagnosticBuilder<'_> {
        match self {
            Error::FileNotFoundForModule {
                ref mod_name,
                ref default_path,
                ref secondary_path,
                ref dir_path,
            } => {
                let mut err = struct_span_err!(
                    handler,
                    sp,
                    E0583,
                    "file not found for module `{}`",
                    mod_name,
                );
                err.help(&format!(
                    "name the file either {} or {} inside the directory \"{}\"",
                    default_path,
                    secondary_path,
                    dir_path,
                ));
                err
            }
            Error::DuplicatePaths { ref mod_name, ref default_path, ref secondary_path } => {
                let mut err = struct_span_err!(
                    handler,
                    sp,
                    E0584,
                    "file for module `{}` found at both {} and {}",
                    mod_name,
                    default_path,
                    secondary_path,
                );
                err.help("delete or rename one of them to remove the ambiguity");
                err
            }
            Error::UselessDocComment => {
                let mut err = struct_span_err!(
                    handler,
                    sp,
                    E0585,
                    "found a documentation comment that doesn't document anything",
                );
                err.help("doc comments must come before what they document, maybe a comment was \
                          intended with `//`?");
                err
            }
            Error::InclusiveRangeWithNoEnd => {
                let mut err = struct_span_err!(
                    handler,
                    sp,
                    E0586,
                    "inclusive range with no end",
                );
                err.help("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)");
                err
            }
        }
    }
}
pub trait RecoverQPath: Sized + 'static {
    const PATH_STYLE: PathStyle = PathStyle::Expr;
    fn to_ty(&self) -> Option<P<Ty>>;
    fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self;
}
impl RecoverQPath for Ty {
    const PATH_STYLE: PathStyle = PathStyle::Type;
    fn to_ty(&self) -> Option<P<Ty>> {
        Some(P(self.clone()))
    }
    fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
        Self {
            span: path.span,
            node: TyKind::Path(qself, path),
            id: ast::DUMMY_NODE_ID,
        }
    }
}
impl RecoverQPath for Pat {
    fn to_ty(&self) -> Option<P<Ty>> {
        self.to_ty()
    }
    fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
        Self {
            span: path.span,
            node: PatKind::Path(qself, path),
            id: ast::DUMMY_NODE_ID,
        }
    }
}
impl RecoverQPath for Expr {
    fn to_ty(&self) -> Option<P<Ty>> {
        self.to_ty()
    }
    fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
        Self {
            span: path.span,
            node: ExprKind::Path(qself, path),
            attrs: ThinVec::new(),
            id: ast::DUMMY_NODE_ID,
        }
    }
}
impl<'a> Parser<'a> {
    pub fn fatal(&self, m: &str) -> DiagnosticBuilder<'a> {
        self.span_fatal(self.token.span, m)
    }
    pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
        self.sess.span_diagnostic.struct_span_fatal(sp, m)
    }
    pub fn span_fatal_err<S: Into<MultiSpan>>(&self, sp: S, err: Error) -> DiagnosticBuilder<'a> {
        err.span_err(sp, self.diagnostic())
    }
    pub fn bug(&self, m: &str) -> ! {
        self.sess.span_diagnostic.span_bug(self.token.span, m)
    }
    pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) {
        self.sess.span_diagnostic.span_err(sp, m)
    }
    crate fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
        self.sess.span_diagnostic.struct_span_err(sp, m)
    }
    crate fn span_bug<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> ! {
        self.sess.span_diagnostic.span_bug(sp, m)
    }
    crate fn cancel(&self, err: &mut DiagnosticBuilder<'_>) {
        self.sess.span_diagnostic.cancel(err)
    }
    crate fn diagnostic(&self) -> &'a errors::Handler {
        &self.sess.span_diagnostic
    }
    crate fn span_to_snippet(&self, span: Span) -> Result<String, SpanSnippetError> {
        self.sess.source_map().span_to_snippet(span)
    }
    crate fn expected_ident_found(&self) -> DiagnosticBuilder<'a> {
        let mut err = self.struct_span_err(
            self.token.span,
            &format!("expected identifier, found {}", self.this_token_descr()),
        );
        if let token::Ident(name, false) = self.token.kind {
            if Ident::new(name, self.token.span).is_raw_guess() {
                err.span_suggestion(
                    self.token.span,
                    "you can escape reserved keywords to use them as identifiers",
                    format!("r#{}", name),
                    Applicability::MaybeIncorrect,
                );
            }
        }
        if let Some(token_descr) = self.token_descr() {
            err.span_label(self.token.span, format!("expected identifier, found {}", token_descr));
        } else {
            err.span_label(self.token.span, "expected identifier");
            if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) {
                err.span_suggestion(
                    self.token.span,
                    "remove this comma",
                    String::new(),
                    Applicability::MachineApplicable,
                );
            }
        }
        err
    }
    pub fn expected_one_of_not_found(
        &mut self,
        edible: &[TokenKind],
        inedible: &[TokenKind],
    ) -> PResult<'a, bool > {
        fn tokens_to_string(tokens: &[TokenType]) -> String {
            let mut i = tokens.iter();
            
            let b = i.next()
                     .map_or(String::new(), |t| t.to_string());
            i.enumerate().fold(b, |mut b, (i, a)| {
                if tokens.len() > 2 && i == tokens.len() - 2 {
                    b.push_str(", or ");
                } else if tokens.len() == 2 && i == tokens.len() - 2 {
                    b.push_str(" or ");
                } else {
                    b.push_str(", ");
                }
                b.push_str(&a.to_string());
                b
            })
        }
        let mut expected = edible.iter()
            .map(|x| TokenType::Token(x.clone()))
            .chain(inedible.iter().map(|x| TokenType::Token(x.clone())))
            .chain(self.expected_tokens.iter().cloned())
            .collect::<Vec<_>>();
        expected.sort_by_cached_key(|x| x.to_string());
        expected.dedup();
        let expect = tokens_to_string(&expected[..]);
        let actual = self.this_token_to_string();
        let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
            let short_expect = if expected.len() > 6 {
                format!("{} possible tokens", expected.len())
            } else {
                expect.clone()
            };
            (format!("expected one of {}, found `{}`", expect, actual),
                (self.sess.source_map().next_point(self.prev_span),
                format!("expected one of {} here", short_expect)))
        } else if expected.is_empty() {
            (format!("unexpected token: `{}`", actual),
                (self.prev_span, "unexpected token after this".to_string()))
        } else {
            (format!("expected {}, found `{}`", expect, actual),
                (self.sess.source_map().next_point(self.prev_span),
                format!("expected {} here", expect)))
        };
        self.last_unexpected_token_span = Some(self.token.span);
        let mut err = self.fatal(&msg_exp);
        if self.token.is_ident_named(sym::and) {
            err.span_suggestion_short(
                self.token.span,
                "use `&&` instead of `and` for the boolean operator",
                "&&".to_string(),
                Applicability::MaybeIncorrect,
            );
        }
        if self.token.is_ident_named(sym::or) {
            err.span_suggestion_short(
                self.token.span,
                "use `||` instead of `or` for the boolean operator",
                "||".to_string(),
                Applicability::MaybeIncorrect,
            );
        }
        let sp = if self.token == token::Eof {
            
            self.prev_span
        } else {
            label_sp
        };
        match self.recover_closing_delimiter(&expected.iter().filter_map(|tt| match tt {
            TokenType::Token(t) => Some(t.clone()),
            _ => None,
        }).collect::<Vec<_>>(), err) {
            Err(e) => err = e,
            Ok(recovered) => {
                return Ok(recovered);
            }
        }
        let is_semi_suggestable = expected.iter().any(|t| match t {
            TokenType::Token(token::Semi) => true, 
            _ => false,
        }) && ( 
            self.token.is_keyword(kw::Break) ||
            self.token.is_keyword(kw::Continue) ||
            self.token.is_keyword(kw::For) ||
            self.token.is_keyword(kw::If) ||
            self.token.is_keyword(kw::Let) ||
            self.token.is_keyword(kw::Loop) ||
            self.token.is_keyword(kw::Match) ||
            self.token.is_keyword(kw::Return) ||
            self.token.is_keyword(kw::While)
        );
        let sm = self.sess.source_map();
        match (sm.lookup_line(self.token.span.lo()), sm.lookup_line(sp.lo())) {
            (Ok(ref a), Ok(ref b)) if a.line != b.line && is_semi_suggestable => {
                
                
                err.span_suggestion_short(
                    label_sp,
                    "a semicolon may be missing here",
                    ";".to_string(),
                    Applicability::MaybeIncorrect,
                );
                err.emit();
                return Ok(true);
            }
            (Ok(ref a), Ok(ref b)) if a.line == b.line => {
                
                
                
                
                
                
                
                
                
                
                
                
                err.span_label(self.token.span, label_exp);
            }
            _ if self.prev_span == syntax_pos::DUMMY_SP => {
                
                
                err.span_label(self.token.span, "unexpected token");
            }
            _ => {
                err.span_label(sp, label_exp);
                err.span_label(self.token.span, "unexpected token");
            }
        }
        self.maybe_annotate_with_ascription(&mut err, false);
        Err(err)
    }
    pub fn maybe_annotate_with_ascription(
        &self,
        err: &mut DiagnosticBuilder<'_>,
        maybe_expected_semicolon: bool,
    ) {
        if let Some((sp, likely_path)) = self.last_type_ascription {
            let sm = self.sess.source_map();
            let next_pos = sm.lookup_char_pos(self.token.span.lo());
            let op_pos = sm.lookup_char_pos(sp.hi());
            if likely_path {
                err.span_suggestion(
                    sp,
                    "maybe write a path separator here",
                    "::".to_string(),
                    match self.sess.unstable_features {
                        UnstableFeatures::Disallow => Applicability::MachineApplicable,
                        _ => Applicability::MaybeIncorrect,
                    },
                );
            } else if op_pos.line != next_pos.line && maybe_expected_semicolon {
                err.span_suggestion(
                    sp,
                    "try using a semicolon",
                    ";".to_string(),
                    Applicability::MaybeIncorrect,
                );
            } else if let UnstableFeatures::Disallow = self.sess.unstable_features {
                err.span_label(sp, "tried to parse a type due to this");
            } else {
                err.span_label(sp, "tried to parse a type due to this type ascription");
            }
            if let UnstableFeatures::Disallow = self.sess.unstable_features {
                
            } else {
                err.note("`#![feature(type_ascription)]` lets you annotate an expression with a \
                          type: `<expr>: <type>`");
                err.note("for more information, see \
                          https://github.com/rust-lang/rust/issues/23416");
            }
        }
    }
    
    
    crate fn eat_to_tokens(&mut self, kets: &[&TokenKind]) {
        let handler = self.diagnostic();
        if let Err(ref mut err) = self.parse_seq_to_before_tokens(
            kets,
            SeqSep::none(),
            TokenExpectType::Expect,
            |p| Ok(p.parse_token_tree()),
        ) {
            handler.cancel(err);
        }
    }
    
    
    
    
    
    
    
    crate fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, end: TokenKind) {
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        let parsed_angle_bracket_args = segment.args
            .as_ref()
            .map(|args| args.is_angle_bracketed())
            .unwrap_or(false);
        debug!(
            "check_trailing_angle_brackets: parsed_angle_bracket_args={:?}",
            parsed_angle_bracket_args,
        );
        if !parsed_angle_bracket_args {
            return;
        }
        
        
        let lo = self.token.span;
        
        
        
        let mut position = 0;
        
        
        
        let mut number_of_shr = 0;
        let mut number_of_gt = 0;
        while self.look_ahead(position, |t| {
            trace!("check_trailing_angle_brackets: t={:?}", t);
            if *t == token::BinOp(token::BinOpToken::Shr) {
                number_of_shr += 1;
                true
            } else if *t == token::Gt {
                number_of_gt += 1;
                true
            } else {
                false
            }
        }) {
            position += 1;
        }
        
        debug!(
            "check_trailing_angle_brackets: number_of_gt={:?} number_of_shr={:?}",
            number_of_gt, number_of_shr,
        );
        if number_of_gt < 1 && number_of_shr < 1 {
            return;
        }
        
        
        if self.look_ahead(position, |t| {
            trace!("check_trailing_angle_brackets: t={:?}", t);
            *t == end
        }) {
            
            
            self.eat_to_tokens(&[&end]);
            let span = lo.until(self.token.span);
            let plural = number_of_gt > 1 || number_of_shr >= 1;
            self.diagnostic()
                .struct_span_err(
                    span,
                    &format!("unmatched angle bracket{}", if plural { "s" } else { "" }),
                )
                .span_suggestion(
                    span,
                    &format!("remove extra angle bracket{}", if plural { "s" } else { "" }),
                    String::new(),
                    Applicability::MachineApplicable,
                )
                .emit();
        }
    }
    
    
    
    crate fn check_no_chained_comparison(&self, lhs: &Expr, outer_op: &AssocOp) {
        debug_assert!(outer_op.is_comparison(),
                      "check_no_chained_comparison: {:?} is not comparison",
                      outer_op);
        match lhs.node {
            ExprKind::Binary(op, _, _) if op.node.is_comparison() => {
                
                let op_span = op.span.to(self.token.span);
                let mut err = self.struct_span_err(
                    op_span,
                    "chained comparison operators require parentheses",
                );
                if op.node == BinOpKind::Lt &&
                    *outer_op == AssocOp::Less ||  
                    *outer_op == AssocOp::Greater  
                {                                  
                    err.help(
                        "use `::<...>` instead of `<...>` if you meant to specify type arguments");
                    err.help("or use `(...)` if you meant to specify fn arguments");
                }
                err.emit();
            }
            _ => {}
        }
    }
    crate fn maybe_report_ambiguous_plus(
        &mut self,
        allow_plus: bool,
        impl_dyn_multi: bool,
        ty: &Ty,
    ) {
        if !allow_plus && impl_dyn_multi {
            let sum_with_parens = format!("({})", pprust::ty_to_string(&ty));
            self.struct_span_err(ty.span, "ambiguous `+` in a type")
                .span_suggestion(
                    ty.span,
                    "use parentheses to disambiguate",
                    sum_with_parens,
                    Applicability::MachineApplicable,
                )
                .emit();
        }
    }
    crate fn maybe_report_invalid_custom_discriminants(
        sess: &ParseSess,
        variants: &[ast::Variant],
    ) {
        let has_fields = variants.iter().any(|variant| match variant.data {
            VariantData::Tuple(..) | VariantData::Struct(..) => true,
            VariantData::Unit(..) => false,
        });
        let discriminant_spans = variants.iter().filter(|variant| match variant.data {
            VariantData::Tuple(..) | VariantData::Struct(..) => false,
            VariantData::Unit(..) => true,
        })
        .filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span))
        .collect::<Vec<_>>();
        if !discriminant_spans.is_empty() && has_fields {
            let mut err = feature_err(
                sess,
                sym::arbitrary_enum_discriminant,
                discriminant_spans.clone(),
                crate::feature_gate::GateIssue::Language,
                "custom discriminant values are not allowed in enums with tuple or struct variants",
            );
            for sp in discriminant_spans {
                err.span_label(sp, "disallowed custom discriminant");
            }
            for variant in variants.iter() {
                match &variant.data {
                    VariantData::Struct(..) => {
                        err.span_label(
                            variant.span,
                            "struct variant defined here",
                        );
                    }
                    VariantData::Tuple(..) => {
                        err.span_label(
                            variant.span,
                            "tuple variant defined here",
                        );
                    }
                    VariantData::Unit(..) => {}
                }
            }
            err.emit();
        }
    }
    crate fn maybe_recover_from_bad_type_plus(
        &mut self,
        allow_plus: bool,
        ty: &Ty,
    ) -> PResult<'a, ()> {
        
        if !allow_plus || !self.token.is_like_plus() {
            return Ok(());
        }
        self.bump(); 
        let bounds = self.parse_generic_bounds(None)?;
        let sum_span = ty.span.to(self.prev_span);
        let mut err = struct_span_err!(
            self.sess.span_diagnostic,
            sum_span,
            E0178,
            "expected a path on the left-hand side of `+`, not `{}`",
            pprust::ty_to_string(ty)
        );
        match ty.node {
            TyKind::Rptr(ref lifetime, ref mut_ty) => {
                let sum_with_parens = pprust::to_string(|s| {
                    s.s.word("&");
                    s.print_opt_lifetime(lifetime);
                    s.print_mutability(mut_ty.mutbl);
                    s.popen();
                    s.print_type(&mut_ty.ty);
                    s.print_type_bounds(" +", &bounds);
                    s.pclose()
                });
                err.span_suggestion(
                    sum_span,
                    "try adding parentheses",
                    sum_with_parens,
                    Applicability::MachineApplicable,
                );
            }
            TyKind::Ptr(..) | TyKind::BareFn(..) => {
                err.span_label(sum_span, "perhaps you forgot parentheses?");
            }
            _ => {
                err.span_label(sum_span, "expected a path");
            }
        }
        err.emit();
        Ok(())
    }
    
    
    
    crate fn maybe_recover_from_bad_qpath<T: RecoverQPath>(
        &mut self,
        base: P<T>,
        allow_recovery: bool,
    ) -> PResult<'a, P<T>> {
        
        if allow_recovery && self.token == token::ModSep {
            if let Some(ty) = base.to_ty() {
                return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty);
            }
        }
        Ok(base)
    }
    
    
    crate fn maybe_recover_from_bad_qpath_stage_2<T: RecoverQPath>(
        &mut self,
        ty_span: Span,
        ty: P<Ty>,
    ) -> PResult<'a, P<T>> {
        self.expect(&token::ModSep)?;
        let mut path = ast::Path {
            segments: Vec::new(),
            span: DUMMY_SP,
        };
        self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?;
        path.span = ty_span.to(self.prev_span);
        let ty_str = self
            .span_to_snippet(ty_span)
            .unwrap_or_else(|_| pprust::ty_to_string(&ty));
        self.diagnostic()
            .struct_span_err(path.span, "missing angle brackets in associated item path")
            .span_suggestion(
                
                path.span,
                "try",
                format!("<{}>::{}", ty_str, path),
                Applicability::MaybeIncorrect,
            )
            .emit();
        let path_span = ty_span.shrink_to_hi(); 
        Ok(P(T::recovered(
            Some(QSelf {
                ty,
                path_span,
                position: 0,
            }),
            path,
        )))
    }
    crate fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
        if self.eat(&token::Semi) {
            let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`");
            err.span_suggestion_short(
                self.prev_span,
                "remove this semicolon",
                String::new(),
                Applicability::MachineApplicable,
            );
            if !items.is_empty() {
                let previous_item = &items[items.len() - 1];
                let previous_item_kind_name = match previous_item.node {
                    
                    
                    ItemKind::Struct(..) => Some("braced struct"),
                    ItemKind::Enum(..) => Some("enum"),
                    ItemKind::Trait(..) => Some("trait"),
                    ItemKind::Union(..) => Some("union"),
                    _ => None,
                };
                if let Some(name) = previous_item_kind_name {
                    err.help(&format!(
                        "{} declarations are not followed by a semicolon",
                        name
                    ));
                }
            }
            err.emit();
            true
        } else {
            false
        }
    }
    
    
    pub fn unexpected_try_recover(
        &mut self,
        t: &TokenKind,
    ) -> PResult<'a, bool > {
        let token_str = pprust::token_kind_to_string(t);
        let this_token_str = self.this_token_descr();
        let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) {
            
            (token::Eof, Some(_)) => {
                let sp = self.sess.source_map().next_point(self.token.span);
                (sp, sp)
            }
            
            
            _ if self.prev_span == DUMMY_SP => (self.token.span, self.token.span),
            
            (token::Eof, None) => (self.prev_span, self.token.span),
            _ => (self.sess.source_map().next_point(self.prev_span), self.token.span),
        };
        let msg = format!(
            "expected `{}`, found {}",
            token_str,
            match (&self.token.kind, self.subparser_name) {
                (token::Eof, Some(origin)) => format!("end of {}", origin),
                _ => this_token_str,
            },
        );
        let mut err = self.struct_span_err(sp, &msg);
        let label_exp = format!("expected `{}`", token_str);
        match self.recover_closing_delimiter(&[t.clone()], err) {
            Err(e) => err = e,
            Ok(recovered) => {
                return Ok(recovered);
            }
        }
        let sm = self.sess.source_map();
        match (sm.lookup_line(prev_sp.lo()), sm.lookup_line(sp.lo())) {
            (Ok(ref a), Ok(ref b)) if a.line == b.line => {
                
                
                err.span_label(sp, label_exp);
            }
            _ => {
                err.span_label(prev_sp, label_exp);
                err.span_label(sp, "unexpected token");
            }
        }
        Err(err)
    }
    crate fn parse_semi_or_incorrect_foreign_fn_body(
        &mut self,
        ident: &Ident,
        extern_sp: Span,
    ) -> PResult<'a, ()> {
        if self.token != token::Semi {
            
            let parser_snapshot = self.clone();
            match self.parse_inner_attrs_and_block() {
                Ok((_, body)) => {
                    self.struct_span_err(ident.span, "incorrect `fn` inside `extern` block")
                        .span_label(ident.span, "can't have a body")
                        .span_label(body.span, "this body is invalid here")
                        .span_label(
                            extern_sp,
                            "`extern` blocks define existing foreign functions and `fn`s \
                             inside of them cannot have a body")
                        .help("you might have meant to write a function accessible through ffi, \
                               which can be done by writing `extern fn` outside of the \
                               `extern` block")
                        .note("for more information, visit \
                               https://doc.rust-lang.org/std/keyword.extern.html")
                        .emit();
                }
                Err(mut err) => {
                    err.cancel();
                    mem::replace(self, parser_snapshot);
                    self.expect(&token::Semi)?;
                }
            }
        } else {
            self.bump();
        }
        Ok(())
    }
    
    
    crate fn parse_incorrect_await_syntax(
        &mut self,
        lo: Span,
        await_sp: Span,
    ) -> PResult<'a, (Span, ExprKind)> {
        if self.token == token::Not {
            
            self.expect(&token::Not)?;
            self.expect(&token::OpenDelim(token::Paren))?;
            let expr = self.parse_expr()?;
            self.expect(&token::CloseDelim(token::Paren))?;
            let sp = self.error_on_incorrect_await(lo, self.prev_span, &expr, false);
            return Ok((sp, ExprKind::Await(expr)))
        }
        let is_question = self.eat(&token::Question); 
        let expr = if self.token == token::OpenDelim(token::Brace) {
            
            
            
            self.parse_block_expr(
                None,
                self.token.span,
                BlockCheckMode::Default,
                ThinVec::new(),
            )
        } else {
            self.parse_expr()
        }.map_err(|mut err| {
            err.span_label(await_sp, "while parsing this incorrect await expression");
            err
        })?;
        let sp = self.error_on_incorrect_await(lo, expr.span, &expr, is_question);
        Ok((sp, ExprKind::Await(expr)))
    }
    fn error_on_incorrect_await(&self, lo: Span, hi: Span, expr: &Expr, is_question: bool) -> Span {
        let expr_str = self.span_to_snippet(expr.span)
            .unwrap_or_else(|_| pprust::expr_to_string(&expr));
        let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" });
        let sp = lo.to(hi);
        let app = match expr.node {
            ExprKind::Try(_) => Applicability::MaybeIncorrect, 
            _ => Applicability::MachineApplicable,
        };
        self.struct_span_err(sp, "incorrect use of `await`")
            .span_suggestion(sp, "`await` is a postfix operation", suggestion, app)
            .emit();
        sp
    }
    
    crate fn recover_from_await_method_call(&mut self) {
        if self.token == token::OpenDelim(token::Paren) &&
            self.look_ahead(1, |t| t == &token::CloseDelim(token::Paren))
        {
            
            let lo = self.token.span;
            self.bump(); 
            let sp = lo.to(self.token.span);
            self.bump(); 
            self.struct_span_err(sp, "incorrect use of `await`")
                .span_suggestion(
                    sp,
                    "`await` is not a method call, remove the parentheses",
                    String::new(),
                    Applicability::MachineApplicable,
                ).emit()
        }
    }
    
    
    
    
    crate fn recover_parens_around_for_head(
        &mut self,
        pat: P<Pat>,
        expr: &Expr,
        begin_paren: Option<Span>,
    ) -> P<Pat> {
        match (&self.token.kind, begin_paren) {
            (token::CloseDelim(token::Paren), Some(begin_par_sp)) => {
                self.bump();
                let pat_str = self
                    
                    .span_to_snippet(pat.span.trim_start(begin_par_sp).unwrap())
                    .unwrap_or_else(|_| pprust::pat_to_string(&pat));
                self.struct_span_err(self.prev_span, "unexpected closing `)`")
                    .span_label(begin_par_sp, "opening `(`")
                    .span_suggestion(
                        begin_par_sp.to(self.prev_span),
                        "remove parenthesis in `for` loop",
                        format!("{} in {}", pat_str, pprust::expr_to_string(&expr)),
                        
                        
                        
                        Applicability::MachineApplicable,
                    )
                    .emit();
                
                pat.and_then(|pat| match pat.node {
                    PatKind::Paren(pat) => pat,
                    _ => P(pat),
                })
            }
            _ => pat,
        }
    }
    crate fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool {
        self.token.is_ident() &&
            if let ast::ExprKind::Path(..) = node { true } else { false } &&
            !self.token.is_reserved_ident() &&           
            self.look_ahead(1, |t| t == &token::OpenDelim(token::Paren)) ||
            self.look_ahead(1, |t| t == &token::Lt) &&     
            self.look_ahead(2, |t| t.is_ident()) ||
            self.look_ahead(1, |t| t == &token::Colon) &&  
            self.look_ahead(2, |t| t.is_ident()) ||
            self.look_ahead(1, |t| t == &token::ModSep) &&
            (self.look_ahead(2, |t| t.is_ident()) ||   
             self.look_ahead(2, |t| t == &token::Lt))  
    }
    crate fn recover_seq_parse_error(
        &mut self,
        delim: token::DelimToken,
        lo: Span,
        result: PResult<'a, P<Expr>>,
    ) -> P<Expr> {
        match result {
            Ok(x) => x,
            Err(mut err) => {
                err.emit();
                
                self.consume_block(delim);
                self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new())
            }
        }
    }
    crate fn recover_closing_delimiter(
        &mut self,
        tokens: &[TokenKind],
        mut err: DiagnosticBuilder<'a>,
    ) -> PResult<'a, bool> {
        let mut pos = None;
        
        for (i, unmatched) in self.unclosed_delims.iter().enumerate().rev() {
            if tokens.contains(&token::CloseDelim(unmatched.expected_delim))
                && Some(self.token.span) > unmatched.unclosed_span
            {
                pos = Some(i);
            }
        }
        match pos {
            Some(pos) => {
                
                
                
                 
                let unmatched = self.unclosed_delims.remove(pos);
                let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim));
                 
                
                
                
                
                
                
                
                
                if let Some(sp) = unmatched.unclosed_span {
                    err.span_label(sp, "unclosed delimiter");
                }
                err.span_suggestion_short(
                    self.sess.source_map().next_point(self.prev_span),
                    &format!("{} may belong here", delim.to_string()),
                    delim.to_string(),
                    Applicability::MaybeIncorrect,
                );
                err.emit();
                self.expected_tokens.clear();  
                Ok(true)
            }
            _ => Err(err),
        }
    }
    
    crate fn eat_bad_pub(&mut self) {
        if self.token.is_keyword(kw::Pub) {
            match self.parse_visibility(false) {
                Ok(vis) => {
                    self.diagnostic()
                        .struct_span_err(vis.span, "unnecessary visibility qualifier")
                        .span_label(vis.span, "`pub` not permitted here")
                        .emit();
                }
                Err(mut err) => err.emit(),
            }
        }
    }
    
    
    
    
    crate fn recover_stmt(&mut self) {
        self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore)
    }
    
    
    
    
    
    
    
    crate fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) {
        let mut brace_depth = 0;
        let mut bracket_depth = 0;
        let mut in_block = false;
        debug!("recover_stmt_ enter loop (semi={:?}, block={:?})",
               break_on_semi, break_on_block);
        loop {
            debug!("recover_stmt_ loop {:?}", self.token);
            match self.token.kind {
                token::OpenDelim(token::DelimToken::Brace) => {
                    brace_depth += 1;
                    self.bump();
                    if break_on_block == BlockMode::Break &&
                       brace_depth == 1 &&
                       bracket_depth == 0 {
                        in_block = true;
                    }
                }
                token::OpenDelim(token::DelimToken::Bracket) => {
                    bracket_depth += 1;
                    self.bump();
                }
                token::CloseDelim(token::DelimToken::Brace) => {
                    if brace_depth == 0 {
                        debug!("recover_stmt_ return - close delim {:?}", self.token);
                        break;
                    }
                    brace_depth -= 1;
                    self.bump();
                    if in_block && bracket_depth == 0 && brace_depth == 0 {
                        debug!("recover_stmt_ return - block end {:?}", self.token);
                        break;
                    }
                }
                token::CloseDelim(token::DelimToken::Bracket) => {
                    bracket_depth -= 1;
                    if bracket_depth < 0 {
                        bracket_depth = 0;
                    }
                    self.bump();
                }
                token::Eof => {
                    debug!("recover_stmt_ return - Eof");
                    break;
                }
                token::Semi => {
                    self.bump();
                    if break_on_semi == SemiColonMode::Break &&
                       brace_depth == 0 &&
                       bracket_depth == 0 {
                        debug!("recover_stmt_ return - Semi");
                        break;
                    }
                }
                token::Comma if break_on_semi == SemiColonMode::Comma &&
                       brace_depth == 0 &&
                       bracket_depth == 0 =>
                {
                    debug!("recover_stmt_ return - Semi");
                    break;
                }
                _ => {
                    self.bump()
                }
            }
        }
    }
    crate fn check_for_for_in_in_typo(&mut self, in_span: Span) {
        if self.eat_keyword(kw::In) {
            
            self.struct_span_err(self.prev_span, "expected iterable, found keyword `in`")
                .span_suggestion_short(
                    in_span.until(self.prev_span),
                    "remove the duplicated `in`",
                    String::new(),
                    Applicability::MachineApplicable,
                )
                .emit();
        }
    }
    crate fn expected_semi_or_open_brace(&mut self) -> PResult<'a, ast::TraitItem> {
        let token_str = self.this_token_descr();
        let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", token_str));
        err.span_label(self.token.span, "expected `;` or `{`");
        Err(err)
    }
    crate fn eat_incorrect_doc_comment_for_param_type(&mut self) {
        if let token::DocComment(_) = self.token.kind {
            self.struct_span_err(
                self.token.span,
                "documentation comments cannot be applied to a function parameter's type",
            )
            .span_label(self.token.span, "doc comments are not allowed here")
            .emit();
            self.bump();
        } else if self.token == token::Pound && self.look_ahead(1, |t| {
            *t == token::OpenDelim(token::Bracket)
        }) {
            let lo = self.token.span;
            
            while self.token != token::CloseDelim(token::Bracket) {
                self.bump();
            }
            let sp = lo.to(self.token.span);
            self.bump();
            self.struct_span_err(
                sp,
                "attributes cannot be applied to a function parameter's type",
            )
            .span_label(sp, "attributes are not allowed here")
            .emit();
        }
    }
    crate fn parameter_without_type(
        &mut self,
        err: &mut DiagnosticBuilder<'_>,
        pat: P<ast::Pat>,
        require_name: bool,
        is_trait_item: bool,
    ) -> Option<Ident> {
        
        
        if self.check_ident() && self.look_ahead(1, |t| {
            *t == token::Comma || *t == token::CloseDelim(token::Paren)
        }) { 
            let ident = self.parse_ident().unwrap();
            let span = pat.span.with_hi(ident.span.hi());
            err.span_suggestion(
                span,
                "declare the type after the parameter binding",
                String::from("<identifier>: <type>"),
                Applicability::HasPlaceholders,
            );
            return Some(ident);
        } else if let PatKind::Ident(_, ident, _) = pat.node {
            if require_name && (
                is_trait_item ||
                self.token == token::Comma ||
                self.token == token::CloseDelim(token::Paren)
            ) { 
                err.span_suggestion(
                    pat.span,
                    "if this was a parameter name, give it a type",
                    format!("{}: TypeName", ident),
                    Applicability::HasPlaceholders,
                );
                err.span_suggestion(
                    pat.span,
                    "if this is a type, explicitly ignore the parameter name",
                    format!("_: {}", ident),
                    Applicability::MachineApplicable,
                );
                err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)");
                return Some(ident);
            }
        }
        None
    }
    crate fn recover_arg_parse(&mut self) -> PResult<'a, (P<ast::Pat>, P<ast::Ty>)> {
        let pat = self.parse_pat(Some("argument name"))?;
        self.expect(&token::Colon)?;
        let ty = self.parse_ty()?;
        self.diagnostic()
            .struct_span_err_with_code(
                pat.span,
                "patterns aren't allowed in methods without bodies",
                DiagnosticId::Error("E0642".into()),
            )
            .span_suggestion_short(
                pat.span,
                "give this argument a name or use an underscore to ignore it",
                "_".to_owned(),
                Applicability::MachineApplicable,
            )
            .emit();
        
        let pat = P(Pat {
            node: PatKind::Wild,
            span: pat.span,
            id: ast::DUMMY_NODE_ID
        });
        Ok((pat, ty))
    }
    crate fn recover_bad_self_param(
        &mut self,
        mut param: ast::Param,
        is_trait_item: bool,
    ) -> PResult<'a, ast::Param> {
        let sp = param.pat.span;
        param.ty.node = TyKind::Err;
        let mut err = self.struct_span_err(sp, "unexpected `self` parameter in function");
        if is_trait_item {
            err.span_label(sp, "must be the first associated function parameter");
        } else {
            err.span_label(sp, "not valid as function parameter");
            err.note("`self` is only valid as the first parameter of an associated function");
        }
        err.emit();
        Ok(param)
    }
    crate fn consume_block(&mut self, delim: token::DelimToken) {
        let mut brace_depth = 0;
        loop {
            if self.eat(&token::OpenDelim(delim)) {
                brace_depth += 1;
            } else if self.eat(&token::CloseDelim(delim)) {
                if brace_depth == 0 {
                    return;
                } else {
                    brace_depth -= 1;
                    continue;
                }
            } else if self.token == token::Eof || self.eat(&token::CloseDelim(token::NoDelim)) {
                return;
            } else {
                self.bump();
            }
        }
    }
    crate fn expected_expression_found(&self) -> DiagnosticBuilder<'a> {
        let (span, msg) = match (&self.token.kind, self.subparser_name) {
            (&token::Eof, Some(origin)) => {
                let sp = self.sess.source_map().next_point(self.token.span);
                (sp, format!("expected expression, found end of {}", origin))
            }
            _ => (self.token.span, format!(
                "expected expression, found {}",
                self.this_token_descr(),
            )),
        };
        let mut err = self.struct_span_err(span, &msg);
        let sp = self.sess.source_map().start_point(self.token.span);
        if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
            self.sess.expr_parentheses_needed(&mut err, *sp, None);
        }
        err.span_label(span, "expected expression");
        err
    }
    
    
    
    
    
    
    
    
    crate fn deduplicate_recovered_params_names(&self, fn_inputs: &mut Vec<Param>) {
        let mut seen_inputs = FxHashSet::default();
        for input in fn_inputs.iter_mut() {
            let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err) = (
                &input.pat.node, &input.ty.node,
            ) {
                Some(*ident)
            } else {
                None
            };
            if let Some(ident) = opt_ident {
                if seen_inputs.contains(&ident) {
                    input.pat.node = PatKind::Wild;
                }
                seen_inputs.insert(ident);
            }
        }
    }
}