Rollup merge of #128762 - fmease:use-more-slice-pats, r=compiler-errors
Use more slice patterns inside the compiler Nothing super noteworthy. Just replacing the common 'fragile' pattern of "length check followed by indexing or unwrap" with slice patterns for legibility and 'robustness'. r? ghost
This commit is contained in:
commit
32e0fe129d
40 changed files with 191 additions and 221 deletions
|
@ -585,7 +585,9 @@ impl Pat {
|
||||||
}
|
}
|
||||||
// A slice/array pattern `[P]` can be reparsed as `[T]`, an unsized array,
|
// A slice/array pattern `[P]` can be reparsed as `[T]`, an unsized array,
|
||||||
// when `P` can be reparsed as a type `T`.
|
// when `P` can be reparsed as a type `T`.
|
||||||
PatKind::Slice(pats) if pats.len() == 1 => pats[0].to_ty().map(TyKind::Slice)?,
|
PatKind::Slice(pats) if let [pat] = pats.as_slice() => {
|
||||||
|
pat.to_ty().map(TyKind::Slice)?
|
||||||
|
}
|
||||||
// A tuple pattern `(P0, .., Pn)` can be reparsed as `(T0, .., Tn)`
|
// A tuple pattern `(P0, .., Pn)` can be reparsed as `(T0, .., Tn)`
|
||||||
// assuming `T0` to `Tn` are all syntactically valid as types.
|
// assuming `T0` to `Tn` are all syntactically valid as types.
|
||||||
PatKind::Tuple(pats) => {
|
PatKind::Tuple(pats) => {
|
||||||
|
@ -1187,8 +1189,8 @@ impl Expr {
|
||||||
/// Does not ensure that the path resolves to a const param, the caller should check this.
|
/// Does not ensure that the path resolves to a const param, the caller should check this.
|
||||||
pub fn is_potential_trivial_const_arg(&self) -> bool {
|
pub fn is_potential_trivial_const_arg(&self) -> bool {
|
||||||
let this = if let ExprKind::Block(block, None) = &self.kind
|
let this = if let ExprKind::Block(block, None) = &self.kind
|
||||||
&& block.stmts.len() == 1
|
&& let [stmt] = block.stmts.as_slice()
|
||||||
&& let StmtKind::Expr(expr) = &block.stmts[0].kind
|
&& let StmtKind::Expr(expr) = &stmt.kind
|
||||||
{
|
{
|
||||||
expr
|
expr
|
||||||
} else {
|
} else {
|
||||||
|
@ -1248,7 +1250,9 @@ impl Expr {
|
||||||
expr.to_ty().map(|ty| TyKind::Array(ty, expr_len.clone()))?
|
expr.to_ty().map(|ty| TyKind::Array(ty, expr_len.clone()))?
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprKind::Array(exprs) if exprs.len() == 1 => exprs[0].to_ty().map(TyKind::Slice)?,
|
ExprKind::Array(exprs) if let [expr] = exprs.as_slice() => {
|
||||||
|
expr.to_ty().map(TyKind::Slice)?
|
||||||
|
}
|
||||||
|
|
||||||
ExprKind::Tup(exprs) => {
|
ExprKind::Tup(exprs) => {
|
||||||
let tys = exprs.iter().map(|expr| expr.to_ty()).collect::<Option<ThinVec<_>>>()?;
|
let tys = exprs.iter().map(|expr| expr.to_ty()).collect::<Option<ThinVec<_>>>()?;
|
||||||
|
|
|
@ -275,8 +275,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
// FIXME(fn_delegation): Alternatives for target expression lowering:
|
// FIXME(fn_delegation): Alternatives for target expression lowering:
|
||||||
// https://github.com/rust-lang/rfcs/pull/3530#issuecomment-2197170600.
|
// https://github.com/rust-lang/rfcs/pull/3530#issuecomment-2197170600.
|
||||||
fn lower_target_expr(&mut self, block: &Block) -> hir::Expr<'hir> {
|
fn lower_target_expr(&mut self, block: &Block) -> hir::Expr<'hir> {
|
||||||
if block.stmts.len() == 1
|
if let [stmt] = block.stmts.as_slice()
|
||||||
&& let StmtKind::Expr(expr) = &block.stmts[0].kind
|
&& let StmtKind::Expr(expr) = &stmt.kind
|
||||||
{
|
{
|
||||||
return self.lower_expr_mut(expr);
|
return self.lower_expr_mut(expr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -502,8 +502,8 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||||
if !self.is_beginning_of_line() {
|
if !self.is_beginning_of_line() {
|
||||||
self.word(" ");
|
self.word(" ");
|
||||||
}
|
}
|
||||||
if cmnt.lines.len() == 1 {
|
if let [line] = cmnt.lines.as_slice() {
|
||||||
self.word(cmnt.lines[0].clone());
|
self.word(line.clone());
|
||||||
self.hardbreak()
|
self.hardbreak()
|
||||||
} else {
|
} else {
|
||||||
self.visual_align();
|
self.visual_align();
|
||||||
|
|
|
@ -783,8 +783,8 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
if items.is_empty() {
|
if items.is_empty() {
|
||||||
self.word("{}");
|
self.word("{}");
|
||||||
} else if items.len() == 1 {
|
} else if let [(item, _)] = items.as_slice() {
|
||||||
self.print_use_tree(&items[0].0);
|
self.print_use_tree(item);
|
||||||
} else {
|
} else {
|
||||||
self.cbox(INDENT_UNIT);
|
self.cbox(INDENT_UNIT);
|
||||||
self.word("{");
|
self.word("{");
|
||||||
|
|
|
@ -665,12 +665,12 @@ pub fn eval_condition(
|
||||||
res & eval_condition(mi.meta_item().unwrap(), sess, features, eval)
|
res & eval_condition(mi.meta_item().unwrap(), sess, features, eval)
|
||||||
}),
|
}),
|
||||||
sym::not => {
|
sym::not => {
|
||||||
if mis.len() != 1 {
|
let [mi] = mis.as_slice() else {
|
||||||
dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
|
dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
|
||||||
return false;
|
return false;
|
||||||
}
|
};
|
||||||
|
|
||||||
!eval_condition(mis[0].meta_item().unwrap(), sess, features, eval)
|
!eval_condition(mi.meta_item().unwrap(), sess, features, eval)
|
||||||
}
|
}
|
||||||
sym::target => {
|
sym::target => {
|
||||||
if let Some(features) = features
|
if let Some(features) = features
|
||||||
|
@ -1051,10 +1051,10 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||||
MetaItemKind::List(nested_items) => {
|
MetaItemKind::List(nested_items) => {
|
||||||
if meta_item.has_name(sym::align) {
|
if meta_item.has_name(sym::align) {
|
||||||
recognised = true;
|
recognised = true;
|
||||||
if nested_items.len() == 1 {
|
if let [nested_item] = nested_items.as_slice() {
|
||||||
sess.dcx().emit_err(
|
sess.dcx().emit_err(
|
||||||
session_diagnostics::IncorrectReprFormatExpectInteger {
|
session_diagnostics::IncorrectReprFormatExpectInteger {
|
||||||
span: nested_items[0].span(),
|
span: nested_item.span(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1066,10 +1066,10 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
||||||
}
|
}
|
||||||
} else if meta_item.has_name(sym::packed) {
|
} else if meta_item.has_name(sym::packed) {
|
||||||
recognised = true;
|
recognised = true;
|
||||||
if nested_items.len() == 1 {
|
if let [nested_item] = nested_items.as_slice() {
|
||||||
sess.dcx().emit_err(
|
sess.dcx().emit_err(
|
||||||
session_diagnostics::IncorrectReprFormatPackedExpectInteger {
|
session_diagnostics::IncorrectReprFormatPackedExpectInteger {
|
||||||
span: nested_items[0].span(),
|
span: nested_item.span(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -206,8 +206,8 @@ impl OutlivesSuggestionBuilder {
|
||||||
|
|
||||||
// If there is exactly one suggestable constraints, then just suggest it. Otherwise, emit a
|
// If there is exactly one suggestable constraints, then just suggest it. Otherwise, emit a
|
||||||
// list of diagnostics.
|
// list of diagnostics.
|
||||||
let mut diag = if suggested.len() == 1 {
|
let mut diag = if let [constraint] = suggested.as_slice() {
|
||||||
mbcx.dcx().struct_help(match suggested.last().unwrap() {
|
mbcx.dcx().struct_help(match constraint {
|
||||||
SuggestedConstraint::Outlives(a, bs) => {
|
SuggestedConstraint::Outlives(a, bs) => {
|
||||||
let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect();
|
let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect();
|
||||||
format!("add bound `{a}: {}`", bs.join(" + "))
|
format!("add bound `{a}: {}`", bs.join(" + "))
|
||||||
|
|
|
@ -745,10 +745,9 @@ fn expand_preparsed_asm(
|
||||||
unused_operands.push((args.operands[idx].1, msg));
|
unused_operands.push((args.operands[idx].1, msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match unused_operands.len() {
|
match unused_operands[..] {
|
||||||
0 => {}
|
[] => {}
|
||||||
1 => {
|
[(sp, msg)] => {
|
||||||
let (sp, msg) = unused_operands.into_iter().next().unwrap();
|
|
||||||
ecx.dcx()
|
ecx.dcx()
|
||||||
.struct_span_err(sp, msg)
|
.struct_span_err(sp, msg)
|
||||||
.with_span_label(sp, msg)
|
.with_span_label(sp, msg)
|
||||||
|
|
|
@ -378,8 +378,8 @@ impl BlockOrExpr {
|
||||||
None => cx.expr_block(cx.block(span, ThinVec::new())),
|
None => cx.expr_block(cx.block(span, ThinVec::new())),
|
||||||
Some(expr) => expr,
|
Some(expr) => expr,
|
||||||
}
|
}
|
||||||
} else if self.0.len() == 1
|
} else if let [stmt] = self.0.as_slice()
|
||||||
&& let ast::StmtKind::Expr(expr) = &self.0[0].kind
|
&& let ast::StmtKind::Expr(expr) = &stmt.kind
|
||||||
&& self.1.is_none()
|
&& self.1.is_none()
|
||||||
{
|
{
|
||||||
// There's only a single statement expression. Pull it out.
|
// There's only a single statement expression. Pull it out.
|
||||||
|
@ -1273,7 +1273,7 @@ impl<'a> MethodDef<'a> {
|
||||||
}
|
}
|
||||||
FieldlessVariantsStrategy::Default => (),
|
FieldlessVariantsStrategy::Default => (),
|
||||||
}
|
}
|
||||||
} else if variants.len() == 1 {
|
} else if let [variant] = variants.as_slice() {
|
||||||
// If there is a single variant, we don't need an operation on
|
// If there is a single variant, we don't need an operation on
|
||||||
// the discriminant(s). Just use the most degenerate result.
|
// the discriminant(s). Just use the most degenerate result.
|
||||||
return self.call_substructure_method(
|
return self.call_substructure_method(
|
||||||
|
@ -1281,7 +1281,7 @@ impl<'a> MethodDef<'a> {
|
||||||
trait_,
|
trait_,
|
||||||
type_ident,
|
type_ident,
|
||||||
nonselflike_args,
|
nonselflike_args,
|
||||||
&EnumMatching(0, &variants[0], Vec::new()),
|
&EnumMatching(0, variant, Vec::new()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,8 +180,8 @@ fn make_format_args(
|
||||||
Ok((mut err, suggested)) => {
|
Ok((mut err, suggested)) => {
|
||||||
if !suggested {
|
if !suggested {
|
||||||
if let ExprKind::Block(block, None) = &efmt.kind
|
if let ExprKind::Block(block, None) = &efmt.kind
|
||||||
&& block.stmts.len() == 1
|
&& let [stmt] = block.stmts.as_slice()
|
||||||
&& let StmtKind::Expr(expr) = &block.stmts[0].kind
|
&& let StmtKind::Expr(expr) = &stmt.kind
|
||||||
&& let ExprKind::Path(None, path) = &expr.kind
|
&& let ExprKind::Path(None, path) = &expr.kind
|
||||||
&& path.is_potential_trivial_const_arg()
|
&& path.is_potential_trivial_const_arg()
|
||||||
{
|
{
|
||||||
|
@ -196,8 +196,8 @@ fn make_format_args(
|
||||||
} else {
|
} else {
|
||||||
let sugg_fmt = match args.explicit_args().len() {
|
let sugg_fmt = match args.explicit_args().len() {
|
||||||
0 => "{}".to_string(),
|
0 => "{}".to_string(),
|
||||||
_ => {
|
count => {
|
||||||
format!("{}{{}}", "{} ".repeat(args.explicit_args().len()))
|
format!("{}{{}}", "{} ".repeat(count))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
|
|
|
@ -203,9 +203,9 @@ impl<T: Eq + Hash + Copy> TransitiveRelation<T> {
|
||||||
/// exists). See `postdom_upper_bound` for details.
|
/// exists). See `postdom_upper_bound` for details.
|
||||||
pub fn mutual_immediate_postdominator(&self, mut mubs: Vec<T>) -> Option<T> {
|
pub fn mutual_immediate_postdominator(&self, mut mubs: Vec<T>) -> Option<T> {
|
||||||
loop {
|
loop {
|
||||||
match mubs.len() {
|
match mubs[..] {
|
||||||
0 => return None,
|
[] => return None,
|
||||||
1 => return Some(mubs[0]),
|
[mub] => return Some(mub),
|
||||||
_ => {
|
_ => {
|
||||||
let m = mubs.pop().unwrap();
|
let m = mubs.pop().unwrap();
|
||||||
let n = mubs.pop().unwrap();
|
let n = mubs.pop().unwrap();
|
||||||
|
|
|
@ -338,12 +338,11 @@ fn run_compiler(
|
||||||
config.input = input;
|
config.input = input;
|
||||||
true // has input: normal compilation
|
true // has input: normal compilation
|
||||||
}
|
}
|
||||||
Ok(None) => match matches.free.len() {
|
Ok(None) => match matches.free.as_slice() {
|
||||||
0 => false, // no input: we will exit early
|
[] => false, // no input: we will exit early
|
||||||
1 => panic!("make_input should have provided valid inputs"),
|
[_] => panic!("make_input should have provided valid inputs"),
|
||||||
_ => default_early_dcx.early_fatal(format!(
|
[fst, snd, ..] => default_early_dcx.early_fatal(format!(
|
||||||
"multiple input filenames provided (first two filenames are `{}` and `{}`)",
|
"multiple input filenames provided (first two filenames are `{fst}` and `{snd}`)"
|
||||||
matches.free[0], matches.free[1],
|
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -491,34 +490,30 @@ fn make_input(
|
||||||
early_dcx: &EarlyDiagCtxt,
|
early_dcx: &EarlyDiagCtxt,
|
||||||
free_matches: &[String],
|
free_matches: &[String],
|
||||||
) -> Result<Option<Input>, ErrorGuaranteed> {
|
) -> Result<Option<Input>, ErrorGuaranteed> {
|
||||||
if free_matches.len() == 1 {
|
let [ifile] = free_matches else { return Ok(None) };
|
||||||
let ifile = &free_matches[0];
|
if ifile == "-" {
|
||||||
if ifile == "-" {
|
let mut src = String::new();
|
||||||
let mut src = String::new();
|
if io::stdin().read_to_string(&mut src).is_err() {
|
||||||
if io::stdin().read_to_string(&mut src).is_err() {
|
// Immediately stop compilation if there was an issue reading
|
||||||
// Immediately stop compilation if there was an issue reading
|
// the input (for example if the input stream is not UTF-8).
|
||||||
// the input (for example if the input stream is not UTF-8).
|
let reported =
|
||||||
let reported = early_dcx
|
early_dcx.early_err("couldn't read from stdin, as it did not contain valid UTF-8");
|
||||||
.early_err("couldn't read from stdin, as it did not contain valid UTF-8");
|
return Err(reported);
|
||||||
return Err(reported);
|
}
|
||||||
}
|
if let Ok(path) = env::var("UNSTABLE_RUSTDOC_TEST_PATH") {
|
||||||
if let Ok(path) = env::var("UNSTABLE_RUSTDOC_TEST_PATH") {
|
let line = env::var("UNSTABLE_RUSTDOC_TEST_LINE").expect(
|
||||||
let line = env::var("UNSTABLE_RUSTDOC_TEST_LINE").expect(
|
"when UNSTABLE_RUSTDOC_TEST_PATH is set \
|
||||||
"when UNSTABLE_RUSTDOC_TEST_PATH is set \
|
|
||||||
UNSTABLE_RUSTDOC_TEST_LINE also needs to be set",
|
UNSTABLE_RUSTDOC_TEST_LINE also needs to be set",
|
||||||
);
|
);
|
||||||
let line = isize::from_str_radix(&line, 10)
|
let line = isize::from_str_radix(&line, 10)
|
||||||
.expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number");
|
.expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number");
|
||||||
let file_name = FileName::doc_test_source_code(PathBuf::from(path), line);
|
let file_name = FileName::doc_test_source_code(PathBuf::from(path), line);
|
||||||
Ok(Some(Input::Str { name: file_name, input: src }))
|
Ok(Some(Input::Str { name: file_name, input: src }))
|
||||||
} else {
|
|
||||||
Ok(Some(Input::Str { name: FileName::anon_source_code(&src), input: src }))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Ok(Some(Input::File(PathBuf::from(ifile))))
|
Ok(Some(Input::Str { name: FileName::anon_source_code(&src), input: src }))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(Some(Input::File(PathBuf::from(ifile))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -226,17 +226,17 @@ pub trait Emitter: Translate {
|
||||||
) {
|
) {
|
||||||
if let Some((sugg, rest)) = suggestions.split_first() {
|
if let Some((sugg, rest)) = suggestions.split_first() {
|
||||||
let msg = self.translate_message(&sugg.msg, fluent_args).map_err(Report::new).unwrap();
|
let msg = self.translate_message(&sugg.msg, fluent_args).map_err(Report::new).unwrap();
|
||||||
if rest.is_empty() &&
|
if rest.is_empty()
|
||||||
// ^ if there is only one suggestion
|
// ^ if there is only one suggestion
|
||||||
// don't display multi-suggestions as labels
|
// don't display multi-suggestions as labels
|
||||||
sugg.substitutions.len() == 1 &&
|
&& let [substitution] = sugg.substitutions.as_slice()
|
||||||
// don't display multipart suggestions as labels
|
// don't display multipart suggestions as labels
|
||||||
sugg.substitutions[0].parts.len() == 1 &&
|
&& let [part] = substitution.parts.as_slice()
|
||||||
// don't display long messages as labels
|
// don't display long messages as labels
|
||||||
msg.split_whitespace().count() < 10 &&
|
&& msg.split_whitespace().count() < 10
|
||||||
// don't display multiline suggestions as labels
|
// don't display multiline suggestions as labels
|
||||||
!sugg.substitutions[0].parts[0].snippet.contains('\n') &&
|
&& !part.snippet.contains('\n')
|
||||||
![
|
&& ![
|
||||||
// when this style is set we want the suggestion to be a message, not inline
|
// when this style is set we want the suggestion to be a message, not inline
|
||||||
SuggestionStyle::HideCodeAlways,
|
SuggestionStyle::HideCodeAlways,
|
||||||
// trivial suggestion for tooling's sake, never shown
|
// trivial suggestion for tooling's sake, never shown
|
||||||
|
@ -245,8 +245,8 @@ pub trait Emitter: Translate {
|
||||||
SuggestionStyle::ShowAlways,
|
SuggestionStyle::ShowAlways,
|
||||||
].contains(&sugg.style)
|
].contains(&sugg.style)
|
||||||
{
|
{
|
||||||
let substitution = &sugg.substitutions[0].parts[0].snippet.trim();
|
let snippet = part.snippet.trim();
|
||||||
let msg = if substitution.is_empty() || sugg.style.hide_inline() {
|
let msg = if snippet.is_empty() || sugg.style.hide_inline() {
|
||||||
// This substitution is only removal OR we explicitly don't want to show the
|
// This substitution is only removal OR we explicitly don't want to show the
|
||||||
// code inline (`hide_inline`). Therefore, we don't show the substitution.
|
// code inline (`hide_inline`). Therefore, we don't show the substitution.
|
||||||
format!("help: {msg}")
|
format!("help: {msg}")
|
||||||
|
@ -255,19 +255,18 @@ pub trait Emitter: Translate {
|
||||||
format!(
|
format!(
|
||||||
"help: {}{}: `{}`",
|
"help: {}{}: `{}`",
|
||||||
msg,
|
msg,
|
||||||
if self.source_map().is_some_and(|sm| is_case_difference(
|
if self
|
||||||
sm,
|
.source_map()
|
||||||
substitution,
|
.is_some_and(|sm| is_case_difference(sm, snippet, part.span,))
|
||||||
sugg.substitutions[0].parts[0].span,
|
{
|
||||||
)) {
|
|
||||||
" (notice the capitalization)"
|
" (notice the capitalization)"
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
},
|
},
|
||||||
substitution,
|
snippet,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
primary_span.push_span_label(sugg.substitutions[0].parts[0].span, msg);
|
primary_span.push_span_label(part.span, msg);
|
||||||
|
|
||||||
// We return only the modified primary_span
|
// We return only the modified primary_span
|
||||||
suggestions.clear();
|
suggestions.clear();
|
||||||
|
|
|
@ -2024,11 +2024,11 @@ pub fn a_or_an(s: &str) -> &'static str {
|
||||||
///
|
///
|
||||||
/// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c"
|
/// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c"
|
||||||
pub fn display_list_with_comma_and<T: std::fmt::Display>(v: &[T]) -> String {
|
pub fn display_list_with_comma_and<T: std::fmt::Display>(v: &[T]) -> String {
|
||||||
match v.len() {
|
match v {
|
||||||
0 => "".to_string(),
|
[] => "".to_string(),
|
||||||
1 => v[0].to_string(),
|
[a] => a.to_string(),
|
||||||
2 => format!("{} and {}", v[0], v[1]),
|
[a, b] => format!("{a} and {b}"),
|
||||||
_ => format!("{}, {}", v[0], display_list_with_comma_and(&v[1..])),
|
[a, v @ ..] => format!("{a}, {}", display_list_with_comma_and(v)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1306,12 +1306,12 @@ pub fn parse_macro_name_and_helper_attrs(
|
||||||
// that it's of the form `#[proc_macro_derive(Foo)]` or
|
// that it's of the form `#[proc_macro_derive(Foo)]` or
|
||||||
// `#[proc_macro_derive(Foo, attributes(A, ..))]`
|
// `#[proc_macro_derive(Foo, attributes(A, ..))]`
|
||||||
let list = attr.meta_item_list()?;
|
let list = attr.meta_item_list()?;
|
||||||
if list.len() != 1 && list.len() != 2 {
|
let ([trait_attr] | [trait_attr, _]) = list.as_slice() else {
|
||||||
dcx.emit_err(errors::AttrNoArguments { span: attr.span });
|
dcx.emit_err(errors::AttrNoArguments { span: attr.span });
|
||||||
return None;
|
return None;
|
||||||
}
|
};
|
||||||
let Some(trait_attr) = list[0].meta_item() else {
|
let Some(trait_attr) = trait_attr.meta_item() else {
|
||||||
dcx.emit_err(errors::NotAMetaItem { span: list[0].span() });
|
dcx.emit_err(errors::NotAMetaItem { span: trait_attr.span() });
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
let trait_ident = match trait_attr.ident() {
|
let trait_ident = match trait_attr.ident() {
|
||||||
|
|
|
@ -2743,15 +2743,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
} else if let ty::RawPtr(ptr_ty, _) = expr_t.kind()
|
} else if let ty::RawPtr(ptr_ty, _) = expr_t.kind()
|
||||||
&& let ty::Adt(adt_def, _) = ptr_ty.kind()
|
&& let ty::Adt(adt_def, _) = ptr_ty.kind()
|
||||||
&& let ExprKind::Field(base_expr, _) = expr.kind
|
&& let ExprKind::Field(base_expr, _) = expr.kind
|
||||||
&& adt_def.variants().len() == 1
|
&& let [variant] = &adt_def.variants().raw
|
||||||
&& adt_def
|
&& variant.fields.iter().any(|f| f.ident(self.tcx) == field)
|
||||||
.variants()
|
|
||||||
.iter()
|
|
||||||
.next()
|
|
||||||
.unwrap()
|
|
||||||
.fields
|
|
||||||
.iter()
|
|
||||||
.any(|f| f.ident(self.tcx) == field)
|
|
||||||
{
|
{
|
||||||
err.multipart_suggestion(
|
err.multipart_suggestion(
|
||||||
"to access the field, dereference first",
|
"to access the field, dereference first",
|
||||||
|
|
|
@ -654,17 +654,17 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
||||||
traits::upcast_choices(self.tcx, source_trait_ref, target_trait_def_id);
|
traits::upcast_choices(self.tcx, source_trait_ref, target_trait_def_id);
|
||||||
|
|
||||||
// must be exactly one trait ref or we'd get an ambig error etc
|
// must be exactly one trait ref or we'd get an ambig error etc
|
||||||
if upcast_trait_refs.len() != 1 {
|
let [upcast_trait_ref] = upcast_trait_refs.as_slice() else {
|
||||||
span_bug!(
|
span_bug!(
|
||||||
self.span,
|
self.span,
|
||||||
"cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`",
|
"cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`",
|
||||||
source_trait_ref,
|
source_trait_ref,
|
||||||
target_trait_def_id,
|
target_trait_def_id,
|
||||||
upcast_trait_refs
|
upcast_trait_refs
|
||||||
);
|
)
|
||||||
}
|
};
|
||||||
|
|
||||||
upcast_trait_refs.into_iter().next().unwrap()
|
*upcast_trait_ref
|
||||||
}
|
}
|
||||||
|
|
||||||
fn instantiate_binder_with_fresh_vars<T>(&self, value: ty::Binder<'tcx, T>) -> T
|
fn instantiate_binder_with_fresh_vars<T>(&self, value: ty::Binder<'tcx, T>) -> T
|
||||||
|
|
|
@ -321,19 +321,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
let suggest_for_privacy =
|
let suggest_for_privacy =
|
||||||
|err: &mut Diag<'_>, mut msg: String, sugg: Vec<String>| {
|
|err: &mut Diag<'_>, mut msg: String, suggs: Vec<String>| {
|
||||||
if sugg.len() == 1 {
|
if let [sugg] = suggs.as_slice() {
|
||||||
let msg = format!("\
|
err.help(format!("\
|
||||||
trait `{}` provides `{item_name}` is implemented but not reachable",
|
trait `{}` provides `{item_name}` is implemented but not reachable",
|
||||||
sugg[0].trim()
|
sugg.trim(),
|
||||||
);
|
));
|
||||||
err.help(msg);
|
|
||||||
} else {
|
} else {
|
||||||
msg += &format!(" but {} not reachable", pluralize!("is", sugg.len()));
|
msg += &format!(" but {} not reachable", pluralize!("is", suggs.len()));
|
||||||
err.span_suggestions(
|
err.span_suggestions(
|
||||||
span,
|
span,
|
||||||
msg,
|
msg,
|
||||||
sugg,
|
suggs,
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2988,11 +2987,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if local_spans.primary_span().is_some() {
|
if local_spans.primary_span().is_some() {
|
||||||
let msg = if local_preds.len() == 1 {
|
let msg = if let [local_pred] = local_preds.as_slice() {
|
||||||
format!(
|
format!(
|
||||||
"an implementation of `{}` might be missing for `{}`",
|
"an implementation of `{}` might be missing for `{}`",
|
||||||
local_preds[0].trait_ref.print_trait_sugared(),
|
local_pred.trait_ref.print_trait_sugared(),
|
||||||
local_preds[0].self_ty()
|
local_pred.self_ty()
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
format!(
|
format!(
|
||||||
|
@ -3034,11 +3033,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if foreign_spans.primary_span().is_some() {
|
if foreign_spans.primary_span().is_some() {
|
||||||
let msg = if foreign_preds.len() == 1 {
|
let msg = if let [foreign_pred] = foreign_preds.as_slice() {
|
||||||
format!(
|
format!(
|
||||||
"the foreign item type `{}` doesn't implement `{}`",
|
"the foreign item type `{}` doesn't implement `{}`",
|
||||||
foreign_preds[0].self_ty(),
|
foreign_pred.self_ty(),
|
||||||
foreign_preds[0].trait_ref.print_trait_sugared()
|
foreign_pred.trait_ref.print_trait_sugared()
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
format!(
|
format!(
|
||||||
|
@ -3388,26 +3387,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
|
|
||||||
self.suggest_use_candidates(candidates, |accessible_sugg, inaccessible_sugg, span| {
|
self.suggest_use_candidates(candidates, |accessible_sugg, inaccessible_sugg, span| {
|
||||||
let suggest_for_access = |err: &mut Diag<'_>, mut msg: String, sugg: Vec<_>| {
|
let suggest_for_access = |err: &mut Diag<'_>, mut msg: String, suggs: Vec<_>| {
|
||||||
msg += &format!(
|
msg += &format!(
|
||||||
"; perhaps you want to import {one_of}",
|
"; perhaps you want to import {one_of}",
|
||||||
one_of = if sugg.len() == 1 { "it" } else { "one of them" },
|
one_of = if suggs.len() == 1 { "it" } else { "one of them" },
|
||||||
);
|
);
|
||||||
err.span_suggestions(span, msg, sugg, Applicability::MaybeIncorrect);
|
err.span_suggestions(span, msg, suggs, Applicability::MaybeIncorrect);
|
||||||
};
|
};
|
||||||
let suggest_for_privacy = |err: &mut Diag<'_>, sugg: Vec<String>| {
|
let suggest_for_privacy = |err: &mut Diag<'_>, suggs: Vec<String>| {
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"{this_trait_is} implemented but not reachable",
|
"{this_trait_is} implemented but not reachable",
|
||||||
this_trait_is = if sugg.len() == 1 {
|
this_trait_is = if let [sugg] = suggs.as_slice() {
|
||||||
format!("trait `{}` which provides `{item_name}` is", sugg[0].trim())
|
format!("trait `{}` which provides `{item_name}` is", sugg.trim())
|
||||||
} else {
|
} else {
|
||||||
format!("the following traits which provide `{item_name}` are")
|
format!("the following traits which provide `{item_name}` are")
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if sugg.len() == 1 {
|
if suggs.len() == 1 {
|
||||||
err.help(msg);
|
err.help(msg);
|
||||||
} else {
|
} else {
|
||||||
err.span_suggestions(span, msg, sugg, Applicability::MaybeIncorrect);
|
err.span_suggestions(span, msg, suggs, Applicability::MaybeIncorrect);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if accessible_sugg.is_empty() {
|
if accessible_sugg.is_empty() {
|
||||||
|
|
|
@ -527,11 +527,11 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
|
||||||
// Lint for constants that look like binding identifiers (#7526)
|
// Lint for constants that look like binding identifiers (#7526)
|
||||||
if let PatKind::Path(hir::QPath::Resolved(None, path)) = p.kind {
|
if let PatKind::Path(hir::QPath::Resolved(None, path)) = p.kind {
|
||||||
if let Res::Def(DefKind::Const, _) = path.res {
|
if let Res::Def(DefKind::Const, _) = path.res {
|
||||||
if path.segments.len() == 1 {
|
if let [segment] = path.segments {
|
||||||
NonUpperCaseGlobals::check_upper_case(
|
NonUpperCaseGlobals::check_upper_case(
|
||||||
cx,
|
cx,
|
||||||
"constant in pattern",
|
"constant in pattern",
|
||||||
&path.segments[0].ident,
|
&segment.ident,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,15 +211,12 @@ fn lint_overflowing_range_endpoint<'tcx>(
|
||||||
if !is_range_literal(struct_expr) {
|
if !is_range_literal(struct_expr) {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let ExprKind::Struct(_, eps, _) = &struct_expr.kind else { return false };
|
let ExprKind::Struct(_, [start, end], _) = &struct_expr.kind else { return false };
|
||||||
if eps.len() != 2 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can suggest using an inclusive range
|
// We can suggest using an inclusive range
|
||||||
// (`..=`) instead only if it is the `end` that is
|
// (`..=`) instead only if it is the `end` that is
|
||||||
// overflowing and only by 1.
|
// overflowing and only by 1.
|
||||||
if !(eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max) {
|
if !(end.expr.hir_id == expr.hir_id && lit_val - 1 == max) {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -232,7 +229,7 @@ fn lint_overflowing_range_endpoint<'tcx>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let sub_sugg = if expr.span.lo() == lit_span.lo() {
|
let sub_sugg = if expr.span.lo() == lit_span.lo() {
|
||||||
let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) else { return false };
|
let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else { return false };
|
||||||
UseInclusiveRange::WithoutParen {
|
UseInclusiveRange::WithoutParen {
|
||||||
sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()),
|
sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()),
|
||||||
start,
|
start,
|
||||||
|
|
|
@ -808,7 +808,7 @@ trait UnusedDelimLint {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let spans = match value.kind {
|
let spans = match value.kind {
|
||||||
ast::ExprKind::Block(ref block, None) if block.stmts.len() == 1 => block.stmts[0]
|
ast::ExprKind::Block(ref block, None) if let [stmt] = block.stmts.as_slice() => stmt
|
||||||
.span
|
.span
|
||||||
.find_ancestor_inside(value.span)
|
.find_ancestor_inside(value.span)
|
||||||
.map(|span| (value.span.with_hi(span.lo()), value.span.with_lo(span.hi()))),
|
.map(|span| (value.span.with_hi(span.lo()), value.span.with_lo(span.hi()))),
|
||||||
|
@ -1544,14 +1544,12 @@ impl UnusedImportBraces {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger the lint only if there is one nested item
|
// Trigger the lint only if there is one nested item
|
||||||
if items.len() != 1 {
|
let [(tree, _)] = items.as_slice() else { return };
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trigger the lint if the nested item is a non-self single item
|
// Trigger the lint if the nested item is a non-self single item
|
||||||
let node_name = match items[0].0.kind {
|
let node_name = match tree.kind {
|
||||||
ast::UseTreeKind::Simple(rename) => {
|
ast::UseTreeKind::Simple(rename) => {
|
||||||
let orig_ident = items[0].0.prefix.segments.last().unwrap().ident;
|
let orig_ident = tree.prefix.segments.last().unwrap().ident;
|
||||||
if orig_ident.name == kw::SelfLower {
|
if orig_ident.name == kw::SelfLower {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -483,9 +483,11 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
||||||
// Check if the match is exhaustive.
|
// Check if the match is exhaustive.
|
||||||
let witnesses = report.non_exhaustiveness_witnesses;
|
let witnesses = report.non_exhaustiveness_witnesses;
|
||||||
if !witnesses.is_empty() {
|
if !witnesses.is_empty() {
|
||||||
if source == hir::MatchSource::ForLoopDesugar && arms.len() == 2 {
|
if source == hir::MatchSource::ForLoopDesugar
|
||||||
|
&& let [_, snd_arm] = *arms
|
||||||
|
{
|
||||||
// the for loop pattern is not irrefutable
|
// the for loop pattern is not irrefutable
|
||||||
let pat = &self.thir[arms[1]].pattern;
|
let pat = &self.thir[snd_arm].pattern;
|
||||||
// `pat` should be `Some(<pat_field>)` from a desugared for loop.
|
// `pat` should be `Some(<pat_field>)` from a desugared for loop.
|
||||||
debug_assert_eq!(pat.span.desugaring_kind(), Some(DesugaringKind::ForLoop));
|
debug_assert_eq!(pat.span.desugaring_kind(), Some(DesugaringKind::ForLoop));
|
||||||
let PatKind::Variant { ref subpatterns, .. } = pat.kind else { bug!() };
|
let PatKind::Variant { ref subpatterns, .. } = pat.kind else { bug!() };
|
||||||
|
|
|
@ -350,8 +350,8 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera
|
||||||
// An inline asm terminator can normally be chained, except when it diverges or uses asm
|
// An inline asm terminator can normally be chained, except when it diverges or uses asm
|
||||||
// goto.
|
// goto.
|
||||||
InlineAsm { ref targets, .. } => {
|
InlineAsm { ref targets, .. } => {
|
||||||
if targets.len() == 1 {
|
if let [target] = targets[..] {
|
||||||
CoverageSuccessors::Chainable(targets[0])
|
CoverageSuccessors::Chainable(target)
|
||||||
} else {
|
} else {
|
||||||
CoverageSuccessors::NotChainable(targets)
|
CoverageSuccessors::NotChainable(targets)
|
||||||
}
|
}
|
||||||
|
|
|
@ -309,11 +309,11 @@ fn verify_candidate_branch<'tcx>(
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// In order for the optimization to be correct, the branch must...
|
// In order for the optimization to be correct, the branch must...
|
||||||
// ...have exactly one statement
|
// ...have exactly one statement
|
||||||
if branch.statements.len() != 1 {
|
let [statement] = branch.statements.as_slice() else {
|
||||||
return false;
|
return false;
|
||||||
}
|
};
|
||||||
// ...assign the discriminant of `place` in that statement
|
// ...assign the discriminant of `place` in that statement
|
||||||
let StatementKind::Assign(boxed) = &branch.statements[0].kind else { return false };
|
let StatementKind::Assign(boxed) = &statement.kind else { return false };
|
||||||
let (discr_place, Rvalue::Discriminant(from_place)) = &**boxed else { return false };
|
let (discr_place, Rvalue::Discriminant(from_place)) = &**boxed else { return false };
|
||||||
if *from_place != place {
|
if *from_place != place {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -264,9 +264,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// It's definitely not a clone if there are multiple arguments
|
// It's definitely not a clone if there are multiple arguments
|
||||||
if args.len() != 1 {
|
let [arg] = &args[..] else { return };
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some(destination_block) = *target else { return };
|
let Some(destination_block) = *target else { return };
|
||||||
|
|
||||||
|
@ -280,7 +278,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
|
||||||
|
|
||||||
// These types are easily available from locals, so check that before
|
// These types are easily available from locals, so check that before
|
||||||
// doing DefId lookups to figure out what we're actually calling.
|
// doing DefId lookups to figure out what we're actually calling.
|
||||||
let arg_ty = args[0].node.ty(self.local_decls, self.tcx);
|
let arg_ty = arg.node.ty(self.local_decls, self.tcx);
|
||||||
|
|
||||||
let ty::Ref(_region, inner_ty, Mutability::Not) = *arg_ty.kind() else { return };
|
let ty::Ref(_region, inner_ty, Mutability::Not) = *arg_ty.kind() else { return };
|
||||||
|
|
||||||
|
|
|
@ -898,8 +898,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
self.param_env,
|
self.param_env,
|
||||||
adt_def.non_enum_variant().fields[field].ty(self.tcx, args),
|
adt_def.non_enum_variant().fields[field].ty(self.tcx, args),
|
||||||
);
|
);
|
||||||
if fields.len() == 1 {
|
if let [field] = fields.raw.as_slice() {
|
||||||
let src_ty = fields.raw[0].ty(self.body, self.tcx);
|
let src_ty = field.ty(self.body, self.tcx);
|
||||||
if !self.mir_assign_valid_types(src_ty, dest_ty) {
|
if !self.mir_assign_valid_types(src_ty, dest_ty) {
|
||||||
self.fail(location, "union field has the wrong type");
|
self.fail(location, "union field has the wrong type");
|
||||||
}
|
}
|
||||||
|
@ -967,11 +967,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
self.fail(location, "RawPtr should be in runtime MIR only");
|
self.fail(location, "RawPtr should be in runtime MIR only");
|
||||||
}
|
}
|
||||||
|
|
||||||
if fields.len() != 2 {
|
if let [data_ptr, metadata] = fields.raw.as_slice() {
|
||||||
self.fail(location, "raw pointer aggregate must have 2 fields");
|
let data_ptr_ty = data_ptr.ty(self.body, self.tcx);
|
||||||
} else {
|
let metadata_ty = metadata.ty(self.body, self.tcx);
|
||||||
let data_ptr_ty = fields.raw[0].ty(self.body, self.tcx);
|
|
||||||
let metadata_ty = fields.raw[1].ty(self.body, self.tcx);
|
|
||||||
if let ty::RawPtr(in_pointee, in_mut) = data_ptr_ty.kind() {
|
if let ty::RawPtr(in_pointee, in_mut) = data_ptr_ty.kind() {
|
||||||
if *in_mut != mutability {
|
if *in_mut != mutability {
|
||||||
self.fail(location, "input and output mutability must match");
|
self.fail(location, "input and output mutability must match");
|
||||||
|
@ -998,6 +996,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
self.fail(location, "metadata for pointer-to-thin must be unit");
|
self.fail(location, "metadata for pointer-to-thin must be unit");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self.fail(location, "raw pointer aggregate must have 2 fields");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -694,12 +694,12 @@ impl<'a> Parser<'a> {
|
||||||
// `foo: `
|
// `foo: `
|
||||||
ExprKind::Path(None, ast::Path { segments, .. }),
|
ExprKind::Path(None, ast::Path { segments, .. }),
|
||||||
token::Ident(kw::For | kw::Loop | kw::While, IdentIsRaw::No),
|
token::Ident(kw::For | kw::Loop | kw::While, IdentIsRaw::No),
|
||||||
) if segments.len() == 1 => {
|
) if let [segment] = segments.as_slice() => {
|
||||||
let snapshot = self.create_snapshot_for_diagnostic();
|
let snapshot = self.create_snapshot_for_diagnostic();
|
||||||
let label = Label {
|
let label = Label {
|
||||||
ident: Ident::from_str_and_span(
|
ident: Ident::from_str_and_span(
|
||||||
&format!("'{}", segments[0].ident),
|
&format!("'{}", segment.ident),
|
||||||
segments[0].ident.span,
|
segment.ident.span,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
match self.parse_expr_labeled(label, false) {
|
match self.parse_expr_labeled(label, false) {
|
||||||
|
|
|
@ -471,9 +471,8 @@ impl<'a> Parser<'a> {
|
||||||
Err(mut err) => {
|
Err(mut err) => {
|
||||||
// Maybe the user misspelled `macro_rules` (issue #91227)
|
// Maybe the user misspelled `macro_rules` (issue #91227)
|
||||||
if self.token.is_ident()
|
if self.token.is_ident()
|
||||||
&& path.segments.len() == 1
|
&& let [segment] = path.segments.as_slice()
|
||||||
&& edit_distance("macro_rules", &path.segments[0].ident.to_string(), 2)
|
&& edit_distance("macro_rules", &segment.ident.to_string(), 2).is_some()
|
||||||
.is_some()
|
|
||||||
{
|
{
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
path.span,
|
path.span,
|
||||||
|
|
|
@ -826,7 +826,8 @@ impl<'a> Parser<'a> {
|
||||||
// We can only resolve single-segment paths at the moment, because multi-segment paths
|
// We can only resolve single-segment paths at the moment, because multi-segment paths
|
||||||
// require type-checking: see `visit_generic_arg` in `src/librustc_resolve/late.rs`.
|
// require type-checking: see `visit_generic_arg` in `src/librustc_resolve/late.rs`.
|
||||||
ast::ExprKind::Path(None, path)
|
ast::ExprKind::Path(None, path)
|
||||||
if path.segments.len() == 1 && path.segments[0].args.is_none() =>
|
if let [segment] = path.segments.as_slice()
|
||||||
|
&& segment.args.is_none() =>
|
||||||
{
|
{
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
|
@ -676,7 +676,7 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
match &expr.kind {
|
match &expr.kind {
|
||||||
ExprKind::Path(None, ast::Path { segments, .. })
|
ExprKind::Path(None, ast::Path { segments, .. })
|
||||||
if segments.len() == 1 =>
|
if let [segment] = segments.as_slice() =>
|
||||||
{
|
{
|
||||||
if self.token == token::Colon
|
if self.token == token::Colon
|
||||||
&& self.look_ahead(1, |token| {
|
&& self.look_ahead(1, |token| {
|
||||||
|
@ -693,8 +693,8 @@ impl<'a> Parser<'a> {
|
||||||
let snapshot = self.create_snapshot_for_diagnostic();
|
let snapshot = self.create_snapshot_for_diagnostic();
|
||||||
let label = Label {
|
let label = Label {
|
||||||
ident: Ident::from_str_and_span(
|
ident: Ident::from_str_and_span(
|
||||||
&format!("'{}", segments[0].ident),
|
&format!("'{}", segment.ident),
|
||||||
segments[0].ident.span,
|
segment.ident.span,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
match self.parse_expr_labeled(label, false) {
|
match self.parse_expr_labeled(label, false) {
|
||||||
|
|
|
@ -2213,8 +2213,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||||
attr.name_or_empty(),
|
attr.name_or_empty(),
|
||||||
sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
|
sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
|
||||||
) && let Some(meta) = attr.meta_item_list()
|
) && let Some(meta) = attr.meta_item_list()
|
||||||
&& meta.len() == 1
|
&& let [meta] = meta.as_slice()
|
||||||
&& let Some(item) = meta[0].meta_item()
|
&& let Some(item) = meta.meta_item()
|
||||||
&& let MetaItemKind::NameValue(_) = &item.kind
|
&& let MetaItemKind::NameValue(_) = &item.kind
|
||||||
&& item.path == sym::reason
|
&& item.path == sym::reason
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,9 +19,7 @@ impl DebuggerVisualizerCollector<'_> {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let hint = if hints.len() == 1 {
|
let [hint] = hints.as_slice() else {
|
||||||
&hints[0]
|
|
||||||
} else {
|
|
||||||
self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
|
self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
|
@ -46,15 +46,14 @@ pub struct EdgeFilter {
|
||||||
|
|
||||||
impl EdgeFilter {
|
impl EdgeFilter {
|
||||||
pub fn new(test: &str) -> Result<EdgeFilter, Box<dyn Error>> {
|
pub fn new(test: &str) -> Result<EdgeFilter, Box<dyn Error>> {
|
||||||
let parts: Vec<_> = test.split("->").collect();
|
if let [source, target] = *test.split("->").collect::<Vec<_>>() {
|
||||||
if parts.len() != 2 {
|
|
||||||
Err(format!("expected a filter like `a&b -> c&d`, not `{test}`").into())
|
|
||||||
} else {
|
|
||||||
Ok(EdgeFilter {
|
Ok(EdgeFilter {
|
||||||
source: DepNodeFilter::new(parts[0]),
|
source: DepNodeFilter::new(source),
|
||||||
target: DepNodeFilter::new(parts[1]),
|
target: DepNodeFilter::new(target),
|
||||||
index_to_node: Lock::new(FxHashMap::default()),
|
index_to_node: Lock::new(FxHashMap::default()),
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
Err(format!("expected a filter like `a&b -> c&d`, not `{test}`").into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -445,8 +445,8 @@ impl<'a> PathSource<'a> {
|
||||||
Some(ExprKind::Call(call_expr, _)) => match &call_expr.kind {
|
Some(ExprKind::Call(call_expr, _)) => match &call_expr.kind {
|
||||||
// the case of `::some_crate()`
|
// the case of `::some_crate()`
|
||||||
ExprKind::Path(_, path)
|
ExprKind::Path(_, path)
|
||||||
if path.segments.len() == 2
|
if let [segment, _] = path.segments.as_slice()
|
||||||
&& path.segments[0].ident.name == kw::PathRoot =>
|
&& segment.ident.name == kw::PathRoot =>
|
||||||
{
|
{
|
||||||
"external crate"
|
"external crate"
|
||||||
}
|
}
|
||||||
|
@ -2396,15 +2396,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn future_proof_import(&mut self, use_tree: &UseTree) {
|
fn future_proof_import(&mut self, use_tree: &UseTree) {
|
||||||
let segments = &use_tree.prefix.segments;
|
if let [segment, rest @ ..] = use_tree.prefix.segments.as_slice() {
|
||||||
if !segments.is_empty() {
|
let ident = segment.ident;
|
||||||
let ident = segments[0].ident;
|
|
||||||
if ident.is_path_segment_keyword() || ident.span.is_rust_2015() {
|
if ident.is_path_segment_keyword() || ident.span.is_rust_2015() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let nss = match use_tree.kind {
|
let nss = match use_tree.kind {
|
||||||
UseTreeKind::Simple(..) if segments.len() == 1 => &[TypeNS, ValueNS][..],
|
UseTreeKind::Simple(..) if rest.is_empty() => &[TypeNS, ValueNS][..],
|
||||||
_ => &[TypeNS],
|
_ => &[TypeNS],
|
||||||
};
|
};
|
||||||
let report_error = |this: &Self, ns| {
|
let report_error = |this: &Self, ns| {
|
||||||
|
@ -4009,16 +4008,15 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||||
|
|
||||||
if this.should_report_errs() {
|
if this.should_report_errs() {
|
||||||
if candidates.is_empty() {
|
if candidates.is_empty() {
|
||||||
if path.len() == 2 && prefix_path.len() == 1 {
|
if path.len() == 2
|
||||||
|
&& let [segment] = prefix_path
|
||||||
|
{
|
||||||
// Delay to check whether methond name is an associated function or not
|
// Delay to check whether methond name is an associated function or not
|
||||||
// ```
|
// ```
|
||||||
// let foo = Foo {};
|
// let foo = Foo {};
|
||||||
// foo::bar(); // possibly suggest to foo.bar();
|
// foo::bar(); // possibly suggest to foo.bar();
|
||||||
//```
|
//```
|
||||||
err.stash(
|
err.stash(segment.ident.span, rustc_errors::StashKey::CallAssocMethod);
|
||||||
prefix_path[0].ident.span,
|
|
||||||
rustc_errors::StashKey::CallAssocMethod,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// When there is no suggested imports, we can just emit the error
|
// When there is no suggested imports, we can just emit the error
|
||||||
// and suggestions immediately. Note that we bypass the usually error
|
// and suggestions immediately. Note that we bypass the usually error
|
||||||
|
|
|
@ -650,14 +650,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
let typo_sugg = self
|
let typo_sugg = self
|
||||||
.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected)
|
.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected)
|
||||||
.to_opt_suggestion();
|
.to_opt_suggestion();
|
||||||
if path.len() == 1
|
if let [segment] = path
|
||||||
&& !matches!(source, PathSource::Delegation)
|
&& !matches!(source, PathSource::Delegation)
|
||||||
&& self.self_type_is_available()
|
&& self.self_type_is_available()
|
||||||
{
|
{
|
||||||
if let Some(candidate) =
|
if let Some(candidate) =
|
||||||
self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
|
self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
|
||||||
{
|
{
|
||||||
let self_is_available = self.self_value_is_available(path[0].ident.span);
|
let self_is_available = self.self_value_is_available(segment.ident.span);
|
||||||
// Account for `Foo { field }` when suggesting `self.field` so we result on
|
// Account for `Foo { field }` when suggesting `self.field` so we result on
|
||||||
// `Foo { field: self.field }`.
|
// `Foo { field: self.field }`.
|
||||||
let pre = match source {
|
let pre = match source {
|
||||||
|
@ -665,7 +665,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
if expr
|
if expr
|
||||||
.fields
|
.fields
|
||||||
.iter()
|
.iter()
|
||||||
.any(|f| f.ident == path[0].ident && f.is_shorthand) =>
|
.any(|f| f.ident == segment.ident && f.is_shorthand) =>
|
||||||
{
|
{
|
||||||
format!("{path_str}: ")
|
format!("{path_str}: ")
|
||||||
}
|
}
|
||||||
|
@ -1258,8 +1258,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
if targets.len() == 1 {
|
if let [target] = targets.as_slice() {
|
||||||
let target = targets[0];
|
|
||||||
return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1));
|
return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2105,8 +2104,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
filter_fn: &impl Fn(Res) -> bool,
|
filter_fn: &impl Fn(Res) -> bool,
|
||||||
) -> TypoCandidate {
|
) -> TypoCandidate {
|
||||||
let mut names = Vec::new();
|
let mut names = Vec::new();
|
||||||
if path.len() == 1 {
|
if let [segment] = path {
|
||||||
let mut ctxt = path.last().unwrap().ident.span.ctxt();
|
let mut ctxt = segment.ident.span.ctxt();
|
||||||
|
|
||||||
// Search in lexical scope.
|
// Search in lexical scope.
|
||||||
// Walk backwards up the ribs in scope and collect candidates.
|
// Walk backwards up the ribs in scope and collect candidates.
|
||||||
|
|
|
@ -109,8 +109,8 @@ pub(crate) fn sub_namespace_match(
|
||||||
// `format!("{}", path)`, because that tries to insert
|
// `format!("{}", path)`, because that tries to insert
|
||||||
// line-breaks and is slow.
|
// line-breaks and is slow.
|
||||||
fn fast_print_path(path: &ast::Path) -> Symbol {
|
fn fast_print_path(path: &ast::Path) -> Symbol {
|
||||||
if path.segments.len() == 1 {
|
if let [segment] = path.segments.as_slice() {
|
||||||
path.segments[0].ident.name
|
segment.ident.name
|
||||||
} else {
|
} else {
|
||||||
let mut path_str = String::with_capacity(64);
|
let mut path_str = String::with_capacity(64);
|
||||||
for (i, segment) in path.segments.iter().enumerate() {
|
for (i, segment) in path.segments.iter().enumerate() {
|
||||||
|
@ -738,10 +738,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||||
// Possibly apply the macro helper hack
|
// Possibly apply the macro helper hack
|
||||||
if deleg_impl.is_none()
|
if deleg_impl.is_none()
|
||||||
&& kind == Some(MacroKind::Bang)
|
&& kind == Some(MacroKind::Bang)
|
||||||
&& path.len() == 1
|
&& let [segment] = path.as_slice()
|
||||||
&& path[0].ident.span.ctxt().outer_expn_data().local_inner_macros
|
&& segment.ident.span.ctxt().outer_expn_data().local_inner_macros
|
||||||
{
|
{
|
||||||
let root = Ident::new(kw::DollarCrate, path[0].ident.span);
|
let root = Ident::new(kw::DollarCrate, segment.ident.span);
|
||||||
path.insert(0, Segment::from_ident(root));
|
path.insert(0, Segment::from_ident(root));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -912,16 +912,9 @@ mod parse {
|
||||||
match v {
|
match v {
|
||||||
None => false,
|
None => false,
|
||||||
Some(s) => {
|
Some(s) => {
|
||||||
let parts = s.split('=').collect::<Vec<_>>();
|
let [crate_name, fuel] = *s.split('=').collect::<Vec<_>>() else { return false };
|
||||||
if parts.len() != 2 {
|
let Ok(fuel) = fuel.parse::<u64>() else { return false };
|
||||||
return false;
|
*slot = Some((crate_name.to_string(), fuel));
|
||||||
}
|
|
||||||
let crate_name = parts[0].to_string();
|
|
||||||
let fuel = parts[1].parse::<u64>();
|
|
||||||
if fuel.is_err() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*slot = Some((crate_name, fuel.unwrap()));
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3149,11 +3149,10 @@ impl Target {
|
||||||
if let Some(a) = o.as_array() {
|
if let Some(a) = o.as_array() {
|
||||||
for o in a {
|
for o in a {
|
||||||
if let Some(s) = o.as_str() {
|
if let Some(s) = o.as_str() {
|
||||||
let p = s.split('=').collect::<Vec<_>>();
|
if let [k, v] = *s.split('=').collect::<Vec<_>>() {
|
||||||
if p.len() == 2 {
|
base.$key_name
|
||||||
let k = p[0].to_string();
|
.to_mut()
|
||||||
let v = p[1].to_string();
|
.push((k.to_string().into(), v.to_string().into()))
|
||||||
base.$key_name.to_mut().push((k.into(), v.into()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -944,8 +944,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
// The current method call returns `Result<_, ()>`
|
// The current method call returns `Result<_, ()>`
|
||||||
&& self.can_eq(obligation.param_env, ty, found_ty)
|
&& self.can_eq(obligation.param_env, ty, found_ty)
|
||||||
// There's a single argument in the method call and it is a closure
|
// There's a single argument in the method call and it is a closure
|
||||||
&& args.len() == 1
|
&& let [arg] = args
|
||||||
&& let Some(arg) = args.get(0)
|
|
||||||
&& let hir::ExprKind::Closure(closure) = arg.kind
|
&& let hir::ExprKind::Closure(closure) = arg.kind
|
||||||
// The closure has a block for its body with no tail expression
|
// The closure has a block for its body with no tail expression
|
||||||
&& let body = self.tcx.hir().body(closure.body)
|
&& let body = self.tcx.hir().body(closure.body)
|
||||||
|
|
|
@ -73,10 +73,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let impl_def_id_and_args = if self_match_impls.len() == 1 {
|
let impl_def_id_and_args = if let [impl_] = self_match_impls[..] {
|
||||||
self_match_impls[0]
|
impl_
|
||||||
} else if fuzzy_match_impls.len() == 1 {
|
} else if let [impl_] = fuzzy_match_impls[..] {
|
||||||
fuzzy_match_impls[0]
|
impl_
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
|
@ -5300,7 +5300,8 @@ impl<'v> Visitor<'v> for FindTypeParam {
|
||||||
match ty.kind {
|
match ty.kind {
|
||||||
hir::TyKind::Ptr(_) | hir::TyKind::Ref(..) | hir::TyKind::TraitObject(..) => {}
|
hir::TyKind::Ptr(_) | hir::TyKind::Ref(..) | hir::TyKind::TraitObject(..) => {}
|
||||||
hir::TyKind::Path(hir::QPath::Resolved(None, path))
|
hir::TyKind::Path(hir::QPath::Resolved(None, path))
|
||||||
if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
|
if let [segment] = path.segments
|
||||||
|
&& segment.ident.name == self.param =>
|
||||||
{
|
{
|
||||||
if !self.nested {
|
if !self.nested {
|
||||||
debug!(?ty, "FindTypeParam::visit_ty");
|
debug!(?ty, "FindTypeParam::visit_ty");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue