Skip to content

Commit

Permalink
Auto merge of rust-lang#99493 - Dylan-DPC:rollup-lli4gcx, r=Dylan-DPC
Browse files Browse the repository at this point in the history
Rollup of 5 pull requests

Successful merges:

 - rust-lang#98784 (Suggest returning local on "expected `ty`, found `()`" due to expr-less block)
 - rust-lang#98916 (Windows: Use `FindFirstFileW` for getting the metadata of locked system files)
 - rust-lang#99433 (Erase regions before comparing signatures of foreign fns.)
 - rust-lang#99452 (int_macros was only using to_xe_bytes_doc and not from_xe_bytes_doc)
 - rust-lang#99481 (Add regression test for rust-lang#71547)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Jul 20, 2022
2 parents 03d488b + d7a65a5 commit 748cb1f
Show file tree
Hide file tree
Showing 16 changed files with 462 additions and 84 deletions.
7 changes: 4 additions & 3 deletions compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
44 changes: 4 additions & 40 deletions compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 {
Expand Down
159 changes: 156 additions & 3 deletions compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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) {
Expand Down Expand Up @@ -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");
}
_ => {}
}
}
}
6 changes: 3 additions & 3 deletions library/core/src/num/int_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
///
Expand Down Expand Up @@ -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
///
Expand Down Expand Up @@ -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
///
Expand Down
17 changes: 17 additions & 0 deletions library/std/src/fs/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Loading

0 comments on commit 748cb1f

Please sign in to comment.