pub(super) fn check_no_chained_comparison(
        &mut self,
        inner_op: &Expr,
        outer_op: &Spanned<AssocOp>,
    ) -> PResult<'a, Option<P<Expr>>> {
        debug_assert!(
            outer_op.node.is_comparison(),
            "check_no_chained_comparison: {:?} is not comparison",
            outer_op.node,
        );

        let mk_err_expr =
            |this: &Self, span| Ok(Some(this.mk_expr(span, ExprKind::Err, AttrVec::new())));

        match inner_op.kind {
            ExprKind::Binary(op, ref l1, ref r1) if op.node.is_comparison() => {
                let mut err = self.struct_span_err(
                    vec![op.span, self.prev_token.span],
                    "comparison operators cannot be chained",
                );

                let suggest = |err: &mut DiagnosticBuilder<'_>| {
                    err.span_suggestion_verbose(
                        op.span.shrink_to_lo(),
                        TURBOFISH,
                        "::".to_string(),
                        Applicability::MaybeIncorrect,
                    );
                };

                // Include `<` to provide this recommendation even in a case like
                // `Foo<Bar<Baz<Qux, ()>>>`
                if op.node == BinOpKind::Lt && outer_op.node == AssocOp::Less
                    || outer_op.node == AssocOp::Greater
                {
                    if outer_op.node == AssocOp::Less {
                        let snapshot = self.clone();
                        self.bump();
                        // So far we have parsed `foo<bar<`, consume the rest of the type args.
                        let modifiers =
                            [(token::Lt, 1), (token::Gt, -1), (token::BinOp(token::Shr), -2)];
                        self.consume_tts(1, &modifiers[..]);

                        if !&[token::OpenDelim(token::Paren), token::ModSep]
                            .contains(&self.token.kind)
                        {
                            // We don't have `foo< bar >(` or `foo< bar >::`, so we rewind the
                            // parser and bail out.
                            *self = snapshot.clone();
                        }
                    }
                    return if token::ModSep == self.token.kind {
                        // We have some certainty that this was a bad turbofish at this point.
                        // `foo< bar >::`
                        suggest(&mut err);

                        let snapshot = self.clone();
                        self.bump(); // `::`

                        // Consume the rest of the likely `foo<bar>::new()` or return at `foo<bar>`.
                        match self.parse_expr() {
                            Ok(_) => {
                                // 99% certain that the suggestion is correct, continue parsing.
                                err.emit();
                                // FIXME: actually check that the two expressions in the binop are
                                // paths and resynthesize new fn call expression instead of using
                                // `ExprKind::Err` placeholder.
                                mk_err_expr(self, inner_op.span.to(self.prev_token.span))
                            }
                            Err(mut expr_err) => {
                                expr_err.cancel();
                                // Not entirely sure now, but we bubble the error up with the
                                // suggestion.
                                *self = snapshot;
                                Err(err)
                            }
                        }
                    } else if token::OpenDelim(token::Paren) == self.token.kind {
                        // We have high certainty that this was a bad turbofish at this point.
                        // `foo< bar >(`
                        suggest(&mut err);
                        // Consume the fn call arguments.
                        match self.consume_fn_args() {
                            Err(()) => Err(err),
                            Ok(()) => {
                                err.emit();
                                // FIXME: actually check that the two expressions in the binop are
                                // paths and resynthesize new fn call expression instead of using
                                // `ExprKind::Err` placeholder.
                                mk_err_expr(self, inner_op.span.to(self.prev_token.span))
                            }
                        }
                    } else {
                        if !matches!(l1.kind, ExprKind::Lit(_))
                            && !matches!(r1.kind, ExprKind::Lit(_))
                        {
                            // All we know is that this is `foo < bar >` and *nothing* else. Try to
                            // be helpful, but don't attempt to recover.
                            err.help(TURBOFISH);
                            err.help("or use `(...)` if you meant to specify fn arguments");
                        }

                        // If it looks like a genuine attempt to chain operators (as opposed to a
                        // misformatted turbofish, for instance), suggest a correct form.
                        if self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op)
                        {
                            err.emit();
                            mk_err_expr(self, inner_op.span.to(self.prev_token.span))
                        } else {
                            // These cases cause too many knock-down errors, bail out (#61329).
                            Err(err)
                        }
                    };
                }
                let recover =
                    self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op);
                err.emit();
                if recover {
                    return mk_err_expr(self, inner_op.span.to(self.prev_token.span));
                }
            }
            _ => {}
        }
        Ok(None)
    }
/// Produces an error if comparison operators are chained (RFC #558).
/// We only need to check the LHS, not the RHS, because all comparison ops have same
/// precedence (see `fn precedence`) and are left-associative (see `fn fixity`).
///
/// This can also be hit if someone incorrectly writes `foo<bar>()` when they should have used
/// the turbofish (`foo::<bar>()`) syntax. We attempt some heuristic recovery if that is the
/// case.
///
/// Keep in mind that given that `outer_op.is_comparison()` holds and comparison ops are left
/// associative we can infer that we have:
///
/// ```text
///           outer_op
///           /   \
///     inner_op   r2
///        /  \
///      l1    r1
/// ```
Produces an error if comparison operators are chained (RFC #558).
We only need to check the LHS, not the RHS, because all comparison ops have same
precedence  and are left-associative .

This can also be hit if someone incorrectly writes `foo()` when they should have used
the turbofish (`foo::()`) syntax. We attempt some heuristic recovery if that is the
case.

Keep in mind that given that `outer_op.is_comparison()` holds and comparison ops are left
associative we can infer that we have.


Produces an error if comparison operators are chained ( RFC #558 ) . We only need to check the LHS not the RHS because all comparison ops have same precedence and are left - associative . This can also be hit if someone incorrectly writes ` foo () ` when they should have used the turbofish ( ` foo :: () ` ) syntax . We attempt some heuristic recovery if that is the case . Keep in mind that given that ` outer_op . is_comparison () ` holds and comparison ops are left associative we can infer that we have .
pub(super) fn check_no_chained_comparison(
        &mut self,
        inner_op: &Expr,
        outer_op: &Spanned<AssocOp>,
    ) -> PResult<'a, Option<P<Expr>>> {
        debug_assert!(
            outer_op.node.is_comparison(),
            "check_no_chained_comparison: {:?} is not comparison",
            outer_op.node,
        );
        let mk_err_expr =
            |this: &Self, span| Ok(Some(this.mk_expr(span, ExprKind::Err, AttrVec::new())));
        match inner_op.kind {
            ExprKind::Binary(op, ref l1, ref r1) if op.node.is_comparison() => {
                let mut err = self.struct_span_err(
                    vec![op.span, self.prev_token.span],
                    "comparison operators cannot be chained",
                );
                let suggest = |err: &mut DiagnosticBuilder<'_>| {
                    err.span_suggestion_verbose(
                        op.span.shrink_to_lo(),
                        TURBOFISH,
                        "::".to_string(),
                        Applicability::MaybeIncorrect,
                    );
                };
                // Include `<` to provide this recommendation even in a case like
                // `Foo<Bar<Baz<Qux, ()>>>`
                if op.node == BinOpKind::Lt && outer_op.node == AssocOp::Less
                    || outer_op.node == AssocOp::Greater
                {
                    if outer_op.node == AssocOp::Less {
                        let snapshot = self.clone();
                        self.bump();
                        // So far we have parsed `foo<bar<`, consume the rest of the type args.
                        let modifiers =
                            [(token::Lt, 1), (token::Gt, -1), (token::BinOp(token::Shr), -2)];
                        self.consume_tts(1, &modifiers[..]);
                        if !&[token::OpenDelim(token::Paren), token::ModSep]
                            .contains(&self.token.kind)
                        {
                            // We don't have `foo< bar >(` or `foo< bar >::`, so we rewind the
                            // parser and bail out.
                            *self = snapshot.clone();
                        }
                    }
                    return if token::ModSep == self.token.kind {
                        // We have some certainty that this was a bad turbofish at this point.
                        // `foo< bar >::`
                        suggest(&mut err);
                        let snapshot = self.clone();
                        self.bump(); // `::`
                        // Consume the rest of the likely `foo<bar>::new()` or return at `foo<bar>`.
                        match self.parse_expr() {
                            Ok(_) => {
                                // 99% certain that the suggestion is correct, continue parsing.
                                err.emit();
                                // FIXME: actually check that the two expressions in the binop are
                                // paths and resynthesize new fn call expression instead of using
                                // `ExprKind::Err` placeholder.
                                mk_err_expr(self, inner_op.span.to(self.prev_token.span))
                            }
                            Err(mut expr_err) => {
                                expr_err.cancel();
                                // Not entirely sure now, but we bubble the error up with the
                                // suggestion.
                                *self = snapshot;
                                Err(err)
                            }
                        }
                    } else if token::OpenDelim(token::Paren) == self.token.kind {
                        // We have high certainty that this was a bad turbofish at this point.
                        // `foo< bar >(`
                        suggest(&mut err);
                        // Consume the fn call arguments.
                        match self.consume_fn_args() {
                            Err(()) => Err(err),
                            Ok(()) => {
                                err.emit();
                                // FIXME: actually check that the two expressions in the binop are
                                // paths and resynthesize new fn call expression instead of using
                                // `ExprKind::Err` placeholder.
                                mk_err_expr(self, inner_op.span.to(self.prev_token.span))
                            }
                        }
                    } else {
                        if !matches!(l1.kind, ExprKind::Lit(_))
                            && !matches!(r1.kind, ExprKind::Lit(_))
                        {
                            // All we know is that this is `foo < bar >` and *nothing* else. Try to
                            // be helpful, but don't attempt to recover.
                            err.help(TURBOFISH);
                            err.help("or use `(...)` if you meant to specify fn arguments");
                        }
                        // If it looks like a genuine attempt to chain operators (as opposed to a
                        // misformatted turbofish, for instance), suggest a correct form.
                        if self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op)
                        {
                            err.emit();
                            mk_err_expr(self, inner_op.span.to(self.prev_token.span))
                        } else {
                            // These cases cause too many knock-down errors, bail out (#61329).
                            Err(err)
                        }
                    };
                }
                let recover =
                    self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op);
                err.emit();
                if recover {
                    return mk_err_expr(self, inner_op.span.to(self.prev_token.span));
                }
            }
            _ => {}
        }
        Ok(None)
    }
pub ( super ) fn check_no_chained_comparison ( & mut self , inner_op : & Expr , outer_op : & Spanned < AssocOp > , ) -> PResult < ' a , Option < P < Expr > > > { debug_assert ! ( outer_op node is_comparison ( ) " " outer_op node ) ; let mk_err_expr = | this : & Self , span | Ok ( Some ( this . mk_expr ( span , ExprKind :: Err , AttrVec :: new ( ) ) ) ) ; match inner_op . kind { ExprKind :: Binary ( op , ref l1 , ref r1 ) if op . node . is_comparison ( ) => { let mut err = self . struct_span_err ( vec ! [ op span self prev_token span ] , " " , ) ; let suggest = | err : & mut DiagnosticBuilder < ' _ > | { err . span_suggestion_verbose ( op . span . shrink_to_lo ( ) , TURBOFISH , " " . to_string ( ) , Applicability :: MaybeIncorrect , ) ; } ; // Include `<` to provide this recommendation even in a case like // `Foo<Bar<Baz<Qux, ()>>>` if op . node == BinOpKind :: Lt && outer_op . node == AssocOp :: Less || outer_op . node == AssocOp :: Greater { if outer_op . node == AssocOp :: Less { let snapshot = self . clone ( ) ; self . bump ( ) ; // So far we have parsed `foo<bar<`, consume the rest of the type args. let modifiers = [ ( token :: Lt , 1 ) , ( token :: Gt , - 1 ) , ( token :: BinOp ( token :: Shr ) , - 2 ) ] ; self . consume_tts ( 1 , & modifiers [ .. ] ) ; if ! & [ token :: OpenDelim ( token :: Paren ) , token :: ModSep ] . contains ( & self . token . kind ) { // We don't have `foo< bar >(` or `foo< bar >::`, so we rewind the // parser and bail out. * self = snapshot . clone ( ) ; } } return if token :: ModSep == self . token . kind { // We have some certainty that this was a bad turbofish at this point. // `foo< bar >::` suggest ( & mut err ) ; let snapshot = self . clone ( ) ; self . bump ( ) ; // `::` // Consume the rest of the likely `foo<bar>::new()` or return at `foo<bar>`. match self . parse_expr ( ) { Ok ( _ ) => { // 99% certain that the suggestion is correct, continue parsing. err . emit ( ) ; // FIXME: actually check that the two expressions in the binop are // paths and resynthesize new fn call expression instead of using // `ExprKind::Err` placeholder. mk_err_expr ( self , inner_op . span . to ( self . prev_token . span ) ) } Err ( mut expr_err ) => { expr_err . cancel ( ) ; // Not entirely sure now, but we bubble the error up with the // suggestion. * self = snapshot ; Err ( err ) } } } else if token :: OpenDelim ( token :: Paren ) == self . token . kind { // We have high certainty that this was a bad turbofish at this point. // `foo< bar >(` suggest ( & mut err ) ; // Consume the fn call arguments. match self . consume_fn_args ( ) { Err ( ( ) ) => Err ( err ) , Ok ( ( ) ) => { err . emit ( ) ; // FIXME: actually check that the two expressions in the binop are // paths and resynthesize new fn call expression instead of using // `ExprKind::Err` placeholder. mk_err_expr ( self , inner_op . span . to ( self . prev_token . span ) ) } } } else { if ! matches ! ( l1 kind ExprKind Lit ( ) ) && ! matches ! ( r1 kind ExprKind Lit ( ) ) { // All we know is that this is `foo < bar >` and *nothing* else. Try to // be helpful, but don't attempt to recover. err . help ( TURBOFISH ) ; err . help ( " " ) ; } // If it looks like a genuine attempt to chain operators (as opposed to a // misformatted turbofish, for instance), suggest a correct form. if self . attempt_chained_comparison_suggestion ( & mut err , inner_op , outer_op ) { err . emit ( ) ; mk_err_expr ( self , inner_op . span . to ( self . prev_token . span ) ) } else { // These cases cause too many knock-down errors, bail out (#61329). Err ( err ) } } ; } let recover = self . attempt_chained_comparison_suggestion ( & mut err , inner_op , outer_op ) ; err . emit ( ) ; if recover { return mk_err_expr ( self , inner_op . span . to ( self . prev_token . span ) ) ; } } _ => { } } Ok ( None ) }
Produces an error if comparison operators are chained (RFC #558).
Produces an error if comparison operators are chained ( RFC #558 ) .
&mut self
inner_op
&Expr
outer_op
&Spanned<AssocOp>
&mut self
inner_op
&Expr
outer_op
&Spanned<AssocOp>