Check associated type bindings for privacy and stability

This commit is contained in:
Vadim Petrochenkov 2017-11-18 18:38:56 +03:00
parent 8dcd26a6df
commit 53779ed5ec
4 changed files with 45 additions and 24 deletions

View File

@ -370,7 +370,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
poly_projections.extend(assoc_bindings.iter().filter_map(|binding| { poly_projections.extend(assoc_bindings.iter().filter_map(|binding| {
// specify type to assert that error was already reported in Err case: // specify type to assert that error was already reported in Err case:
let predicate: Result<_, ErrorReported> = let predicate: Result<_, ErrorReported> =
self.ast_type_binding_to_poly_projection_predicate(poly_trait_ref, binding); self.ast_type_binding_to_poly_projection_predicate(trait_ref.ref_id, poly_trait_ref,
binding);
predicate.ok() // ok to ignore Err() because ErrorReported (see above) predicate.ok() // ok to ignore Err() because ErrorReported (see above)
})); }));
@ -442,6 +443,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
fn ast_type_binding_to_poly_projection_predicate( fn ast_type_binding_to_poly_projection_predicate(
&self, &self,
ref_id: ast::NodeId,
trait_ref: ty::PolyTraitRef<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>,
binding: &ConvertedBinding<'tcx>) binding: &ConvertedBinding<'tcx>)
-> Result<ty::PolyProjectionPredicate<'tcx>, ErrorReported> -> Result<ty::PolyProjectionPredicate<'tcx>, ErrorReported>
@ -494,30 +496,30 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
.emit(); .emit();
} }
// Simple case: X is defined in the current trait. let candidate = if self.trait_defines_associated_type_named(trait_ref.def_id(),
if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) { binding.item_name) {
return Ok(trait_ref.map_bound(|trait_ref| { // Simple case: X is defined in the current trait.
ty::ProjectionPredicate { Ok(trait_ref)
projection_ty: ty::ProjectionTy::from_ref_and_name( } else {
tcx, // Otherwise, we have to walk through the supertraits to find
trait_ref, // those that do.
binding.item_name, let candidates = traits::supertraits(tcx, trait_ref).filter(|r| {
), self.trait_defines_associated_type_named(r.def_id(), binding.item_name)
ty: binding.ty, });
} self.one_bound_for_assoc_type(candidates, &trait_ref.to_string(),
})); binding.item_name, binding.span)
}?;
let (assoc_ident, def_scope) = tcx.adjust(binding.item_name, candidate.def_id(), ref_id);
let assoc_ty = tcx.associated_items(candidate.def_id()).find(|i| {
i.kind == ty::AssociatedKind::Type && i.name.to_ident() == assoc_ident
}).expect("missing associated type");
if !assoc_ty.vis.is_accessible_from(def_scope, tcx) {
let msg = format!("associated type `{}` is private", binding.item_name);
tcx.sess.span_err(binding.span, &msg);
} }
tcx.check_stability(assoc_ty.def_id, ref_id, binding.span);
// Otherwise, we have to walk through the supertraits to find
// those that do.
let candidates =
traits::supertraits(tcx, trait_ref.clone())
.filter(|r| self.trait_defines_associated_type_named(r.def_id(), binding.item_name));
let candidate = self.one_bound_for_assoc_type(candidates,
&trait_ref.to_string(),
binding.item_name,
binding.span)?;
Ok(candidate.map_bound(|trait_ref| { Ok(candidate.map_bound(|trait_ref| {
ty::ProjectionPredicate { ty::ProjectionPredicate {

View File

@ -108,6 +108,11 @@ mod cross_crate {
struct S1<T: TraitWithAssociatedTypes>(T::TypeUnstable); struct S1<T: TraitWithAssociatedTypes>(T::TypeUnstable);
struct S2<T: TraitWithAssociatedTypes>(T::TypeDeprecated); struct S2<T: TraitWithAssociatedTypes>(T::TypeDeprecated);
//~^ WARN use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated': text //~^ WARN use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated': text
type A = TraitWithAssociatedTypes<
TypeUnstable = u8,
TypeDeprecated = u16,
//~^ WARN use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated'
>;
let _ = DeprecatedStruct { //~ WARN use of deprecated item 'lint_stability::DeprecatedStruct' let _ = DeprecatedStruct { //~ WARN use of deprecated item 'lint_stability::DeprecatedStruct'
i: 0 //~ WARN use of deprecated item 'lint_stability::DeprecatedStruct::i' i: 0 //~ WARN use of deprecated item 'lint_stability::DeprecatedStruct::i'

View File

@ -96,6 +96,10 @@ mod cross_crate {
struct S1<T: TraitWithAssociatedTypes>(T::TypeUnstable); struct S1<T: TraitWithAssociatedTypes>(T::TypeUnstable);
//~^ ERROR use of unstable library feature //~^ ERROR use of unstable library feature
struct S2<T: TraitWithAssociatedTypes>(T::TypeDeprecated); struct S2<T: TraitWithAssociatedTypes>(T::TypeDeprecated);
type A = TraitWithAssociatedTypes<
TypeUnstable = u8, //~ ERROR use of unstable library feature
TypeDeprecated = u16,
>;
let _ = DeprecatedStruct { let _ = DeprecatedStruct {
i: 0 i: 0

View File

@ -131,6 +131,16 @@ fn check_assoc_ty<T: assoc_ty::C>() {
let _: T::A; //~ ERROR associated type `A` is private let _: T::A; //~ ERROR associated type `A` is private
let _: T::B; // OK let _: T::B; // OK
let _: T::C; // OK let _: T::C; // OK
// Associated types, bindings
let _: assoc_ty::B<
B = u8, // OK
>;
let _: C<
A = u8, //~ ERROR associated type `A` is private
B = u8, // OK
C = u8, // OK
>;
} }
fn main() {} fn main() {}