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:
parent
c8a94c5dfa
commit
efef81e966
3 changed files with 70 additions and 56 deletions
|
@ -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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue