Skip to content

Commit a3c0a02

Browse files
committed
Auto merge of rust-lang#104246 - Manishearth:rollup-9o3txc7, r=Manishearth
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
2 parents 01a6f30 + ea56e80 commit a3c0a02

File tree

38 files changed

+827
-104
lines changed

38 files changed

+827
-104
lines changed

compiler/rustc_hir_typeck/src/coercion.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ use rustc_span::{self, BytePos, DesugaringKind, Span};
6262
use rustc_target::spec::abi::Abi;
6363
use rustc_trait_selection::infer::InferCtxtExt as _;
6464
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
65+
use rustc_trait_selection::traits::TraitEngineExt as _;
6566
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
6667

6768
use smallvec::{smallvec, SmallVec};
@@ -1038,7 +1039,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10381039
let Ok(ok) = coerce.coerce(source, target) else {
10391040
return false;
10401041
};
1041-
let mut fcx = traits::FulfillmentContext::new_in_snapshot();
1042+
let mut fcx = <dyn TraitEngine<'tcx>>::new_in_snapshot(self.tcx);
10421043
fcx.register_predicate_obligations(self, ok.obligations);
10431044
fcx.select_where_possible(&self).is_empty()
10441045
})

compiler/rustc_hir_typeck/src/demand.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
4242
|| self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty)
4343
|| self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
4444
|| self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
45-
|| self.suggest_into(err, expr, expr_ty, expected);
45+
|| self.suggest_into(err, expr, expr_ty, expected)
46+
|| self.suggest_option_to_bool(err, expr, expr_ty, expected);
4647

4748
self.note_type_is_not_clone(err, expected, expr_ty, expr);
4849
self.note_need_for_fn_pointer(err, expected, expr_ty);

compiler/rustc_hir_typeck/src/expr.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
103103
}
104104

105105
if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) {
106-
let expr = expr.peel_drop_temps();
107-
self.suggest_deref_ref_or_into(&mut err, expr, expected_ty, ty, None);
106+
// FIXME(compiler-errors): We probably should fold some of the
107+
// `suggest_` functions from `emit_coerce_suggestions` into here,
108+
// since some of those aren't necessarily just coerce suggestions.
109+
let _ = self.suggest_deref_ref_or_into(
110+
&mut err,
111+
expr.peel_drop_temps(),
112+
expected_ty,
113+
ty,
114+
None,
115+
) || self.suggest_option_to_bool(&mut err, expr, ty, expected_ty);
108116
extend_err(&mut err);
109117
err.emit();
110118
}

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+48-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_hir_analysis::astconv::AstConv;
1313
use rustc_infer::infer::{self, TyCtxtInferExt};
1414
use rustc_infer::traits::{self, StatementAsExpression};
1515
use rustc_middle::lint::in_external_macro;
16-
use rustc_middle::ty::{self, Binder, IsSuggestable, ToPredicate, Ty};
16+
use rustc_middle::ty::{self, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty};
1717
use rustc_session::errors::ExprParenthesesNeeded;
1818
use rustc_span::symbol::sym;
1919
use rustc_span::Span;
@@ -1116,6 +1116,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11161116
false
11171117
}
11181118

1119+
/// When expecting a `bool` and finding an `Option`, suggests using `let Some(..)` or `.is_some()`
1120+
pub(crate) fn suggest_option_to_bool(
1121+
&self,
1122+
diag: &mut Diagnostic,
1123+
expr: &hir::Expr<'_>,
1124+
expr_ty: Ty<'tcx>,
1125+
expected_ty: Ty<'tcx>,
1126+
) -> bool {
1127+
if !expected_ty.is_bool() {
1128+
return false;
1129+
}
1130+
1131+
let ty::Adt(def, _) = expr_ty.peel_refs().kind() else { return false; };
1132+
if !self.tcx.is_diagnostic_item(sym::Option, def.did()) {
1133+
return false;
1134+
}
1135+
1136+
let hir = self.tcx.hir();
1137+
let cond_parent = hir.parent_iter(expr.hir_id).skip_while(|(_, node)| {
1138+
matches!(node, hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, _, _), .. }) if op.node == hir::BinOpKind::And)
1139+
}).next();
1140+
// Don't suggest:
1141+
// `let Some(_) = a.is_some() && b`
1142+
// ++++++++++
1143+
// since the user probably just misunderstood how `let else`
1144+
// and `&&` work together.
1145+
if let Some((_, hir::Node::Local(local))) = cond_parent
1146+
&& let hir::PatKind::Path(qpath) | hir::PatKind::TupleStruct(qpath, _, _) = &local.pat.kind
1147+
&& let hir::QPath::Resolved(None, path) = qpath
1148+
&& let Some(did) = path.res.opt_def_id()
1149+
.and_then(|did| self.tcx.opt_parent(did))
1150+
.and_then(|did| self.tcx.opt_parent(did))
1151+
&& self.tcx.is_diagnostic_item(sym::Option, did)
1152+
{
1153+
return false;
1154+
}
1155+
1156+
diag.span_suggestion(
1157+
expr.span.shrink_to_hi(),
1158+
"use `Option::is_some` to test if the `Option` has a value",
1159+
".is_some()",
1160+
Applicability::MachineApplicable,
1161+
);
1162+
1163+
true
1164+
}
1165+
11191166
/// Suggest wrapping the block in square brackets instead of curly braces
11201167
/// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`.
11211168
pub(crate) fn suggest_block_to_brackets(

compiler/rustc_middle/src/mir/interpret/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ use rustc_ast::LitKind;
106106
use rustc_data_structures::fx::FxHashMap;
107107
use rustc_data_structures::sync::{HashMapExt, Lock};
108108
use rustc_data_structures::tiny_list::TinyList;
109+
use rustc_errors::ErrorGuaranteed;
109110
use rustc_hir::def_id::DefId;
110111
use rustc_macros::HashStable;
111112
use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -176,7 +177,7 @@ pub enum LitToConstError {
176177
/// This is used for graceful error handling (`delay_span_bug`) in
177178
/// type checking (`Const::from_anon_const`).
178179
TypeError,
179-
Reported,
180+
Reported(ErrorGuaranteed),
180181
}
181182

182183
#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]

compiler/rustc_middle/src/mir/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -2251,7 +2251,9 @@ impl<'tcx> ConstantKind<'tcx> {
22512251
match tcx.const_eval_resolve(param_env, uneval, None) {
22522252
Ok(val) => Self::Val(val, ty),
22532253
Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => self,
2254-
Err(_) => Self::Ty(tcx.const_error(ty)),
2254+
Err(ErrorHandled::Reported(guar)) => {
2255+
Self::Ty(tcx.const_error_with_guaranteed(ty, guar))
2256+
}
22552257
}
22562258
}
22572259
}

compiler/rustc_middle/src/ty/consts.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use crate::mir::interpret::LitToConstInput;
22
use crate::mir::ConstantKind;
33
use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
44
use rustc_data_structures::intern::Interned;
5-
use rustc_errors::ErrorGuaranteed;
65
use rustc_hir as hir;
76
use rustc_hir::def_id::{DefId, LocalDefId};
87
use rustc_macros::HashStable;
@@ -225,7 +224,7 @@ impl<'tcx> Const<'tcx> {
225224
if let Some(val) = self.kind().try_eval_for_typeck(tcx, param_env) {
226225
match val {
227226
Ok(val) => Const::from_value(tcx, val, self.ty()),
228-
Err(ErrorGuaranteed { .. }) => tcx.const_error(self.ty()),
227+
Err(guar) => tcx.const_error_with_guaranteed(self.ty(), guar),
229228
}
230229
} else {
231230
// Either the constant isn't evaluatable or ValTree creation failed.
@@ -240,7 +239,7 @@ impl<'tcx> Const<'tcx> {
240239
if let Some(val) = self.kind().try_eval_for_mir(tcx, param_env) {
241240
match val {
242241
Ok(const_val) => ConstantKind::from_value(const_val, self.ty()),
243-
Err(ErrorGuaranteed { .. }) => ConstantKind::Ty(tcx.const_error(self.ty())),
242+
Err(guar) => ConstantKind::Ty(tcx.const_error_with_guaranteed(self.ty(), guar)),
244243
}
245244
} else {
246245
ConstantKind::Ty(self)

compiler/rustc_middle/src/ty/subst.rs

+3
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,9 @@ impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for &'tcx ty::List<T> {
506506
}
507507
}
508508

509+
/// Similar to [`super::Binder`] except that it tracks early bound generics, i.e. `struct Foo<T>(T)`
510+
/// needs `T` substituted immediately. This type primarily exists to avoid forgetting to call
511+
/// `subst`.
509512
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
510513
#[derive(Encodable, Decodable, HashStable)]
511514
pub struct EarlyBinder<T>(pub T);

compiler/rustc_mir_build/src/build/expr/as_constant.rs

+25-6
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_middle::mir::interpret::{
99
use rustc_middle::mir::*;
1010
use rustc_middle::thir::*;
1111
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, TyCtxt};
12+
use rustc_span::DUMMY_SP;
1213
use rustc_target::abi::Size;
1314

1415
impl<'a, 'tcx> Builder<'a, 'tcx> {
@@ -26,7 +27,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2627
let literal =
2728
match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
2829
Ok(c) => c,
29-
Err(LitToConstError::Reported) => ConstantKind::Ty(tcx.const_error(ty)),
30+
Err(LitToConstError::Reported(guar)) => {
31+
ConstantKind::Ty(tcx.const_error_with_guaranteed(ty, guar))
32+
}
3033
Err(LitToConstError::TypeError) => {
3134
bug!("encountered type error in `lit_to_mir_constant")
3235
}
@@ -105,7 +108,15 @@ pub(crate) fn lit_to_mir_constant<'tcx>(
105108
let LitToConstInput { lit, ty, neg } = lit_input;
106109
let trunc = |n| {
107110
let param_ty = ty::ParamEnv::reveal_all().and(ty);
108-
let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
111+
let width = tcx
112+
.layout_of(param_ty)
113+
.map_err(|_| {
114+
LitToConstError::Reported(tcx.sess.delay_span_bug(
115+
DUMMY_SP,
116+
format!("couldn't compute width of literal: {:?}", lit_input.lit),
117+
))
118+
})?
119+
.size;
109120
trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
110121
let result = width.truncate(n);
111122
trace!("trunc result: {}", result);
@@ -136,12 +147,20 @@ pub(crate) fn lit_to_mir_constant<'tcx>(
136147
(ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
137148
trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?
138149
}
139-
(ast::LitKind::Float(n, _), ty::Float(fty)) => {
140-
parse_float_into_constval(*n, *fty, neg).ok_or(LitToConstError::Reported)?
141-
}
150+
(ast::LitKind::Float(n, _), ty::Float(fty)) => parse_float_into_constval(*n, *fty, neg)
151+
.ok_or_else(|| {
152+
LitToConstError::Reported(tcx.sess.delay_span_bug(
153+
DUMMY_SP,
154+
format!("couldn't parse float literal: {:?}", lit_input.lit),
155+
))
156+
})?,
142157
(ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
143158
(ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
144-
(ast::LitKind::Err, _) => return Err(LitToConstError::Reported),
159+
(ast::LitKind::Err, _) => {
160+
return Err(LitToConstError::Reported(
161+
tcx.sess.delay_span_bug(DUMMY_SP, "encountered LitKind::Err during mir build"),
162+
));
163+
}
145164
_ => return Err(LitToConstError::TypeError),
146165
};
147166

compiler/rustc_mir_build/src/thir/constant.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use rustc_ast as ast;
22
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
33
use rustc_middle::ty::{self, ParamEnv, ScalarInt, TyCtxt};
4+
use rustc_span::DUMMY_SP;
45

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

1112
let trunc = |n| {
1213
let param_ty = ParamEnv::reveal_all().and(ty);
13-
let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
14+
let width = tcx
15+
.layout_of(param_ty)
16+
.map_err(|_| {
17+
LitToConstError::Reported(tcx.sess.delay_span_bug(
18+
DUMMY_SP,
19+
format!("couldn't compute width of literal: {:?}", lit_input.lit),
20+
))
21+
})?
22+
.size;
1423
trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
1524
let result = width.truncate(n);
1625
trace!("trunc result: {}", result);
@@ -44,7 +53,11 @@ pub(crate) fn lit_to_const<'tcx>(
4453
}
4554
(ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()),
4655
(ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()),
47-
(ast::LitKind::Err, _) => return Err(LitToConstError::Reported),
56+
(ast::LitKind::Err, _) => {
57+
return Err(LitToConstError::Reported(
58+
tcx.sess.delay_span_bug(DUMMY_SP, "encountered LitKind::Err during mir build"),
59+
));
60+
}
4861
_ => return Err(LitToConstError::TypeError),
4962
};
5063

compiler/rustc_mir_build/src/thir/pattern/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
614614
LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
615615
match self.tcx.at(expr.span).lit_to_mir_constant(lit_input) {
616616
Ok(constant) => self.const_to_pat(constant, expr.hir_id, lit.span, false).kind,
617-
Err(LitToConstError::Reported) => PatKind::Wild,
617+
Err(LitToConstError::Reported(_)) => PatKind::Wild,
618618
Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
619619
}
620620
}

compiler/rustc_mir_transform/src/required_consts.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> {
1717
let literal = constant.literal;
1818
match literal {
1919
ConstantKind::Ty(c) => match c.kind() {
20-
ConstKind::Param(_) => {}
20+
ConstKind::Param(_) | ConstKind::Error(_) => {}
2121
_ => bug!("only ConstKind::Param should be encountered here, got {:#?}", c),
2222
},
2323
ConstantKind::Unevaluated(..) => self.required_consts.push(*constant),

compiler/rustc_resolve/src/late.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,7 @@ struct DiagnosticMetadata<'ast> {
527527

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

531532
/// If we are currently in a trait object definition. Used to point at the bounds when
532533
/// encountering a struct or enum.
@@ -3963,10 +3964,15 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
39633964
self.resolve_expr(elem, Some(expr));
39643965
self.visit_expr(idx);
39653966
}
3966-
ExprKind::Assign(..) => {
3967-
let old = self.diagnostic_metadata.in_assignment.replace(expr);
3968-
visit::walk_expr(self, expr);
3969-
self.diagnostic_metadata.in_assignment = old;
3967+
ExprKind::Assign(ref lhs, ref rhs, _) => {
3968+
if !self.diagnostic_metadata.is_assign_rhs {
3969+
self.diagnostic_metadata.in_assignment = Some(expr);
3970+
}
3971+
self.visit_expr(lhs);
3972+
self.diagnostic_metadata.is_assign_rhs = true;
3973+
self.diagnostic_metadata.in_assignment = None;
3974+
self.visit_expr(rhs);
3975+
self.diagnostic_metadata.is_assign_rhs = false;
39703976
}
39713977
_ => {
39723978
visit::walk_expr(self, expr);

compiler/rustc_resolve/src/late/diagnostics.rs

+7-14
Original file line numberDiff line numberDiff line change
@@ -1810,29 +1810,22 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
18101810
false
18111811
}
18121812

1813-
fn let_binding_suggestion(&self, err: &mut Diagnostic, ident_span: Span) -> bool {
1814-
// try to give a suggestion for this pattern: `name = 1`, which is common in other languages
1815-
let mut added_suggestion = false;
1816-
if let Some(Expr { kind: ExprKind::Assign(lhs, _rhs, _), .. }) = self.diagnostic_metadata.in_assignment &&
1813+
// try to give a suggestion for this pattern: `name = blah`, which is common in other languages
1814+
// suggest `let name = blah` to introduce a new binding
1815+
fn let_binding_suggestion(&mut self, err: &mut Diagnostic, ident_span: Span) -> bool {
1816+
if let Some(Expr { kind: ExprKind::Assign(lhs, .. ), .. }) = self.diagnostic_metadata.in_assignment &&
18171817
let ast::ExprKind::Path(None, _) = lhs.kind {
1818-
let sm = self.r.session.source_map();
1819-
let line_span = sm.span_extend_to_line(ident_span);
1820-
let ident_name = sm.span_to_snippet(ident_span).unwrap();
1821-
// HACK(chenyukang): make sure ident_name is at the starting of the line to protect against macros
1822-
if sm
1823-
.span_to_snippet(line_span)
1824-
.map_or(false, |s| s.trim().starts_with(&ident_name))
1825-
{
1818+
if !ident_span.from_expansion() {
18261819
err.span_suggestion_verbose(
18271820
ident_span.shrink_to_lo(),
18281821
"you might have meant to introduce a new binding",
18291822
"let ".to_string(),
18301823
Applicability::MaybeIncorrect,
18311824
);
1832-
added_suggestion = true;
1825+
return true;
18331826
}
18341827
}
1835-
added_suggestion
1828+
false
18361829
}
18371830

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

0 commit comments

Comments
 (0)