move ExplicitSelf to rustc::ty::util, and use it to implement object safety checks
This commit is contained in:
parent
0b27dcc665
commit
3902643c27
@ -23,6 +23,7 @@ use hir::def_id::DefId;
|
||||
use traits;
|
||||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use ty::subst::Substs;
|
||||
use ty::util::ExplicitSelf;
|
||||
use std::borrow::Cow;
|
||||
use syntax::ast;
|
||||
|
||||
@ -57,6 +58,8 @@ impl ObjectSafetyViolation {
|
||||
in its arguments or return type", name).into(),
|
||||
ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) =>
|
||||
format!("method `{}` has generic type parameters", name).into(),
|
||||
ObjectSafetyViolation::Method(name, MethodViolationCode::NonStandardSelfType) =>
|
||||
format!("method `{}` has a non-standard `self` type. Only `&self`, `&mut self`, and `Box<Self>` are currently supported for trait objects", name).into(),
|
||||
ObjectSafetyViolation::AssociatedConst(name) =>
|
||||
format!("the trait cannot contain associated consts like `{}`", name).into(),
|
||||
}
|
||||
@ -74,6 +77,9 @@ pub enum MethodViolationCode {
|
||||
|
||||
/// e.g., `fn foo<A>()`
|
||||
Generic,
|
||||
|
||||
/// arbitrary `self` type, e.g. `self: Rc<Self>`
|
||||
NonStandardSelfType,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
@ -260,9 +266,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
return Some(MethodViolationCode::StaticMethod);
|
||||
}
|
||||
|
||||
let sig = self.fn_sig(method.def_id);
|
||||
|
||||
let self_ty = self.mk_self_type();
|
||||
let self_arg_ty = sig.skip_binder().inputs()[0];
|
||||
if let ExplicitSelf::Other = ExplicitSelf::determine(self_arg_ty, |ty| ty == self_ty) {
|
||||
return Some(MethodViolationCode::NonStandardSelfType);
|
||||
}
|
||||
|
||||
// The `Self` type is erased, so it should not appear in list of
|
||||
// arguments or return type apart from the receiver.
|
||||
let ref sig = self.fn_sig(method.def_id);
|
||||
for input_ty in &sig.skip_binder().inputs()[1..] {
|
||||
if self.contains_illegal_self_type_reference(trait_def_id, input_ty) {
|
||||
return Some(MethodViolationCode::ReferencesSelf);
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
use hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use hir::map::DefPathData;
|
||||
use hir;
|
||||
use ich::NodeIdHashingMode;
|
||||
use middle::const_val::ConstVal;
|
||||
use traits::{self, Reveal};
|
||||
@ -1178,6 +1179,56 @@ fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
layout
|
||||
}
|
||||
|
||||
pub enum ExplicitSelf<'tcx> {
|
||||
ByValue,
|
||||
ByReference(ty::Region<'tcx>, hir::Mutability),
|
||||
ByBox,
|
||||
Other
|
||||
}
|
||||
|
||||
impl<'tcx> ExplicitSelf<'tcx> {
|
||||
/// Categorizes an explicit self declaration like `self: SomeType`
|
||||
/// into either `self`, `&self`, `&mut self`, `Box<self>`, or
|
||||
/// `Other`.
|
||||
/// This is mainly used to require the arbitrary_self_types feature
|
||||
/// in the case of `Other`, to improve error messages in the common cases,
|
||||
/// and to make `Other` non-object-safe.
|
||||
///
|
||||
/// Examples:
|
||||
///
|
||||
/// ```
|
||||
/// impl<'a> Foo for &'a T {
|
||||
/// // Legal declarations:
|
||||
/// fn method1(self: &&'a T); // ExplicitSelf::ByReference
|
||||
/// fn method2(self: &'a T); // ExplicitSelf::ByValue
|
||||
/// fn method3(self: Box<&'a T>); // ExplicitSelf::ByBox
|
||||
/// fn method4(self: Rc<&'a T>); // ExplicitSelf::Other
|
||||
///
|
||||
/// // Invalid cases will be caught by `check_method_receiver`:
|
||||
/// fn method_err1(self: &'a mut T); // ExplicitSelf::Other
|
||||
/// fn method_err2(self: &'static T) // ExplicitSelf::ByValue
|
||||
/// fn method_err3(self: &&T) // ExplicitSelf::ByReference
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
pub fn determine<P>(
|
||||
self_arg_ty: Ty<'tcx>,
|
||||
is_self_ty: P
|
||||
) -> ExplicitSelf<'tcx>
|
||||
where
|
||||
P: Fn(Ty<'tcx>) -> bool
|
||||
{
|
||||
use self::ExplicitSelf::*;
|
||||
|
||||
match self_arg_ty.sty {
|
||||
_ if is_self_ty(self_arg_ty) => ByValue,
|
||||
ty::TyRef(region, ty::TypeAndMut { ty, mutbl}) if is_self_ty(ty) => ByReference(region, mutbl),
|
||||
ty::TyAdt(def, _) if def.is_box() && is_self_ty(self_arg_ty.boxed_ty()) => ByBox,
|
||||
_ => Other
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut ty::maps::Providers) {
|
||||
*providers = ty::maps::Providers {
|
||||
is_copy_raw,
|
||||
|
@ -1403,53 +1403,3 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> {
|
||||
vec
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ExplicitSelf<'tcx> {
|
||||
ByValue,
|
||||
ByReference(ty::Region<'tcx>, hir::Mutability),
|
||||
ByBox,
|
||||
Other
|
||||
}
|
||||
|
||||
impl<'tcx> ExplicitSelf<'tcx> {
|
||||
/// Categorizes an explicit self declaration like `self: SomeType`
|
||||
/// into either `self`, `&self`, `&mut self`, `Box<self>`, or
|
||||
/// `Other`.
|
||||
/// This is mainly used to require the arbitrary_self_types feature
|
||||
/// in the case of `Other`, to improve error messages in the common cases,
|
||||
/// and to make `Other` non-object-safe.
|
||||
///
|
||||
/// Examples:
|
||||
///
|
||||
/// ```
|
||||
/// impl<'a> Foo for &'a T {
|
||||
/// // Legal declarations:
|
||||
/// fn method1(self: &&'a T); // ExplicitSelf::ByReference
|
||||
/// fn method2(self: &'a T); // ExplicitSelf::ByValue
|
||||
/// fn method3(self: Box<&'a T>); // ExplicitSelf::ByBox
|
||||
/// fn method4(self: Rc<&'a T>); // ExplicitSelf::Other
|
||||
///
|
||||
/// // Invalid cases will be caught by `check_method_receiver`:
|
||||
/// fn method_err1(self: &'a mut T); // ExplicitSelf::Other
|
||||
/// fn method_err2(self: &'static T) // ExplicitSelf::ByValue
|
||||
/// fn method_err3(self: &&T) // ExplicitSelf::ByReference
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
pub fn determine<'a, 'gcx, P>(
|
||||
self_arg_ty: Ty<'tcx>,
|
||||
is_self_ty: P
|
||||
) -> ExplicitSelf<'tcx>
|
||||
where
|
||||
P: Fn(Ty<'tcx>) -> bool
|
||||
{
|
||||
use self::ExplicitSelf::*;
|
||||
|
||||
match self_arg_ty.sty {
|
||||
_ if is_self_ty(self_arg_ty) => ByValue,
|
||||
ty::TyRef(region, ty::TypeAndMut { ty, mutbl}) if is_self_ty(ty) => ByReference(region, mutbl),
|
||||
ty::TyAdt(def, _) if def.is_box() && is_self_ty(self_arg_ty.boxed_ty()) => ByBox,
|
||||
_ => Other
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ use rustc::infer::{self, InferOk};
|
||||
use rustc::middle::free_region::FreeRegionMap;
|
||||
use rustc::middle::region;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::ty::util::ExplicitSelf;
|
||||
use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
|
||||
use rustc::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc::ty::subst::{Subst, Substs};
|
||||
@ -21,7 +22,6 @@ use rustc::util::common::ErrorReported;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use super::{Inherited, FnCtxt};
|
||||
use astconv::ExplicitSelf;
|
||||
|
||||
/// Checks that a method from an impl conforms to the signature of
|
||||
/// the same method as declared in the trait.
|
||||
|
@ -8,7 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use astconv::ExplicitSelf;
|
||||
use check::{Inherited, FnCtxt};
|
||||
use constrained_type_params::{identify_constrained_type_params, Parameter};
|
||||
|
||||
@ -16,6 +15,7 @@ use hir::def_id::DefId;
|
||||
use rustc::infer::InferOk;
|
||||
use rustc::traits::{self, ObligationCauseCode};
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::ty::util::ExplicitSelf;
|
||||
use rustc::util::nodemap::{FxHashSet, FxHashMap};
|
||||
use rustc::middle::lang_items;
|
||||
|
||||
|
@ -30,7 +30,10 @@ impl Bar for usize {
|
||||
fn make_foo() {
|
||||
let x = Box::new(5usize) as Box<Foo>;
|
||||
//~^ ERROR E0038
|
||||
//~| NOTE the method `foo` has an arbitrary self type
|
||||
//~| NOTE method `foo` has a non-standard `self` type
|
||||
//~| NOTE the trait `Foo` cannot be made into an object
|
||||
//~| ERROR E0038
|
||||
//~| NOTE method `foo` has a non-standard `self` type
|
||||
//~| NOTE the trait `Foo` cannot be made into an object
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user