Auto merge of #99493 - Dylan-DPC:rollup-lli4gcx, r=Dylan-DPC
Rollup of 5 pull requests Successful merges: - #98784 (Suggest returning local on "expected `ty`, found `()`" due to expr-less block) - #98916 (Windows: Use `FindFirstFileW` for getting the metadata of locked system files) - #99433 (Erase regions before comparing signatures of foreign fns.) - #99452 (int_macros was only using to_xe_bytes_doc and not from_xe_bytes_doc) - #99481 (Add regression test for #71547) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
748cb1f01d
@ -2858,9 +2858,10 @@ impl ClashingExternDeclarations {
|
||||
let a_poly_sig = a.fn_sig(tcx);
|
||||
let b_poly_sig = b.fn_sig(tcx);
|
||||
|
||||
// As we don't compare regions, skip_binder is fine.
|
||||
let a_sig = a_poly_sig.skip_binder();
|
||||
let b_sig = b_poly_sig.skip_binder();
|
||||
// We don't compare regions, but leaving bound regions around ICEs, so
|
||||
// we erase them.
|
||||
let a_sig = tcx.erase_late_bound_regions(a_poly_sig);
|
||||
let b_sig = tcx.erase_late_bound_regions(b_poly_sig);
|
||||
|
||||
(a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
|
||||
== (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
|
||||
|
@ -31,9 +31,7 @@ use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{self, Span};
|
||||
use rustc_trait_selection::traits::{
|
||||
self, ObligationCauseCode, SelectionContext, StatementAsExpression,
|
||||
};
|
||||
use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
|
||||
|
||||
use std::iter;
|
||||
use std::slice;
|
||||
@ -1410,7 +1408,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
&self.misc(sp),
|
||||
&mut |err| {
|
||||
if let Some(expected_ty) = expected.only_has_type(self) {
|
||||
self.consider_hint_about_removing_semicolon(blk, expected_ty, err);
|
||||
if !self.consider_removing_semicolon(blk, expected_ty, err) {
|
||||
self.consider_returning_binding(blk, expected_ty, err);
|
||||
}
|
||||
if expected_ty == self.tcx.types.bool {
|
||||
// If this is caused by a missing `let` in a `while let`,
|
||||
// silence this redundant error, as we already emit E0070.
|
||||
@ -1478,42 +1478,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ty
|
||||
}
|
||||
|
||||
/// A common error is to add an extra semicolon:
|
||||
///
|
||||
/// ```compile_fail,E0308
|
||||
/// fn foo() -> usize {
|
||||
/// 22;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This routine checks if the final statement in a block is an
|
||||
/// expression with an explicit semicolon whose type is compatible
|
||||
/// with `expected_ty`. If so, it suggests removing the semicolon.
|
||||
fn consider_hint_about_removing_semicolon(
|
||||
&self,
|
||||
blk: &'tcx hir::Block<'tcx>,
|
||||
expected_ty: Ty<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
) {
|
||||
if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) {
|
||||
if let StatementAsExpression::NeedsBoxing = boxed {
|
||||
err.span_suggestion_verbose(
|
||||
span_semi,
|
||||
"consider removing this semicolon and boxing the expression",
|
||||
"",
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
} else {
|
||||
err.span_suggestion_short(
|
||||
span_semi,
|
||||
"remove this semicolon",
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_item_span(&self, id: hir::HirId) -> Option<Span> {
|
||||
let node = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(id));
|
||||
match node {
|
||||
|
@ -3,6 +3,7 @@ use crate::astconv::AstConv;
|
||||
use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
|
||||
|
||||
use rustc_ast::util::parser::ExprPrecedence;
|
||||
use rustc_data_structures::stable_set::FxHashSet;
|
||||
use rustc_errors::{Applicability, Diagnostic, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind};
|
||||
@ -11,12 +12,12 @@ use rustc_hir::{
|
||||
Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
|
||||
};
|
||||
use rustc_infer::infer::{self, TyCtxtInferExt};
|
||||
use rustc_infer::traits;
|
||||
use rustc_infer::traits::{self, StatementAsExpression};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty};
|
||||
use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty, TypeVisitable};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub(in super::super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut Diagnostic) {
|
||||
@ -864,4 +865,156 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A common error is to add an extra semicolon:
|
||||
///
|
||||
/// ```compile_fail,E0308
|
||||
/// fn foo() -> usize {
|
||||
/// 22;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This routine checks if the final statement in a block is an
|
||||
/// expression with an explicit semicolon whose type is compatible
|
||||
/// with `expected_ty`. If so, it suggests removing the semicolon.
|
||||
pub(crate) fn consider_removing_semicolon(
|
||||
&self,
|
||||
blk: &'tcx hir::Block<'tcx>,
|
||||
expected_ty: Ty<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
) -> bool {
|
||||
if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) {
|
||||
if let StatementAsExpression::NeedsBoxing = boxed {
|
||||
err.span_suggestion_verbose(
|
||||
span_semi,
|
||||
"consider removing this semicolon and boxing the expression",
|
||||
"",
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
} else {
|
||||
err.span_suggestion_short(
|
||||
span_semi,
|
||||
"remove this semicolon",
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn consider_returning_binding(
|
||||
&self,
|
||||
blk: &'tcx hir::Block<'tcx>,
|
||||
expected_ty: Ty<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
) {
|
||||
let mut shadowed = FxHashSet::default();
|
||||
let mut candidate_idents = vec![];
|
||||
let mut find_compatible_candidates = |pat: &hir::Pat<'_>| {
|
||||
if let hir::PatKind::Binding(_, hir_id, ident, _) = &pat.kind
|
||||
&& let Some(pat_ty) = self.typeck_results.borrow().node_type_opt(*hir_id)
|
||||
{
|
||||
let pat_ty = self.resolve_vars_if_possible(pat_ty);
|
||||
if self.can_coerce(pat_ty, expected_ty)
|
||||
&& !(pat_ty, expected_ty).references_error()
|
||||
&& shadowed.insert(ident.name)
|
||||
{
|
||||
candidate_idents.push((*ident, pat_ty));
|
||||
}
|
||||
}
|
||||
true
|
||||
};
|
||||
|
||||
let hir = self.tcx.hir();
|
||||
for stmt in blk.stmts.iter().rev() {
|
||||
let StmtKind::Local(local) = &stmt.kind else { continue; };
|
||||
local.pat.walk(&mut find_compatible_candidates);
|
||||
}
|
||||
match hir.find(hir.get_parent_node(blk.hir_id)) {
|
||||
Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => {
|
||||
match hir.find(hir.get_parent_node(*hir_id)) {
|
||||
Some(hir::Node::Arm(hir::Arm { pat, .. })) => {
|
||||
pat.walk(&mut find_compatible_candidates);
|
||||
}
|
||||
Some(
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. })
|
||||
| hir::Node::ImplItem(hir::ImplItem {
|
||||
kind: hir::ImplItemKind::Fn(_, body),
|
||||
..
|
||||
})
|
||||
| hir::Node::TraitItem(hir::TraitItem {
|
||||
kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)),
|
||||
..
|
||||
})
|
||||
| hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
|
||||
..
|
||||
}),
|
||||
) => {
|
||||
for param in hir.body(*body).params {
|
||||
param.pat.walk(&mut find_compatible_candidates);
|
||||
}
|
||||
}
|
||||
Some(hir::Node::Expr(hir::Expr {
|
||||
kind:
|
||||
hir::ExprKind::If(
|
||||
hir::Expr { kind: hir::ExprKind::Let(let_), .. },
|
||||
then_block,
|
||||
_,
|
||||
),
|
||||
..
|
||||
})) if then_block.hir_id == *hir_id => {
|
||||
let_.pat.walk(&mut find_compatible_candidates);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match &candidate_idents[..] {
|
||||
[(ident, _ty)] => {
|
||||
let sm = self.tcx.sess.source_map();
|
||||
if let Some(stmt) = blk.stmts.last() {
|
||||
let stmt_span = sm.stmt_span(stmt.span, blk.span);
|
||||
let sugg = if sm.is_multiline(blk.span)
|
||||
&& let Some(spacing) = sm.indentation_before(stmt_span)
|
||||
{
|
||||
format!("\n{spacing}{ident}")
|
||||
} else {
|
||||
format!(" {ident}")
|
||||
};
|
||||
err.span_suggestion_verbose(
|
||||
stmt_span.shrink_to_hi(),
|
||||
format!("consider returning the local binding `{ident}`"),
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
let sugg = if sm.is_multiline(blk.span)
|
||||
&& let Some(spacing) = sm.indentation_before(blk.span.shrink_to_lo())
|
||||
{
|
||||
format!("\n{spacing} {ident}\n{spacing}")
|
||||
} else {
|
||||
format!(" {ident} ")
|
||||
};
|
||||
let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi();
|
||||
err.span_suggestion_verbose(
|
||||
sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span),
|
||||
format!("consider returning the local binding `{ident}`"),
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
values if (1..3).contains(&values.len()) => {
|
||||
let spans = values.iter().map(|(ident, _)| ident.span).collect::<Vec<_>>();
|
||||
err.span_note(spans, "consider returning one of these bindings");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2612,7 +2612,7 @@ macro_rules! int_impl {
|
||||
/// Create an integer value from its representation as a byte array in
|
||||
/// big endian.
|
||||
///
|
||||
#[doc = $to_xe_bytes_doc]
|
||||
#[doc = $from_xe_bytes_doc]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -2641,7 +2641,7 @@ macro_rules! int_impl {
|
||||
/// Create an integer value from its representation as a byte array in
|
||||
/// little endian.
|
||||
///
|
||||
#[doc = $to_xe_bytes_doc]
|
||||
#[doc = $from_xe_bytes_doc]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -2677,7 +2677,7 @@ macro_rules! int_impl {
|
||||
/// [`from_be_bytes`]: Self::from_be_bytes
|
||||
/// [`from_le_bytes`]: Self::from_le_bytes
|
||||
///
|
||||
#[doc = $to_xe_bytes_doc]
|
||||
#[doc = $from_xe_bytes_doc]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -1534,3 +1534,20 @@ fn read_large_dir() {
|
||||
entry.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
/// Test the fallback for getting the metadata of files like hiberfil.sys that
|
||||
/// Windows holds a special lock on, preventing normal means of querying
|
||||
/// metadata. See #96980.
|
||||
///
|
||||
/// Note this fails in CI because `hiberfil.sys` does not actually exist there.
|
||||
/// Therefore it's marked as ignored.
|
||||
#[test]
|
||||
#[ignore]
|
||||
#[cfg(windows)]
|
||||
fn hiberfil_sys() {
|
||||
let hiberfil = Path::new(r"C:\hiberfil.sys");
|
||||
assert_eq!(true, hiberfil.try_exists().unwrap());
|
||||
fs::symlink_metadata(hiberfil).unwrap();
|
||||
fs::metadata(hiberfil).unwrap();
|
||||
assert_eq!(true, hiberfil.exists());
|
||||
}
|
||||
|
@ -155,22 +155,7 @@ impl DirEntry {
|
||||
}
|
||||
|
||||
pub fn metadata(&self) -> io::Result<FileAttr> {
|
||||
Ok(FileAttr {
|
||||
attributes: self.data.dwFileAttributes,
|
||||
creation_time: self.data.ftCreationTime,
|
||||
last_access_time: self.data.ftLastAccessTime,
|
||||
last_write_time: self.data.ftLastWriteTime,
|
||||
file_size: ((self.data.nFileSizeHigh as u64) << 32) | (self.data.nFileSizeLow as u64),
|
||||
reparse_tag: if self.data.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
|
||||
// reserved unless this is a reparse point
|
||||
self.data.dwReserved0
|
||||
} else {
|
||||
0
|
||||
},
|
||||
volume_serial_number: None,
|
||||
number_of_links: None,
|
||||
file_index: None,
|
||||
})
|
||||
Ok(self.data.into())
|
||||
}
|
||||
}
|
||||
|
||||
@ -879,6 +864,26 @@ impl FileAttr {
|
||||
self.file_index
|
||||
}
|
||||
}
|
||||
impl From<c::WIN32_FIND_DATAW> for FileAttr {
|
||||
fn from(wfd: c::WIN32_FIND_DATAW) -> Self {
|
||||
FileAttr {
|
||||
attributes: wfd.dwFileAttributes,
|
||||
creation_time: wfd.ftCreationTime,
|
||||
last_access_time: wfd.ftLastAccessTime,
|
||||
last_write_time: wfd.ftLastWriteTime,
|
||||
file_size: ((wfd.nFileSizeHigh as u64) << 32) | (wfd.nFileSizeLow as u64),
|
||||
reparse_tag: if wfd.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
|
||||
// reserved unless this is a reparse point
|
||||
wfd.dwReserved0
|
||||
} else {
|
||||
0
|
||||
},
|
||||
volume_serial_number: None,
|
||||
number_of_links: None,
|
||||
file_index: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_u64(ft: &c::FILETIME) -> u64 {
|
||||
(ft.dwLowDateTime as u64) | ((ft.dwHighDateTime as u64) << 32)
|
||||
@ -1145,22 +1150,73 @@ pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
|
||||
}
|
||||
|
||||
pub fn stat(path: &Path) -> io::Result<FileAttr> {
|
||||
let mut opts = OpenOptions::new();
|
||||
// No read or write permissions are necessary
|
||||
opts.access_mode(0);
|
||||
// This flag is so we can open directories too
|
||||
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
|
||||
let file = File::open(path, &opts)?;
|
||||
file.file_attr()
|
||||
metadata(path, ReparsePoint::Follow)
|
||||
}
|
||||
|
||||
pub fn lstat(path: &Path) -> io::Result<FileAttr> {
|
||||
metadata(path, ReparsePoint::Open)
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum ReparsePoint {
|
||||
Follow = 0,
|
||||
Open = c::FILE_FLAG_OPEN_REPARSE_POINT,
|
||||
}
|
||||
impl ReparsePoint {
|
||||
fn as_flag(self) -> u32 {
|
||||
self as u32
|
||||
}
|
||||
}
|
||||
|
||||
fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> {
|
||||
let mut opts = OpenOptions::new();
|
||||
// No read or write permissions are necessary
|
||||
opts.access_mode(0);
|
||||
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT);
|
||||
let file = File::open(path, &opts)?;
|
||||
file.file_attr()
|
||||
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | reparse.as_flag());
|
||||
|
||||
// Attempt to open the file normally.
|
||||
// If that fails with `ERROR_SHARING_VIOLATION` then retry using `FindFirstFileW`.
|
||||
// If the fallback fails for any reason we return the original error.
|
||||
match File::open(path, &opts) {
|
||||
Ok(file) => file.file_attr(),
|
||||
Err(e) if e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as _) => {
|
||||
// `ERROR_SHARING_VIOLATION` will almost never be returned.
|
||||
// Usually if a file is locked you can still read some metadata.
|
||||
// However, there are special system files, such as
|
||||
// `C:\hiberfil.sys`, that are locked in a way that denies even that.
|
||||
unsafe {
|
||||
let path = maybe_verbatim(path)?;
|
||||
|
||||
// `FindFirstFileW` accepts wildcard file names.
|
||||
// Fortunately wildcards are not valid file names and
|
||||
// `ERROR_SHARING_VIOLATION` means the file exists (but is locked)
|
||||
// therefore it's safe to assume the file name given does not
|
||||
// include wildcards.
|
||||
let mut wfd = mem::zeroed();
|
||||
let handle = c::FindFirstFileW(path.as_ptr(), &mut wfd);
|
||||
|
||||
if handle == c::INVALID_HANDLE_VALUE {
|
||||
// This can fail if the user does not have read access to the
|
||||
// directory.
|
||||
Err(e)
|
||||
} else {
|
||||
// We no longer need the find handle.
|
||||
c::FindClose(handle);
|
||||
|
||||
// `FindFirstFileW` reads the cached file information from the
|
||||
// directory. The downside is that this metadata may be outdated.
|
||||
let attrs = FileAttr::from(wfd);
|
||||
if reparse == ReparsePoint::Follow && attrs.file_type().is_symlink() {
|
||||
Err(e)
|
||||
} else {
|
||||
Ok(attrs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
|
||||
|
@ -18,6 +18,14 @@ LL | | break 0u8;
|
||||
LL | | };
|
||||
| |_________- enclosing `async` block
|
||||
|
||||
error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
|
||||
--> $DIR/async-block-control-flow-static-semantics.rs:26:39
|
||||
|
|
||||
LL | let _: &dyn Future<Output = ()> = █
|
||||
| ^^^^^^ expected `()`, found `u8`
|
||||
|
|
||||
= note: required for the cast from `impl Future<Output = u8>` to the object type `dyn Future<Output = ()>`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/async-block-control-flow-static-semantics.rs:21:58
|
||||
|
|
||||
@ -32,7 +40,7 @@ LL | | }
|
||||
| |_^ expected `u8`, found `()`
|
||||
|
||||
error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
|
||||
--> $DIR/async-block-control-flow-static-semantics.rs:26:39
|
||||
--> $DIR/async-block-control-flow-static-semantics.rs:17:39
|
||||
|
|
||||
LL | let _: &dyn Future<Output = ()> = █
|
||||
| ^^^^^^ expected `()`, found `u8`
|
||||
@ -47,14 +55,6 @@ LL | fn return_targets_async_block_not_fn() -> u8 {
|
||||
| |
|
||||
| implicitly returns `()` as its body has no tail or `return` expression
|
||||
|
||||
error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
|
||||
--> $DIR/async-block-control-flow-static-semantics.rs:17:39
|
||||
|
|
||||
LL | let _: &dyn Future<Output = ()> = █
|
||||
| ^^^^^^ expected `()`, found `u8`
|
||||
|
|
||||
= note: required for the cast from `impl Future<Output = u8>` to the object type `dyn Future<Output = ()>`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/async-block-control-flow-static-semantics.rs:47:44
|
||||
|
|
||||
|
18
src/test/ui/const-generics/issues/issue-71547.rs
Normal file
18
src/test/ui/const-generics/issues/issue-71547.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(adt_const_params)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
pub trait GetType<const N: &'static str> {
|
||||
type Ty;
|
||||
fn get(&self) -> &Self::Ty;
|
||||
}
|
||||
|
||||
pub fn get_val<T>(value: &T) -> &T::Ty
|
||||
where
|
||||
T: GetType<"hello">,
|
||||
{
|
||||
value.get()
|
||||
}
|
||||
|
||||
fn main() {}
|
24
src/test/ui/foreign/issue-99276-same-type-lifetimes.rs
Normal file
24
src/test/ui/foreign/issue-99276-same-type-lifetimes.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// Check that we do not ICE when structurally comparing types with lifetimes present.
|
||||
// check-pass
|
||||
|
||||
pub struct Record<'a> {
|
||||
pub args: &'a [(usize, &'a str)],
|
||||
}
|
||||
|
||||
mod a {
|
||||
extern "Rust" {
|
||||
fn foo<'a, 'b>(record: &'a super::Record<'b>);
|
||||
|
||||
fn bar<'a, 'b>(record: &'a super::Record<'b>);
|
||||
}
|
||||
}
|
||||
|
||||
mod b {
|
||||
extern "Rust" {
|
||||
fn foo<'a, 'b>(record: &'a super::Record<'b>);
|
||||
|
||||
fn bar<'a, 'b>(record: &'a super::Record<'b>);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -5,6 +5,11 @@ LL | fn f(a: isize) -> isize { if god_exists(a) { return 5; }; }
|
||||
| - ^^^^^ expected `isize`, found `()`
|
||||
| |
|
||||
| implicitly returns `()` as its body has no tail or `return` expression
|
||||
|
|
||||
help: consider returning the local binding `a`
|
||||
|
|
||||
LL | fn f(a: isize) -> isize { if god_exists(a) { return 5; }; a }
|
||||
| +
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -11,6 +11,11 @@ LL | fn f(*, a: u8) -> u8 {}
|
||||
| - ^^ expected `u8`, found `()`
|
||||
| |
|
||||
| implicitly returns `()` as its body has no tail or `return` expression
|
||||
|
|
||||
help: consider returning the local binding `a`
|
||||
|
|
||||
LL | fn f(*, a: u8) -> u8 { a }
|
||||
| +
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
9
src/test/ui/suggestions/return-bindings-multi.rs
Normal file
9
src/test/ui/suggestions/return-bindings-multi.rs
Normal file
@ -0,0 +1,9 @@
|
||||
fn a(i: i32) -> i32 {
|
||||
//~^ ERROR mismatched types
|
||||
let j = 2i32;
|
||||
}
|
||||
|
||||
fn b(i: i32, j: i32) -> i32 {}
|
||||
//~^ ERROR mismatched types
|
||||
|
||||
fn main() {}
|
34
src/test/ui/suggestions/return-bindings-multi.stderr
Normal file
34
src/test/ui/suggestions/return-bindings-multi.stderr
Normal file
@ -0,0 +1,34 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/return-bindings-multi.rs:1:17
|
||||
|
|
||||
LL | fn a(i: i32) -> i32 {
|
||||
| - ^^^ expected `i32`, found `()`
|
||||
| |
|
||||
| implicitly returns `()` as its body has no tail or `return` expression
|
||||
|
|
||||
note: consider returning one of these bindings
|
||||
--> $DIR/return-bindings-multi.rs:1:6
|
||||
|
|
||||
LL | fn a(i: i32) -> i32 {
|
||||
| ^
|
||||
LL |
|
||||
LL | let j = 2i32;
|
||||
| ^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/return-bindings-multi.rs:6:25
|
||||
|
|
||||
LL | fn b(i: i32, j: i32) -> i32 {}
|
||||
| - ^^^ expected `i32`, found `()`
|
||||
| |
|
||||
| implicitly returns `()` as its body has no tail or `return` expression
|
||||
|
|
||||
note: consider returning one of these bindings
|
||||
--> $DIR/return-bindings-multi.rs:6:6
|
||||
|
|
||||
LL | fn b(i: i32, j: i32) -> i32 {}
|
||||
| ^ ^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
23
src/test/ui/suggestions/return-bindings.fixed
Normal file
23
src/test/ui/suggestions/return-bindings.fixed
Normal file
@ -0,0 +1,23 @@
|
||||
// run-rustfix
|
||||
|
||||
#![allow(unused)]
|
||||
|
||||
fn a(i: i32) -> i32 { i }
|
||||
//~^ ERROR mismatched types
|
||||
|
||||
fn b(opt_str: Option<String>) {
|
||||
let s: String = if let Some(s) = opt_str {
|
||||
s
|
||||
//~^ ERROR mismatched types
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
}
|
||||
|
||||
fn c() -> Option<i32> {
|
||||
//~^ ERROR mismatched types
|
||||
let x = Some(1);
|
||||
x
|
||||
}
|
||||
|
||||
fn main() {}
|
21
src/test/ui/suggestions/return-bindings.rs
Normal file
21
src/test/ui/suggestions/return-bindings.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// run-rustfix
|
||||
|
||||
#![allow(unused)]
|
||||
|
||||
fn a(i: i32) -> i32 {}
|
||||
//~^ ERROR mismatched types
|
||||
|
||||
fn b(opt_str: Option<String>) {
|
||||
let s: String = if let Some(s) = opt_str {
|
||||
//~^ ERROR mismatched types
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
}
|
||||
|
||||
fn c() -> Option<i32> {
|
||||
//~^ ERROR mismatched types
|
||||
let x = Some(1);
|
||||
}
|
||||
|
||||
fn main() {}
|
48
src/test/ui/suggestions/return-bindings.stderr
Normal file
48
src/test/ui/suggestions/return-bindings.stderr
Normal file
@ -0,0 +1,48 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/return-bindings.rs:5:17
|
||||
|
|
||||
LL | fn a(i: i32) -> i32 {}
|
||||
| - ^^^ expected `i32`, found `()`
|
||||
| |
|
||||
| implicitly returns `()` as its body has no tail or `return` expression
|
||||
|
|
||||
help: consider returning the local binding `i`
|
||||
|
|
||||
LL | fn a(i: i32) -> i32 { i }
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/return-bindings.rs:9:46
|
||||
|
|
||||
LL | let s: String = if let Some(s) = opt_str {
|
||||
| ______________________________________________^
|
||||
LL | |
|
||||
LL | | } else {
|
||||
| |_____^ expected struct `String`, found `()`
|
||||
|
|
||||
help: consider returning the local binding `s`
|
||||
|
|
||||
LL ~ let s: String = if let Some(s) = opt_str {
|
||||
LL + s
|
||||
LL ~
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/return-bindings.rs:16:11
|
||||
|
|
||||
LL | fn c() -> Option<i32> {
|
||||
| - ^^^^^^^^^^^ expected enum `Option`, found `()`
|
||||
| |
|
||||
| implicitly returns `()` as its body has no tail or `return` expression
|
||||
|
|
||||
= note: expected enum `Option<i32>`
|
||||
found unit type `()`
|
||||
help: consider returning the local binding `x`
|
||||
|
|
||||
LL ~ let x = Some(1);
|
||||
LL + x
|
||||
|
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
Loading…
x
Reference in New Issue
Block a user