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:
commit
e7b07ea7a1
6 changed files with 97 additions and 69 deletions
|
@ -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 ->
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue