Merge pull request #8479 from catamorphism/derived-errors
rustc: Eliminate a derived error in check::_match
This commit is contained in:
commit
9b9250052c
4 changed files with 73 additions and 13 deletions
|
@ -156,6 +156,7 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path,
|
||||||
kind_name = "variant";
|
kind_name = "variant";
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
// See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
|
||||||
fcx.infcx().type_error_message_str_with_expected(pat.span,
|
fcx.infcx().type_error_message_str_with_expected(pat.span,
|
||||||
|expected, actual| {
|
|expected, actual| {
|
||||||
expected.map_move_default(~"", |e| {
|
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";
|
kind_name = "structure";
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
// See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
|
||||||
fcx.infcx().type_error_message_str_with_expected(pat.span,
|
fcx.infcx().type_error_message_str_with_expected(pat.span,
|
||||||
|expected, actual| {
|
|expected, actual| {
|
||||||
expected.map_move_default(~"", |e| {
|
expected.map_move_default(~"", |e| {
|
||||||
|
@ -302,10 +304,13 @@ pub fn check_struct_pat_fields(pcx: &pat_ctxt,
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let name = pprust::path_to_str(path, tcx.sess.intr());
|
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,
|
tcx.sess.span_err(span,
|
||||||
fmt!("struct `%s` does not have a field
|
fmt!("struct `%s` does not have a field named `%s`",
|
||||||
named `%s`", name,
|
name,
|
||||||
tcx.sess.str_of(field.ident)));
|
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,
|
pub fn check_struct_pat(pcx: &pat_ctxt, pat_id: ast::NodeId, span: span,
|
||||||
expected: ty::t, path: &ast::Path,
|
expected: ty::t, path: &ast::Path,
|
||||||
fields: &[ast::field_pat], etc: bool,
|
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 fcx = pcx.fcx;
|
||||||
let tcx = pcx.fcx.ccx.tcx;
|
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.
|
// Check to ensure that the struct is the one specified.
|
||||||
match tcx.def_map.find(&pat_id) {
|
match tcx.def_map.find(&pat_id) {
|
||||||
Some(&ast::def_struct(supplied_def_id))
|
Some(&ast::def_struct(supplied_def_id))
|
||||||
if supplied_def_id == class_id => {
|
if supplied_def_id == struct_id => {
|
||||||
// OK.
|
// OK.
|
||||||
}
|
}
|
||||||
Some(&ast::def_struct(*)) | Some(&ast::def_variant(*)) => {
|
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));
|
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);
|
substitutions, etc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,9 +505,22 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) {
|
||||||
substs);
|
substs);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
tcx.sess.span_err(pat.span,
|
// See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
|
||||||
fmt!("mismatched types: expected `%s` but found struct",
|
fcx.infcx().type_error_message_str_with_expected(pat.span,
|
||||||
fcx.infcx().ty_to_str(expected)));
|
|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;
|
error_happened = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -534,6 +553,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) {
|
||||||
found: e_count}),
|
found: e_count}),
|
||||||
_ => ty::terr_mismatch
|
_ => 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| {
|
fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| {
|
||||||
expected.map_move_default(~"", |e| {
|
expected.map_move_default(~"", |e| {
|
||||||
fmt!("mismatched types: expected `%s` but found %s",
|
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() {
|
for &elt in after.iter() {
|
||||||
check_pat(pcx, elt, ty::mk_err());
|
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(
|
fcx.infcx().type_error_message_str_with_expected(
|
||||||
pat.span,
|
pat.span,
|
||||||
|expected, actual| {
|
|expected, actual| {
|
||||||
|
@ -639,6 +660,7 @@ pub fn check_pointer_pat(pcx: &pat_ctxt,
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
check_pat(pcx, inner, ty::mk_err());
|
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(
|
fcx.infcx().type_error_message_str_with_expected(
|
||||||
span,
|
span,
|
||||||
|expected, actual| {
|
|expected, actual| {
|
||||||
|
|
|
@ -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,
|
pub fn type_error_message_str(@mut self,
|
||||||
sp: span,
|
sp: span,
|
||||||
mk_msg: &fn(Option<~str>, ~str) -> ~str,
|
mk_msg: &fn(Option<~str>, ~str) -> ~str,
|
||||||
|
|
|
@ -29,8 +29,9 @@ fn main() {
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
match 'c' {
|
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`
|
f(true); //~ ERROR mismatched types: expected `char` but found `bool`
|
||||||
}
|
}
|
||||||
|
|
26
src/test/compile-fail/struct-pat-derived-error.rs
Normal file
26
src/test/compile-fail/struct-pat-derived-error.rs
Normal file
|
@ -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() {}
|
Loading…
Add table
Add a link
Reference in a new issue