about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@pobox.com>2013-08-14 18:23:55 -0700
committerGraydon Hoare <graydon@pobox.com>2013-08-14 18:23:55 -0700
commit9b9250052c018d073da85b2cb05693fec2efec22 (patch)
treeeb842b665a61826d33ce9770442ca7c5c439a7cb /src
parente7b572952c76fd6b05c947aa3193e10410773078 (diff)
parent63083ee7670f5331f6264b6bd235b1d9b909a943 (diff)
downloadrust-9b9250052c018d073da85b2cb05693fec2efec22.tar.gz
rust-9b9250052c018d073da85b2cb05693fec2efec22.zip
Merge pull request #8479 from catamorphism/derived-errors
rustc: Eliminate a derived error in check::_match
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/typeck/check/_match.rs44
-rw-r--r--src/librustc/middle/typeck/infer/mod.rs11
-rw-r--r--src/test/compile-fail/pattern-error-continue.rs5
-rw-r--r--src/test/compile-fail/struct-pat-derived-error.rs26
4 files changed, 73 insertions, 13 deletions
diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs
index d8a9350e695..b7114e60283 100644
--- a/src/librustc/middle/typeck/check/_match.rs
+++ b/src/librustc/middle/typeck/check/_match.rs
@@ -156,6 +156,7 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path,
                     kind_name = "variant";
                 }
                 None => {
+                    // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
                     fcx.infcx().type_error_message_str_with_expected(pat.span,
                                                        |expected, actual| {
                                                        expected.map_move_default(~"", |e| {
@@ -199,6 +200,7 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path,
             kind_name = "structure";
         }
         _ => {
+            // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
             fcx.infcx().type_error_message_str_with_expected(pat.span,
                                                |expected, actual| {
                                                expected.map_move_default(~"", |e| {
@@ -302,10 +304,13 @@ pub fn check_struct_pat_fields(pcx: &pat_ctxt,
             }
             None => {
                 let name = pprust::path_to_str(path, tcx.sess.intr());
+                // Check the pattern anyway, so that attempts to look
+                // up its type won't fail
+                check_pat(pcx, field.pat, ty::mk_err());
                 tcx.sess.span_err(span,
-                                  fmt!("struct `%s` does not have a field
-                                        named `%s`", name,
-                                       tcx.sess.str_of(field.ident)));
+                    fmt!("struct `%s` does not have a field named `%s`",
+                         name,
+                         tcx.sess.str_of(field.ident)));
             }
         }
     }
@@ -326,16 +331,17 @@ pub fn check_struct_pat_fields(pcx: &pat_ctxt,
 pub fn check_struct_pat(pcx: &pat_ctxt, pat_id: ast::NodeId, span: span,
                         expected: ty::t, path: &ast::Path,
                         fields: &[ast::field_pat], etc: bool,
-                        class_id: ast::def_id, substitutions: &ty::substs) {
+                        struct_id: ast::def_id,
+                        substitutions: &ty::substs) {
     let fcx = pcx.fcx;
     let tcx = pcx.fcx.ccx.tcx;
 
-    let class_fields = ty::lookup_struct_fields(tcx, class_id);
+    let class_fields = ty::lookup_struct_fields(tcx, struct_id);
 
     // Check to ensure that the struct is the one specified.
     match tcx.def_map.find(&pat_id) {
         Some(&ast::def_struct(supplied_def_id))
-                if supplied_def_id == class_id => {
+                if supplied_def_id == struct_id => {
             // OK.
         }
         Some(&ast::def_struct(*)) | Some(&ast::def_variant(*)) => {
@@ -346,11 +352,11 @@ pub fn check_struct_pat(pcx: &pat_ctxt, pat_id: ast::NodeId, span: span,
                                    name));
         }
         _ => {
-            tcx.sess.span_bug(span, "resolve didn't write in class");
+            tcx.sess.span_bug(span, "resolve didn't write in struct ID");
         }
     }
 
-    check_struct_pat_fields(pcx, span, path, fields, class_fields, class_id,
+    check_struct_pat_fields(pcx, span, path, fields, class_fields, struct_id,
                             substitutions, etc);
 }
 
@@ -499,9 +505,22 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) {
                     substs);
             }
             _ => {
-                tcx.sess.span_err(pat.span,
-                                  fmt!("mismatched types: expected `%s` but found struct",
-                                       fcx.infcx().ty_to_str(expected)));
+               // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
+               fcx.infcx().type_error_message_str_with_expected(pat.span,
+                                                                |expected, actual| {
+                            expected.map_move_default(~"", |e| {
+                                    fmt!("mismatched types: expected `%s` but found %s",
+                                         e, actual)})},
+                                         Some(expected), ~"a structure pattern",
+                                         None);
+                match tcx.def_map.find(&pat.id) {
+                    Some(&ast::def_struct(supplied_def_id)) => {
+                         check_struct_pat(pcx, pat.id, pat.span, ty::mk_err(), path, *fields, etc,
+                         supplied_def_id,
+                         &ty::substs { self_ty: None, tps: ~[], regions: ty::ErasedRegions} );
+                    }
+                    _ => () // Error, but we're already in an error case
+                }
                 error_happened = true;
             }
         }
@@ -534,6 +553,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) {
                                                            found: e_count}),
                     _ => ty::terr_mismatch
                 };
+                // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
                 fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| {
                 expected.map_move_default(~"", |e| {
                     fmt!("mismatched types: expected `%s` but found %s",
@@ -581,6 +601,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) {
               for &elt in after.iter() {
                   check_pat(pcx, elt, ty::mk_err());
               }
+              // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
               fcx.infcx().type_error_message_str_with_expected(
                   pat.span,
                   |expected, actual| {
@@ -639,6 +660,7 @@ pub fn check_pointer_pat(pcx: &pat_ctxt,
         }
         _ => {
             check_pat(pcx, inner, ty::mk_err());
+            // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
             fcx.infcx().type_error_message_str_with_expected(
                 span,
                 |expected, actual| {
diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs
index 7fa7daf6149..a11abda8ec5 100644
--- a/src/librustc/middle/typeck/infer/mod.rs
+++ b/src/librustc/middle/typeck/infer/mod.rs
@@ -698,6 +698,17 @@ impl InferCtxt {
         }
     }
 
+    // [Note-Type-error-reporting]
+    // An invariant is that anytime the expected or actual type is ty_err (the special
+    // error type, meaning that an error occurred when typechecking this expression),
+    // this is a derived error. The error cascaded from another error (that was already
+    // reported), so it's not useful to display it to the user.
+    // The following four methods -- type_error_message_str, type_error_message_str_with_expected,
+    // type_error_message, and report_mismatched_types -- implement this logic.
+    // They check if either the actual or expected type is ty_err, and don't print the error
+    // in this case. The typechecker should only ever report type errors involving mismatched
+    // types using one of these four methods, and should not call span_err directly for such
+    // errors.
     pub fn type_error_message_str(@mut self,
                                   sp: span,
                                   mk_msg: &fn(Option<~str>, ~str) -> ~str,
diff --git a/src/test/compile-fail/pattern-error-continue.rs b/src/test/compile-fail/pattern-error-continue.rs
index 14d8b04ade4..09e4380f346 100644
--- a/src/test/compile-fail/pattern-error-continue.rs
+++ b/src/test/compile-fail/pattern-error-continue.rs
@@ -29,8 +29,9 @@ fn main() {
         _ => ()
     }
     match 'c' {
-        S { _ } => (),   //~ ERROR mismatched types: expected `char` but found struct
+        S { _ } => (),   //~ ERROR mismatched types: expected `char` but found a structure pattern
+
         _ => ()
     }
     f(true);            //~ ERROR mismatched types: expected `char` but found `bool`
-}
\ No newline at end of file
+}
diff --git a/src/test/compile-fail/struct-pat-derived-error.rs b/src/test/compile-fail/struct-pat-derived-error.rs
new file mode 100644
index 00000000000..cafead3af0e
--- /dev/null
+++ b/src/test/compile-fail/struct-pat-derived-error.rs
@@ -0,0 +1,26 @@
+// Copyright 2013 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.
+
+struct a {
+    b: uint,
+    c: uint
+}
+
+impl a {
+    fn foo(&self) {
+        let a { x, y } = self.d; //~ ERROR attempted access of field `d`
+        //~^ ERROR struct `a` does not have a field named `x`
+        //~^^ ERROR struct `a` does not have a field named `y`
+        //~^^^ ERROR pattern does not mention field `b`
+        //~^^^^ ERROR pattern does not mention field `c`
+    }
+}
+
+fn main() {}