Rollup merge of #93214 - ibraheemdev:issue-93210, r=davidtwco
Respect doc(hidden) when suggesting available fields Resolves #93210
This commit is contained in:
commit
7de90d5b65
3 changed files with 75 additions and 9 deletions
|
@ -35,6 +35,7 @@ use rustc_hir::{ExprKind, HirId, QPath};
|
||||||
use rustc_infer::infer;
|
use rustc_infer::infer;
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use rustc_infer::infer::InferOk;
|
use rustc_infer::infer::InferOk;
|
||||||
|
use rustc_middle::middle::stability;
|
||||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
|
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
|
||||||
use rustc_middle::ty::error::ExpectedFound;
|
use rustc_middle::ty::error::ExpectedFound;
|
||||||
use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts};
|
use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts};
|
||||||
|
@ -1720,9 +1721,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
_ => {
|
_ => {
|
||||||
// prevent all specified fields from being suggested
|
// prevent all specified fields from being suggested
|
||||||
let skip_fields = skip_fields.iter().map(|x| x.ident.name);
|
let skip_fields = skip_fields.iter().map(|x| x.ident.name);
|
||||||
if let Some(field_name) =
|
if let Some(field_name) = self.suggest_field_name(
|
||||||
Self::suggest_field_name(variant, field.ident.name, skip_fields.collect())
|
variant,
|
||||||
{
|
field.ident.name,
|
||||||
|
skip_fields.collect(),
|
||||||
|
expr_span,
|
||||||
|
) {
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
field.ident.span,
|
field.ident.span,
|
||||||
"a field with a similar name exists",
|
"a field with a similar name exists",
|
||||||
|
@ -1743,7 +1747,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
format!("`{}` does not have this field", ty),
|
format!("`{}` does not have this field", ty),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let available_field_names = self.available_field_names(variant);
|
let available_field_names =
|
||||||
|
self.available_field_names(variant, expr_span);
|
||||||
if !available_field_names.is_empty() {
|
if !available_field_names.is_empty() {
|
||||||
err.note(&format!(
|
err.note(&format!(
|
||||||
"available fields are: {}",
|
"available fields are: {}",
|
||||||
|
@ -1759,19 +1764,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return an hint about the closest match in field names
|
// Return a hint about the closest match in field names
|
||||||
fn suggest_field_name(
|
fn suggest_field_name(
|
||||||
|
&self,
|
||||||
variant: &'tcx ty::VariantDef,
|
variant: &'tcx ty::VariantDef,
|
||||||
field: Symbol,
|
field: Symbol,
|
||||||
skip: Vec<Symbol>,
|
skip: Vec<Symbol>,
|
||||||
|
// The span where stability will be checked
|
||||||
|
span: Span,
|
||||||
) -> Option<Symbol> {
|
) -> Option<Symbol> {
|
||||||
let names = variant
|
let names = variant
|
||||||
.fields
|
.fields
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|field| {
|
.filter_map(|field| {
|
||||||
// ignore already set fields and private fields from non-local crates
|
// ignore already set fields and private fields from non-local crates
|
||||||
|
// and unstable fields.
|
||||||
if skip.iter().any(|&x| x == field.name)
|
if skip.iter().any(|&x| x == field.name)
|
||||||
|| (!variant.def_id.is_local() && !field.vis.is_public())
|
|| (!variant.def_id.is_local() && !field.vis.is_public())
|
||||||
|
|| matches!(
|
||||||
|
self.tcx.eval_stability(field.did, None, span, None),
|
||||||
|
stability::EvalResult::Deny { .. }
|
||||||
|
)
|
||||||
{
|
{
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -1783,7 +1796,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
find_best_match_for_name(&names, field, None)
|
find_best_match_for_name(&names, field, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn available_field_names(&self, variant: &'tcx ty::VariantDef) -> Vec<Symbol> {
|
fn available_field_names(
|
||||||
|
&self,
|
||||||
|
variant: &'tcx ty::VariantDef,
|
||||||
|
access_span: Span,
|
||||||
|
) -> Vec<Symbol> {
|
||||||
variant
|
variant
|
||||||
.fields
|
.fields
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1793,7 +1810,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
.adjust_ident_and_get_scope(field.ident(self.tcx), variant.def_id, self.body_id)
|
.adjust_ident_and_get_scope(field.ident(self.tcx), variant.def_id, self.body_id)
|
||||||
.1;
|
.1;
|
||||||
field.vis.is_accessible_from(def_scope, self.tcx)
|
field.vis.is_accessible_from(def_scope, self.tcx)
|
||||||
|
&& !matches!(
|
||||||
|
self.tcx.eval_stability(field.did, None, access_span, None),
|
||||||
|
stability::EvalResult::Deny { .. }
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
.filter(|field| !self.tcx.is_doc_hidden(field.did))
|
||||||
.map(|field| field.name)
|
.map(|field| field.name)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
@ -1958,7 +1980,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.suggest_first_deref_field(&mut err, expr, base, field);
|
self.suggest_first_deref_field(&mut err, expr, base, field);
|
||||||
}
|
}
|
||||||
ty::Adt(def, _) if !def.is_enum() => {
|
ty::Adt(def, _) if !def.is_enum() => {
|
||||||
self.suggest_fields_on_recordish(&mut err, def, field);
|
self.suggest_fields_on_recordish(&mut err, def, field, expr.span);
|
||||||
}
|
}
|
||||||
ty::Param(param_ty) => {
|
ty::Param(param_ty) => {
|
||||||
self.point_at_param_definition(&mut err, param_ty);
|
self.point_at_param_definition(&mut err, param_ty);
|
||||||
|
@ -2121,9 +2143,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
err: &mut DiagnosticBuilder<'_>,
|
err: &mut DiagnosticBuilder<'_>,
|
||||||
def: &'tcx ty::AdtDef,
|
def: &'tcx ty::AdtDef,
|
||||||
field: Ident,
|
field: Ident,
|
||||||
|
access_span: Span,
|
||||||
) {
|
) {
|
||||||
if let Some(suggested_field_name) =
|
if let Some(suggested_field_name) =
|
||||||
Self::suggest_field_name(def.non_enum_variant(), field.name, vec![])
|
self.suggest_field_name(def.non_enum_variant(), field.name, vec![], access_span)
|
||||||
{
|
{
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
field.span,
|
field.span,
|
||||||
|
@ -2134,7 +2157,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
} else {
|
} else {
|
||||||
err.span_label(field.span, "unknown field");
|
err.span_label(field.span, "unknown field");
|
||||||
let struct_variant_def = def.non_enum_variant();
|
let struct_variant_def = def.non_enum_variant();
|
||||||
let field_names = self.available_field_names(struct_variant_def);
|
let field_names = self.available_field_names(struct_variant_def, access_span);
|
||||||
if !field_names.is_empty() {
|
if !field_names.is_empty() {
|
||||||
err.note(&format!(
|
err.note(&format!(
|
||||||
"available fields are: {}",
|
"available fields are: {}",
|
||||||
|
|
24
src/test/ui/did_you_mean/issue-93210-ignore-doc-hidden.rs
Normal file
24
src/test/ui/did_you_mean/issue-93210-ignore-doc-hidden.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct A {
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub hello: i32,
|
||||||
|
pub bye: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct B {
|
||||||
|
pub hello: i32,
|
||||||
|
pub bye: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
A::default().hey;
|
||||||
|
//~^ ERROR no field `hey` on type `A`
|
||||||
|
//~| NOTE unknown field
|
||||||
|
//~| NOTE available fields are: `bye`
|
||||||
|
|
||||||
|
B::default().hey;
|
||||||
|
//~^ ERROR no field `hey` on type `B`
|
||||||
|
//~| NOTE unknown field
|
||||||
|
//~| NOTE available fields are: `hello`, `bye`
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
error[E0609]: no field `hey` on type `A`
|
||||||
|
--> $DIR/issue-93210-ignore-doc-hidden.rs:15:18
|
||||||
|
|
|
||||||
|
LL | A::default().hey;
|
||||||
|
| ^^^ unknown field
|
||||||
|
|
|
||||||
|
= note: available fields are: `bye`
|
||||||
|
|
||||||
|
error[E0609]: no field `hey` on type `B`
|
||||||
|
--> $DIR/issue-93210-ignore-doc-hidden.rs:20:18
|
||||||
|
|
|
||||||
|
LL | B::default().hey;
|
||||||
|
| ^^^ unknown field
|
||||||
|
|
|
||||||
|
= note: available fields are: `hello`, `bye`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0609`.
|
Loading…
Add table
Add a link
Reference in a new issue