diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index d85f8eab7cd07dcab60032219b1924fb4893ad8b..90238f7913558ff65df7468c80976a153be8fd96 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -1215,8 +1215,9 @@ fn determine_explicit_self_category<'tcx, AC: AstConv<'tcx>, this: &AC, rscope: &RS, self_info: &SelfInfo) - -> ty::ExplicitSelfCategory { - match self_info.explicit_self.node { + -> ty::ExplicitSelfCategory +{ + return match self_info.explicit_self.node { ast::SelfStatic => ty::StaticExplicitSelfCategory, ast::SelfValue(_) => ty::ByValueExplicitSelfCategory, ast::SelfRegion(ref lifetime, mutability, _) => { @@ -1230,57 +1231,63 @@ fn determine_explicit_self_category<'tcx, AC: AstConv<'tcx>, ast::SelfExplicit(ref ast_type, _) => { let explicit_type = ast_ty_to_ty(this, rscope, &**ast_type); - { - let inference_context = infer::new_infer_ctxt(this.tcx()); - let expected_self = self_info.untransformed_self_ty; - let actual_self = explicit_type; - let result = infer::mk_eqty( - &inference_context, - false, - infer::Misc(self_info.explicit_self.span), - expected_self, - actual_self); - match result { - Ok(_) => { - inference_context.resolve_regions_and_report_errors(); - return ty::ByValueExplicitSelfCategory - } - Err(_) => {} + // We wish to (for now) categorize an explicit self + // declaration like `self: SomeType` into either `self`, + // `&self`, `&mut self`, or `Box`. We do this here + // by some simple pattern matching. A more precise check + // is done later in `check_method_self_type()`. + // + // Examples: + // + // ``` + // impl Foo for &T { + // // Legal declarations: + // fn method1(self: &&T); // ByReferenceExplicitSelfCategory + // fn method2(self: &T); // ByValueExplicitSelfCategory + // fn method3(self: Box<&T>); // ByBoxExplicitSelfCategory + // + // // 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. + + let impl_modifiers = count_modifiers(self_info.untransformed_self_ty); + let method_modifiers = count_modifiers(explicit_type); + + debug!("determine_explicit_self_category(self_info.untransformed_self_ty={} \ + explicit_type={} \ + modifiers=({},{})", + self_info.untransformed_self_ty.repr(this.tcx()), + explicit_type.repr(this.tcx()), + impl_modifiers, + method_modifiers); + + if impl_modifiers >= method_modifiers { + ty::ByValueExplicitSelfCategory + } else { + match ty::get(explicit_type).sty { + ty::ty_rptr(r, mt) => ty::ByReferenceExplicitSelfCategory(r, mt.mutbl), + ty::ty_uniq(_) => ty::ByBoxExplicitSelfCategory, + _ => ty::ByValueExplicitSelfCategory, } } + } + }; - match ty::get(explicit_type).sty { - ty::ty_rptr(region, tm) => { - typeck::require_same_types( - this.tcx(), - None, - false, - self_info.explicit_self.span, - self_info.untransformed_self_ty, - tm.ty, - || "not a valid type for `self`".to_string()); - return ty::ByReferenceExplicitSelfCategory(region, - tm.mutbl) - } - ty::ty_uniq(typ) => { - typeck::require_same_types( - this.tcx(), - None, - false, - 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, } } } diff --git a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs index d1ae535d8309760adc58eae1e5928e97d0577e61..9b2264b8902a3614b2c2c4441fd0f319fcb7b349 100644 --- a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs +++ b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs @@ -14,12 +14,9 @@ struct 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>) {} //~^ 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() {} diff --git a/src/test/compile-fail/ufcs-explicit-self-bad.rs b/src/test/compile-fail/ufcs-explicit-self-bad.rs index b639af617574cc8d874d570658f7c9e183fc5614..8d3610affdfb967aa4f0539b7c5bf6a5c85449f8 100644 --- a/src/test/compile-fail/ufcs-explicit-self-bad.rs +++ b/src/test/compile-fail/ufcs-explicit-self-bad.rs @@ -14,7 +14,6 @@ struct Foo { impl Foo { fn foo(self: int, x: int) -> int { //~ ERROR mismatched self type -//~^ ERROR not a valid type for `self` self.f + x } } @@ -25,15 +24,26 @@ struct Bar { impl Bar { fn foo(self: Bar, x: int) -> int { //~ ERROR mismatched self type -//~^ ERROR not a valid type for `self` x } fn bar(self: &Bar, x: int) -> int { //~ ERROR mismatched self type -//~^ ERROR not a valid type for `self` x } } +trait SomeTrait { + fn dummy1(&self); + fn dummy2(&self); + fn dummy3(&self); +} + +impl<'a, T> SomeTrait for &'a Bar { + fn dummy1(self: &&'a Bar) { } + fn dummy2(self: &Bar) {} //~ ERROR mismatched self type + fn dummy3(self: &&Bar) {} //~ ERROR lifetime mismatch + //~^ ERROR lifetime mismatch +} + fn main() { let foo = box Foo { f: 1,