Skip to content

Commit 3902643

Browse files
committed
move ExplicitSelf to rustc::ty::util, and use it to implement object safety checks
1 parent 0b27dcc commit 3902643

File tree

6 files changed

+71
-54
lines changed

6 files changed

+71
-54
lines changed

src/librustc/traits/object_safety.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use hir::def_id::DefId;
2323
use traits;
2424
use ty::{self, Ty, TyCtxt, TypeFoldable};
2525
use ty::subst::Substs;
26+
use ty::util::ExplicitSelf;
2627
use std::borrow::Cow;
2728
use syntax::ast;
2829

@@ -57,6 +58,8 @@ impl ObjectSafetyViolation {
5758
in its arguments or return type", name).into(),
5859
ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) =>
5960
format!("method `{}` has generic type parameters", name).into(),
61+
ObjectSafetyViolation::Method(name, MethodViolationCode::NonStandardSelfType) =>
62+
format!("method `{}` has a non-standard `self` type. Only `&self`, `&mut self`, and `Box<Self>` are currently supported for trait objects", name).into(),
6063
ObjectSafetyViolation::AssociatedConst(name) =>
6164
format!("the trait cannot contain associated consts like `{}`", name).into(),
6265
}
@@ -74,6 +77,9 @@ pub enum MethodViolationCode {
7477

7578
/// e.g., `fn foo<A>()`
7679
Generic,
80+
81+
/// arbitrary `self` type, e.g. `self: Rc<Self>`
82+
NonStandardSelfType,
7783
}
7884

7985
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
@@ -260,9 +266,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
260266
return Some(MethodViolationCode::StaticMethod);
261267
}
262268

269+
let sig = self.fn_sig(method.def_id);
270+
271+
let self_ty = self.mk_self_type();
272+
let self_arg_ty = sig.skip_binder().inputs()[0];
273+
if let ExplicitSelf::Other = ExplicitSelf::determine(self_arg_ty, |ty| ty == self_ty) {
274+
return Some(MethodViolationCode::NonStandardSelfType);
275+
}
276+
263277
// The `Self` type is erased, so it should not appear in list of
264278
// arguments or return type apart from the receiver.
265-
let ref sig = self.fn_sig(method.def_id);
266279
for input_ty in &sig.skip_binder().inputs()[1..] {
267280
if self.contains_illegal_self_type_reference(trait_def_id, input_ty) {
268281
return Some(MethodViolationCode::ReferencesSelf);

src/librustc/ty/util.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
1313
use hir::def_id::{DefId, LOCAL_CRATE};
1414
use hir::map::DefPathData;
15+
use hir;
1516
use ich::NodeIdHashingMode;
1617
use middle::const_val::ConstVal;
1718
use traits::{self, Reveal};
@@ -1178,6 +1179,56 @@ fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
11781179
layout
11791180
}
11801181

1182+
pub enum ExplicitSelf<'tcx> {
1183+
ByValue,
1184+
ByReference(ty::Region<'tcx>, hir::Mutability),
1185+
ByBox,
1186+
Other
1187+
}
1188+
1189+
impl<'tcx> ExplicitSelf<'tcx> {
1190+
/// Categorizes an explicit self declaration like `self: SomeType`
1191+
/// into either `self`, `&self`, `&mut self`, `Box<self>`, or
1192+
/// `Other`.
1193+
/// This is mainly used to require the arbitrary_self_types feature
1194+
/// in the case of `Other`, to improve error messages in the common cases,
1195+
/// and to make `Other` non-object-safe.
1196+
///
1197+
/// Examples:
1198+
///
1199+
/// ```
1200+
/// impl<'a> Foo for &'a T {
1201+
/// // Legal declarations:
1202+
/// fn method1(self: &&'a T); // ExplicitSelf::ByReference
1203+
/// fn method2(self: &'a T); // ExplicitSelf::ByValue
1204+
/// fn method3(self: Box<&'a T>); // ExplicitSelf::ByBox
1205+
/// fn method4(self: Rc<&'a T>); // ExplicitSelf::Other
1206+
///
1207+
/// // Invalid cases will be caught by `check_method_receiver`:
1208+
/// fn method_err1(self: &'a mut T); // ExplicitSelf::Other
1209+
/// fn method_err2(self: &'static T) // ExplicitSelf::ByValue
1210+
/// fn method_err3(self: &&T) // ExplicitSelf::ByReference
1211+
/// }
1212+
/// ```
1213+
///
1214+
pub fn determine<P>(
1215+
self_arg_ty: Ty<'tcx>,
1216+
is_self_ty: P
1217+
) -> ExplicitSelf<'tcx>
1218+
where
1219+
P: Fn(Ty<'tcx>) -> bool
1220+
{
1221+
use self::ExplicitSelf::*;
1222+
1223+
match self_arg_ty.sty {
1224+
_ if is_self_ty(self_arg_ty) => ByValue,
1225+
ty::TyRef(region, ty::TypeAndMut { ty, mutbl}) if is_self_ty(ty) => ByReference(region, mutbl),
1226+
ty::TyAdt(def, _) if def.is_box() && is_self_ty(self_arg_ty.boxed_ty()) => ByBox,
1227+
_ => Other
1228+
}
1229+
}
1230+
}
1231+
11811232
pub fn provide(providers: &mut ty::maps::Providers) {
11821233
*providers = ty::maps::Providers {
11831234
is_copy_raw,

src/librustc_typeck/astconv.rs

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,53 +1403,3 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> {
14031403
vec
14041404
}
14051405
}
1406-
1407-
pub enum ExplicitSelf<'tcx> {
1408-
ByValue,
1409-
ByReference(ty::Region<'tcx>, hir::Mutability),
1410-
ByBox,
1411-
Other
1412-
}
1413-
1414-
impl<'tcx> ExplicitSelf<'tcx> {
1415-
/// Categorizes an explicit self declaration like `self: SomeType`
1416-
/// into either `self`, `&self`, `&mut self`, `Box<self>`, or
1417-
/// `Other`.
1418-
/// This is mainly used to require the arbitrary_self_types feature
1419-
/// in the case of `Other`, to improve error messages in the common cases,
1420-
/// and to make `Other` non-object-safe.
1421-
///
1422-
/// Examples:
1423-
///
1424-
/// ```
1425-
/// impl<'a> Foo for &'a T {
1426-
/// // Legal declarations:
1427-
/// fn method1(self: &&'a T); // ExplicitSelf::ByReference
1428-
/// fn method2(self: &'a T); // ExplicitSelf::ByValue
1429-
/// fn method3(self: Box<&'a T>); // ExplicitSelf::ByBox
1430-
/// fn method4(self: Rc<&'a T>); // ExplicitSelf::Other
1431-
///
1432-
/// // Invalid cases will be caught by `check_method_receiver`:
1433-
/// fn method_err1(self: &'a mut T); // ExplicitSelf::Other
1434-
/// fn method_err2(self: &'static T) // ExplicitSelf::ByValue
1435-
/// fn method_err3(self: &&T) // ExplicitSelf::ByReference
1436-
/// }
1437-
/// ```
1438-
///
1439-
pub fn determine<'a, 'gcx, P>(
1440-
self_arg_ty: Ty<'tcx>,
1441-
is_self_ty: P
1442-
) -> ExplicitSelf<'tcx>
1443-
where
1444-
P: Fn(Ty<'tcx>) -> bool
1445-
{
1446-
use self::ExplicitSelf::*;
1447-
1448-
match self_arg_ty.sty {
1449-
_ if is_self_ty(self_arg_ty) => ByValue,
1450-
ty::TyRef(region, ty::TypeAndMut { ty, mutbl}) if is_self_ty(ty) => ByReference(region, mutbl),
1451-
ty::TyAdt(def, _) if def.is_box() && is_self_ty(self_arg_ty.boxed_ty()) => ByBox,
1452-
_ => Other
1453-
}
1454-
}
1455-
}

src/librustc_typeck/check/compare_method.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc::infer::{self, InferOk};
1313
use rustc::middle::free_region::FreeRegionMap;
1414
use rustc::middle::region;
1515
use rustc::ty::{self, TyCtxt};
16+
use rustc::ty::util::ExplicitSelf;
1617
use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
1718
use rustc::ty::error::{ExpectedFound, TypeError};
1819
use rustc::ty::subst::{Subst, Substs};
@@ -21,7 +22,6 @@ use rustc::util::common::ErrorReported;
2122
use syntax_pos::Span;
2223

2324
use super::{Inherited, FnCtxt};
24-
use astconv::ExplicitSelf;
2525

2626
/// Checks that a method from an impl conforms to the signature of
2727
/// the same method as declared in the trait.

src/librustc_typeck/check/wfcheck.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use astconv::ExplicitSelf;
1211
use check::{Inherited, FnCtxt};
1312
use constrained_type_params::{identify_constrained_type_params, Parameter};
1413

1514
use hir::def_id::DefId;
1615
use rustc::infer::InferOk;
1716
use rustc::traits::{self, ObligationCauseCode};
1817
use rustc::ty::{self, Ty, TyCtxt};
18+
use rustc::ty::util::ExplicitSelf;
1919
use rustc::util::nodemap::{FxHashSet, FxHashMap};
2020
use rustc::middle::lang_items;
2121

src/test/compile-fail/arbitrary-self-types-not-object-safe.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ impl Bar for usize {
3030
fn make_foo() {
3131
let x = Box::new(5usize) as Box<Foo>;
3232
//~^ ERROR E0038
33-
//~| NOTE the method `foo` has an arbitrary self type
33+
//~| NOTE method `foo` has a non-standard `self` type
34+
//~| NOTE the trait `Foo` cannot be made into an object
35+
//~| ERROR E0038
36+
//~| NOTE method `foo` has a non-standard `self` type
3437
//~| NOTE the trait `Foo` cannot be made into an object
3538
}
3639

0 commit comments

Comments
 (0)