Skip to content

rustc: Eliminate a derived error in check::_match #8479

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 15, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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() {}