Rollup merge of #104348 - fmease:iat-vis-stab, r=cjgillot
Respect visibility & stability of inherent associated types As discussed in #103621, this probably won't be the final location of the code that resolves inherent associated types. Still, I think it's valuable to push correctness fixes for this feature (in regards to visibility and stability). Let me know if I should write a translatable diagnostic instead and if I should move the tests to `privacy/` and `stability-attribute/` respectively. Fixes #104243. ````@rustbot```` label A-visibility F-inherent_associated_types r? ````@cjgillot```` (since you reviewed #103621, feel free to reroll though)
This commit is contained in:
commit
3a8cacd7fb
@ -1917,17 +1917,13 @@ pub fn associated_path_to_ty(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// see if we can satisfy using an inherent associated type
|
// see if we can satisfy using an inherent associated type
|
||||||
for impl_ in tcx.inherent_impls(adt_def.did()) {
|
for &impl_ in tcx.inherent_impls(adt_def.did()) {
|
||||||
let assoc_ty = tcx.associated_items(impl_).find_by_name_and_kind(
|
let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, impl_) else {
|
||||||
tcx,
|
continue;
|
||||||
assoc_ident,
|
};
|
||||||
ty::AssocKind::Type,
|
// FIXME(inherent_associated_types): This does not substitute parameters.
|
||||||
*impl_,
|
let ty = tcx.type_of(assoc_ty_did);
|
||||||
);
|
return Ok((ty, DefKind::AssocTy, assoc_ty_did));
|
||||||
if let Some(assoc_ty) = assoc_ty {
|
|
||||||
let ty = tcx.type_of(assoc_ty.def_id);
|
|
||||||
return Ok((ty, DefKind::AssocTy, assoc_ty.def_id));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2014,37 +2010,17 @@ pub fn associated_path_to_ty(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let trait_did = bound.def_id();
|
let trait_did = bound.def_id();
|
||||||
let (assoc_ident, def_scope) =
|
let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, trait_did) else {
|
||||||
tcx.adjust_ident_and_get_scope(assoc_ident, trait_did, hir_ref_id);
|
// Assume that if it's not matched, there must be a const defined with the same name
|
||||||
|
// but it was used in a type position.
|
||||||
// We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
|
|
||||||
// of calling `filter_by_name_and_kind`.
|
|
||||||
let item = tcx.associated_items(trait_did).in_definition_order().find(|i| {
|
|
||||||
i.kind.namespace() == Namespace::TypeNS
|
|
||||||
&& i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
|
|
||||||
});
|
|
||||||
// Assume that if it's not matched, there must be a const defined with the same name
|
|
||||||
// but it was used in a type position.
|
|
||||||
let Some(item) = item else {
|
|
||||||
let msg = format!("found associated const `{assoc_ident}` when type was expected");
|
let msg = format!("found associated const `{assoc_ident}` when type was expected");
|
||||||
let guar = tcx.sess.struct_span_err(span, &msg).emit();
|
let guar = tcx.sess.struct_span_err(span, &msg).emit();
|
||||||
return Err(guar);
|
return Err(guar);
|
||||||
};
|
};
|
||||||
|
|
||||||
let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, assoc_segment, bound);
|
let ty = self.projected_ty_from_poly_trait_ref(span, assoc_ty_did, assoc_segment, bound);
|
||||||
let ty = self.normalize_ty(span, ty);
|
let ty = self.normalize_ty(span, ty);
|
||||||
|
|
||||||
let kind = DefKind::AssocTy;
|
|
||||||
if !item.visibility(tcx).is_accessible_from(def_scope, tcx) {
|
|
||||||
let kind = kind.descr(item.def_id);
|
|
||||||
let msg = format!("{} `{}` is private", kind, assoc_ident);
|
|
||||||
tcx.sess
|
|
||||||
.struct_span_err(span, &msg)
|
|
||||||
.span_label(span, &format!("private {}", kind))
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
tcx.check_stability(item.def_id, Some(hir_ref_id), span, None);
|
|
||||||
|
|
||||||
if let Some(variant_def_id) = variant_resolution {
|
if let Some(variant_def_id) = variant_resolution {
|
||||||
tcx.struct_span_lint_hir(
|
tcx.struct_span_lint_hir(
|
||||||
AMBIGUOUS_ASSOCIATED_ITEMS,
|
AMBIGUOUS_ASSOCIATED_ITEMS,
|
||||||
@ -2063,7 +2039,7 @@ pub fn associated_path_to_ty(
|
|||||||
};
|
};
|
||||||
|
|
||||||
could_refer_to(DefKind::Variant, variant_def_id, "");
|
could_refer_to(DefKind::Variant, variant_def_id, "");
|
||||||
could_refer_to(kind, item.def_id, " also");
|
could_refer_to(DefKind::AssocTy, assoc_ty_did, " also");
|
||||||
|
|
||||||
lint.span_suggestion(
|
lint.span_suggestion(
|
||||||
span,
|
span,
|
||||||
@ -2076,7 +2052,40 @@ pub fn associated_path_to_ty(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ok((ty, kind, item.def_id))
|
Ok((ty, DefKind::AssocTy, assoc_ty_did))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lookup_assoc_ty(
|
||||||
|
&self,
|
||||||
|
ident: Ident,
|
||||||
|
block: hir::HirId,
|
||||||
|
span: Span,
|
||||||
|
scope: DefId,
|
||||||
|
) -> Option<DefId> {
|
||||||
|
let tcx = self.tcx();
|
||||||
|
let (ident, def_scope) = tcx.adjust_ident_and_get_scope(ident, scope, block);
|
||||||
|
|
||||||
|
// We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
|
||||||
|
// of calling `find_by_name_and_kind`.
|
||||||
|
let item = tcx.associated_items(scope).in_definition_order().find(|i| {
|
||||||
|
i.kind.namespace() == Namespace::TypeNS
|
||||||
|
&& i.ident(tcx).normalize_to_macros_2_0() == ident
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let kind = DefKind::AssocTy;
|
||||||
|
if !item.visibility(tcx).is_accessible_from(def_scope, tcx) {
|
||||||
|
let kind = kind.descr(item.def_id);
|
||||||
|
let msg = format!("{kind} `{ident}` is private");
|
||||||
|
let def_span = self.tcx().def_span(item.def_id);
|
||||||
|
tcx.sess
|
||||||
|
.struct_span_err_with_code(span, &msg, rustc_errors::error_code!(E0624))
|
||||||
|
.span_label(span, &format!("private {kind}"))
|
||||||
|
.span_label(def_span, &format!("{kind} defined here"))
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
tcx.check_stability(item.def_id, Some(block), span, None);
|
||||||
|
|
||||||
|
Some(item.def_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn qpath_to_ty(
|
fn qpath_to_ty(
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
#![feature(inherent_associated_types)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
mod m {
|
||||||
|
pub struct T;
|
||||||
|
impl T {
|
||||||
|
type P = ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type U = m::T::P; //~ ERROR associated type `P` is private
|
||||||
|
|
||||||
|
mod n {
|
||||||
|
pub mod n {
|
||||||
|
pub struct T;
|
||||||
|
impl T {
|
||||||
|
pub(super) type P = bool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type U = n::T::P;
|
||||||
|
}
|
||||||
|
type V = n::n::T::P; //~ ERROR associated type `P` is private
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,21 @@
|
|||||||
|
error[E0624]: associated type `P` is private
|
||||||
|
--> $DIR/assoc-inherent-private.rs:10:10
|
||||||
|
|
|
||||||
|
LL | type P = ();
|
||||||
|
| ------ associated type defined here
|
||||||
|
...
|
||||||
|
LL | type U = m::T::P;
|
||||||
|
| ^^^^^^^ private associated type
|
||||||
|
|
||||||
|
error[E0624]: associated type `P` is private
|
||||||
|
--> $DIR/assoc-inherent-private.rs:21:10
|
||||||
|
|
|
||||||
|
LL | pub(super) type P = bool;
|
||||||
|
| ----------------- associated type defined here
|
||||||
|
...
|
||||||
|
LL | type V = n::n::T::P;
|
||||||
|
| ^^^^^^^^^^ private associated type
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0624`.
|
@ -0,0 +1,6 @@
|
|||||||
|
// aux-crate:aux=assoc-inherent-unstable.rs
|
||||||
|
// edition: 2021
|
||||||
|
|
||||||
|
type Data = aux::Owner::Data; //~ ERROR use of unstable library feature 'data'
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,11 @@
|
|||||||
|
error[E0658]: use of unstable library feature 'data'
|
||||||
|
--> $DIR/assoc-inherent-unstable.rs:4:13
|
||||||
|
|
|
||||||
|
LL | type Data = aux::Owner::Data;
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: add `#![feature(data)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
@ -0,0 +1,11 @@
|
|||||||
|
#![feature(staged_api)]
|
||||||
|
#![feature(inherent_associated_types)]
|
||||||
|
#![stable(feature = "main", since = "1.0.0")]
|
||||||
|
|
||||||
|
#[stable(feature = "main", since = "1.0.0")]
|
||||||
|
pub struct Owner;
|
||||||
|
|
||||||
|
impl Owner {
|
||||||
|
#[unstable(feature = "data", issue = "none")]
|
||||||
|
pub type Data = ();
|
||||||
|
}
|
@ -162,9 +162,12 @@ error[E0223]: ambiguous associated type
|
|||||||
LL | let _: S::C;
|
LL | let _: S::C;
|
||||||
| ^^^^ help: use fully-qualified syntax: `<S as Trait>::C`
|
| ^^^^ help: use fully-qualified syntax: `<S as Trait>::C`
|
||||||
|
|
||||||
error: associated type `A` is private
|
error[E0624]: associated type `A` is private
|
||||||
--> $DIR/item-privacy.rs:119:12
|
--> $DIR/item-privacy.rs:119:12
|
||||||
|
|
|
|
||||||
|
LL | type A = u8;
|
||||||
|
| ------ associated type defined here
|
||||||
|
...
|
||||||
LL | let _: T::A;
|
LL | let _: T::A;
|
||||||
| ^^^^ private associated type
|
| ^^^^ private associated type
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user