1
Fork 0

Cleanup: HIR ty lowering: Consolidate assoc item access checking

This commit is contained in:
León Orell Valerian Liehr 2024-06-04 16:47:23 +02:00
parent 9f2d0b3490
commit c59a2b2746
No known key found for this signature in database
GPG key ID: D17A07215F68E713
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

@ -292,30 +292,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)
@ -406,10 +391,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),
@ -428,15 +412,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

@ -1166,8 +1166,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| {
@ -1183,7 +1185,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,
@ -1193,7 +1195,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(
@ -1220,7 +1222,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() {
@ -1264,7 +1270,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
@ -1351,50 +1357,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

@ -195,14 +195,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