1
Fork 0

Rollup merge of #125978 - fmease:cleanup-hir-ty-lowering-consolidate-assoc-item-access-checking, r=davidtwco

Cleanup: HIR ty lowering: Consolidate the places that do assoc item probing & access checking

Use `probe_assoc_item` (for hygienically probing an assoc item and checking if it's accessible wrt. visibility and stability) for assoc item constraints, too, not just for assoc type paths and make the privacy error translatable.
This commit is contained in:
Jubilee 2024-06-12 03:57:19 -07:00 committed by GitHub
commit e7b07ea7a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 97 additions and 69 deletions

View file

@ -8,6 +8,10 @@ hir_analysis_assoc_item_constraints_not_allowed_here =
associated item constraints are not allowed here associated item constraints are not allowed here
.label = associated item constraint not allowed here .label = associated item constraint not allowed here
hir_analysis_assoc_item_is_private = {$kind} `{$name}` is private
.label = private {$kind}
.defined_here_label = the {$kind} is defined here
hir_analysis_assoc_item_not_found = associated {$assoc_kind} `{$assoc_name}` not found for `{$ty_param_name}` hir_analysis_assoc_item_not_found = associated {$assoc_kind} `{$assoc_name}` not found for `{$ty_param_name}`
hir_analysis_assoc_item_not_found_found_in_other_trait_label = there is {$identically_named -> hir_analysis_assoc_item_not_found_found_in_other_trait_label = there is {$identically_named ->

View file

@ -55,6 +55,18 @@ pub struct AssocKindMismatchWrapInBracesSugg {
pub hi: Span, pub hi: Span,
} }
#[derive(Diagnostic)]
#[diag(hir_analysis_assoc_item_is_private, code = E0624)]
pub struct AssocItemIsPrivate {
#[primary_span]
#[label]
pub span: Span,
pub kind: &'static str,
pub name: Ident,
#[label(hir_analysis_defined_here_label)]
pub defined_here_label: Span,
}
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(hir_analysis_assoc_item_not_found, code = E0220)] #[diag(hir_analysis_assoc_item_not_found, code = E0220)]
pub struct AssocItemNotFound<'a> { pub struct AssocItemNotFound<'a> {

View file

@ -294,30 +294,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)? )?
}; };
let (assoc_ident, def_scope) = let assoc_item = self
tcx.adjust_ident_and_get_scope(constraint.ident, candidate.def_id(), hir_ref_id); .probe_assoc_item(
constraint.ident,
// We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()` assoc_kind,
// instead of calling `filter_by_name_and_kind` which would needlessly normalize the hir_ref_id,
// `assoc_ident` again and again.
let assoc_item = tcx
.associated_items(candidate.def_id())
.filter_by_name_unhygienic(assoc_ident.name)
.find(|i| i.kind == assoc_kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
.expect("missing associated item");
if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
let reported = tcx
.dcx()
.struct_span_err(
constraint.span, constraint.span,
format!("{} `{}` is private", assoc_item.kind, constraint.ident), candidate.def_id(),
) )
.with_span_label(constraint.span, format!("private {}", assoc_item.kind)) .expect("failed to find associated item");
.emit();
self.set_tainted_by_errors(reported);
}
tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), constraint.span, None);
duplicates duplicates
.entry(assoc_item.def_id) .entry(assoc_item.def_id)
@ -404,10 +389,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// Create the generic arguments for the associated type or constant by joining the // Create the generic arguments for the associated type or constant by joining the
// parent arguments (the arguments of the trait) and the own arguments (the ones of // parent arguments (the arguments of the trait) and the own arguments (the ones of
// the associated item itself) and construct an alias type using them. // the associated item itself) and construct an alias type using them.
let alias_ty = candidate.map_bound(|trait_ref| { let alias_term = candidate.map_bound(|trait_ref| {
let ident = Ident::new(assoc_item.name, constraint.ident.span);
let item_segment = hir::PathSegment { let item_segment = hir::PathSegment {
ident, ident: constraint.ident,
hir_id: constraint.hir_id, hir_id: constraint.hir_id,
res: Res::Err, res: Res::Err,
args: Some(constraint.gen_args), args: Some(constraint.gen_args),
@ -426,15 +410,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}); });
// Provide the resolved type of the associated constant to `type_of(AnonConst)`. // Provide the resolved type of the associated constant to `type_of(AnonConst)`.
if let hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(anon_const) } = if let Some(anon_const) = constraint.ct() {
constraint.kind let ty = alias_term
{ .map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args));
let ty = alias_ty.map_bound(|ty| tcx.type_of(ty.def_id).instantiate(tcx, ty.args)); let ty =
let ty = check_assoc_const_binding_type(tcx, assoc_ident, ty, constraint.hir_id); check_assoc_const_binding_type(tcx, constraint.ident, ty, constraint.hir_id);
tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty)); tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty));
} }
alias_ty alias_term
}; };
match constraint.kind { match constraint.kind {

View file

@ -1151,8 +1151,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}; };
let trait_did = bound.def_id(); let trait_did = bound.def_id();
let assoc_ty_did = self.probe_assoc_ty(assoc_ident, hir_ref_id, span, trait_did).unwrap(); let assoc_ty = self
let ty = self.lower_assoc_ty(span, assoc_ty_did, assoc_segment, bound); .probe_assoc_item(assoc_ident, ty::AssocKind::Type, hir_ref_id, span, trait_did)
.expect("failed to find associated type");
let ty = self.lower_assoc_ty(span, assoc_ty.def_id, assoc_segment, bound);
if let Some(variant_def_id) = variant_resolution { if let Some(variant_def_id) = variant_resolution {
tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| { tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| {
@ -1168,7 +1170,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}; };
could_refer_to(DefKind::Variant, variant_def_id, ""); could_refer_to(DefKind::Variant, variant_def_id, "");
could_refer_to(DefKind::AssocTy, assoc_ty_did, " also"); could_refer_to(DefKind::AssocTy, assoc_ty.def_id, " also");
lint.span_suggestion( lint.span_suggestion(
span, span,
@ -1178,7 +1180,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
); );
}); });
} }
Ok((ty, DefKind::AssocTy, assoc_ty_did)) Ok((ty, DefKind::AssocTy, assoc_ty.def_id))
} }
fn probe_inherent_assoc_ty( fn probe_inherent_assoc_ty(
@ -1205,7 +1207,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let candidates: Vec<_> = tcx let candidates: Vec<_> = tcx
.inherent_impls(adt_did)? .inherent_impls(adt_did)?
.iter() .iter()
.filter_map(|&impl_| Some((impl_, self.probe_assoc_ty_unchecked(name, block, impl_)?))) .filter_map(|&impl_| {
let (item, scope) =
self.probe_assoc_item_unchecked(name, ty::AssocKind::Type, block, impl_)?;
Some((impl_, (item.def_id, scope)))
})
.collect(); .collect();
if candidates.is_empty() { if candidates.is_empty() {
@ -1249,7 +1255,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}, },
)?; )?;
self.check_assoc_ty(assoc_item, name, def_scope, block, span); self.check_assoc_item(assoc_item, name, def_scope, block, span);
// FIXME(fmease): Currently creating throwaway `parent_args` to please // FIXME(fmease): Currently creating throwaway `parent_args` to please
// `lower_generic_args_of_assoc_item`. Modify the latter instead (or sth. similar) to // `lower_generic_args_of_assoc_item`. Modify the latter instead (or sth. similar) to
@ -1336,50 +1342,69 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
} }
} }
fn probe_assoc_ty(&self, name: Ident, block: HirId, span: Span, scope: DefId) -> Option<DefId> { /// Given name and kind search for the assoc item in the provided scope and check if it's accessible[^1].
let (item, def_scope) = self.probe_assoc_ty_unchecked(name, block, scope)?; ///
self.check_assoc_ty(item, name, def_scope, block, span); /// [^1]: I.e., accessible in the provided scope wrt. visibility and stability.
fn probe_assoc_item(
&self,
ident: Ident,
kind: ty::AssocKind,
block: HirId,
span: Span,
scope: DefId,
) -> Option<ty::AssocItem> {
let (item, scope) = self.probe_assoc_item_unchecked(ident, kind, block, scope)?;
self.check_assoc_item(item.def_id, ident, scope, block, span);
Some(item) Some(item)
} }
fn probe_assoc_ty_unchecked( /// Given name and kind search for the assoc item in the provided scope
/// *without* checking if it's accessible[^1].
///
/// [^1]: I.e., accessible in the provided scope wrt. visibility and stability.
fn probe_assoc_item_unchecked(
&self, &self,
name: Ident, ident: Ident,
kind: ty::AssocKind,
block: HirId, block: HirId,
scope: DefId, scope: DefId,
) -> Option<(DefId, DefId)> { ) -> Option<(ty::AssocItem, /*scope*/ DefId)> {
let tcx = self.tcx(); let tcx = self.tcx();
let (ident, def_scope) = tcx.adjust_ident_and_get_scope(name, scope, block);
let (ident, def_scope) = tcx.adjust_ident_and_get_scope(ident, scope, block);
// We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()` // We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()`
// instead of calling `filter_by_name_and_kind` which would needlessly normalize the // instead of calling `filter_by_name_and_kind` which would needlessly normalize the
// `ident` again and again. // `ident` again and again.
let item = tcx.associated_items(scope).in_definition_order().find(|i| { let item = tcx
i.kind.namespace() == Namespace::TypeNS .associated_items(scope)
&& i.ident(tcx).normalize_to_macros_2_0() == ident .filter_by_name_unhygienic(ident.name)
})?; .find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == ident)?;
Some((item.def_id, def_scope)) Some((*item, def_scope))
} }
fn check_assoc_ty(&self, item: DefId, name: Ident, def_scope: DefId, block: HirId, span: Span) { /// Check if the given assoc item is accessible in the provided scope wrt. visibility and stability.
fn check_assoc_item(
&self,
item_def_id: DefId,
ident: Ident,
scope: DefId,
block: HirId,
span: Span,
) {
let tcx = self.tcx(); let tcx = self.tcx();
let kind = DefKind::AssocTy;
if !tcx.visibility(item).is_accessible_from(def_scope, tcx) { if !tcx.visibility(item_def_id).is_accessible_from(scope, tcx) {
let kind = tcx.def_kind_descr(kind, item); let reported = tcx.dcx().emit_err(crate::errors::AssocItemIsPrivate {
let msg = format!("{kind} `{name}` is private"); span,
let def_span = tcx.def_span(item); kind: tcx.def_descr(item_def_id),
let reported = tcx name: ident,
.dcx() defined_here_label: tcx.def_span(item_def_id),
.struct_span_err(span, msg) });
.with_code(E0624)
.with_span_label(span, format!("private {kind}"))
.with_span_label(def_span, format!("{kind} defined here"))
.emit();
self.set_tainted_by_errors(reported); self.set_tainted_by_errors(reported);
} }
tcx.check_stability(item, Some(block), span, None);
tcx.check_stability(item_def_id, Some(block), span, None);
} }
fn probe_traits_that_match_assoc_ty( fn probe_traits_that_match_assoc_ty(

View file

@ -2,7 +2,7 @@ error[E0624]: associated type `P` is private
--> $DIR/assoc-inherent-private.rs:10:10 --> $DIR/assoc-inherent-private.rs:10:10
| |
LL | type P = (); LL | type P = ();
| ------ associated type defined here | ------ the associated type is defined here
... ...
LL | type U = m::T::P; LL | type U = m::T::P;
| ^^^^^^^ private associated type | ^^^^^^^ private associated type
@ -11,7 +11,7 @@ error[E0624]: associated type `P` is private
--> $DIR/assoc-inherent-private.rs:21:10 --> $DIR/assoc-inherent-private.rs:21:10
| |
LL | pub(super) type P = bool; LL | pub(super) type P = bool;
| ----------------- associated type defined here | ----------------- the associated type is defined here
... ...
LL | type V = n::n::T::P; LL | type V = n::n::T::P;
| ^^^^^^^^^^ private associated type | ^^^^^^^^^^ private associated type

View file

@ -196,14 +196,17 @@ error[E0624]: associated type `A` is private
--> $DIR/item-privacy.rs:119:12 --> $DIR/item-privacy.rs:119:12
| |
LL | type A = u8; LL | type A = u8;
| ------ associated type defined here | ------ the associated type is defined here
... ...
LL | let _: T::A; LL | let _: T::A;
| ^^^^ private associated type | ^^^^ private associated type
error: associated type `A` is private error[E0624]: associated type `A` is private
--> $DIR/item-privacy.rs:128:9 --> $DIR/item-privacy.rs:128:9
| |
LL | type A = u8;
| ------ the associated type is defined here
...
LL | A = u8, LL | A = u8,
| ^^^^^^ private associated type | ^^^^^^ private associated type