Auto merge of #117249 - matthiaskrgr:rollup-h4og5rv, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #116968 (Invalid `?` suggestion on mismatched `Ok(T)`) - #117032 (Enable cg_clif tests for riscv64gc) - #117106 (When expecting closure argument but finding block provide suggestion) - #117114 (Improve `stringify.rs` test) - #117188 (Avoid repeated interning of `env!("CFG_RELEASE")`) - #117243 (Explain implementation of mem::replace) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
dab715641e
@ -734,6 +734,8 @@ pub enum RangeSyntax {
|
||||
}
|
||||
|
||||
/// All the different flavors of pattern that Rust recognizes.
|
||||
//
|
||||
// Adding a new variant? Please update `test_pat` in `tests/ui/macros/stringify.rs`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum PatKind {
|
||||
/// Represents a wildcard pattern (`_`).
|
||||
@ -967,6 +969,7 @@ impl Stmt {
|
||||
}
|
||||
}
|
||||
|
||||
// Adding a new variant? Please update `test_stmt` in `tests/ui/macros/stringify.rs`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum StmtKind {
|
||||
/// A local (let) binding.
|
||||
@ -1345,6 +1348,7 @@ pub struct StructExpr {
|
||||
pub rest: StructRest,
|
||||
}
|
||||
|
||||
// Adding a new variant? Please update `test_expr` in `tests/ui/macros/stringify.rs`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum ExprKind {
|
||||
/// An array (`[a, b, c, d]`)
|
||||
@ -2015,6 +2019,8 @@ pub struct BareFnTy {
|
||||
}
|
||||
|
||||
/// The various kinds of type recognized by the compiler.
|
||||
//
|
||||
// Adding a new variant? Please update `test_ty` in `tests/ui/macros/stringify.rs`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum TyKind {
|
||||
/// A variable-length slice (`[T]`).
|
||||
@ -2880,6 +2886,7 @@ pub struct ConstItem {
|
||||
pub expr: Option<P<Expr>>,
|
||||
}
|
||||
|
||||
// Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum ItemKind {
|
||||
/// An `extern crate` item, with the optional *original* crate name if the crate was renamed.
|
||||
|
@ -26,10 +26,6 @@ pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
|
||||
|
||||
pub const CURRENT_RUSTC_VERSION: &str = env!("CFG_RELEASE");
|
||||
|
||||
pub fn rust_version_symbol() -> Symbol {
|
||||
Symbol::intern(CURRENT_RUSTC_VERSION)
|
||||
}
|
||||
|
||||
pub fn is_builtin_attr(attr: &Attribute) -> bool {
|
||||
attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name))
|
||||
}
|
||||
|
@ -962,38 +962,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
expected: Ty<'tcx>,
|
||||
found: Ty<'tcx>,
|
||||
) -> bool {
|
||||
let ty::Adt(e, args_e) = expected.kind() else {
|
||||
return false;
|
||||
};
|
||||
let ty::Adt(f, args_f) = found.kind() else {
|
||||
return false;
|
||||
};
|
||||
if e.did() != f.did() {
|
||||
return false;
|
||||
}
|
||||
if Some(e.did()) != self.tcx.get_diagnostic_item(sym::Result) {
|
||||
return false;
|
||||
}
|
||||
let map = self.tcx.hir();
|
||||
if let Some(hir::Node::Expr(expr)) = map.find_parent(expr.hir_id)
|
||||
&& let hir::ExprKind::Ret(_) = expr.kind
|
||||
{
|
||||
// `return foo;`
|
||||
} else if map.get_return_block(expr.hir_id).is_some() {
|
||||
// Function's tail expression.
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
let e = args_e.type_at(1);
|
||||
let f = args_f.type_at(1);
|
||||
if self
|
||||
.infcx
|
||||
.type_implements_trait(
|
||||
self.tcx.get_diagnostic_item(sym::Into).unwrap(),
|
||||
[f, e],
|
||||
self.param_env,
|
||||
)
|
||||
.must_apply_modulo_regions()
|
||||
let returned = matches!(
|
||||
map.find_parent(expr.hir_id),
|
||||
Some(hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. }))
|
||||
) || map.get_return_block(expr.hir_id).is_some();
|
||||
if returned
|
||||
&& let ty::Adt(e, args_e) = expected.kind()
|
||||
&& let ty::Adt(f, args_f) = found.kind()
|
||||
&& e.did() == f.did()
|
||||
&& Some(e.did()) == self.tcx.get_diagnostic_item(sym::Result)
|
||||
&& let e_ok = args_e.type_at(0)
|
||||
&& let f_ok = args_f.type_at(0)
|
||||
&& self.infcx.can_eq(self.param_env, f_ok, e_ok)
|
||||
&& let e_err = args_e.type_at(1)
|
||||
&& let f_err = args_f.type_at(1)
|
||||
&& self
|
||||
.infcx
|
||||
.type_implements_trait(
|
||||
self.tcx.get_diagnostic_item(sym::Into).unwrap(),
|
||||
[f_err, e_err],
|
||||
self.param_env,
|
||||
)
|
||||
.must_apply_modulo_regions()
|
||||
{
|
||||
err.multipart_suggestion(
|
||||
"use `?` to coerce and return an appropriate `Err`, and wrap the resulting value \
|
||||
|
@ -4,6 +4,7 @@
|
||||
#![feature(never_type)]
|
||||
#![feature(proc_macro_diagnostic)]
|
||||
#![feature(proc_macro_span)]
|
||||
#![feature(proc_macro_tracked_env)]
|
||||
#![allow(rustc::default_hash_types)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
@ -26,7 +26,7 @@ use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use std::collections::HashMap;
|
||||
use syn::parse::{Parse, ParseStream, Result};
|
||||
use syn::{braced, punctuated::Punctuated, Ident, LitStr, Token};
|
||||
use syn::{braced, punctuated::Punctuated, Expr, Ident, Lit, LitStr, Macro, Token};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
@ -53,21 +53,46 @@ impl Parse for Keyword {
|
||||
|
||||
struct Symbol {
|
||||
name: Ident,
|
||||
value: Option<LitStr>,
|
||||
value: Value,
|
||||
}
|
||||
|
||||
enum Value {
|
||||
SameAsName,
|
||||
String(LitStr),
|
||||
Env(LitStr, Macro),
|
||||
Unsupported(Expr),
|
||||
}
|
||||
|
||||
impl Parse for Symbol {
|
||||
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
||||
let name = input.parse()?;
|
||||
let value = match input.parse::<Token![:]>() {
|
||||
Ok(_) => Some(input.parse()?),
|
||||
Err(_) => None,
|
||||
};
|
||||
let colon_token: Option<Token![:]> = input.parse()?;
|
||||
let value = if colon_token.is_some() { input.parse()? } else { Value::SameAsName };
|
||||
|
||||
Ok(Symbol { name, value })
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for Value {
|
||||
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
||||
let expr: Expr = input.parse()?;
|
||||
match &expr {
|
||||
Expr::Lit(expr) => {
|
||||
if let Lit::Str(lit) = &expr.lit {
|
||||
return Ok(Value::String(lit.clone()));
|
||||
}
|
||||
}
|
||||
Expr::Macro(expr) => {
|
||||
if expr.mac.path.is_ident("env") && let Ok(lit) = expr.mac.parse_body() {
|
||||
return Ok(Value::Env(lit, expr.mac.clone()));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(Value::Unsupported(expr))
|
||||
}
|
||||
}
|
||||
|
||||
struct Input {
|
||||
keywords: Punctuated<Keyword, Token![,]>,
|
||||
symbols: Punctuated<Symbol, Token![,]>,
|
||||
@ -111,6 +136,37 @@ pub fn symbols(input: TokenStream) -> TokenStream {
|
||||
output
|
||||
}
|
||||
|
||||
struct Preinterned {
|
||||
idx: u32,
|
||||
span_of_name: Span,
|
||||
}
|
||||
|
||||
struct Entries {
|
||||
map: HashMap<String, Preinterned>,
|
||||
}
|
||||
|
||||
impl Entries {
|
||||
fn with_capacity(capacity: usize) -> Self {
|
||||
Entries { map: HashMap::with_capacity(capacity) }
|
||||
}
|
||||
|
||||
fn insert(&mut self, span: Span, str: &str, errors: &mut Errors) -> u32 {
|
||||
if let Some(prev) = self.map.get(str) {
|
||||
errors.error(span, format!("Symbol `{str}` is duplicated"));
|
||||
errors.error(prev.span_of_name, "location of previous definition".to_string());
|
||||
prev.idx
|
||||
} else {
|
||||
let idx = self.len();
|
||||
self.map.insert(str.to_string(), Preinterned { idx, span_of_name: span });
|
||||
idx
|
||||
}
|
||||
}
|
||||
|
||||
fn len(&self) -> u32 {
|
||||
u32::try_from(self.map.len()).expect("way too many symbols")
|
||||
}
|
||||
}
|
||||
|
||||
fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
|
||||
let mut errors = Errors::default();
|
||||
|
||||
@ -127,20 +183,9 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
|
||||
let mut keyword_stream = quote! {};
|
||||
let mut symbols_stream = quote! {};
|
||||
let mut prefill_stream = quote! {};
|
||||
let mut counter = 0u32;
|
||||
let mut keys =
|
||||
HashMap::<String, Span>::with_capacity(input.keywords.len() + input.symbols.len() + 10);
|
||||
let mut entries = Entries::with_capacity(input.keywords.len() + input.symbols.len() + 10);
|
||||
let mut prev_key: Option<(Span, String)> = None;
|
||||
|
||||
let mut check_dup = |span: Span, str: &str, errors: &mut Errors| {
|
||||
if let Some(prev_span) = keys.get(str) {
|
||||
errors.error(span, format!("Symbol `{str}` is duplicated"));
|
||||
errors.error(*prev_span, "location of previous definition".to_string());
|
||||
} else {
|
||||
keys.insert(str.to_string(), span);
|
||||
}
|
||||
};
|
||||
|
||||
let mut check_order = |span: Span, str: &str, errors: &mut Errors| {
|
||||
if let Some((prev_span, ref prev_str)) = prev_key {
|
||||
if str < prev_str {
|
||||
@ -156,49 +201,98 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
|
||||
let name = &keyword.name;
|
||||
let value = &keyword.value;
|
||||
let value_string = value.value();
|
||||
check_dup(keyword.name.span(), &value_string, &mut errors);
|
||||
let idx = entries.insert(keyword.name.span(), &value_string, &mut errors);
|
||||
prefill_stream.extend(quote! {
|
||||
#value,
|
||||
});
|
||||
keyword_stream.extend(quote! {
|
||||
pub const #name: Symbol = Symbol::new(#counter);
|
||||
pub const #name: Symbol = Symbol::new(#idx);
|
||||
});
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
// Generate the listed symbols.
|
||||
for symbol in input.symbols.iter() {
|
||||
let name = &symbol.name;
|
||||
let value = match &symbol.value {
|
||||
Some(value) => value.value(),
|
||||
None => name.to_string(),
|
||||
};
|
||||
check_dup(symbol.name.span(), &value, &mut errors);
|
||||
check_order(symbol.name.span(), &name.to_string(), &mut errors);
|
||||
|
||||
let value = match &symbol.value {
|
||||
Value::SameAsName => name.to_string(),
|
||||
Value::String(lit) => lit.value(),
|
||||
Value::Env(..) => continue, // in another loop below
|
||||
Value::Unsupported(expr) => {
|
||||
errors.list.push(syn::Error::new_spanned(
|
||||
expr,
|
||||
concat!(
|
||||
"unsupported expression for symbol value; implement support for this in ",
|
||||
file!(),
|
||||
),
|
||||
));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let idx = entries.insert(symbol.name.span(), &value, &mut errors);
|
||||
|
||||
prefill_stream.extend(quote! {
|
||||
#value,
|
||||
});
|
||||
symbols_stream.extend(quote! {
|
||||
pub const #name: Symbol = Symbol::new(#counter);
|
||||
pub const #name: Symbol = Symbol::new(#idx);
|
||||
});
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
// Generate symbols for the strings "0", "1", ..., "9".
|
||||
let digits_base = counter;
|
||||
counter += 10;
|
||||
for n in 0..10 {
|
||||
let n = n.to_string();
|
||||
check_dup(Span::call_site(), &n, &mut errors);
|
||||
entries.insert(Span::call_site(), &n, &mut errors);
|
||||
prefill_stream.extend(quote! {
|
||||
#n,
|
||||
});
|
||||
}
|
||||
|
||||
// Symbols whose value comes from an environment variable. It's allowed for
|
||||
// these to have the same value as another symbol.
|
||||
for symbol in &input.symbols {
|
||||
let (env_var, expr) = match &symbol.value {
|
||||
Value::Env(lit, expr) => (lit, expr),
|
||||
Value::SameAsName | Value::String(_) | Value::Unsupported(_) => continue,
|
||||
};
|
||||
|
||||
if !proc_macro::is_available() {
|
||||
errors.error(
|
||||
Span::call_site(),
|
||||
"proc_macro::tracked_env is not available in unit test".to_owned(),
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
let value = match proc_macro::tracked_env::var(env_var.value()) {
|
||||
Ok(value) => value,
|
||||
Err(err) => {
|
||||
errors.list.push(syn::Error::new_spanned(expr, err));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let idx = if let Some(prev) = entries.map.get(&value) {
|
||||
prev.idx
|
||||
} else {
|
||||
prefill_stream.extend(quote! {
|
||||
#value,
|
||||
});
|
||||
entries.insert(symbol.name.span(), &value, &mut errors)
|
||||
};
|
||||
|
||||
let name = &symbol.name;
|
||||
symbols_stream.extend(quote! {
|
||||
pub const #name: Symbol = Symbol::new(#idx);
|
||||
});
|
||||
}
|
||||
|
||||
let symbol_digits_base = entries.map["0"].idx;
|
||||
let preinterned_symbols_count = entries.len();
|
||||
let output = quote! {
|
||||
const SYMBOL_DIGITS_BASE: u32 = #digits_base;
|
||||
const PREINTERNED_SYMBOLS_COUNT: u32 = #counter;
|
||||
const SYMBOL_DIGITS_BASE: u32 = #symbol_digits_base;
|
||||
const PREINTERNED_SYMBOLS_COUNT: u32 = #preinterned_symbols_count;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(non_upper_case_globals)]
|
||||
|
@ -27,7 +27,7 @@ fn test_symbols() {
|
||||
|
||||
let body_tokens = m.mac.tokens.clone();
|
||||
|
||||
test_symbols_macro(body_tokens, &[]);
|
||||
test_symbols_macro(body_tokens, &["proc_macro::tracked_env is not available in unit test"]);
|
||||
}
|
||||
|
||||
fn test_symbols_macro(input: TokenStream, expected_errors: &[&str]) {
|
||||
|
@ -5,7 +5,7 @@
|
||||
//! collect them instead.
|
||||
|
||||
use rustc_ast::Attribute;
|
||||
use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER};
|
||||
use rustc_attr::VERSION_PLACEHOLDER;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::middle::lib_features::LibFeatures;
|
||||
@ -59,7 +59,7 @@ impl<'tcx> LibFeatureCollector<'tcx> {
|
||||
if let Some(s) = since
|
||||
&& s.as_str() == VERSION_PLACEHOLDER
|
||||
{
|
||||
since = Some(rust_version_symbol());
|
||||
since = Some(sym::env_CFG_RELEASE);
|
||||
}
|
||||
|
||||
if let Some(feature) = feature {
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
use crate::errors;
|
||||
use rustc_attr::{
|
||||
self as attr, rust_version_symbol, ConstStability, Since, Stability, StabilityLevel, Unstable,
|
||||
UnstableReason, VERSION_PLACEHOLDER,
|
||||
self as attr, ConstStability, Since, Stability, StabilityLevel, Unstable, UnstableReason,
|
||||
VERSION_PLACEHOLDER,
|
||||
};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||
use rustc_hir as hir;
|
||||
@ -1115,7 +1115,7 @@ fn unnecessary_stable_feature_lint(
|
||||
mut since: Symbol,
|
||||
) {
|
||||
if since.as_str() == VERSION_PLACEHOLDER {
|
||||
since = rust_version_symbol();
|
||||
since = sym::env_CFG_RELEASE;
|
||||
}
|
||||
tcx.emit_spanned_lint(
|
||||
lint::builtin::STABLE_FEATURES,
|
||||
|
@ -713,6 +713,7 @@ symbols! {
|
||||
encode,
|
||||
end,
|
||||
env,
|
||||
env_CFG_RELEASE: env!("CFG_RELEASE"),
|
||||
eprint_macro,
|
||||
eprintln_macro,
|
||||
eq,
|
||||
|
@ -3465,11 +3465,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
if let Some(Node::Expr(expr)) = hir.find(arg_hir_id)
|
||||
&& let Some(typeck_results) = &self.typeck_results
|
||||
{
|
||||
if let hir::Expr { kind: hir::ExprKind::Block(..), .. } = expr {
|
||||
let expr = expr.peel_blocks();
|
||||
let ty =
|
||||
typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx));
|
||||
let span = expr.span;
|
||||
if let hir::Expr { kind: hir::ExprKind::Block(block, _), .. } = expr {
|
||||
let inner_expr = expr.peel_blocks();
|
||||
let ty = typeck_results.expr_ty_adjusted_opt(inner_expr)
|
||||
.unwrap_or(Ty::new_misc_error(tcx));
|
||||
let span = inner_expr.span;
|
||||
if Some(span) != err.span.primary_span() {
|
||||
err.span_label(
|
||||
span,
|
||||
@ -3480,6 +3480,49 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
format!("this tail expression is of type `{ty}`")
|
||||
},
|
||||
);
|
||||
if let ty::PredicateKind::Clause(clause) = failed_pred.kind().skip_binder()
|
||||
&& let ty::ClauseKind::Trait(pred) = clause
|
||||
&& [
|
||||
tcx.lang_items().fn_once_trait(),
|
||||
tcx.lang_items().fn_mut_trait(),
|
||||
tcx.lang_items().fn_trait(),
|
||||
].contains(&Some(pred.def_id()))
|
||||
{
|
||||
if let [stmt, ..] = block.stmts
|
||||
&& let hir::StmtKind::Semi(value) = stmt.kind
|
||||
&& let hir::ExprKind::Closure(hir::Closure {
|
||||
body,
|
||||
fn_decl_span,
|
||||
..
|
||||
}) = value.kind
|
||||
&& let body = hir.body(*body)
|
||||
&& !matches!(body.value.kind, hir::ExprKind::Block(..))
|
||||
{
|
||||
// Check if the failed predicate was an expectation of a closure type
|
||||
// and if there might have been a `{ |args|` typo instead of `|args| {`.
|
||||
err.multipart_suggestion(
|
||||
"you might have meant to open the closure body instead of placing \
|
||||
a closure within a block",
|
||||
vec![
|
||||
(expr.span.with_hi(value.span.lo()), String::new()),
|
||||
(fn_decl_span.shrink_to_hi(), " {".to_string()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
// Maybe the bare block was meant to be a closure.
|
||||
err.span_suggestion_verbose(
|
||||
expr.span.shrink_to_lo(),
|
||||
"you might have meant to create the closure instead of a block",
|
||||
format!(
|
||||
"|{}| ",
|
||||
(0..pred.trait_ref.args.len() - 1).map(|_| "_")
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -909,6 +909,10 @@ pub fn take<T: Default>(dest: &mut T) -> T {
|
||||
#[rustc_const_unstable(feature = "const_replace", issue = "83164")]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "mem_replace")]
|
||||
pub const fn replace<T>(dest: &mut T, src: T) -> T {
|
||||
// It may be tempting to use `swap` to avoid `unsafe` here. Don't!
|
||||
// The compiler optimizes the implementation below to two `memcpy`s
|
||||
// while `swap` would require at least three. See PR#83022 for details.
|
||||
|
||||
// SAFETY: We read from `dest` but directly write `src` into it afterwards,
|
||||
// such that the old value is not duplicated. Nothing is dropped and
|
||||
// nothing here can panic.
|
||||
|
@ -3000,7 +3000,10 @@ impl Step for CodegenCranelift {
|
||||
|
||||
let triple = run.target.triple;
|
||||
let target_supported = if triple.contains("linux") {
|
||||
triple.contains("x86_64") || triple.contains("aarch64") || triple.contains("s390x")
|
||||
triple.contains("x86_64")
|
||||
|| triple.contains("aarch64")
|
||||
|| triple.contains("s390x")
|
||||
|| triple.contains("riscv64gc")
|
||||
} else if triple.contains("darwin") || triple.contains("windows") {
|
||||
triple.contains("x86_64")
|
||||
} else {
|
||||
|
@ -0,0 +1,10 @@
|
||||
fn main() {
|
||||
let number = 2;
|
||||
Some(true).filter({ //~ ERROR expected a `FnOnce<(&bool,)>` closure, found `bool`
|
||||
if number % 2 == 0 {
|
||||
number == 0
|
||||
} else {
|
||||
number != 0
|
||||
}
|
||||
});
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
error[E0277]: expected a `FnOnce<(&bool,)>` closure, found `bool`
|
||||
--> $DIR/block_instead_of_closure_in_arg.rs:3:23
|
||||
|
|
||||
LL | Some(true).filter({
|
||||
| _________________------_^
|
||||
| | |
|
||||
| | required by a bound introduced by this call
|
||||
LL | |/ if number % 2 == 0 {
|
||||
LL | || number == 0
|
||||
LL | || } else {
|
||||
LL | || number != 0
|
||||
LL | || }
|
||||
| ||_________- this tail expression is of type `bool`
|
||||
LL | | });
|
||||
| |______^ expected an `FnOnce<(&bool,)>` closure, found `bool`
|
||||
|
|
||||
= help: the trait `for<'a> FnOnce<(&'a bool,)>` is not implemented for `bool`
|
||||
note: required by a bound in `Option::<T>::filter`
|
||||
--> $SRC_DIR/core/src/option.rs:LL:COL
|
||||
help: you might have meant to create the closure instead of a block
|
||||
|
|
||||
LL | Some(true).filter(|_| {
|
||||
| +++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
@ -0,0 +1,7 @@
|
||||
const x: usize =42;
|
||||
fn main() {
|
||||
let p = Some(45).and_then({|x| //~ ERROR expected a `FnOnce<({integer},)>` closure, found `Option<usize>`
|
||||
1 + 1;
|
||||
Some(x * 2)
|
||||
});
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
error[E0277]: expected a `FnOnce<({integer},)>` closure, found `Option<usize>`
|
||||
--> $DIR/ruby_style_closure_successful_parse.rs:3:31
|
||||
|
|
||||
LL | let p = Some(45).and_then({|x|
|
||||
| ______________________--------_^
|
||||
| | |
|
||||
| | required by a bound introduced by this call
|
||||
LL | | 1 + 1;
|
||||
LL | | Some(x * 2)
|
||||
| | ----------- this tail expression is of type `Option<usize>`
|
||||
LL | | });
|
||||
| |_____^ expected an `FnOnce<({integer},)>` closure, found `Option<usize>`
|
||||
|
|
||||
= help: the trait `FnOnce<({integer},)>` is not implemented for `Option<usize>`
|
||||
note: required by a bound in `Option::<T>::and_then`
|
||||
--> $SRC_DIR/core/src/option.rs:LL:COL
|
||||
help: you might have meant to open the closure body instead of placing a closure within a block
|
||||
|
|
||||
LL - let p = Some(45).and_then({|x|
|
||||
LL + let p = Some(45).and_then(|x| {
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,6 @@
|
||||
fn foo() -> Result<String, ()> {
|
||||
let out: Result<(), ()> = Ok(());
|
||||
out //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,15 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-116967-cannot-coerce-returned-result.rs:3:5
|
||||
|
|
||||
LL | fn foo() -> Result<String, ()> {
|
||||
| ------------------ expected `Result<String, ()>` because of return type
|
||||
LL | let out: Result<(), ()> = Ok(());
|
||||
LL | out
|
||||
| ^^^ expected `Result<String, ()>`, found `Result<(), ()>`
|
||||
|
|
||||
= note: expected enum `Result<String, _>`
|
||||
found enum `Result<(), _>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
Loading…
x
Reference in New Issue
Block a user