Consolidate two copies of ty_kind_suggestion
This commit is contained in:
parent
78bc0a5656
commit
d6ac50e547
4 changed files with 73 additions and 130 deletions
|
@ -671,68 +671,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
err
|
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(
|
fn suggest_assign_value(
|
||||||
&self,
|
&self,
|
||||||
err: &mut Diag<'_>,
|
err: &mut Diag<'_>,
|
||||||
|
@ -742,7 +680,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
|
let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
|
||||||
debug!("ty: {:?}, kind: {:?}", ty, ty.kind());
|
debug!("ty: {:?}, kind: {:?}", ty, ty.kind());
|
||||||
|
|
||||||
let Some(assign_value) = self.ty_kind_suggestion(ty) else {
|
let Some(assign_value) = self.infcx.err_ctxt().ty_kind_suggestion(self.param_env, ty)
|
||||||
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,6 @@ use rustc_errors::ErrorGuaranteed;
|
||||||
use rustc_errors::{pluralize, struct_span_code_err, Diag};
|
use rustc_errors::{pluralize, struct_span_code_err, Diag};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_hir::intravisit::Visitor;
|
use rustc_hir::intravisit::Visitor;
|
||||||
use rustc_hir::Mutability;
|
|
||||||
use rustc_index::bit_set::BitSet;
|
use rustc_index::bit_set::BitSet;
|
||||||
use rustc_infer::infer::error_reporting::ObligationCauseExt as _;
|
use rustc_infer::infer::error_reporting::ObligationCauseExt as _;
|
||||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||||
|
@ -96,8 +95,9 @@ use rustc_span::symbol::{kw, sym, Ident};
|
||||||
use rustc_span::{def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP};
|
use rustc_span::{def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP};
|
||||||
use rustc_target::abi::VariantIdx;
|
use rustc_target::abi::VariantIdx;
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
use rustc_trait_selection::traits::error_reporting::suggestions::{
|
||||||
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
|
ReturnsVisitor, TypeErrCtxtExt as _,
|
||||||
|
};
|
||||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
||||||
use rustc_trait_selection::traits::ObligationCtxt;
|
use rustc_trait_selection::traits::ObligationCtxt;
|
||||||
|
|
||||||
|
@ -467,67 +467,6 @@ fn fn_sig_suggestion<'tcx>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
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::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(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return placeholder code for the given associated item.
|
/// Return placeholder code for the given associated item.
|
||||||
/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
|
/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
|
||||||
/// structured suggestion.
|
/// structured suggestion.
|
||||||
|
@ -562,7 +501,12 @@ fn suggestion_signature<'tcx>(
|
||||||
}
|
}
|
||||||
ty::AssocKind::Const => {
|
ty::AssocKind::Const => {
|
||||||
let ty = tcx.type_of(assoc.def_id).instantiate_identity();
|
let ty = tcx.type_of(assoc.def_id).instantiate_identity();
|
||||||
let val = ty_kind_suggestion(ty, tcx).unwrap_or_else(|| "value".to_string());
|
let val = tcx
|
||||||
|
.infer_ctxt()
|
||||||
|
.build()
|
||||||
|
.err_ctxt()
|
||||||
|
.ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)
|
||||||
|
.unwrap_or_else(|| "value".to_string());
|
||||||
format!("const {}: {} = {};", assoc.name, ty, val)
|
format!("const {}: {} = {};", assoc.name, ty, val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,6 @@ use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::intravisit::Visitor;
|
use rustc_hir::intravisit::Visitor;
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_hir::{ExprKind, HirId, QPath};
|
use rustc_hir::{ExprKind, HirId, QPath};
|
||||||
use rustc_hir_analysis::check::ty_kind_suggestion;
|
|
||||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _;
|
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _;
|
||||||
use rustc_infer::infer;
|
use rustc_infer::infer;
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
|
@ -57,6 +56,7 @@ use rustc_span::Span;
|
||||||
use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
|
use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
|
||||||
use rustc_target::spec::abi::Abi::RustIntrinsic;
|
use rustc_target::spec::abi::Abi::RustIntrinsic;
|
||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
|
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
|
||||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
||||||
use rustc_trait_selection::traits::ObligationCtxt;
|
use rustc_trait_selection::traits::ObligationCtxt;
|
||||||
use rustc_trait_selection::traits::{self, ObligationCauseCode};
|
use rustc_trait_selection::traits::{self, ObligationCauseCode};
|
||||||
|
@ -694,7 +694,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
let error = Some(Sorts(ExpectedFound { expected: ty, found: e_ty }));
|
let error = Some(Sorts(ExpectedFound { expected: ty, found: e_ty }));
|
||||||
self.annotate_loop_expected_due_to_inference(err, expr, error);
|
self.annotate_loop_expected_due_to_inference(err, expr, error);
|
||||||
if let Some(val) = ty_kind_suggestion(ty, tcx) {
|
if let Some(val) =
|
||||||
|
self.err_ctxt().ty_kind_suggestion(self.param_env, ty)
|
||||||
|
{
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
expr.span.shrink_to_hi(),
|
expr.span.shrink_to_hi(),
|
||||||
"give the `break` a value of the expected type",
|
"give the `break` a value of the expected type",
|
||||||
|
|
|
@ -4540,6 +4540,64 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ty_kind_suggestion(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> Option<String> {
|
||||||
|
let tcx = self.infcx.tcx;
|
||||||
|
let implements_default = |ty| {
|
||||||
|
let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
self.type_implements_trait(default_trait, [ty], 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(param_env, 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(param_env, 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(param_env, *ty) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
format!("&{}{ty}", mutability.prefix_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ty::Array(ty, len) => format!(
|
||||||
|
"[{}; {}]",
|
||||||
|
self.ty_kind_suggestion(param_env, *ty)?,
|
||||||
|
len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()),
|
||||||
|
),
|
||||||
|
ty::Tuple(tys) => format!(
|
||||||
|
"({})",
|
||||||
|
tys.iter()
|
||||||
|
.map(|ty| self.ty_kind_suggestion(param_env, ty))
|
||||||
|
.collect::<Option<Vec<String>>>()?
|
||||||
|
.join(", ")
|
||||||
|
),
|
||||||
|
_ => "value".to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a hint to add a missing borrow or remove an unnecessary one.
|
/// Add a hint to add a missing borrow or remove an unnecessary one.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue