Skip to content

Commit

Permalink
Auto merge of rust-lang#104246 - Manishearth:rollup-9o3txc7, r=Manish…
Browse files Browse the repository at this point in the history
…earth

Rollup of 9 pull requests

Successful merges:

 - rust-lang#101939 (Add loongarch64 abi support)
 - rust-lang#103863 (Use `TraitEngine` in more places, restrict visibility of `FulfillmentCtxt` constructor)
 - rust-lang#104036 (Suggest `is_some` when we've found `Option` but expected `bool`)
 - rust-lang#104060 (Make `Hash`, `Hasher` and `BuildHasher` `#[const_trait]` and make `Sip` const `Hasher`)
 - rust-lang#104077 (Use aapcs for efiapi calling convention on arm)
 - rust-lang#104186 (Tighten the 'introduce new binding' suggestion)
 - rust-lang#104194 (`EarlyBinder` docs)
 - rust-lang#104233 (Don't ICE when encountering `ConstKind::Error` in `RequiredConstsVisitor`)
 - rust-lang#104235 (Use `const_error_with_guaranteed` more)

Failed merges:

 - rust-lang#104078 (Print "Checking/Building ..." message even when --dry-run is passed)
 - rust-lang#104169 (Migrate `:target` rules to use CSS variables)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Nov 10, 2022
2 parents 01a6f30 + ea56e80 commit a3c0a02
Show file tree
Hide file tree
Showing 38 changed files with 827 additions and 104 deletions.
3 changes: 2 additions & 1 deletion compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ use rustc_span::{self, BytePos, DesugaringKind, Span};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::TraitEngineExt as _;
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};

use smallvec::{smallvec, SmallVec};
Expand Down Expand Up @@ -1038,7 +1039,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Ok(ok) = coerce.coerce(source, target) else {
return false;
};
let mut fcx = traits::FulfillmentContext::new_in_snapshot();
let mut fcx = <dyn TraitEngine<'tcx>>::new_in_snapshot(self.tcx);
fcx.register_predicate_obligations(self, ok.obligations);
fcx.select_where_possible(&self).is_empty()
})
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_hir_typeck/src/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|| self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty)
|| self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
|| self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
|| self.suggest_into(err, expr, expr_ty, expected);
|| self.suggest_into(err, expr, expr_ty, expected)
|| self.suggest_option_to_bool(err, expr, expr_ty, expected);

self.note_type_is_not_clone(err, expected, expr_ty, expr);
self.note_need_for_fn_pointer(err, expected, expr_ty);
Expand Down
12 changes: 10 additions & 2 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) {
let expr = expr.peel_drop_temps();
self.suggest_deref_ref_or_into(&mut err, expr, expected_ty, ty, None);
// FIXME(compiler-errors): We probably should fold some of the
// `suggest_` functions from `emit_coerce_suggestions` into here,
// since some of those aren't necessarily just coerce suggestions.
let _ = self.suggest_deref_ref_or_into(
&mut err,
expr.peel_drop_temps(),
expected_ty,
ty,
None,
) || self.suggest_option_to_bool(&mut err, expr, ty, expected_ty);
extend_err(&mut err);
err.emit();
}
Expand Down
49 changes: 48 additions & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::{self, TyCtxtInferExt};
use rustc_infer::traits::{self, StatementAsExpression};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Binder, IsSuggestable, ToPredicate, Ty};
use rustc_middle::ty::{self, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty};
use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::symbol::sym;
use rustc_span::Span;
Expand Down Expand Up @@ -1116,6 +1116,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
false
}

/// When expecting a `bool` and finding an `Option`, suggests using `let Some(..)` or `.is_some()`
pub(crate) fn suggest_option_to_bool(
&self,
diag: &mut Diagnostic,
expr: &hir::Expr<'_>,
expr_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>,
) -> bool {
if !expected_ty.is_bool() {
return false;
}

let ty::Adt(def, _) = expr_ty.peel_refs().kind() else { return false; };
if !self.tcx.is_diagnostic_item(sym::Option, def.did()) {
return false;
}

let hir = self.tcx.hir();
let cond_parent = hir.parent_iter(expr.hir_id).skip_while(|(_, node)| {
matches!(node, hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, _, _), .. }) if op.node == hir::BinOpKind::And)
}).next();
// Don't suggest:
// `let Some(_) = a.is_some() && b`
// ++++++++++
// since the user probably just misunderstood how `let else`
// and `&&` work together.
if let Some((_, hir::Node::Local(local))) = cond_parent
&& let hir::PatKind::Path(qpath) | hir::PatKind::TupleStruct(qpath, _, _) = &local.pat.kind
&& let hir::QPath::Resolved(None, path) = qpath
&& let Some(did) = path.res.opt_def_id()
.and_then(|did| self.tcx.opt_parent(did))
.and_then(|did| self.tcx.opt_parent(did))
&& self.tcx.is_diagnostic_item(sym::Option, did)
{
return false;
}

diag.span_suggestion(
expr.span.shrink_to_hi(),
"use `Option::is_some` to test if the `Option` has a value",
".is_some()",
Applicability::MachineApplicable,
);

true
}

/// Suggest wrapping the block in square brackets instead of curly braces
/// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`.
pub(crate) fn suggest_block_to_brackets(
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_middle/src/mir/interpret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ use rustc_ast::LitKind;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::{HashMapExt, Lock};
use rustc_data_structures::tiny_list::TinyList;
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::DefId;
use rustc_macros::HashStable;
use rustc_middle::ty::print::with_no_trimmed_paths;
Expand Down Expand Up @@ -176,7 +177,7 @@ pub enum LitToConstError {
/// This is used for graceful error handling (`delay_span_bug`) in
/// type checking (`Const::from_anon_const`).
TypeError,
Reported,
Reported(ErrorGuaranteed),
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2251,7 +2251,9 @@ impl<'tcx> ConstantKind<'tcx> {
match tcx.const_eval_resolve(param_env, uneval, None) {
Ok(val) => Self::Val(val, ty),
Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => self,
Err(_) => Self::Ty(tcx.const_error(ty)),
Err(ErrorHandled::Reported(guar)) => {
Self::Ty(tcx.const_error_with_guaranteed(ty, guar))
}
}
}
}
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_middle/src/ty/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use crate::mir::interpret::LitToConstInput;
use crate::mir::ConstantKind;
use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
use rustc_data_structures::intern::Interned;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_macros::HashStable;
Expand Down Expand Up @@ -225,7 +224,7 @@ impl<'tcx> Const<'tcx> {
if let Some(val) = self.kind().try_eval_for_typeck(tcx, param_env) {
match val {
Ok(val) => Const::from_value(tcx, val, self.ty()),
Err(ErrorGuaranteed { .. }) => tcx.const_error(self.ty()),
Err(guar) => tcx.const_error_with_guaranteed(self.ty(), guar),
}
} else {
// Either the constant isn't evaluatable or ValTree creation failed.
Expand All @@ -240,7 +239,7 @@ impl<'tcx> Const<'tcx> {
if let Some(val) = self.kind().try_eval_for_mir(tcx, param_env) {
match val {
Ok(const_val) => ConstantKind::from_value(const_val, self.ty()),
Err(ErrorGuaranteed { .. }) => ConstantKind::Ty(tcx.const_error(self.ty())),
Err(guar) => ConstantKind::Ty(tcx.const_error_with_guaranteed(self.ty(), guar)),
}
} else {
ConstantKind::Ty(self)
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_middle/src/ty/subst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,9 @@ impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for &'tcx ty::List<T> {
}
}

/// Similar to [`super::Binder`] except that it tracks early bound generics, i.e. `struct Foo<T>(T)`
/// needs `T` substituted immediately. This type primarily exists to avoid forgetting to call
/// `subst`.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[derive(Encodable, Decodable, HashStable)]
pub struct EarlyBinder<T>(pub T);
Expand Down
31 changes: 25 additions & 6 deletions compiler/rustc_mir_build/src/build/expr/as_constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use rustc_middle::mir::interpret::{
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, TyCtxt};
use rustc_span::DUMMY_SP;
use rustc_target::abi::Size;

impl<'a, 'tcx> Builder<'a, 'tcx> {
Expand All @@ -26,7 +27,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let literal =
match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
Ok(c) => c,
Err(LitToConstError::Reported) => ConstantKind::Ty(tcx.const_error(ty)),
Err(LitToConstError::Reported(guar)) => {
ConstantKind::Ty(tcx.const_error_with_guaranteed(ty, guar))
}
Err(LitToConstError::TypeError) => {
bug!("encountered type error in `lit_to_mir_constant")
}
Expand Down Expand Up @@ -105,7 +108,15 @@ pub(crate) fn lit_to_mir_constant<'tcx>(
let LitToConstInput { lit, ty, neg } = lit_input;
let trunc = |n| {
let param_ty = ty::ParamEnv::reveal_all().and(ty);
let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
let width = tcx
.layout_of(param_ty)
.map_err(|_| {
LitToConstError::Reported(tcx.sess.delay_span_bug(
DUMMY_SP,
format!("couldn't compute width of literal: {:?}", lit_input.lit),
))
})?
.size;
trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
let result = width.truncate(n);
trace!("trunc result: {}", result);
Expand Down Expand Up @@ -136,12 +147,20 @@ pub(crate) fn lit_to_mir_constant<'tcx>(
(ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?
}
(ast::LitKind::Float(n, _), ty::Float(fty)) => {
parse_float_into_constval(*n, *fty, neg).ok_or(LitToConstError::Reported)?
}
(ast::LitKind::Float(n, _), ty::Float(fty)) => parse_float_into_constval(*n, *fty, neg)
.ok_or_else(|| {
LitToConstError::Reported(tcx.sess.delay_span_bug(
DUMMY_SP,
format!("couldn't parse float literal: {:?}", lit_input.lit),
))
})?,
(ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
(ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
(ast::LitKind::Err, _) => return Err(LitToConstError::Reported),
(ast::LitKind::Err, _) => {
return Err(LitToConstError::Reported(
tcx.sess.delay_span_bug(DUMMY_SP, "encountered LitKind::Err during mir build"),
));
}
_ => return Err(LitToConstError::TypeError),
};

Expand Down
17 changes: 15 additions & 2 deletions compiler/rustc_mir_build/src/thir/constant.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use rustc_ast as ast;
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
use rustc_middle::ty::{self, ParamEnv, ScalarInt, TyCtxt};
use rustc_span::DUMMY_SP;

pub(crate) fn lit_to_const<'tcx>(
tcx: TyCtxt<'tcx>,
Expand All @@ -10,7 +11,15 @@ pub(crate) fn lit_to_const<'tcx>(

let trunc = |n| {
let param_ty = ParamEnv::reveal_all().and(ty);
let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
let width = tcx
.layout_of(param_ty)
.map_err(|_| {
LitToConstError::Reported(tcx.sess.delay_span_bug(
DUMMY_SP,
format!("couldn't compute width of literal: {:?}", lit_input.lit),
))
})?
.size;
trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
let result = width.truncate(n);
trace!("trunc result: {}", result);
Expand Down Expand Up @@ -44,7 +53,11 @@ pub(crate) fn lit_to_const<'tcx>(
}
(ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()),
(ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()),
(ast::LitKind::Err, _) => return Err(LitToConstError::Reported),
(ast::LitKind::Err, _) => {
return Err(LitToConstError::Reported(
tcx.sess.delay_span_bug(DUMMY_SP, "encountered LitKind::Err during mir build"),
));
}
_ => return Err(LitToConstError::TypeError),
};

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
match self.tcx.at(expr.span).lit_to_mir_constant(lit_input) {
Ok(constant) => self.const_to_pat(constant, expr.hir_id, lit.span, false).kind,
Err(LitToConstError::Reported) => PatKind::Wild,
Err(LitToConstError::Reported(_)) => PatKind::Wild,
Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/required_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> {
let literal = constant.literal;
match literal {
ConstantKind::Ty(c) => match c.kind() {
ConstKind::Param(_) => {}
ConstKind::Param(_) | ConstKind::Error(_) => {}
_ => bug!("only ConstKind::Param should be encountered here, got {:#?}", c),
},
ConstantKind::Unevaluated(..) => self.required_consts.push(*constant),
Expand Down
14 changes: 10 additions & 4 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ struct DiagnosticMetadata<'ast> {

/// Used to detect possible new binding written without `let` and to provide structured suggestion.
in_assignment: Option<&'ast Expr>,
is_assign_rhs: bool,

/// If we are currently in a trait object definition. Used to point at the bounds when
/// encountering a struct or enum.
Expand Down Expand Up @@ -3963,10 +3964,15 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
self.resolve_expr(elem, Some(expr));
self.visit_expr(idx);
}
ExprKind::Assign(..) => {
let old = self.diagnostic_metadata.in_assignment.replace(expr);
visit::walk_expr(self, expr);
self.diagnostic_metadata.in_assignment = old;
ExprKind::Assign(ref lhs, ref rhs, _) => {
if !self.diagnostic_metadata.is_assign_rhs {
self.diagnostic_metadata.in_assignment = Some(expr);
}
self.visit_expr(lhs);
self.diagnostic_metadata.is_assign_rhs = true;
self.diagnostic_metadata.in_assignment = None;
self.visit_expr(rhs);
self.diagnostic_metadata.is_assign_rhs = false;
}
_ => {
visit::walk_expr(self, expr);
Expand Down
21 changes: 7 additions & 14 deletions compiler/rustc_resolve/src/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1810,29 +1810,22 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
false
}

fn let_binding_suggestion(&self, err: &mut Diagnostic, ident_span: Span) -> bool {
// try to give a suggestion for this pattern: `name = 1`, which is common in other languages
let mut added_suggestion = false;
if let Some(Expr { kind: ExprKind::Assign(lhs, _rhs, _), .. }) = self.diagnostic_metadata.in_assignment &&
// try to give a suggestion for this pattern: `name = blah`, which is common in other languages
// suggest `let name = blah` to introduce a new binding
fn let_binding_suggestion(&mut self, err: &mut Diagnostic, ident_span: Span) -> bool {
if let Some(Expr { kind: ExprKind::Assign(lhs, .. ), .. }) = self.diagnostic_metadata.in_assignment &&
let ast::ExprKind::Path(None, _) = lhs.kind {
let sm = self.r.session.source_map();
let line_span = sm.span_extend_to_line(ident_span);
let ident_name = sm.span_to_snippet(ident_span).unwrap();
// HACK(chenyukang): make sure ident_name is at the starting of the line to protect against macros
if sm
.span_to_snippet(line_span)
.map_or(false, |s| s.trim().starts_with(&ident_name))
{
if !ident_span.from_expansion() {
err.span_suggestion_verbose(
ident_span.shrink_to_lo(),
"you might have meant to introduce a new binding",
"let ".to_string(),
Applicability::MaybeIncorrect,
);
added_suggestion = true;
return true;
}
}
added_suggestion
false
}

fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> {
Expand Down
Loading

0 comments on commit a3c0a02

Please sign in to comment.