]> git.lizzy.rs Git - rust.git/commitdiff
suggestion applicabilities for libsyntax and librustc, run-rustfix tests
authorZack M. Davis <code@zackmdavis.net>
Sat, 19 May 2018 21:52:24 +0000 (14:52 -0700)
committerZack M. Davis <code@zackmdavis.net>
Sun, 20 May 2018 21:13:25 +0000 (14:13 -0700)
Consider this a down payment on #50723. To recap, an `Applicability`
enum was recently (#50204) added, to convey to Rustfix and other tools
whether we think it's OK for them to blindly apply the suggestion, or
whether to prompt a human for guidance (because the suggestion might
contain placeholders that we can't infer, or because we think it has a
sufficiently high probability of being wrong even though it's—
presumably—right often enough to be worth emitting in the first place).

When a suggestion is marked as `MaybeIncorrect`, we try to use comments
to indicate precisely why (although there are a few places where we just
say `// speculative` because the present author's subjective judgement
balked at the idea that the suggestion has no false positives).

The `run-rustfix` directive is opporunistically set on some relevant UI
tests (and a couple tests that were in the `test/ui/suggestions`
directory, even if the suggestions didn't originate in librustc or
libsyntax). This is less trivial than it sounds, because a surprising
number of test files aren't equipped to be tested as fixed even when
they contain successfully fixable errors, because, e.g., there are more,
not-directly-related errors after fixing. Some test files need an
attribute or underscore to avoid unused warnings tripping up the "fixed
code is still producing diagnostics" check despite the fixes being
correct; this is an interesting contrast-to/inconsistency-with the
behavior of UI tests (which secretly pass `-A unused`), a behavior which
we probably ought to resolve one way or the other (filed issue #50926).

A few suggestion labels are reworded (e.g., to avoid phrasing it as a
question, which which is discouraged by the style guidelines listed in
`.span_suggestion`'s doc-comment).

33 files changed:
src/librustc/infer/error_reporting/mod.rs
src/librustc/lint/levels.rs
src/librustc/middle/liveness.rs
src/librustc/traits/error_reporting.rs
src/libsyntax/attr.rs
src/libsyntax/ext/expand.rs
src/libsyntax/parse/lexer/mod.rs
src/libsyntax/parse/parser.rs
src/test/ui/extern-const.fixed [new file with mode: 0644]
src/test/ui/extern-const.rs
src/test/ui/extern-const.stderr
src/test/ui/issue-42954.fixed [new file with mode: 0644]
src/test/ui/issue-42954.rs
src/test/ui/issue-42954.stderr
src/test/ui/issue-44406.stderr
src/test/ui/issue-48636.fixed [new file with mode: 0644]
src/test/ui/issue-48636.rs
src/test/ui/issue-48636.stderr
src/test/ui/mismatched_types/closure-arg-count-expected-type-issue-47244.fixed [new file with mode: 0644]
src/test/ui/mismatched_types/closure-arg-count-expected-type-issue-47244.rs
src/test/ui/mismatched_types/closure-arg-count-expected-type-issue-47244.stderr
src/test/ui/repr-align-assign.fixed [new file with mode: 0644]
src/test/ui/repr-align-assign.rs
src/test/ui/repr-align-assign.stderr
src/test/ui/suggestions/issue-32354-suggest-import-rename.fixed [new file with mode: 0644]
src/test/ui/suggestions/issue-32354-suggest-import-rename.rs
src/test/ui/suggestions/issue-32354-suggest-import-rename.stderr
src/test/ui/suggestions/pub-ident-fn-or-struct-2.stderr
src/test/ui/suggestions/pub-ident-fn-or-struct.stderr
src/test/ui/suggestions/pub-ident-fn.fixed [new file with mode: 0644]
src/test/ui/suggestions/pub-ident-fn.rs
src/test/ui/suggestions/pub-ident-fn.stderr
src/test/ui/suggestions/type-ascription-instead-of-statement-end.stderr

index da93156b0b0bd53c2acfd930d7346b08bbbca934..4bde363672dcc68f4f08b845e4d75fe3dc0644b2 100644 (file)
@@ -70,7 +70,7 @@
 use ty::error::TypeError;
 use syntax::ast::DUMMY_NODE_ID;
 use syntax_pos::{Pos, Span};
-use errors::{DiagnosticBuilder, DiagnosticStyledString};
+use errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
 
 use rustc_data_structures::indexed_vec::Idx;
 
@@ -1097,7 +1097,10 @@ fn binding_suggestion<'tcx, S: fmt::Display>(
             if let Some((sp, has_lifetimes)) = type_param_span {
                 let tail = if has_lifetimes { " + " } else { "" };
                 let suggestion = format!("{}: {}{}", bound_kind, sub, tail);
-                err.span_suggestion_short(sp, consider, suggestion);
+                err.span_suggestion_short_with_applicability(
+                    sp, consider, suggestion,
+                    Applicability::MaybeIncorrect // Issue #41966
+                );
             } else {
                 err.help(consider);
             }
index d158f52c643ceca2c2896acabe6c8cf02bd21add..3393a2bf89d4b41408108d3a636a88fdf75c6b2f 100644 (file)
@@ -10,7 +10,7 @@
 
 use std::cmp;
 
-use errors::DiagnosticBuilder;
+use errors::{Applicability, DiagnosticBuilder};
 use hir::HirId;
 use ich::StableHashingContext;
 use lint::builtin;
@@ -265,10 +265,11 @@ pub fn push(&mut self, attrs: &[ast::Attribute]) -> BuilderPush {
                                     store.check_lint_name(&name_lower) {
                                 db.emit();
                             } else {
-                                db.span_suggestion(
+                                db.span_suggestion_with_applicability(
                                     li.span,
                                     "lowercase the lint name",
-                                    name_lower
+                                    name_lower,
+                                    Applicability::MachineApplicable
                                 ).emit();
                             }
                         } else {
index 3db8c746713fd3f7cf64202b28804ba5029cef2e..0ac0fdd79cbb882eb384d71b7bec34ad7eeb2a00 100644 (file)
 use hir::def::*;
 use ty::{self, TyCtxt};
 use lint;
+use errors::Applicability;
 use util::nodemap::{NodeMap, NodeSet};
 
 use std::collections::VecDeque;
@@ -1541,11 +1542,15 @@ fn warn_about_unused(&self,
                     let mut err = self.ir.tcx
                         .struct_span_lint_node(lint::builtin::UNUSED_VARIABLES, id, sp, &msg);
                     if self.ir.variable_is_shorthand(var) {
-                        err.span_suggestion(sp, "try ignoring the field",
-                                            format!("{}: _", name));
+                        err.span_suggestion_with_applicability(sp, "try ignoring the field",
+                                                               format!("{}: _", name),
+                                                               Applicability::MachineApplicable);
                     } else {
-                        err.span_suggestion_short(sp, &suggest_underscore_msg,
-                                                  format!("_{}", name));
+                        err.span_suggestion_short_with_applicability(
+                            sp, &suggest_underscore_msg,
+                            format!("_{}", name),
+                            Applicability::MachineApplicable,
+                        );
                     }
                     err.emit()
                 }
index 97ce730c59ec508f76e16a0c824529207e2270d0..66eee3e7c1ac87bb1370d2414ef0427b86ab84d1 100644 (file)
@@ -27,7 +27,7 @@
     Overflow,
 };
 
-use errors::DiagnosticBuilder;
+use errors::{Applicability, DiagnosticBuilder};
 use hir;
 use hir::def_id::DefId;
 use infer::{self, InferCtxt};
@@ -856,9 +856,12 @@ fn suggest_borrow_on_unsized_slice(&self,
                 if let Some(ref expr) = local.init {
                     if let hir::ExprIndex(_, _) = expr.node {
                         if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(expr.span) {
-                            err.span_suggestion(expr.span,
-                                                "consider borrowing here",
-                                                format!("&{}", snippet));
+                            err.span_suggestion_with_applicability(
+                                expr.span,
+                                "consider borrowing here",
+                                format!("&{}", snippet),
+                                Applicability::MachineApplicable
+                            );
                         }
                     }
                 }
@@ -901,7 +904,9 @@ fn suggest_remove_reference(&self,
                         let format_str = format!("consider removing {} leading `&`-references",
                                                  remove_refs);
 
-                        err.span_suggestion_short(sp, &format_str, String::from(""));
+                        err.span_suggestion_short_with_applicability(
+                            sp, &format_str, String::from(""), Applicability::MachineApplicable
+                        );
                         break;
                     }
                 } else {
@@ -1046,10 +1051,11 @@ pub fn report_arg_count_mismatch(
                     let sugg = fields.iter()
                         .map(|(name, _)| name.to_owned())
                         .collect::<Vec<String>>().join(", ");
-                    err.span_suggestion(found_span,
-                                        "change the closure to take multiple arguments instead of \
-                                         a single tuple",
-                                        format!("|{}|", sugg));
+                    err.span_suggestion_with_applicability(found_span,
+                                                           "change the closure to take multiple \
+                                                            arguments instead of a single tuple",
+                                                           format!("|{}|", sugg),
+                                                           Applicability::MachineApplicable);
                 }
             }
             if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] {
@@ -1077,10 +1083,13 @@ pub fn report_arg_count_mismatch(
                             "".to_owned()
                         },
                     );
-                    err.span_suggestion(found_span,
-                                        "change the closure to accept a tuple instead of \
-                                         individual arguments",
-                                        sugg);
+                    err.span_suggestion_with_applicability(
+                        found_span,
+                        "change the closure to accept a tuple instead of \
+                         individual arguments",
+                        sugg,
+                        Applicability::MachineApplicable
+                    );
                 }
             }
         }
index fcda6ce9b164deb00384bcba5b31aba3bc6332db..076b6d1765848104aecc0fe2e6fae18eb0aa2c05 100644 (file)
@@ -20,7 +20,7 @@
 use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind};
 use codemap::{BytePos, Spanned, respan, dummy_spanned};
 use syntax_pos::Span;
-use errors::Handler;
+use errors::{Applicability, Handler};
 use feature_gate::{Features, GatedCfg};
 use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
 use parse::parser::Parser;
@@ -1067,14 +1067,20 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr>
                                     "incorrect `repr(align)` attribute format");
                                 match value.node {
                                     ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
-                                        err.span_suggestion(item.span,
-                                                            "use parentheses instead",
-                                                            format!("align({})", int));
+                                        err.span_suggestion_with_applicability(
+                                            item.span,
+                                            "use parentheses instead",
+                                            format!("align({})", int),
+                                            Applicability::MachineApplicable
+                                        );
                                     }
                                     ast::LitKind::Str(s, _) => {
-                                        err.span_suggestion(item.span,
-                                                            "use parentheses instead",
-                                                            format!("align({})", s));
+                                        err.span_suggestion_with_applicability(
+                                            item.span,
+                                            "use parentheses instead",
+                                            format!("align({})", s),
+                                            Applicability::MachineApplicable
+                                        );
                                     }
                                     _ => {}
                                 }
index 146db632c07bae6c12b33bc92db529764843be34..0bee8e20009a6662e669652676034834d4eb7466 100644 (file)
@@ -13,7 +13,7 @@
 use attr::{self, HasAttrs};
 use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute, dummy_spanned, respan};
 use config::{is_test_or_bench, StripUnconfigured};
-use errors::FatalError;
+use errors::{Applicability, FatalError};
 use ext::base::*;
 use ext::derive::{add_derived_markers, collect_derives};
 use ext::hygiene::{self, Mark, SyntaxContext};
@@ -331,7 +331,11 @@ fn expand(&mut self, expansion: Expansion) -> Expansion {
                             let trait_list = traits.iter()
                                 .map(|t| format!("{}", t)).collect::<Vec<_>>();
                             let suggestion = format!("#[derive({})]", trait_list.join(", "));
-                            err.span_suggestion(span, "try an outer attribute", suggestion);
+                            err.span_suggestion_with_applicability(
+                                span, "try an outer attribute", suggestion,
+                                // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT
+                                Applicability::MaybeIncorrect
+                            );
                         }
                         err.emit();
                     }
index bbece1ee5e3d4474e286737cb53d74b5bbb73a6a..b665f528cfc030662c308c144acb383b0715fec8 100644 (file)
@@ -11,7 +11,7 @@
 use ast::{self, Ident};
 use syntax_pos::{self, BytePos, CharPos, Pos, Span, NO_EXPANSION};
 use codemap::{CodeMap, FilePathMapping};
-use errors::{FatalError, DiagnosticBuilder};
+use errors::{Applicability, FatalError, DiagnosticBuilder};
 use parse::{token, ParseSess};
 use str::char_at;
 use symbol::{Symbol, keywords};
@@ -1345,11 +1345,12 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
                             self.sess.span_diagnostic
                                 .struct_span_err(span,
                                                  "character literal may only contain one codepoint")
-                                .span_suggestion(span,
-                                                 "if you meant to write a `str` literal, \
-                                                  use double quotes",
-                                                 format!("\"{}\"", &self.src[start..end]))
-                                .emit();
+                                .span_suggestion_with_applicability(
+                                    span,
+                                    "if you meant to write a `str` literal, use double quotes",
+                                    format!("\"{}\"", &self.src[start..end]),
+                                    Applicability::MachineApplicable
+                                ).emit();
                             return Ok(token::Literal(token::Str_(Symbol::intern("??")), None))
                         }
                         if self.ch_is('\n') || self.is_eof() || self.ch_is('/') {
index 3e9869494f93449beae7f57f654c4d2e394dfff3..1a7f897802aa901083acb292f4eecac6386d0297 100644 (file)
@@ -43,7 +43,7 @@
 use {ast, attr};
 use codemap::{self, CodeMap, Spanned, respan};
 use syntax_pos::{self, Span, MultiSpan, BytePos, FileName, DUMMY_SP};
-use errors::{self, DiagnosticBuilder};
+use errors::{self, Applicability, DiagnosticBuilder};
 use parse::{self, classify, token};
 use parse::common::SeqSep;
 use parse::lexer::TokenAndSpan;
@@ -1648,8 +1648,12 @@ fn maybe_report_ambiguous_plus(&mut self, allow_plus: bool, impl_dyn_multi: bool
         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)
-                .emit();
+                .span_suggestion_with_applicability(
+                    ty.span,
+                    "use parentheses to disambiguate",
+                    sum_with_parens,
+                    Applicability::MachineApplicable
+                ).emit();
         }
     }
 
@@ -1679,7 +1683,12 @@ fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PRe
                     s.print_bounds(" +", &bounds)?;
                     s.pclose()
                 });
-                err.span_suggestion(sum_span, "try adding parentheses", sum_with_parens);
+                err.span_suggestion_with_applicability(
+                    sum_span,
+                    "try adding parentheses",
+                    sum_with_parens,
+                    Applicability::MachineApplicable
+                );
             }
             TyKind::Ptr(..) | TyKind::BareFn(..) => {
                 err.span_label(sum_span, "perhaps you forgot parentheses?");
@@ -1714,7 +1723,9 @@ fn maybe_recover_from_bad_qpath<T: RecoverQPath>(&mut self, base: T, allow_recov
 
         self.diagnostic()
             .struct_span_err(span, "missing angle brackets in associated item path")
-            .span_suggestion(span, "try", recovered.to_string()).emit();
+            .span_suggestion_with_applicability( // this is a best-effort recovery
+                span, "try", recovered.to_string(), Applicability::MaybeIncorrect
+            ).emit();
 
         Ok(recovered)
     }
@@ -2465,7 +2476,12 @@ fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec<Att
                         exp_span.to(self.prev_span),
                         "cannot use a comma after the base struct",
                     );
-                    err.span_suggestion_short(self.span, "remove this comma", "".to_owned());
+                    err.span_suggestion_short_with_applicability(
+                        self.span,
+                        "remove this comma",
+                        "".to_owned(),
+                        Applicability::MachineApplicable
+                    );
                     err.note("the base struct must always be the last field");
                     err.emit();
                     self.recover_stmt();
@@ -2638,10 +2654,12 @@ fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>, lo: Span) -> PResult<'a,
                             s.s.word(".")?;
                             s.s.word(fstr.splitn(2, ".").last().unwrap())
                         });
-                        err.span_suggestion(
+                        err.span_suggestion_with_applicability(
                             lo.to(self.prev_span),
                             "try parenthesizing the first index",
-                            sugg);
+                            sugg,
+                            Applicability::MachineApplicable
+                        );
                     }
                     return Err(err);
 
@@ -2781,9 +2799,12 @@ pub fn parse_prefix_expr(&mut self,
                 let span_of_tilde = lo;
                 let mut err = self.diagnostic().struct_span_err(span_of_tilde,
                         "`~` cannot be used as a unary operator");
-                err.span_suggestion_short(span_of_tilde,
-                                          "use `!` to perform bitwise negation",
-                                          "!".to_owned());
+                err.span_suggestion_short_with_applicability(
+                    span_of_tilde,
+                    "use `!` to perform bitwise negation",
+                    "!".to_owned(),
+                    Applicability::MachineApplicable
+                );
                 err.emit();
                 (lo.to(span), self.mk_unary(UnOp::Not, e))
             }
@@ -2840,9 +2861,12 @@ pub fn parse_prefix_expr(&mut self,
                     // trailing whitespace after the `!` in our suggestion
                     let to_replace = self.sess.codemap()
                         .span_until_non_whitespace(lo.to(self.span));
-                    err.span_suggestion_short(to_replace,
-                                              "use `!` to perform logical negation",
-                                              "!".to_owned());
+                    err.span_suggestion_short_with_applicability(
+                        to_replace,
+                        "use `!` to perform logical negation",
+                        "!".to_owned(),
+                        Applicability::MachineApplicable
+                    );
                     err.emit();
                     // —and recover! (just as if we were in the block
                     // for the `token::Not` arm)
@@ -2937,9 +2961,12 @@ pub fn parse_assoc_expr_with(&mut self,
                         let cur_pos = cm.lookup_char_pos(self.span.lo());
                         let op_pos = cm.lookup_char_pos(cur_op_span.hi());
                         if cur_pos.line != op_pos.line {
-                            err.span_suggestion_short(cur_op_span,
-                                                      "did you mean to use `;` here?",
-                                                      ";".to_string());
+                            err.span_suggestion_with_applicability(
+                                cur_op_span,
+                                "try using a semicolon",
+                                ";".to_string(),
+                                Applicability::MaybeIncorrect // speculative
+                            );
                         }
                         return Err(err);
                     }
@@ -3091,9 +3118,12 @@ fn parse_assoc_op_cast(&mut self, lhs: P<Expr>, lhs_span: Span,
 
                         let expr_str = self.sess.codemap().span_to_snippet(expr.span)
                                                 .unwrap_or(pprust::expr_to_string(&expr));
-                        err.span_suggestion(expr.span,
-                                            &format!("try {} the cast value", op_verb),
-                                            format!("({})", expr_str));
+                        err.span_suggestion_with_applicability(
+                            expr.span,
+                            &format!("try {} the cast value", op_verb),
+                            format!("({})", expr_str),
+                            Applicability::MachineApplicable
+                        );
                         err.emit();
 
                         Ok(expr)
@@ -3301,7 +3331,11 @@ pub fn parse_for_expr(&mut self, opt_label: Option<Label>,
             let in_span = self.prev_span.between(self.span);
             let mut err = self.sess.span_diagnostic
                 .struct_span_err(in_span, "missing `in` in `for` loop");
-            err.span_suggestion_short(in_span, "try adding `in` here", " in ".into());
+            err.span_suggestion_short_with_applicability(
+                in_span, "try adding `in` here", " in ".into(),
+                // has been misleading, at least in the past (closed Issue #48492)
+                Applicability::MaybeIncorrect
+            );
             err.emit();
         }
         let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
@@ -3367,7 +3401,12 @@ fn parse_match_expr(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<E
                                                None)?;
         if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) {
             if self.token == token::Token::Semi {
-                e.span_suggestion_short(match_span, "try removing this `match`", "".to_owned());
+                e.span_suggestion_short_with_applicability(
+                    match_span,
+                    "try removing this `match`",
+                    "".to_owned(),
+                    Applicability::MaybeIncorrect // speculative
+                );
             }
             return Err(e)
         }
@@ -3439,10 +3478,11 @@ pub fn parse_arm(&mut self) -> PResult<'a, Arm> {
                             //   |      - ^^ self.span
                             //   |      |
                             //   |      parsed until here as `"y" & X`
-                            err.span_suggestion_short(
+                            err.span_suggestion_short_with_applicability(
                                 cm.next_point(arm_start_span),
                                 "missing a comma here to end this `match` arm",
-                                ",".to_owned()
+                                ",".to_owned(),
+                                Applicability::MachineApplicable
                             );
                         }
                         _ => {
@@ -3511,9 +3551,12 @@ fn parse_pats(&mut self) -> PResult<'a, Vec<P<Pat>>> {
             if self.token == token::OrOr {
                 let mut err = self.struct_span_err(self.span,
                                                    "unexpected token `||` after pattern");
-                err.span_suggestion(self.span,
-                                    "use a single `|` to specify multiple patterns",
-                                    "|".to_owned());
+                err.span_suggestion_with_applicability(
+                    self.span,
+                    "use a single `|` to specify multiple patterns",
+                    "|".to_owned(),
+                    Applicability::MachineApplicable
+                );
                 err.emit();
                 self.bump();
             } else if self.check(&token::BinOp(token::Or)) {
@@ -3643,9 +3686,12 @@ fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<codemap::Spanned<ast::FieldPa
                 if self.token == token::DotDotDot { // Issue #46718
                     let mut err = self.struct_span_err(self.span,
                                                        "expected field pattern, found `...`");
-                    err.span_suggestion(self.span,
-                                        "to omit remaining fields, use one fewer `.`",
-                                        "..".to_owned());
+                    err.span_suggestion_with_applicability(
+                        self.span,
+                        "to omit remaining fields, use one fewer `.`",
+                        "..".to_owned(),
+                        Applicability::MachineApplicable
+                    );
                     err.emit();
                 }
 
@@ -3776,8 +3822,12 @@ pub fn parse_top_level_pat(&mut self) -> PResult<'a, P<Pat>> {
             let mut err = self.struct_span_err(comma_span,
                                                "unexpected `,` in pattern");
             if let Ok(seq_snippet) = self.sess.codemap().span_to_snippet(seq_span) {
-                err.span_suggestion(seq_span, "try adding parentheses",
-                                    format!("({})", seq_snippet));
+                err.span_suggestion_with_applicability(
+                    seq_span,
+                    "try adding parentheses",
+                    format!("({})", seq_snippet),
+                    Applicability::MachineApplicable
+                );
             }
             return Err(err);
         }
@@ -3836,8 +3886,12 @@ fn parse_pat_with_range_pat(&mut self, allow_range_pat: bool) -> PResult<'a, P<P
                 let binding_mode = if self.eat_keyword(keywords::Ref) {
                     self.diagnostic()
                         .struct_span_err(mutref_span, "the order of `mut` and `ref` is incorrect")
-                        .span_suggestion(mutref_span, "try switching the order", "ref mut".into())
-                        .emit();
+                        .span_suggestion_with_applicability(
+                            mutref_span,
+                            "try switching the order",
+                            "ref mut".into(),
+                            Applicability::MachineApplicable
+                        ).emit();
                     BindingMode::ByRef(Mutability::Mutable)
                 } else {
                     BindingMode::ByValue(Mutability::Mutable)
@@ -3962,10 +4016,12 @@ fn parse_pat_with_range_pat(&mut self, allow_range_pat: bool) -> PResult<'a, P<P
                         pat.span,
                         "the range pattern here has ambiguous interpretation",
                     );
-                    err.span_suggestion(
+                    err.span_suggestion_with_applicability(
                         pat.span,
                         "add parentheses to clarify the precedence",
                         format!("({})", pprust::pat_to_string(&pat)),
+                        // "ambiguous interpretation" implies that we have to be guessing
+                        Applicability::MaybeIncorrect
                     );
                     return Err(err);
                 }
@@ -4036,9 +4092,12 @@ fn parse_local(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Local>> {
             (Ok(init), Some((_, colon_sp, mut err))) => {  // init parsed, ty error
                 // Could parse the type as if it were the initializer, it is likely there was a
                 // typo in the code: `:` instead of `=`. Add suggestion and emit the error.
-                err.span_suggestion_short(colon_sp,
-                                          "use `=` if you meant to assign",
-                                          "=".to_string());
+                err.span_suggestion_short_with_applicability(
+                    colon_sp,
+                    "use `=` if you meant to assign",
+                    "=".to_string(),
+                    Applicability::MachineApplicable
+                );
                 err.emit();
                 // As this was parsed successfully, continue as if the code has been fixed for the
                 // rest of the file. It will still fail due to the emitted error, but we avoid
@@ -4526,7 +4585,13 @@ pub fn parse_block(&mut self) -> PResult<'a, P<Block>> {
                         s.print_stmt(&stmt)?;
                         s.bclose_maybe_open(stmt.span, INDENT_UNIT, false)
                     });
-                    e.span_suggestion(stmt_span, "try placing this code inside a block", sugg);
+                    e.span_suggestion_with_applicability(
+                        stmt_span,
+                        "try placing this code inside a block",
+                        sugg,
+                        // speculative, has been misleading in the past (closed Issue #46836)
+                        Applicability::MaybeIncorrect
+                    );
                 }
                 Err(mut e) => {
                     self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
@@ -5370,9 +5435,12 @@ fn complain_if_pub_macro_diag(&mut self, vis: &VisibilityKind, sp: Span) -> PRes
                 if is_macro_rules {
                     let mut err = self.diagnostic()
                         .struct_span_err(sp, "can't qualify macro_rules invocation with `pub`");
-                    err.span_suggestion(sp,
-                                        "try exporting the macro",
-                                        "#[macro_export]".to_owned());
+                    err.span_suggestion_with_applicability(
+                        sp,
+                        "try exporting the macro",
+                        "#[macro_export]".to_owned(),
+                        Applicability::MaybeIncorrect // speculative
+                    );
                     Err(err)
                 } else {
                     let mut err = self.diagnostic()
@@ -5793,7 +5861,12 @@ pub fn parse_single_struct_field(&mut self,
                 } else {
                     if seen_comma == false {
                         let sp = self.sess.codemap().next_point(previous_span);
-                        err.span_suggestion(sp, "missing comma here", ",".into());
+                        err.span_suggestion_with_applicability(
+                            sp,
+                            "missing comma here",
+                            ",".into(),
+                            Applicability::MachineApplicable
+                        );
                     }
                     return Err(err);
                 }
@@ -5883,7 +5956,9 @@ pub fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibili
                 let help_msg = format!("make this visible only to module `{}` with `in`", path);
                 self.expect(&token::CloseDelim(token::Paren))?;  // `)`
                 let mut err = self.span_fatal_help(path_span, msg, suggestion);
-                err.span_suggestion(path_span, &help_msg, format!("in {}", path));
+                err.span_suggestion_with_applicability(
+                    path_span, &help_msg, format!("in {}", path), Applicability::MachineApplicable
+                );
                 err.emit();  // emit diagnostic, but continue with public visibility
             }
         }
@@ -5921,7 +5996,9 @@ fn parse_mod_items(&mut self, term: &token::Token, inner_lo: Span) -> PResult<'a
             let mut err = self.fatal(&format!("expected item, found `{}`", token_str));
             if token_str == ";" {
                 let msg = "consider removing this semicolon";
-                err.span_suggestion_short(self.span, msg, "".to_string());
+                err.span_suggestion_short_with_applicability(
+                    self.span, msg, "".to_string(), Applicability::MachineApplicable
+                );
             } else {
                 err.span_label(self.span, "expected item");
             }
@@ -6735,7 +6812,9 @@ fn parse_item_(&mut self, attrs: Vec<Attribute>,
                                   ident);
                 let mut err = self.diagnostic()
                     .struct_span_err(sp, "missing `struct` for struct definition");
-                err.span_suggestion_short(sp, &msg, " struct ".into());
+                err.span_suggestion_short_with_applicability(
+                    sp, &msg, " struct ".into(), Applicability::MaybeIncorrect // speculative
+                );
                 return Err(err);
             } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) {
                 let ident = self.parse_ident().unwrap();
@@ -6758,13 +6837,18 @@ fn parse_item_(&mut self, attrs: Vec<Attribute>,
                                              kw,
                                              ident,
                                              kw_name);
-                    err.span_suggestion_short(sp, &suggestion, format!(" {} ", kw));
+                    err.span_suggestion_short_with_applicability(
+                        sp, &suggestion, format!(" {} ", kw), Applicability::MachineApplicable
+                    );
                 } else {
                     if let Ok(snippet) = self.sess.codemap().span_to_snippet(ident_sp) {
-                        err.span_suggestion(
+                        err.span_suggestion_with_applicability(
                             full_sp,
-                            "if you meant to call a macro, write instead",
-                            format!("{}!", snippet));
+                            "if you meant to call a macro, try",
+                            format!("{}!", snippet),
+                            // this is the `ambiguous` conditional branch
+                            Applicability::MaybeIncorrect
+                        );
                     } else {
                         err.help("if you meant to call a macro, remove the `pub` \
                                   and add a trailing `!` after the identifier");
@@ -6790,8 +6874,12 @@ pub fn parse_foreign_item(&mut self) -> PResult<'a, Option<ForeignItem>> {
             if self.token.is_keyword(keywords::Const) {
                 self.diagnostic()
                     .struct_span_err(self.span, "extern items cannot be `const`")
-                    .span_suggestion(self.span, "instead try using", "static".to_owned())
-                    .emit();
+                    .span_suggestion_with_applicability(
+                        self.span,
+                        "try using a static value",
+                        "static".to_owned(),
+                        Applicability::MachineApplicable
+                    ).emit();
             }
             self.bump(); // `static` or `const`
             return Ok(Some(self.parse_item_foreign_static(visibility, lo, attrs)?));
diff --git a/src/test/ui/extern-const.fixed b/src/test/ui/extern-const.fixed
new file mode 100644 (file)
index 0000000..6e131ca
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-rustfix
+// compile-flags: -Z continue-parse-after-error
+
+extern "C" {
+    static C: u8; //~ ERROR extern items cannot be `const`
+}
+
+fn main() {
+    // We suggest turning the (illegal) extern `const` into an extern `static`,
+    // but this also requires `unsafe` (a deny-by-default lint at comment time,
+    // future error; Issue #36247)
+    unsafe {
+        let _x = C;
+    }
+}
index a77d7b118956653e8b5df8dca22188f27a3b21c2..4a766b9724dc2754486f6b512f256360eac1dd8b 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// run-rustfix
 // compile-flags: -Z continue-parse-after-error
 
 extern "C" {
 }
 
 fn main() {
-    let x = C;
+    // We suggest turning the (illegal) extern `const` into an extern `static`,
+    // but this also requires `unsafe` (a deny-by-default lint at comment time,
+    // future error; Issue #36247)
+    unsafe {
+        let _x = C;
+    }
 }
index f416f596b25520806a51f7295cd46cb369bf24af..cbed5e56c76c4523c42e39712d30cfc575bd2416 100644 (file)
@@ -1,8 +1,8 @@
 error: extern items cannot be `const`
-  --> $DIR/extern-const.rs:14:5
+  --> $DIR/extern-const.rs:15:5
    |
 LL |     const C: u8; //~ ERROR extern items cannot be `const`
-   |     ^^^^^ help: instead try using: `static`
+   |     ^^^^^ help: try using a static value: `static`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issue-42954.fixed b/src/test/ui/issue-42954.fixed
new file mode 100644 (file)
index 0000000..d05996f
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-rustfix
+
+#![allow(unused_must_use, unused_comparisons)]
+
+macro_rules! is_plainly_printable {
+    ($i: ident) => {
+        ($i as u32) < 0 //~ `<` is interpreted as a start of generic arguments
+    };
+}
+
+fn main() {
+    let c = 'a';
+    is_plainly_printable!(c);
+}
index 6fa2c69bf66968739fe85a4eaa25feae45bebbc3..8226cedc0c42199aa24bb2ba527832b1af7b2c57 100644 (file)
@@ -8,6 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// run-rustfix
+
+#![allow(unused_must_use, unused_comparisons)]
+
 macro_rules! is_plainly_printable {
     ($i: ident) => {
         $i as u32 < 0 //~ `<` is interpreted as a start of generic arguments
index 9164434006f6170f39dfd1f9aec281b2dc3b2f67..aa332602f9e8fbd50b36751b65eb91faa3d755e1 100644 (file)
@@ -1,5 +1,5 @@
 error: `<` is interpreted as a start of generic arguments for `u32`, not a comparison
-  --> $DIR/issue-42954.rs:13:19
+  --> $DIR/issue-42954.rs:17:19
    |
 LL |         $i as u32 < 0 //~ `<` is interpreted as a start of generic arguments
    |         --------- ^ - interpreted as generic arguments
index de7c11732e4a39e029c9df88134f2ba062f4da30..5cd9b3f065eb8fbc07ce3bd341ebe60154da0c04 100644 (file)
@@ -8,7 +8,7 @@ error: expected type, found keyword `true`
   --> $DIR/issue-44406.rs:18:10
    |
 LL |         bar(baz: $rest)
-   |                - help: did you mean to use `;` here?
+   |                - help: try using a semicolon: `;`
 ...
 LL |     foo!(true); //~ ERROR expected type, found keyword
    |          ^^^^ expecting a type here because of type ascription
diff --git a/src/test/ui/issue-48636.fixed b/src/test/ui/issue-48636.fixed
new file mode 100644 (file)
index 0000000..0ff33c4
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-rustfix
+
+#![allow(dead_code)]
+
+struct S {
+    x: u8,
+    /// The id of the parent core
+    y: u8,
+}
+//~^^^ ERROR found a documentation comment that doesn't document anything
+fn main() {}
index 03e45d88e6cf1e3698123a65be7597fefb778f5d..2ac41211347b5ccbeab613142185f92e0b0a3172 100644 (file)
@@ -8,6 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// run-rustfix
+
+#![allow(dead_code)]
+
 struct S {
     x: u8
     /// The id of the parent core
index 4e014a5bd1d1d50c41ade358ef67afbd3151394b..c4706f982ed74ff2cb201c49f0ddf5bca1cf1f43 100644 (file)
@@ -1,5 +1,5 @@
 error[E0585]: found a documentation comment that doesn't document anything
-  --> $DIR/issue-48636.rs:13:5
+  --> $DIR/issue-48636.rs:17:5
    |
 LL |     x: u8
    |          - help: missing comma here: `,`
diff --git a/src/test/ui/mismatched_types/closure-arg-count-expected-type-issue-47244.fixed b/src/test/ui/mismatched_types/closure-arg-count-expected-type-issue-47244.fixed
new file mode 100644 (file)
index 0000000..1a7608f
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for #47244: in this specific scenario, when the
+// expected type indicated 1 argument but the closure takes two, we
+// would (early on) create type variables for the type of `b`. If the
+// user then attempts to invoke a method on `b`, we would get an error
+// saying that the type of `b` must be known, which was not very
+// helpful.
+
+// run-rustfix
+
+use std::collections::HashMap;
+
+fn main() {
+    let mut m = HashMap::new();
+    m.insert("foo", "bar");
+
+    let _n = m.iter().map(|(_, b)| {
+        //~^ ERROR closure is expected to take a single 2-tuple
+        b.to_string()
+    });
+}
index b6463ca067b7f5c7eb1faba7e36f396e7ca3e8c8..0ca0753490a2ffdf7a949ab4d6a4c2e43ddb4c82 100644 (file)
 // saying that the type of `b` must be known, which was not very
 // helpful.
 
+// run-rustfix
+
 use std::collections::HashMap;
-fn main() {
 
-    let m = HashMap::new();
-    m.insert( "foo", "bar" );
+fn main() {
+    let mut m = HashMap::new();
+    m.insert("foo", "bar");
 
-    m.iter().map( |_, b| {
+    let _n = m.iter().map(|_, b| {
         //~^ ERROR closure is expected to take a single 2-tuple
-
         b.to_string()
     });
 }
index 262c4aa1a7c7af57ea878ef4d68ddad5368fd0de..c95d8157b0ce1b7638366ea9f5b4105565de2bc9 100644 (file)
@@ -1,14 +1,14 @@
 error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments
-  --> $DIR/closure-arg-count-expected-type-issue-47244.rs:24:14
+  --> $DIR/closure-arg-count-expected-type-issue-47244.rs:26:23
    |
-LL |     m.iter().map( |_, b| {
-   |              ^^^  ------ takes 2 distinct arguments
-   |              |
-   |              expected closure that takes a single 2-tuple as argument
+LL |     let _n = m.iter().map(|_, b| {
+   |                       ^^^ ------ takes 2 distinct arguments
+   |                       |
+   |                       expected closure that takes a single 2-tuple as argument
 help: change the closure to accept a tuple instead of individual arguments
    |
-LL |     m.iter().map( |(_, b)| {
-   |                   ^^^^^^^^
+LL |     let _n = m.iter().map(|(_, b)| {
+   |                           ^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/repr-align-assign.fixed b/src/test/ui/repr-align-assign.fixed
new file mode 100644 (file)
index 0000000..62147e7
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-rustfix
+
+#![allow(dead_code)]
+
+#[repr(align(8))] //~ ERROR incorrect `repr(align)` attribute format
+struct A(u64);
+
+#[repr(align(8))] //~ ERROR incorrect `repr(align)` attribute format
+struct B(u64);
+
+fn main() {}
index c9780dde235bcb7485159ea84bb260ad68a65ef6..3bc3b5c64ce251cec6f5f63cbd0f0319428086dd 100644 (file)
@@ -8,6 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// run-rustfix
+
+#![allow(dead_code)]
+
 #[repr(align=8)] //~ ERROR incorrect `repr(align)` attribute format
 struct A(u64);
 
index 1fa1263b9467ef62d7e61a536221b361208709c3..c325b6968fe438ccd68c504163b3d8752a16600d 100644 (file)
@@ -1,11 +1,11 @@
 error[E0693]: incorrect `repr(align)` attribute format
-  --> $DIR/repr-align-assign.rs:11:8
+  --> $DIR/repr-align-assign.rs:15:8
    |
 LL | #[repr(align=8)] //~ ERROR incorrect `repr(align)` attribute format
    |        ^^^^^^^ help: use parentheses instead: `align(8)`
 
 error[E0693]: incorrect `repr(align)` attribute format
-  --> $DIR/repr-align-assign.rs:14:8
+  --> $DIR/repr-align-assign.rs:18:8
    |
 LL | #[repr(align="8")] //~ ERROR incorrect `repr(align)` attribute format
    |        ^^^^^^^^^ help: use parentheses instead: `align(8)`
diff --git a/src/test/ui/suggestions/issue-32354-suggest-import-rename.fixed b/src/test/ui/suggestions/issue-32354-suggest-import-rename.fixed
new file mode 100644 (file)
index 0000000..251f7eb
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-rustfix
+
+#![allow(unused_imports)]
+
+pub mod extension1 {
+    pub trait ConstructorExtension {}
+}
+
+pub mod extension2 {
+    pub trait ConstructorExtension {}
+}
+
+use extension1::ConstructorExtension;
+use extension2::ConstructorExtension as OtherConstructorExtension; //~ ERROR is defined multiple times
+
+fn main() {}
index 9d71ab1a788ebf4420c13ea1954fd8c3c68ba32c..57cbeb47a1e0492a41aa02bb43c662667a016c54 100644 (file)
@@ -8,6 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// run-rustfix
+
+#![allow(unused_imports)]
+
 pub mod extension1 {
     pub trait ConstructorExtension {}
 }
index 7cf7a1d15a27a57f5fc71f40b9d1ca4c55d8e870..f45a5f7dd619ba168ec5079af74afb934051afbb 100644 (file)
@@ -1,5 +1,5 @@
 error[E0252]: the name `ConstructorExtension` is defined multiple times
-  --> $DIR/issue-32354-suggest-import-rename.rs:20:5
+  --> $DIR/issue-32354-suggest-import-rename.rs:24:5
    |
 LL | use extension1::ConstructorExtension;
    |     -------------------------------- previous import of the trait `ConstructorExtension` here
index c945033ad74abd4c951b5baa521065193b4d68cd..e492a8c47567e214c639be39f3bab802e9e925ff 100644 (file)
@@ -2,7 +2,7 @@ error: missing `fn` or `struct` for method or struct definition
   --> $DIR/pub-ident-fn-or-struct-2.rs:11:4
    |
 LL | pub S();
-   | ---^- help: if you meant to call a macro, write instead: `S!`
+   | ---^- help: if you meant to call a macro, try: `S!`
 
 error: aborting due to previous error
 
index 9528c15dfa18fbd679f7fa16ebc62c6389b314b7..c1bff34cec3e61695bac530d29774369124012be 100644 (file)
@@ -2,7 +2,7 @@ error: missing `fn` or `struct` for method or struct definition
   --> $DIR/pub-ident-fn-or-struct.rs:11:4
    |
 LL | pub S (foo) bar
-   | ---^- help: if you meant to call a macro, write instead: `S!`
+   | ---^- help: if you meant to call a macro, try: `S!`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/pub-ident-fn.fixed b/src/test/ui/suggestions/pub-ident-fn.fixed
new file mode 100644 (file)
index 0000000..f2d0c6c
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-rustfix
+
+pub fn foo(_s: usize) -> bool { true }
+//~^ ERROR missing `fn` for method definition
+
+fn main() {
+    foo(2);
+}
index 1d64199642093bf868c65c3417013b5710a8c164..82c32f57eeae0f30df70d7712137bc0e2b01ddbf 100644 (file)
@@ -8,7 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub   foo(s: usize) -> bool { true }
+// run-rustfix
+
+pub   foo(_s: usize) -> bool { true }
 //~^ ERROR missing `fn` for method definition
 
 fn main() {
index de7ee71d1b40ffd88c1296d01341d6bc19953822..f7c96b8b9f4bb951c8b9e087d193245d226a4398 100644 (file)
@@ -1,11 +1,11 @@
 error: missing `fn` for method definition
-  --> $DIR/pub-ident-fn.rs:11:4
+  --> $DIR/pub-ident-fn.rs:13:4
    |
-LL | pub   foo(s: usize) -> bool { true }
+LL | pub   foo(_s: usize) -> bool { true }
    |    ^^^
 help: add `fn` here to parse `foo` as a public method
    |
-LL | pub fn foo(s: usize) -> bool { true }
+LL | pub fn foo(_s: usize) -> bool { true }
    |     ^^
 
 error: aborting due to previous error
index 02a80d86c846d58eea09117feddb9afa67510e4a..314c9060d4f7dc68a5d2469623c96a230bbbe472 100644 (file)
@@ -2,7 +2,7 @@ error: expected type, found `0`
   --> $DIR/type-ascription-instead-of-statement-end.rs:15:5
    |
 LL |     println!("test"):
-   |                     - help: did you mean to use `;` here?
+   |                     - help: try using a semicolon: `;`
 LL |     0; //~ ERROR expected type, found `0`
    |     ^ expecting a type here because of type ascription