Skip to content

Commit efef81e

Browse files
committed
Stop checking the correctness of explicit self twice; instead, just
use simple pattern matching to take a guess at what the method's self category is in astconv, and check it more thoroughly later.
1 parent c8a94c5 commit efef81e

File tree

3 files changed

+70
-56
lines changed

3 files changed

+70
-56
lines changed

src/librustc/middle/typeck/astconv.rs

+57-50
Original file line numberDiff line numberDiff line change
@@ -1215,8 +1215,9 @@ fn determine_explicit_self_category<'tcx, AC: AstConv<'tcx>,
12151215
this: &AC,
12161216
rscope: &RS,
12171217
self_info: &SelfInfo)
1218-
-> ty::ExplicitSelfCategory {
1219-
match self_info.explicit_self.node {
1218+
-> ty::ExplicitSelfCategory
1219+
{
1220+
return match self_info.explicit_self.node {
12201221
ast::SelfStatic => ty::StaticExplicitSelfCategory,
12211222
ast::SelfValue(_) => ty::ByValueExplicitSelfCategory,
12221223
ast::SelfRegion(ref lifetime, mutability, _) => {
@@ -1230,57 +1231,63 @@ fn determine_explicit_self_category<'tcx, AC: AstConv<'tcx>,
12301231
ast::SelfExplicit(ref ast_type, _) => {
12311232
let explicit_type = ast_ty_to_ty(this, rscope, &**ast_type);
12321233

1233-
{
1234-
let inference_context = infer::new_infer_ctxt(this.tcx());
1235-
let expected_self = self_info.untransformed_self_ty;
1236-
let actual_self = explicit_type;
1237-
let result = infer::mk_eqty(
1238-
&inference_context,
1239-
false,
1240-
infer::Misc(self_info.explicit_self.span),
1241-
expected_self,
1242-
actual_self);
1243-
match result {
1244-
Ok(_) => {
1245-
inference_context.resolve_regions_and_report_errors();
1246-
return ty::ByValueExplicitSelfCategory
1247-
}
1248-
Err(_) => {}
1234+
// We wish to (for now) categorize an explicit self
1235+
// declaration like `self: SomeType` into either `self`,
1236+
// `&self`, `&mut self`, or `Box<self>`. We do this here
1237+
// by some simple pattern matching. A more precise check
1238+
// is done later in `check_method_self_type()`.
1239+
//
1240+
// Examples:
1241+
//
1242+
// ```
1243+
// impl Foo for &T {
1244+
// // Legal declarations:
1245+
// fn method1(self: &&T); // ByReferenceExplicitSelfCategory
1246+
// fn method2(self: &T); // ByValueExplicitSelfCategory
1247+
// fn method3(self: Box<&T>); // ByBoxExplicitSelfCategory
1248+
//
1249+
// // Invalid cases will be caught later by `check_method_self_type`:
1250+
// fn method_err1(self: &mut T); // ByReferenceExplicitSelfCategory
1251+
// }
1252+
// ```
1253+
//
1254+
// To do the check we just count the number of "modifiers"
1255+
// on each type and compare them. If they are the same or
1256+
// the impl has more, we call it "by value". Otherwise, we
1257+
// look at the outermost modifier on the method decl and
1258+
// call it by-ref, by-box as appropriate. For method1, for
1259+
// example, the impl type has one modifier, but the method
1260+
// type has two, so we end up with
1261+
// ByReferenceExplicitSelfCategory.
1262+
1263+
let impl_modifiers = count_modifiers(self_info.untransformed_self_ty);
1264+
let method_modifiers = count_modifiers(explicit_type);
1265+
1266+
debug!("determine_explicit_self_category(self_info.untransformed_self_ty={} \
1267+
explicit_type={} \
1268+
modifiers=({},{})",
1269+
self_info.untransformed_self_ty.repr(this.tcx()),
1270+
explicit_type.repr(this.tcx()),
1271+
impl_modifiers,
1272+
method_modifiers);
1273+
1274+
if impl_modifiers >= method_modifiers {
1275+
ty::ByValueExplicitSelfCategory
1276+
} else {
1277+
match ty::get(explicit_type).sty {
1278+
ty::ty_rptr(r, mt) => ty::ByReferenceExplicitSelfCategory(r, mt.mutbl),
1279+
ty::ty_uniq(_) => ty::ByBoxExplicitSelfCategory,
1280+
_ => ty::ByValueExplicitSelfCategory,
12491281
}
12501282
}
1283+
}
1284+
};
12511285

1252-
match ty::get(explicit_type).sty {
1253-
ty::ty_rptr(region, tm) => {
1254-
typeck::require_same_types(
1255-
this.tcx(),
1256-
None,
1257-
false,
1258-
self_info.explicit_self.span,
1259-
self_info.untransformed_self_ty,
1260-
tm.ty,
1261-
|| "not a valid type for `self`".to_string());
1262-
return ty::ByReferenceExplicitSelfCategory(region,
1263-
tm.mutbl)
1264-
}
1265-
ty::ty_uniq(typ) => {
1266-
typeck::require_same_types(
1267-
this.tcx(),
1268-
None,
1269-
false,
1270-
self_info.explicit_self.span,
1271-
self_info.untransformed_self_ty,
1272-
typ,
1273-
|| "not a valid type for `self`".to_string());
1274-
return ty::ByBoxExplicitSelfCategory
1275-
}
1276-
_ => {
1277-
this.tcx()
1278-
.sess
1279-
.span_err(self_info.explicit_self.span,
1280-
"not a valid type for `self`");
1281-
return ty::ByValueExplicitSelfCategory
1282-
}
1283-
}
1286+
fn count_modifiers(ty: ty::t) -> uint {
1287+
match ty::get(ty).sty {
1288+
ty::ty_rptr(_, mt) => count_modifiers(mt.ty) + 1,
1289+
ty::ty_uniq(t) => count_modifiers(t) + 1,
1290+
_ => 0,
12841291
}
12851292
}
12861293
}

src/test/compile-fail/explicit-self-lifetime-mismatch.rs

-3
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,9 @@ struct Foo<'a,'b> {
1414
}
1515

1616
impl<'a,'b> Foo<'a,'b> {
17-
// The number of errors is related to the way invariance works.
1817
fn bar(self: Foo<'b,'a>) {}
1918
//~^ ERROR mismatched types: expected `Foo<'a, 'b>`, found `Foo<'b, 'a>`
2019
//~^^ ERROR mismatched types: expected `Foo<'a, 'b>`, found `Foo<'b, 'a>`
21-
//~^^^ ERROR mismatched types: expected `Foo<'b, 'a>`, found `Foo<'a, 'b>`
22-
//~^^^^ ERROR mismatched types: expected `Foo<'b, 'a>`, found `Foo<'a, 'b>`
2320
}
2421

2522
fn main() {}

src/test/compile-fail/ufcs-explicit-self-bad.rs

+13-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ struct Foo {
1414

1515
impl Foo {
1616
fn foo(self: int, x: int) -> int { //~ ERROR mismatched self type
17-
//~^ ERROR not a valid type for `self`
1817
self.f + x
1918
}
2019
}
@@ -25,15 +24,26 @@ struct Bar<T> {
2524

2625
impl<T> Bar<T> {
2726
fn foo(self: Bar<int>, x: int) -> int { //~ ERROR mismatched self type
28-
//~^ ERROR not a valid type for `self`
2927
x
3028
}
3129
fn bar(self: &Bar<uint>, x: int) -> int { //~ ERROR mismatched self type
32-
//~^ ERROR not a valid type for `self`
3330
x
3431
}
3532
}
3633

34+
trait SomeTrait {
35+
fn dummy1(&self);
36+
fn dummy2(&self);
37+
fn dummy3(&self);
38+
}
39+
40+
impl<'a, T> SomeTrait for &'a Bar<T> {
41+
fn dummy1(self: &&'a Bar<T>) { }
42+
fn dummy2(self: &Bar<T>) {} //~ ERROR mismatched self type
43+
fn dummy3(self: &&Bar<T>) {} //~ ERROR lifetime mismatch
44+
//~^ ERROR lifetime mismatch
45+
}
46+
3747
fn main() {
3848
let foo = box Foo {
3949
f: 1,

0 commit comments

Comments
 (0)