From e6657154c4f0359fc67730d3e9aa0eb1a4a4e108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Duquette?= Date: Wed, 15 Aug 2018 22:59:56 -0400 Subject: [PATCH 01/10] Mark some suggestions as MachineApplicable --- src/librustc_borrowck/borrowck/unused.rs | 7 ++++++- src/librustc_mir/borrow_check/mod.rs | 8 ++++++-- src/librustc_typeck/check/method/suggest.rs | 7 ++++--- src/librustc_typeck/check_unused.rs | 7 ++++++- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/librustc_borrowck/borrowck/unused.rs b/src/librustc_borrowck/borrowck/unused.rs index 475ff0b744349..e29842100412c 100644 --- a/src/librustc_borrowck/borrowck/unused.rs +++ b/src/librustc_borrowck/borrowck/unused.rs @@ -13,6 +13,7 @@ use rustc::hir::{self, HirId}; use rustc::lint::builtin::UNUSED_MUT; use rustc::ty; use rustc::util::nodemap::{FxHashMap, FxHashSet}; +use errors::Applicability; use std::slice; use syntax::ptr::P; @@ -83,7 +84,11 @@ impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> { hir_id, span, "variable does not need to be mutable") - .span_suggestion_short(mut_span, "remove this `mut`", "".to_owned()) + .span_suggestion_short_with_applicability( + mut_span, + "remove this `mut`", + "".to_owned(), + Applicability::MachineApplicable) .emit(); } } diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index f96b9b8082fa7..e4e2aca0ebf0c 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -24,7 +24,7 @@ use rustc::mir::{Terminator, TerminatorKind}; use rustc::ty::query::Providers; use rustc::ty::{self, ParamEnv, TyCtxt, Ty}; -use rustc_errors::{Diagnostic, DiagnosticBuilder, Level}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, Level}; use rustc_data_structures::graph::dominators::Dominators; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_set::IdxSetBuf; @@ -324,7 +324,11 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( span, "variable does not need to be mutable", ); - err.span_suggestion_short(mut_span, "remove this `mut`", "".to_owned()); + err.span_suggestion_short_with_applicability( + mut_span, + "remove this `mut`", + "".to_owned(), + Applicability::MachineApplicable); err.buffer(&mut mbcx.errors_buffer); } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 0fbdecffb8be8..1c78421b9a28b 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -24,7 +24,7 @@ use util::nodemap::FxHashSet; use syntax::ast; use syntax::util::lev_distance::find_best_match_for_name; -use errors::DiagnosticBuilder; +use errors::{Applicability, DiagnosticBuilder}; use syntax_pos::{Span, FileName}; @@ -406,11 +406,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } if static_sources.len() == 1 { if let Some(expr) = rcvr_expr { - err.span_suggestion(expr.span.to(span), + err.span_suggestion_with_applicability(expr.span.to(span), "use associated function syntax instead", format!("{}::{}", self.ty_to_string(actual), - item_name)); + item_name), + Applicability::MachineApplicable); } else { err.help(&format!("try with `{}::{}`", self.ty_to_string(actual), item_name)); diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index 1a57dfd745e3a..e60139ed48d99 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -11,6 +11,7 @@ use lint; use rustc::ty::TyCtxt; +use errors::Applicability; use syntax::ast; use syntax_pos::Span; @@ -138,7 +139,11 @@ fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) { let id = tcx.hir.hir_to_node_id(hir_id); let msg = "unused extern crate"; tcx.struct_span_lint_node(lint, id, span, msg) - .span_suggestion_short(span, "remove it", "".to_string()) + .span_suggestion_short_with_applicability( + span, + "remove it", + "".to_string(), + Applicability::MachineApplicable) .emit(); continue; } From 9511ffeb2d4da6b2514f92bd594c5ff4770febde Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Thu, 16 Aug 2018 17:03:49 +0100 Subject: [PATCH 02/10] Moved some feature gate ui tests to correct location --- src/test/ui/{ => feature-gates}/feature-gate-rustc-attrs-1.rs | 0 src/test/ui/{ => feature-gates}/feature-gate-rustc-attrs-1.stderr | 0 src/test/ui/{ => feature-gates}/feature-gate-uniform-paths.rs | 0 src/test/ui/{ => feature-gates}/feature-gate-uniform-paths.stderr | 0 .../feature-gate-unrestricted-attribute-tokens.rs | 0 .../feature-gate-unrestricted-attribute-tokens.stderr | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{ => feature-gates}/feature-gate-rustc-attrs-1.rs (100%) rename src/test/ui/{ => feature-gates}/feature-gate-rustc-attrs-1.stderr (100%) rename src/test/ui/{ => feature-gates}/feature-gate-uniform-paths.rs (100%) rename src/test/ui/{ => feature-gates}/feature-gate-uniform-paths.stderr (100%) rename src/test/ui/{ => feature-gates}/feature-gate-unrestricted-attribute-tokens.rs (100%) rename src/test/ui/{ => feature-gates}/feature-gate-unrestricted-attribute-tokens.stderr (100%) diff --git a/src/test/ui/feature-gate-rustc-attrs-1.rs b/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.rs similarity index 100% rename from src/test/ui/feature-gate-rustc-attrs-1.rs rename to src/test/ui/feature-gates/feature-gate-rustc-attrs-1.rs diff --git a/src/test/ui/feature-gate-rustc-attrs-1.stderr b/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr similarity index 100% rename from src/test/ui/feature-gate-rustc-attrs-1.stderr rename to src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr diff --git a/src/test/ui/feature-gate-uniform-paths.rs b/src/test/ui/feature-gates/feature-gate-uniform-paths.rs similarity index 100% rename from src/test/ui/feature-gate-uniform-paths.rs rename to src/test/ui/feature-gates/feature-gate-uniform-paths.rs diff --git a/src/test/ui/feature-gate-uniform-paths.stderr b/src/test/ui/feature-gates/feature-gate-uniform-paths.stderr similarity index 100% rename from src/test/ui/feature-gate-uniform-paths.stderr rename to src/test/ui/feature-gates/feature-gate-uniform-paths.stderr diff --git a/src/test/ui/feature-gate-unrestricted-attribute-tokens.rs b/src/test/ui/feature-gates/feature-gate-unrestricted-attribute-tokens.rs similarity index 100% rename from src/test/ui/feature-gate-unrestricted-attribute-tokens.rs rename to src/test/ui/feature-gates/feature-gate-unrestricted-attribute-tokens.rs diff --git a/src/test/ui/feature-gate-unrestricted-attribute-tokens.stderr b/src/test/ui/feature-gates/feature-gate-unrestricted-attribute-tokens.stderr similarity index 100% rename from src/test/ui/feature-gate-unrestricted-attribute-tokens.stderr rename to src/test/ui/feature-gates/feature-gate-unrestricted-attribute-tokens.stderr From a50f29a47be1b0e0af91482b43f14be8cbd3e411 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Thu, 16 Aug 2018 21:40:25 -0400 Subject: [PATCH 03/10] Update version of rls-data used with save-analysis This part 1/3 for fixing rust-lang/rust#53440. --- src/Cargo.lock | 12 +++++++++++- src/librustc_save_analysis/Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 99b768ab1a92e..7982faec0e62e 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1858,6 +1858,15 @@ dependencies = [ "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rls-data" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rls-rustc" version = "0.5.0" @@ -2382,7 +2391,7 @@ name = "rustc_save_analysis" version = "0.0.0" dependencies = [ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3286,6 +3295,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rls-analysis 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96f84d303dcbe1c1bdd41b10867d3399c38fbdac32c4e3645cdb6dbd7f82db1d" "checksum rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e4a9cc2545ccb7e05b355bfe047b8039a6ec12270d5f3c996b766b340a50f7d2" "checksum rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd20763e1c60ae8945384c8a8fa4ac44f8afa7b0a817511f5e8927e5d24f988" +"checksum rls-data 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f81e838ecff6830ed33c2907fd236f38d441c206e983a2aa29fbce99295fab9" "checksum rls-rustc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9dba7390427aefa953608429701e3665192ca810ba8ae09301e001b7c7bed0" "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a" "checksum rls-vfs 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ecbc8541b4c341d6271eae10f869dd9d36db871afe184f5b6f9bffbd6ed0373f" diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index 7b94170ef6d99..2dbea2155aec2 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -16,7 +16,7 @@ rustc_target = { path = "../librustc_target" } rustc_typeck = { path = "../librustc_typeck" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rls-data = "0.16" +rls-data = "0.18" rls-span = "0.4" # FIXME(#40527) should move rustc serialize out of tree rustc-serialize = "0.3" From 5a23a0d283653c79fd623b479b1e8e71d5eea093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Duquette?= Date: Sun, 19 Aug 2018 15:01:33 -0400 Subject: [PATCH 04/10] Set applicability for more suggestions. --- .../borrowck/gather_loans/move_error.rs | 11 +- src/librustc_passes/ast_validation.rs | 4 +- src/librustc_resolve/macros.rs | 18 +- src/librustc_typeck/check/callee.rs | 12 +- src/librustc_typeck/check/demand.rs | 241 +++++++++++------- src/librustc_typeck/check/mod.rs | 44 ++-- src/libsyntax/parse/lexer/unicode_chars.rs | 8 +- src/libsyntax_ext/format.rs | 4 +- 8 files changed, 217 insertions(+), 125 deletions(-) diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index e1c3ac839902f..87f2c7576a4e6 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -17,7 +17,7 @@ use rustc::ty; use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin}; use syntax::ast; use syntax_pos; -use errors::DiagnosticBuilder; +use errors::{DiagnosticBuilder, Applicability}; use borrowck::gather_loans::gather_moves::PatternSource; pub struct MoveErrorCollector<'tcx> { @@ -80,9 +80,12 @@ fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &[MoveErr let initializer = e.init.as_ref().expect("should have an initializer to get an error"); if let Ok(snippet) = bccx.tcx.sess.source_map().span_to_snippet(initializer.span) { - err.span_suggestion(initializer.span, - "consider using a reference instead", - format!("&{}", snippet)); + err.span_suggestion_with_applicability( + initializer.span, + "consider using a reference instead", + format!("&{}", snippet), + Applicability::MaybeIncorrect // using a reference may not be the right fix + ); } } _ => { diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 99ea62e80298c..ca7dcbcc307b8 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -25,6 +25,7 @@ use syntax::symbol::keywords; use syntax::visit::{self, Visitor}; use syntax_pos::Span; use errors; +use errors::Applicability; struct AstValidator<'a> { session: &'a Session, @@ -185,11 +186,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ); match val.node { ExprKind::Lit(ref v) if v.node.is_numeric() => { - err.span_suggestion( + err.span_suggestion_with_applicability( place.span.between(val.span), "if you meant to write a comparison against a negative value, add a \ space in between `<` and `-`", "< -".to_string(), + Applicability::MaybeIncorrect ); } _ => {} diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 8f2e76d8866dd..0a33aae076be1 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -38,6 +38,7 @@ use syntax::symbol::{Symbol, keywords}; use syntax::tokenstream::{TokenStream, TokenTree, Delimited}; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::{Span, DUMMY_SP}; +use errors::Applicability; use std::cell::Cell; use std::mem; @@ -1000,9 +1001,19 @@ impl<'a, 'cl> Resolver<'a, 'cl> { if let Some(suggestion) = suggestion { if suggestion != name { if let MacroKind::Bang = kind { - err.span_suggestion(span, "you could try the macro", suggestion.to_string()); + err.span_suggestion_with_applicability( + span, + "you could try the macro", + suggestion.to_string(), + Applicability::MaybeIncorrect + ); } else { - err.span_suggestion(span, "try", suggestion.to_string()); + err.span_suggestion_with_applicability( + span, + "try", + suggestion.to_string(), + Applicability::MaybeIncorrect + ); } } else { err.help("have you added the `#[macro_use]` on the module/import?"); @@ -1123,10 +1134,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> { if let Some(span) = span { let found_use = if found_use { "" } else { "\n" }; self.session.struct_span_err(err.use_span, err.warn_msg) - .span_suggestion( + .span_suggestion_with_applicability( span, "instead, import the procedural macro like any other item", format!("use {}::{};{}", err.crate_name, err.name, found_use), + Applicability::MachineApplicable ).emit(); } else { self.session.struct_span_err(err.use_span, err.warn_msg) diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index ec127d26ab307..7f3aaa6792ffe 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -20,6 +20,7 @@ use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoB use rustc_target::spec::abi; use syntax::ast::Ident; use syntax_pos::Span; +use errors::Applicability; use rustc::hir; @@ -234,10 +235,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { err.span_label(call_expr.span, "not a function"); if let Some(ref path) = unit_variant { - err.span_suggestion(call_expr.span, - &format!("`{}` is a unit variant, you need to write it \ - without the parenthesis", path), - path.to_string()); + err.span_suggestion_with_applicability( + call_expr.span, + &format!("`{}` is a unit variant, you need to write it \ + without the parenthesis", path), + path.to_string(), + Applicability::MachineApplicable + ); } if let hir::ExprKind::Call(ref expr, _) = call_expr.node { diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 00cc36ecd428c..9ca8686eb226f 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -21,7 +21,7 @@ use rustc::hir::map::{NodeItem, NodeExpr}; use rustc::hir::{Item, ItemKind, print}; use rustc::ty::{self, Ty, AssociatedItem}; use rustc::ty::adjustment::AllowTwoPhase; -use errors::{DiagnosticBuilder, SourceMapper}; +use errors::{Applicability, DiagnosticBuilder, SourceMapper}; use super::method::probe; @@ -422,24 +422,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match (found.bit_width(), exp.bit_width()) { (Some(found), Some(exp)) if found > exp => { if can_cast { - err.span_suggestion(expr.span, - &format!("{}, which {}", msg, will_truncate), - cast_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, which {}", msg, will_truncate), + cast_suggestion, + Applicability::MaybeIncorrect // lossy conversion + ); } } (None, _) | (_, None) => { if can_cast { - err.span_suggestion(expr.span, - &format!("{}, which {}", - msg, - depending_on_isize), - cast_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, which {}", msg, depending_on_isize), + cast_suggestion, + Applicability::MaybeIncorrect // lossy conversion + ); } } _ => { - err.span_suggestion(expr.span, - &format!("{}, which {}", msg, will_sign_extend), - into_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, which {}", msg, will_sign_extend), + into_suggestion, + Applicability::MachineApplicable + ); } } true @@ -448,24 +455,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match (found.bit_width(), exp.bit_width()) { (Some(found), Some(exp)) if found > exp => { if can_cast { - err.span_suggestion(expr.span, - &format!("{}, which {}", msg, will_truncate), - cast_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, which {}", msg, will_truncate), + cast_suggestion, + Applicability::MaybeIncorrect // lossy conversion + ); } } (None, _) | (_, None) => { if can_cast { - err.span_suggestion(expr.span, - &format!("{}, which {}", - msg, - depending_on_usize), - cast_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, which {}", msg, depending_on_usize), + cast_suggestion, + Applicability::MaybeIncorrect // lossy conversion + ); } } _ => { - err.span_suggestion(expr.span, - &format!("{}, which {}", msg, will_zero_extend), - into_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, which {}", msg, will_zero_extend), + into_suggestion, + Applicability::MachineApplicable + ); } } true @@ -474,33 +488,44 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if can_cast { match (found.bit_width(), exp.bit_width()) { (Some(found), Some(exp)) if found > exp - 1 => { - err.span_suggestion(expr.span, - &format!("{}, which {}", msg, will_truncate), - cast_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, which {}", msg, will_truncate), + cast_suggestion, + Applicability::MaybeIncorrect // lossy conversion + ); } (None, None) => { - err.span_suggestion(expr.span, - &format!("{}, which {}", msg, will_truncate), - cast_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, which {}", msg, will_truncate), + cast_suggestion, + Applicability::MaybeIncorrect // lossy conversion + ); } (None, _) => { - err.span_suggestion(expr.span, - &format!("{}, which {}", - msg, - depending_on_isize), - cast_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, which {}", msg, depending_on_isize), + cast_suggestion, + Applicability::MaybeIncorrect // lossy conversion + ); } (_, None) => { - err.span_suggestion(expr.span, - &format!("{}, which {}", - msg, - depending_on_usize), - cast_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, which {}", msg, depending_on_usize), + cast_suggestion, + Applicability::MaybeIncorrect // lossy conversion + ); } _ => { - err.span_suggestion(expr.span, - &format!("{}, which {}", msg, will_zero_extend), - cast_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, which {}", msg, will_zero_extend), + cast_suggestion, + Applicability::MachineApplicable + ); } } } @@ -510,33 +535,44 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if can_cast { match (found.bit_width(), exp.bit_width()) { (Some(found), Some(exp)) if found - 1 > exp => { - err.span_suggestion(expr.span, - &format!("{}, which {}", msg, will_truncate), - cast_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, which {}", msg, will_truncate), + cast_suggestion, + Applicability::MaybeIncorrect // lossy conversion + ); } (None, None) => { - err.span_suggestion(expr.span, - &format!("{}, which {}", msg, will_sign_extend), - cast_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, which {}", msg, will_sign_extend), + cast_suggestion, + Applicability::MachineApplicable // lossy conversion + ); } (None, _) => { - err.span_suggestion(expr.span, - &format!("{}, which {}", - msg, - depending_on_usize), - cast_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, which {}", msg, depending_on_usize), + cast_suggestion, + Applicability::MaybeIncorrect // lossy conversion + ); } (_, None) => { - err.span_suggestion(expr.span, - &format!("{}, which {}", - msg, - depending_on_isize), - cast_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, which {}", msg, depending_on_isize), + cast_suggestion, + Applicability::MaybeIncorrect // lossy conversion + ); } _ => { - err.span_suggestion(expr.span, - &format!("{}, which {}", msg, will_sign_extend), - cast_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, which {}", msg, will_sign_extend), + cast_suggestion, + Applicability::MachineApplicable + ); } } } @@ -544,24 +580,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } (&ty::TyFloat(ref exp), &ty::TyFloat(ref found)) => { if found.bit_width() < exp.bit_width() { - err.span_suggestion(expr.span, - &format!("{} in a lossless way", - msg), - into_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{} in a lossless way", msg), + into_suggestion, + Applicability::MachineApplicable + ); } else if can_cast { - err.span_suggestion(expr.span, - &format!("{}, producing the closest possible value", - msg), - cast_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, producing the closest possible value", msg), + cast_suggestion, + Applicability::MaybeIncorrect // lossy conversion + ); } true } (&ty::TyUint(_), &ty::TyFloat(_)) | (&ty::TyInt(_), &ty::TyFloat(_)) => { if can_cast { - err.span_suggestion(expr.span, - &format!("{}, rounding the float towards zero", - msg), - cast_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, rounding the float towards zero", msg), + cast_suggestion, + Applicability::MaybeIncorrect // lossy conversion + ); err.warn("casting here will cause undefined behavior if the rounded value \ cannot be represented by the target integer type, including \ `Inf` and `NaN` (this is a bug and will be fixed)"); @@ -571,36 +613,45 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (&ty::TyFloat(ref exp), &ty::TyUint(ref found)) => { // if `found` is `None` (meaning found is `usize`), don't suggest `.into()` if exp.bit_width() > found.bit_width().unwrap_or(256) { - err.span_suggestion(expr.span, - &format!("{}, producing the floating point \ - representation of the integer", - msg), - into_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, producing the floating point representation of the \ + integer", + msg), + into_suggestion, + Applicability::MachineApplicable + ); } else if can_cast { - err.span_suggestion(expr.span, - &format!("{}, producing the floating point \ - representation of the integer, rounded if \ - necessary", - msg), - cast_suggestion); + err.span_suggestion_with_applicability(expr.span, + &format!("{}, producing the floating point representation of the \ + integer, rounded if necessary", + msg), + cast_suggestion, + Applicability::MaybeIncorrect // lossy conversion + ); } true } (&ty::TyFloat(ref exp), &ty::TyInt(ref found)) => { // if `found` is `None` (meaning found is `isize`), don't suggest `.into()` if exp.bit_width() > found.bit_width().unwrap_or(256) { - err.span_suggestion(expr.span, - &format!("{}, producing the floating point \ - representation of the integer", - msg), - into_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, producing the floating point representation of the \ + integer", + msg), + into_suggestion, + Applicability::MachineApplicable + ); } else if can_cast { - err.span_suggestion(expr.span, - &format!("{}, producing the floating point \ - representation of the integer, rounded if \ - necessary", - msg), - cast_suggestion); + err.span_suggestion_with_applicability( + expr.span, + &format!("{}, producing the floating point representation of the \ + integer, rounded if necessary", + msg), + cast_suggestion, + Applicability::MaybeIncorrect // lossy conversion + ); } true } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b57967a7aab21..7c46cff890e43 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -102,7 +102,7 @@ use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoB use rustc::ty::fold::TypeFoldable; use rustc::ty::query::Providers; use rustc::ty::util::{Representability, IntTypeExt, Discr}; -use errors::{DiagnosticBuilder, DiagnosticId}; +use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; use require_c_abi_if_variadic; use session::{CompileIncomplete, config, Session}; @@ -2675,10 +2675,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let sugg_span = tcx.sess.source_map().end_point(expr_sp); // remove closing `)` from the span let sugg_span = sugg_span.shrink_to_lo(); - err.span_suggestion( + err.span_suggestion_with_applicability( sugg_span, "expected the unit value `()`; create it with empty parentheses", - String::from("()")); + String::from("()"), + Applicability::MachineApplicable); } else { err.span_label(sp, format!("expected {}{} parameter{}", if variadic {"at least "} else {""}, @@ -2940,7 +2941,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tcx.sess.source_map().span_to_snippet(lhs.span), self.tcx.sess.source_map().span_to_snippet(rhs.span)) { - err.span_suggestion(expr.span, msg, format!("{} == {}", left, right)); + err.span_suggestion_with_applicability( + expr.span, + msg, + format!("{} == {}", left, right), + Applicability::MaybeIncorrect); } else { err.help(msg); } @@ -4234,9 +4239,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ast::LitIntType::Unsuffixed) = lit.node { let snip = tcx.sess.source_map().span_to_snippet(base.span); if let Ok(snip) = snip { - err.span_suggestion(expr.span, - "to access tuple elements, use", - format!("{}.{}", snip, i)); + err.span_suggestion_with_applicability( + expr.span, + "to access tuple elements, use", + format!("{}.{}", snip, i), + Applicability::MachineApplicable); needs_note = false; } } @@ -4674,9 +4681,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprKind::Match(..) | hir::ExprKind::Block(..) => { let sp = self.tcx.sess.source_map().next_point(cause_span); - err.span_suggestion(sp, - "try adding a semicolon", - ";".to_string()); + err.span_suggestion_with_applicability( + sp, + "try adding a semicolon", + ";".to_string(), + Applicability::MachineApplicable); } _ => (), } @@ -4705,10 +4714,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // haven't set a return type at all (and aren't `fn main()` or an impl). match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_nil()) { (&hir::FunctionRetTy::DefaultReturn(span), true, true, true) => { - err.span_suggestion(span, - "try adding a return type", - format!("-> {} ", - self.resolve_type_vars_with_obligations(found))); + err.span_suggestion_with_applicability( + span, + "try adding a return type", + format!("-> {} ", self.resolve_type_vars_with_obligations(found)), + Applicability::MachineApplicable); } (&hir::FunctionRetTy::DefaultReturn(span), false, true, true) => { err.span_label(span, "possibly return type missing here?"); @@ -4767,7 +4777,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } let original_span = original_sp(last_stmt.span, blk.span); let span_semi = original_span.with_lo(original_span.hi() - BytePos(1)); - err.span_suggestion(span_semi, "consider removing this semicolon", "".to_string()); + err.span_suggestion_with_applicability( + span_semi, + "consider removing this semicolon", + "".to_string(), + Applicability::MachineApplicable); } // Instantiates the given path, which must refer to an item with the given diff --git a/src/libsyntax/parse/lexer/unicode_chars.rs b/src/libsyntax/parse/lexer/unicode_chars.rs index 88ff8582da801..03bf1b5a4e1ed 100644 --- a/src/libsyntax/parse/lexer/unicode_chars.rs +++ b/src/libsyntax/parse/lexer/unicode_chars.rs @@ -12,7 +12,7 @@ // http://www.unicode.org/Public/security/10.0.0/confusables.txt use syntax_pos::{Span, NO_EXPANSION}; -use errors::DiagnosticBuilder; +use errors::{Applicability, DiagnosticBuilder}; use super::StringReader; const UNICODE_ARRAY: &[(char, &str, char)] = &[ @@ -346,7 +346,11 @@ crate fn check_for_substitution<'a>(reader: &StringReader<'a>, let msg = format!("Unicode character '{}' ({}) looks like '{}' ({}), but it is not", ch, u_name, ascii_char, ascii_name); - err.span_suggestion(span, &msg, ascii_char.to_string()); + err.span_suggestion_with_applicability( + span, + &msg, + ascii_char.to_string(), + Applicability::MaybeIncorrect); true }, None => { diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index d97c0b14f797a..a77feae2733f4 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -22,6 +22,7 @@ use syntax::ptr::P; use syntax::symbol::Symbol; use syntax::tokenstream; use syntax_pos::{MultiSpan, Span, DUMMY_SP}; +use errors::Applicability; use std::borrow::Cow; use std::collections::hash_map::Entry; @@ -791,10 +792,11 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, 0 => "{}".to_string(), _ => format!("{}{{}}", "{} ".repeat(args.len())), }; - err.span_suggestion( + err.span_suggestion_with_applicability( fmt_sp.shrink_to_lo(), "you might be missing a string literal to format with", format!("\"{}\", ", sugg_fmt), + Applicability::MaybeIncorrect, ); err.emit(); return DummyResult::raw_expr(sp); From 05d19fba27d2e53c64ea8ec488dca4fec7f2b984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 20 Aug 2018 16:16:17 -0700 Subject: [PATCH 05/10] Point at the trait argument when using unboxed closure --- src/libsyntax/parse/parser.rs | 15 ++++++++------- .../unboxed-closure-sugar-wrong-trait.stderr | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b1e2e69863d97..c80187ba77ee0 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1079,12 +1079,13 @@ impl<'a> Parser<'a> { self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f) } - fn parse_seq_to_before_tokens(&mut self, - kets: &[&token::Token], - sep: SeqSep, - expect: TokenExpectType, - mut f: F) - -> PResult<'a, Vec> + fn parse_seq_to_before_tokens( + &mut self, + kets: &[&token::Token], + sep: SeqSep, + expect: TokenExpectType, + mut f: F, + ) -> PResult<'a, Vec> where F: FnMut(&mut Parser<'a>) -> PResult<'a, T> { let mut first: bool = true; @@ -2058,12 +2059,12 @@ impl<'a> Parser<'a> { TokenExpectType::Expect, |p| p.parse_ty())?; self.bump(); // `)` + let span = lo.to(self.prev_span); let output = if self.eat(&token::RArrow) { Some(self.parse_ty_common(false, false)?) } else { None }; - let span = lo.to(self.prev_span); ParenthesisedArgs { inputs, output, span }.into() }; diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr index 5d8c86f5a5809..91f57cbd468a8 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-wrong-trait.stderr @@ -2,7 +2,7 @@ error[E0244]: wrong number of type arguments: expected 0, found 1 --> $DIR/unboxed-closure-sugar-wrong-trait.rs:15:13 | LL | fn f isize>(x: F) {} - | ^^^^^^^^^^^^^^^^ unexpected type argument + | ^^^^^^^ unexpected type argument error[E0220]: associated type `Output` not found for `Trait` --> $DIR/unboxed-closure-sugar-wrong-trait.rs:15:24 From 6e24868384408da8b542f70085f7a45a3c383fc7 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 21 Aug 2018 12:57:11 +0200 Subject: [PATCH 06/10] Normalize source line and column numbers. This commit adds a normalization for line and column numbers in stderr files where the line/col is from the source directory rather than the test itself - thereby removing the need to update tests as compiler source changes. --- src/test/ui/consts/const-size_of-cycle.stderr | 4 ++-- src/test/ui/impl-trait/impl-generic-mismatch.stderr | 2 +- src/tools/compiletest/src/runtest.rs | 7 +++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index b10dd509e0b13..16d87f7e31c9b 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -2,13 +2,13 @@ error[E0391]: cycle detected when computing layout of `Foo` | note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All }, value: [u8; _] }`... note: ...which requires const-evaluating `Foo::bytes::{{constant}}`... - --> $SRC_DIR/libcore/mem.rs:323:14 + --> $SRC_DIR/libcore/mem.rs:LL:COL | LL | unsafe { intrinsics::size_of::() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires computing layout of `Foo`, completing the cycle note: cycle used when const-evaluating `Foo::bytes::{{constant}}` - --> $SRC_DIR/libcore/mem.rs:323:14 + --> $SRC_DIR/libcore/mem.rs:LL:COL | LL | unsafe { intrinsics::size_of::() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/impl-generic-mismatch.stderr b/src/test/ui/impl-trait/impl-generic-mismatch.stderr index a5f1580b60d2f..7ad16b1f8f237 100644 --- a/src/test/ui/impl-trait/impl-generic-mismatch.stderr +++ b/src/test/ui/impl-trait/impl-generic-mismatch.stderr @@ -30,7 +30,7 @@ error[E0643]: method `hash` has incompatible signature for trait LL | fn hash(&self, hasher: &mut impl Hasher) {} | ^^^^^^^^^^^ expected generic parameter, found `impl Trait` | - ::: $SRC_DIR/libcore/hash/mod.rs:185:13 + ::: $SRC_DIR/libcore/hash/mod.rs:LL:COL | LL | fn hash(&self, state: &mut H); | - declaration in trait here diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index b136173082600..24b575aae12f9 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2963,6 +2963,13 @@ impl<'test> TestCx<'test> { normalized = normalized.replace("\\n", "\n"); } + // If there are `$SRC_DIR` normalizations with line and column numbers, then replace them + // with placeholders as we do not want tests needing updated when compiler source code + // changes. + // eg. $SRC_DIR/libcore/mem.rs:323:14 becomes $SRC_DIR/libcore/mem.rs:LL:COL + normalized = Regex::new("SRC_DIR(.+):\\d+:\\d+").unwrap() + .replace_all(&normalized, "SRC_DIR$1:LL:COL").into_owned(); + normalized = normalized.replace("\\\\", "\\") // denormalize for paths on windows .replace("\\", "/") // normalize for paths on windows .replace("\r\n", "\n") // normalize for linebreaks on windows From 18f41e54d9c457da3e60735f494bffe92f8a303b Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Tue, 21 Aug 2018 19:57:59 +0200 Subject: [PATCH 07/10] Suggest direct raw-pointer dereference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit People often come looking for some kind of `as_ref_unchecked` method on raw pointers that would give them `&T` and not `Option<&T>` when they are sure the pointer is not NULL. There's no such method, but taking a reference of the dereferenced pointer accomplishes the same thing. Therefore, suggest using that, at the `as_ref` site ‒ it's a place people are likely going to look into. --- src/libcore/ptr.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 61033e7511253..6f248a71a4c8f 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -582,6 +582,21 @@ impl *const T { /// } /// } /// ``` + /// + /// # Null-unchecked version + /// + /// If you are sure the pointer can never be null and are looking for some kind of + /// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>, know that you can + /// dereference the pointer directly. + /// + /// ``` + /// let ptr: *const u8 = &10u8 as *const u8; + /// + /// unsafe { + /// let val_back = &*ptr; + /// println!("We got back the value: {}!", val_back); + /// } + /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] #[inline] pub unsafe fn as_ref<'a>(self) -> Option<&'a T> { @@ -1303,6 +1318,21 @@ impl *mut T { /// } /// } /// ``` + /// + /// # Null-unchecked version + /// + /// If you are sure the pointer can never be null and are looking for some kind of + /// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>, know that you can + /// dereference the pointer directly. + /// + /// ``` + /// let ptr: *mut u8 = &mut 10u8 as *mut u8; + /// + /// unsafe { + /// let val_back = &*ptr; + /// println!("We got back the value: {}!", val_back); + /// } + /// ``` #[stable(feature = "ptr_as_ref", since = "1.9.0")] #[inline] pub unsafe fn as_ref<'a>(self) -> Option<&'a T> { From e67bba8ebe14c815c4f756aa267249e5c35d5ec5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 21 Aug 2018 00:43:02 +0200 Subject: [PATCH 08/10] Fix missing impl trait display as ret type --- src/librustdoc/clean/mod.rs | 9 +++++++ src/test/rustdoc/impl-everywhere.rs | 40 +++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 src/test/rustdoc/impl-everywhere.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9b77ff82f9096..57ae2ac3a5b2a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2378,6 +2378,7 @@ impl From for PrimitiveType { impl Clean for hir::Ty { fn clean(&self, cx: &DocContext) -> Type { use rustc::hir::*; + match self.node { TyKind::Never => Never, TyKind::Ptr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)), @@ -2415,6 +2416,14 @@ impl Clean for hir::Ty { if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did) { return ImplTrait(bounds); } + } else if let Def::Existential(did) = path.def { + // This block is for returned impl trait only. + if let Some(node_id) = cx.tcx.hir.as_local_node_id(did) { + let item = cx.tcx.hir.expect_item(node_id); + if let hir::ItemKind::Existential(ref ty) = item.node { + return ImplTrait(ty.bounds.clean(cx)); + } + } } let mut alias = None; diff --git a/src/test/rustdoc/impl-everywhere.rs b/src/test/rustdoc/impl-everywhere.rs new file mode 100644 index 0000000000000..62da6f13942d8 --- /dev/null +++ b/src/test/rustdoc/impl-everywhere.rs @@ -0,0 +1,40 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +pub trait Foo {} +pub trait Foo2 {} + +pub struct Bar; + +impl Foo for Bar {} +impl Foo2 for Bar {} + +// @!has foo/fn.foo.html '//section[@id="main"]//pre' "x: &\'x impl Foo" +// @!has foo/fn.foo.html '//section[@id="main"]//pre' "-> &\'x impl Foo {" +pub fn foo<'x>(x: &'x impl Foo) -> &'x impl Foo { + x +} + +// @!has foo/fn.foo2.html '//section[@id="main"]//pre' "x: &\'x impl Foo" +// @!has foo/fn.foo2.html '//section[@id="main"]//pre' '-> impl Foo2 {' +pub fn foo2<'x>(_x: &'x impl Foo) -> impl Foo2 { + Bar +} + +// @!has foo/fn.foo_foo.html '//section[@id="main"]//pre' '-> impl Foo + Foo2 {' +pub fn foo_foo() -> impl Foo + Foo2 { + Bar +} + +// @!has foo/fn.foo2.html '//section[@id="main"]//pre' "x: &'x (impl Foo + Foo2)" +pub fn foo_foo_foo<'x>(_x: &'x (impl Foo + Foo2)) { +} From cf1b6d6fe87b01f556d49372d1c988c7cc686057 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Aug 2018 21:46:56 -0400 Subject: [PATCH 09/10] Remove super old comment on function that parses items This comment was added more than 5 years ago in ab03c1e4221. As far as anyone reading this comment today needs to know, the function has never parsed items from inside an extern crate. --- src/libsyntax/parse/parser.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5467bab33f90d..d7f339a6942f9 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -6842,8 +6842,6 @@ impl<'a> Parser<'a> { } /// Parse one of the items allowed by the flags. - /// NB: this function no longer parses the items inside an - /// extern crate. fn parse_item_implementation( &mut self, attrs: Vec, From 3d5fef6f3001beeffde80b57658809fe383ea242 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 21 Aug 2018 14:44:36 +0100 Subject: [PATCH 10/10] Lament the invincibility of the Turbofish --- src/test/ui/bastion-of-the-turbofish.rs | 42 +++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/test/ui/bastion-of-the-turbofish.rs diff --git a/src/test/ui/bastion-of-the-turbofish.rs b/src/test/ui/bastion-of-the-turbofish.rs new file mode 100644 index 0000000000000..bd789737552c1 --- /dev/null +++ b/src/test/ui/bastion-of-the-turbofish.rs @@ -0,0 +1,42 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +// Bastion of the Turbofish +// ------------------------ +// Beware travellers, lest you venture into waters callous and unforgiving, +// where hope must be abandoned, ere it is cruelly torn from you. For here +// stands the bastion of the Turbofish: an impenetrable fortress holding +// unshaking against those who would dare suggest the supererogation of the +// Turbofish. +// +// Once I was young and foolish and had the impudence to imagine that I could +// shake free from the coils by which that creature had us tightly bound. I +// dared to suggest that there was a better way: a brighter future, in which +// Rustaceans both new and old could be rid of that vile beast. But alas! In +// my foolhardiness my ignorance was unveiled and my dreams were dashed +// unforgivingly against the rock of syntactic ambiguity. +// +// This humble program, small and insignificant though it might seem, +// demonstrates that to which we had previously cast a blind eye: an ambiguity +// in permitting generic arguments to be provided without the consent of the +// Great Turbofish. Should you be so naïve as to try to revolt against its +// mighty clutches, here shall its wrath be indomitably displayed. This +// program must pass for all eternity, fundamentally at odds with an impetuous +// rebellion against the Turbofish. +// +// My heart aches in sorrow, for I know I am defeated. Let this be a warning +// to all those who come after. Here stands the bastion of the Turbofish. + +fn main() { + let (oh, woe, is, me) = ("the", "Turbofish", "remains", "undefeated"); + let _: (bool, bool) = (oh(me)); +}