Skip to content

Commit

Permalink
Auto merge of #123776 - matthiaskrgr:rollup-x8wzvdf, r=matthiaskrgr
Browse files Browse the repository at this point in the history
Rollup of 2 pull requests

Successful merges:

 - #123704 (Tweak value suggestions in `borrowck` and `hir_analysis`)
 - #123753 (compiletest: error when finding a trailing directive)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Apr 11, 2024
2 parents 05ccc49 + a6448d3 commit 241fc13
Show file tree
Hide file tree
Showing 59 changed files with 441 additions and 199 deletions.
96 changes: 70 additions & 26 deletions compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,68 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err
}

fn ty_kind_suggestion(&self, ty: Ty<'tcx>) -> Option<String> {
// Keep in sync with `rustc_hir_analysis/src/check/mod.rs:ty_kind_suggestion`.
// FIXME: deduplicate the above.
let tcx = self.infcx.tcx;
let implements_default = |ty| {
let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
return false;
};
self.infcx
.type_implements_trait(default_trait, [ty], self.param_env)
.must_apply_modulo_regions()
};

Some(match ty.kind() {
ty::Never | ty::Error(_) => return None,
ty::Bool => "false".to_string(),
ty::Char => "\'x\'".to_string(),
ty::Int(_) | ty::Uint(_) => "42".into(),
ty::Float(_) => "3.14159".into(),
ty::Slice(_) => "[]".to_string(),
ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => {
"vec![]".to_string()
}
ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::String) => {
"String::new()".to_string()
}
ty::Adt(def, args) if def.is_box() => {
format!("Box::new({})", self.ty_kind_suggestion(args[0].expect_ty())?)
}
ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Option) => {
"None".to_string()
}
ty::Adt(def, args) if Some(def.did()) == tcx.get_diagnostic_item(sym::Result) => {
format!("Ok({})", self.ty_kind_suggestion(args[0].expect_ty())?)
}
ty::Adt(_, _) if implements_default(ty) => "Default::default()".to_string(),
ty::Ref(_, ty, mutability) => {
if let (ty::Str, hir::Mutability::Not) = (ty.kind(), mutability) {
"\"\"".to_string()
} else {
let Some(ty) = self.ty_kind_suggestion(*ty) else {
return None;
};
format!("&{}{ty}", mutability.prefix_str())
}
}
ty::Array(ty, len) => format!(
"[{}; {}]",
self.ty_kind_suggestion(*ty)?,
len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()),
),
ty::Tuple(tys) => format!(
"({})",
tys.iter()
.map(|ty| self.ty_kind_suggestion(ty))
.collect::<Option<Vec<String>>>()?
.join(", ")
),
_ => "value".to_string(),
})
}

fn suggest_assign_value(
&self,
err: &mut Diag<'_>,
Expand All @@ -661,34 +723,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
debug!("ty: {:?}, kind: {:?}", ty, ty.kind());

let tcx = self.infcx.tcx;
let implements_default = |ty, param_env| {
let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
return false;
};
self.infcx
.type_implements_trait(default_trait, [ty], param_env)
.must_apply_modulo_regions()
};

let assign_value = match ty.kind() {
ty::Bool => "false",
ty::Float(_) => "0.0",
ty::Int(_) | ty::Uint(_) => "0",
ty::Never | ty::Error(_) => "",
ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => "vec![]",
ty::Adt(_, _) if implements_default(ty, self.param_env) => "Default::default()",
_ => "todo!()",
let Some(assign_value) = self.ty_kind_suggestion(ty) else {
return;
};

if !assign_value.is_empty() {
err.span_suggestion_verbose(
sugg_span.shrink_to_hi(),
"consider assigning a value",
format!(" = {assign_value}"),
Applicability::MaybeIncorrect,
);
}
err.span_suggestion_verbose(
sugg_span.shrink_to_hi(),
"consider assigning a value",
format!(" = {assign_value}"),
Applicability::MaybeIncorrect,
);
}

fn suggest_borrow_fn_like(
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ use rustc_middle::ty::{
AdtDef, ParamEnv, RegionKind, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
};
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
use rustc_span::symbol::sym;
use rustc_target::abi::FieldIdx;
use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
Expand Down
72 changes: 62 additions & 10 deletions compiler/rustc_hir_analysis/src/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ use rustc_errors::ErrorGuaranteed;
use rustc_errors::{pluralize, struct_span_code_err, Diag};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::Mutability;
use rustc_index::bit_set::BitSet;
use rustc_infer::infer::error_reporting::ObligationCauseExt as _;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
Expand All @@ -91,10 +92,11 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{GenericArgs, GenericArgsRef};
use rustc_session::parse::feature_err;
use rustc_span::symbol::{kw, Ident};
use rustc_span::{self, def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP};
use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::ObligationCtxt;
Expand Down Expand Up @@ -466,14 +468,64 @@ fn fn_sig_suggestion<'tcx>(
)
}

pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
pub fn ty_kind_suggestion<'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<String> {
// Keep in sync with `rustc_borrowck/src/diagnostics/conflict_errors.rs:ty_kind_suggestion`.
// FIXME: deduplicate the above.
let implements_default = |ty| {
let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
return false;
};
let infcx = tcx.infer_ctxt().build();
infcx
.type_implements_trait(default_trait, [ty], ty::ParamEnv::reveal_all())
.must_apply_modulo_regions()
};
Some(match ty.kind() {
ty::Bool => "true",
ty::Char => "'a'",
ty::Int(_) | ty::Uint(_) => "42",
ty::Float(_) => "3.14159",
ty::Error(_) | ty::Never => return None,
_ => "value",
ty::Never | ty::Error(_) => return None,
ty::Bool => "false".to_string(),
ty::Char => "\'x\'".to_string(),
ty::Int(_) | ty::Uint(_) => "42".into(),
ty::Float(_) => "3.14159".into(),
ty::Slice(_) => "[]".to_string(),
ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => {
"vec![]".to_string()
}
ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::String) => {
"String::new()".to_string()
}
ty::Adt(def, args) if def.is_box() => {
format!("Box::new({})", ty_kind_suggestion(args[0].expect_ty(), tcx)?)
}
ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Option) => {
"None".to_string()
}
ty::Adt(def, args) if Some(def.did()) == tcx.get_diagnostic_item(sym::Result) => {
format!("Ok({})", ty_kind_suggestion(args[0].expect_ty(), tcx)?)
}
ty::Adt(_, _) if implements_default(ty) => "Default::default()".to_string(),
ty::Ref(_, ty, mutability) => {
if let (ty::Str, Mutability::Not) = (ty.kind(), mutability) {
"\"\"".to_string()
} else {
let Some(ty) = ty_kind_suggestion(*ty, tcx) else {
return None;
};
format!("&{}{ty}", mutability.prefix_str())
}
}
ty::Array(ty, len) => format!(
"[{}; {}]",
ty_kind_suggestion(*ty, tcx)?,
len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()),
),
ty::Tuple(tys) => format!(
"({})",
tys.iter()
.map(|ty| ty_kind_suggestion(ty, tcx))
.collect::<Option<Vec<String>>>()?
.join(", ")
),
_ => "value".to_string(),
})
}

Expand Down Expand Up @@ -511,7 +563,7 @@ fn suggestion_signature<'tcx>(
}
ty::AssocKind::Const => {
let ty = tcx.type_of(assoc.def_id).instantiate_identity();
let val = ty_kind_suggestion(ty).unwrap_or("todo!()");
let val = ty_kind_suggestion(ty, tcx).unwrap_or_else(|| "value".to_string());
format!("const {}: {} = {};", assoc.name, ty, val)
}
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -694,10 +694,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
let error = Some(Sorts(ExpectedFound { expected: ty, found: e_ty }));
self.annotate_loop_expected_due_to_inference(err, expr, error);
if let Some(val) = ty_kind_suggestion(ty) {
if let Some(val) = ty_kind_suggestion(ty, tcx) {
err.span_suggestion_verbose(
expr.span.shrink_to_hi(),
"give it a value of the expected type",
"give the `break` a value of the expected type",
format!(" {val}"),
Applicability::HasPlaceholders,
);
Expand Down
36 changes: 31 additions & 5 deletions src/tools/compiletest/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -935,16 +935,25 @@ struct HeaderLine<'ln> {
pub(crate) struct CheckDirectiveResult<'ln> {
is_known_directive: bool,
directive_name: &'ln str,
trailing_directive: Option<&'ln str>,
}

// Returns `(is_known_directive, directive_name)`.
pub(crate) fn check_directive(directive_ln: &str) -> CheckDirectiveResult<'_> {
let directive_name =
directive_ln.split_once([':', ' ']).map(|(pre, _)| pre).unwrap_or(directive_ln);
let (directive_name, post) = directive_ln.split_once([':', ' ']).unwrap_or((directive_ln, ""));

let trailing = post.trim().split_once(' ').map(|(pre, _)| pre).unwrap_or(post);
let trailing_directive = {
// 1. is the directive name followed by a space? (to exclude `:`)
matches!(directive_ln.get(directive_name.len()..), Some(s) if s.starts_with(" "))
// 2. is what is after that directive also a directive (ex: "only-x86 only-arm")
&& KNOWN_DIRECTIVE_NAMES.contains(&trailing)
}
.then_some(trailing);

CheckDirectiveResult {
is_known_directive: KNOWN_DIRECTIVE_NAMES.contains(&directive_name),
directive_name: directive_ln,
trailing_directive,
}
}

Expand Down Expand Up @@ -1014,7 +1023,8 @@ fn iter_header(
if testfile.extension().map(|e| e == "rs").unwrap_or(false) {
let directive_ln = non_revisioned_directive_line.trim();

let CheckDirectiveResult { is_known_directive, .. } = check_directive(directive_ln);
let CheckDirectiveResult { is_known_directive, trailing_directive, .. } =
check_directive(directive_ln);

if !is_known_directive {
*poisoned = true;
Expand All @@ -1028,6 +1038,21 @@ fn iter_header(

return;
}

if let Some(trailing_directive) = &trailing_directive {
*poisoned = true;

eprintln!(
"error: detected trailing compiletest test directive `{}` in {}:{}\n \
help: put the trailing directive in it's own line: `//@ {}`",
trailing_directive,
testfile.display(),
line_number,
trailing_directive,
);

return;
}
}

it(HeaderLine {
Expand All @@ -1051,7 +1076,8 @@ fn iter_header(

let rest = rest.trim_start();

let CheckDirectiveResult { is_known_directive, directive_name } = check_directive(rest);
let CheckDirectiveResult { is_known_directive, directive_name, .. } =
check_directive(rest);

if is_known_directive {
*poisoned = true;
Expand Down
21 changes: 21 additions & 0 deletions src/tools/compiletest/src/header/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -667,3 +667,24 @@ fn test_non_rs_unknown_directive_not_checked() {
);
assert!(!poisoned);
}

#[test]
fn test_trailing_directive() {
let mut poisoned = false;
run_path(&mut poisoned, Path::new("a.rs"), b"//@ only-x86 only-arm");
assert!(poisoned);
}

#[test]
fn test_trailing_directive_with_comment() {
let mut poisoned = false;
run_path(&mut poisoned, Path::new("a.rs"), b"//@ only-x86 only-arm with comment");
assert!(poisoned);
}

#[test]
fn test_not_trailing_directive() {
let mut poisoned = false;
run_path(&mut poisoned, Path::new("a.rs"), b"//@ revisions: incremental");
assert!(!poisoned);
}
8 changes: 4 additions & 4 deletions tests/ui/asm/aarch64/type-check-2-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ LL | asm!("{}", in(reg) x);
|
help: consider assigning a value
|
LL | let x: u64 = 0;
| +++
LL | let x: u64 = 42;
| ++++

error[E0381]: used binding `y` isn't initialized
--> $DIR/type-check-2-2.rs:22:9
Expand All @@ -21,8 +21,8 @@ LL | asm!("{}", inout(reg) y);
|
help: consider assigning a value
|
LL | let mut y: u64 = 0;
| +++
LL | let mut y: u64 = 42;
| ++++

error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
--> $DIR/type-check-2-2.rs:28:13
Expand Down
8 changes: 4 additions & 4 deletions tests/ui/asm/x86_64/type-check-5.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ LL | asm!("{}", in(reg) x);
|
help: consider assigning a value
|
LL | let x: u64 = 0;
| +++
LL | let x: u64 = 42;
| ++++

error[E0381]: used binding `y` isn't initialized
--> $DIR/type-check-5.rs:18:9
Expand All @@ -21,8 +21,8 @@ LL | asm!("{}", inout(reg) y);
|
help: consider assigning a value
|
LL | let mut y: u64 = 0;
| +++
LL | let mut y: u64 = 42;
| ++++

error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
--> $DIR/type-check-5.rs:24:13
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/binop/issue-77910-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ LL | xs
|
help: consider assigning a value
|
LL | let xs = todo!();
| +++++++++
LL | let xs = &42;
| +++++

error: aborting due to 3 previous errors

Expand Down
4 changes: 2 additions & 2 deletions tests/ui/binop/issue-77910-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ LL | xs
|
help: consider assigning a value
|
LL | let xs = todo!();
| +++++++++
LL | let xs = &42;
| +++++

error: aborting due to 2 previous errors

Expand Down

0 comments on commit 241fc13

Please sign in to comment.