]> git.lizzy.rs Git - rust.git/commitdiff
Make destructuring trait reference work
authorEdward Wang <edward.yu.wang@gmail.com>
Sat, 21 Jun 2014 20:03:15 +0000 (04:03 +0800)
committerEdward Wang <edward.yu.wang@gmail.com>
Sat, 21 Jun 2014 20:03:15 +0000 (04:03 +0800)
Closes #15031.

src/librustc/middle/typeck/check/_match.rs
src/test/compile-fail/destructure-trait-ref.rs [new file with mode: 0644]
src/test/compile-fail/issue-4972.rs

index e198653165a61a5e1216ae67cd66ee83a7e9e766..fd89423f304cac70a167dfd8f31c49ae9c0658a0 100644 (file)
@@ -726,22 +726,38 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
 }
 
 // Helper function to check gc, box and & patterns
-pub fn check_pointer_pat(pcx: &pat_ctxt,
-                         pointer_kind: PointerKind,
-                         inner: &ast::Pat,
-                         pat_id: ast::NodeId,
-                         span: Span,
-                         expected: ty::t) {
+fn check_pointer_pat(pcx: &pat_ctxt,
+                     pointer_kind: PointerKind,
+                     inner: &ast::Pat,
+                     pat_id: ast::NodeId,
+                     span: Span,
+                     expected: ty::t) {
     let fcx = pcx.fcx;
+    let tcx = fcx.ccx.tcx;
     let check_inner: |ty::t| = |e_inner| {
-        check_pat(pcx, inner, e_inner);
-        fcx.write_ty(pat_id, expected);
+        match ty::get(e_inner).sty {
+            ty::ty_trait(_) if pat_is_binding(&tcx.def_map, inner) => {
+                // This is "x = SomeTrait" being reduced from
+                // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
+                check_pat(pcx, inner, ty::mk_err());
+                tcx.sess.span_err(
+                    span,
+                    format!("type `{}` cannot be dereferenced",
+                            fcx.infcx().ty_to_str(expected)).as_slice());
+                fcx.write_error(pat_id);
+            }
+            _ => {
+                check_pat(pcx, inner, e_inner);
+                fcx.write_ty(pat_id, expected);
+            }
+        }
     };
+
     match *structure_of(fcx, span, expected) {
-        ty::ty_uniq(e_inner) if pointer_kind == Send && !ty::type_is_trait(e_inner) => {
+        ty::ty_uniq(e_inner) if pointer_kind == Send => {
             check_inner(e_inner);
         }
-        ty::ty_rptr(_, e_inner) if pointer_kind == Borrowed && !ty::type_is_trait(e_inner.ty) => {
+        ty::ty_rptr(_, e_inner) if pointer_kind == Borrowed => {
             check_inner(e_inner.ty);
         }
         _ => {
diff --git a/src/test/compile-fail/destructure-trait-ref.rs b/src/test/compile-fail/destructure-trait-ref.rs
new file mode 100644 (file)
index 0000000..671bf45
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// The regression test for #15031 to make sure destructuring trait
+// reference work properly.
+
+trait T {}
+impl T for int {}
+
+fn main() {
+    // For an expression of the form:
+    //
+    //      let &...&x = &..&SomeTrait;
+    //
+    // Say we have n `&` at the left hand and m `&` right hand, then:
+    // if n < m, we are golden;
+    // if n == m, it's a derefing non-derefable type error;
+    // if n > m, it's a type mismatch error.
+
+    // n < m
+    let &x = &(&1 as &T);
+    let &x = &&(&1 as &T);
+    let &&x = &&(&1 as &T);
+
+    // n == m
+    let &x = &1 as &T;      //~ ERROR cannot be dereferenced
+    let &&x = &(&1 as &T);  //~ ERROR cannot be dereferenced
+    let box x = box 1 as Box<T>; //~ ERROR cannot be dereferenced
+
+    // n > m
+    let &&x = &1 as &T;     //~ ERROR found an `&`-pointer pattern
+    let &&&x = &(&1 as &T); //~ ERROR found an `&`-pointer pattern
+    let box box x = box 1 as Box<T>;    //~ ERROR found a box pattern
+}
index ffac6b499f4c1f9add5542404f1807081c1c44ca..edd6932aec6f0d3900614ad11699aced0a25fb3f 100644 (file)
@@ -17,7 +17,7 @@ pub enum TraitWrapper {
 
 fn get_tw_map<'lt>(tw: &'lt TraitWrapper) -> &'lt MyTrait {
     match *tw {
-        A(box ref map) => map, //~ ERROR found a box pattern
+        A(box ref map) => map, //~ ERROR cannot be dereferenced
     }
 }