]> git.lizzy.rs Git - rust.git/commitdiff
Stop checking the correctness of explicit self twice; instead, just
authorNiko Matsakis <niko@alum.mit.edu>
Sat, 15 Nov 2014 21:58:09 +0000 (16:58 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Tue, 18 Nov 2014 17:32:38 +0000 (12:32 -0500)
use simple pattern matching to take a guess at what the method's self
category is in astconv, and check it more thoroughly later.

src/librustc/middle/typeck/astconv.rs
src/test/compile-fail/explicit-self-lifetime-mismatch.rs
src/test/compile-fail/ufcs-explicit-self-bad.rs

index d85f8eab7cd07dcab60032219b1924fb4893ad8b..90238f7913558ff65df7468c80976a153be8fd96 100644 (file)
@@ -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<self>`. 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,
         }
     }
 }
index d1ae535d8309760adc58eae1e5928e97d0577e61..9b2264b8902a3614b2c2c4441fd0f319fcb7b349 100644 (file)
@@ -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() {}
index b639af617574cc8d874d570658f7c9e183fc5614..8d3610affdfb967aa4f0539b7c5bf6a5c85449f8 100644 (file)
@@ -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<T> {
 
 impl<T> Bar<T> {
     fn foo(self: Bar<int>, x: int) -> int { //~ ERROR mismatched self type
-//~^ ERROR not a valid type for `self`
         x
     }
     fn bar(self: &Bar<uint>, 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<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() {
     let foo = box Foo {
         f: 1,