1
Fork 0

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.
This commit is contained in:
Niko Matsakis 2014-11-15 16:58:09 -05:00
parent c8a94c5dfa
commit efef81e966
3 changed files with 70 additions and 56 deletions

View file

@ -1215,8 +1215,9 @@ fn determine_explicit_self_category<'tcx, AC: AstConv<'tcx>,
this: &AC, this: &AC,
rscope: &RS, rscope: &RS,
self_info: &SelfInfo) self_info: &SelfInfo)
-> ty::ExplicitSelfCategory { -> ty::ExplicitSelfCategory
match self_info.explicit_self.node { {
return match self_info.explicit_self.node {
ast::SelfStatic => ty::StaticExplicitSelfCategory, ast::SelfStatic => ty::StaticExplicitSelfCategory,
ast::SelfValue(_) => ty::ByValueExplicitSelfCategory, ast::SelfValue(_) => ty::ByValueExplicitSelfCategory,
ast::SelfRegion(ref lifetime, mutability, _) => { ast::SelfRegion(ref lifetime, mutability, _) => {
@ -1230,58 +1231,64 @@ fn determine_explicit_self_category<'tcx, AC: AstConv<'tcx>,
ast::SelfExplicit(ref ast_type, _) => { ast::SelfExplicit(ref ast_type, _) => {
let explicit_type = ast_ty_to_ty(this, rscope, &**ast_type); let explicit_type = ast_ty_to_ty(this, rscope, &**ast_type);
{ // We wish to (for now) categorize an explicit self
let inference_context = infer::new_infer_ctxt(this.tcx()); // declaration like `self: SomeType` into either `self`,
let expected_self = self_info.untransformed_self_ty; // `&self`, `&mut self`, or `Box<self>`. We do this here
let actual_self = explicit_type; // by some simple pattern matching. A more precise check
let result = infer::mk_eqty( // is done later in `check_method_self_type()`.
&inference_context, //
false, // Examples:
infer::Misc(self_info.explicit_self.span), //
expected_self, // ```
actual_self); // impl Foo for &T {
match result { // // Legal declarations:
Ok(_) => { // fn method1(self: &&T); // ByReferenceExplicitSelfCategory
inference_context.resolve_regions_and_report_errors(); // fn method2(self: &T); // ByValueExplicitSelfCategory
return ty::ByValueExplicitSelfCategory // fn method3(self: Box<&T>); // ByBoxExplicitSelfCategory
} //
Err(_) => {} // // Invalid cases will be caught later by `check_method_self_type`:
} // fn method_err1(self: &mut T); // ByReferenceExplicitSelfCategory
} // }
// ```
//
// To do the check we just count the number of "modifiers"
// on each type and compare them. If they are the same or
// the impl has more, we call it "by value". Otherwise, we
// look at the outermost modifier on the method decl and
// call it by-ref, by-box as appropriate. For method1, for
// example, the impl type has one modifier, but the method
// type has two, so we end up with
// ByReferenceExplicitSelfCategory.
match ty::get(explicit_type).sty { let impl_modifiers = count_modifiers(self_info.untransformed_self_ty);
ty::ty_rptr(region, tm) => { let method_modifiers = count_modifiers(explicit_type);
typeck::require_same_types(
this.tcx(), debug!("determine_explicit_self_category(self_info.untransformed_self_ty={} \
None, explicit_type={} \
false, modifiers=({},{})",
self_info.explicit_self.span, self_info.untransformed_self_ty.repr(this.tcx()),
self_info.untransformed_self_ty, explicit_type.repr(this.tcx()),
tm.ty, impl_modifiers,
|| "not a valid type for `self`".to_string()); method_modifiers);
return ty::ByReferenceExplicitSelfCategory(region,
tm.mutbl) if impl_modifiers >= method_modifiers {
} ty::ByValueExplicitSelfCategory
ty::ty_uniq(typ) => { } else {
typeck::require_same_types( match ty::get(explicit_type).sty {
this.tcx(), ty::ty_rptr(r, mt) => ty::ByReferenceExplicitSelfCategory(r, mt.mutbl),
None, ty::ty_uniq(_) => ty::ByBoxExplicitSelfCategory,
false, _ => ty::ByValueExplicitSelfCategory,
self_info.explicit_self.span,
self_info.untransformed_self_ty,
typ,
|| "not a valid type for `self`".to_string());
return ty::ByBoxExplicitSelfCategory
}
_ => {
this.tcx()
.sess
.span_err(self_info.explicit_self.span,
"not a valid type for `self`");
return ty::ByValueExplicitSelfCategory
} }
} }
} }
};
fn count_modifiers(ty: ty::t) -> uint {
match ty::get(ty).sty {
ty::ty_rptr(_, mt) => count_modifiers(mt.ty) + 1,
ty::ty_uniq(t) => count_modifiers(t) + 1,
_ => 0,
}
} }
} }

View file

@ -14,12 +14,9 @@ struct Foo<'a,'b> {
} }
impl<'a,'b> Foo<'a,'b> { impl<'a,'b> Foo<'a,'b> {
// The number of errors is related to the way invariance works.
fn bar(self: Foo<'b,'a>) {} fn bar(self: Foo<'b,'a>) {}
//~^ ERROR mismatched types: expected `Foo<'a, 'b>`, found `Foo<'b, 'a>` //~^ ERROR mismatched types: expected `Foo<'a, 'b>`, found `Foo<'b, 'a>`
//~^^ ERROR mismatched types: expected `Foo<'a, 'b>`, found `Foo<'b, 'a>` //~^^ ERROR mismatched types: expected `Foo<'a, 'b>`, found `Foo<'b, 'a>`
//~^^^ ERROR mismatched types: expected `Foo<'b, 'a>`, found `Foo<'a, 'b>`
//~^^^^ ERROR mismatched types: expected `Foo<'b, 'a>`, found `Foo<'a, 'b>`
} }
fn main() {} fn main() {}

View file

@ -14,7 +14,6 @@ struct Foo {
impl Foo { impl Foo {
fn foo(self: int, x: int) -> int { //~ ERROR mismatched self type fn foo(self: int, x: int) -> int { //~ ERROR mismatched self type
//~^ ERROR not a valid type for `self`
self.f + x self.f + x
} }
} }
@ -25,15 +24,26 @@ struct Bar<T> {
impl<T> Bar<T> { impl<T> Bar<T> {
fn foo(self: Bar<int>, x: int) -> int { //~ ERROR mismatched self type fn foo(self: Bar<int>, x: int) -> int { //~ ERROR mismatched self type
//~^ ERROR not a valid type for `self`
x x
} }
fn bar(self: &Bar<uint>, x: int) -> int { //~ ERROR mismatched self type fn bar(self: &Bar<uint>, x: int) -> int { //~ ERROR mismatched self type
//~^ ERROR not a valid type for `self`
x x
} }
} }
trait SomeTrait {
fn dummy1(&self);
fn dummy2(&self);
fn dummy3(&self);
}
impl<'a, T> SomeTrait for &'a Bar<T> {
fn dummy1(self: &&'a Bar<T>) { }
fn dummy2(self: &Bar<T>) {} //~ ERROR mismatched self type
fn dummy3(self: &&Bar<T>) {} //~ ERROR lifetime mismatch
//~^ ERROR lifetime mismatch
}
fn main() { fn main() {
let foo = box Foo { let foo = box Foo {
f: 1, f: 1,