Skip to content

Commit

Permalink
Merge pull request rust-lang#8479 from catamorphism/derived-errors
Browse files Browse the repository at this point in the history
rustc: Eliminate a derived error in check::_match
  • Loading branch information
graydon committed Aug 15, 2013
2 parents e7b5729 + 63083ee commit 9b92500
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 13 deletions.
44 changes: 33 additions & 11 deletions src/librustc/middle/typeck/check/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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| {
Expand Down Expand Up @@ -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| {
Expand Down Expand Up @@ -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)));
}
}
}
Expand All @@ -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(*)) => {
Expand All @@ -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);
}

Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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| {
Expand Down Expand Up @@ -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| {
Expand Down
11 changes: 11 additions & 0 deletions src/librustc/middle/typeck/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 3 additions & 2 deletions src/test/compile-fail/pattern-error-continue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`
}
}
26 changes: 26 additions & 0 deletions src/test/compile-fail/struct-pat-derived-error.rs
Original file line number Diff line number Diff line change
@@ -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() {}

0 comments on commit 9b92500

Please sign in to comment.