Skip to content

Commit 9b92500

Browse files
committed
Merge pull request rust-lang#8479 from catamorphism/derived-errors
rustc: Eliminate a derived error in check::_match
2 parents e7b5729 + 63083ee commit 9b92500

File tree

4 files changed

+73
-13
lines changed

4 files changed

+73
-13
lines changed

src/librustc/middle/typeck/check/_match.rs

+33-11
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path,
156156
kind_name = "variant";
157157
}
158158
None => {
159+
// See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
159160
fcx.infcx().type_error_message_str_with_expected(pat.span,
160161
|expected, actual| {
161162
expected.map_move_default(~"", |e| {
@@ -199,6 +200,7 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path,
199200
kind_name = "structure";
200201
}
201202
_ => {
203+
// See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
202204
fcx.infcx().type_error_message_str_with_expected(pat.span,
203205
|expected, actual| {
204206
expected.map_move_default(~"", |e| {
@@ -302,10 +304,13 @@ pub fn check_struct_pat_fields(pcx: &pat_ctxt,
302304
}
303305
None => {
304306
let name = pprust::path_to_str(path, tcx.sess.intr());
307+
// Check the pattern anyway, so that attempts to look
308+
// up its type won't fail
309+
check_pat(pcx, field.pat, ty::mk_err());
305310
tcx.sess.span_err(span,
306-
fmt!("struct `%s` does not have a field
307-
named `%s`", name,
308-
tcx.sess.str_of(field.ident)));
311+
fmt!("struct `%s` does not have a field named `%s`",
312+
name,
313+
tcx.sess.str_of(field.ident)));
309314
}
310315
}
311316
}
@@ -326,16 +331,17 @@ pub fn check_struct_pat_fields(pcx: &pat_ctxt,
326331
pub fn check_struct_pat(pcx: &pat_ctxt, pat_id: ast::NodeId, span: span,
327332
expected: ty::t, path: &ast::Path,
328333
fields: &[ast::field_pat], etc: bool,
329-
class_id: ast::def_id, substitutions: &ty::substs) {
334+
struct_id: ast::def_id,
335+
substitutions: &ty::substs) {
330336
let fcx = pcx.fcx;
331337
let tcx = pcx.fcx.ccx.tcx;
332338

333-
let class_fields = ty::lookup_struct_fields(tcx, class_id);
339+
let class_fields = ty::lookup_struct_fields(tcx, struct_id);
334340

335341
// Check to ensure that the struct is the one specified.
336342
match tcx.def_map.find(&pat_id) {
337343
Some(&ast::def_struct(supplied_def_id))
338-
if supplied_def_id == class_id => {
344+
if supplied_def_id == struct_id => {
339345
// OK.
340346
}
341347
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,
346352
name));
347353
}
348354
_ => {
349-
tcx.sess.span_bug(span, "resolve didn't write in class");
355+
tcx.sess.span_bug(span, "resolve didn't write in struct ID");
350356
}
351357
}
352358

353-
check_struct_pat_fields(pcx, span, path, fields, class_fields, class_id,
359+
check_struct_pat_fields(pcx, span, path, fields, class_fields, struct_id,
354360
substitutions, etc);
355361
}
356362

@@ -499,9 +505,22 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) {
499505
substs);
500506
}
501507
_ => {
502-
tcx.sess.span_err(pat.span,
503-
fmt!("mismatched types: expected `%s` but found struct",
504-
fcx.infcx().ty_to_str(expected)));
508+
// See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
509+
fcx.infcx().type_error_message_str_with_expected(pat.span,
510+
|expected, actual| {
511+
expected.map_move_default(~"", |e| {
512+
fmt!("mismatched types: expected `%s` but found %s",
513+
e, actual)})},
514+
Some(expected), ~"a structure pattern",
515+
None);
516+
match tcx.def_map.find(&pat.id) {
517+
Some(&ast::def_struct(supplied_def_id)) => {
518+
check_struct_pat(pcx, pat.id, pat.span, ty::mk_err(), path, *fields, etc,
519+
supplied_def_id,
520+
&ty::substs { self_ty: None, tps: ~[], regions: ty::ErasedRegions} );
521+
}
522+
_ => () // Error, but we're already in an error case
523+
}
505524
error_happened = true;
506525
}
507526
}
@@ -534,6 +553,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) {
534553
found: e_count}),
535554
_ => ty::terr_mismatch
536555
};
556+
// See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
537557
fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| {
538558
expected.map_move_default(~"", |e| {
539559
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) {
581601
for &elt in after.iter() {
582602
check_pat(pcx, elt, ty::mk_err());
583603
}
604+
// See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
584605
fcx.infcx().type_error_message_str_with_expected(
585606
pat.span,
586607
|expected, actual| {
@@ -639,6 +660,7 @@ pub fn check_pointer_pat(pcx: &pat_ctxt,
639660
}
640661
_ => {
641662
check_pat(pcx, inner, ty::mk_err());
663+
// See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
642664
fcx.infcx().type_error_message_str_with_expected(
643665
span,
644666
|expected, actual| {

src/librustc/middle/typeck/infer/mod.rs

+11
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,17 @@ impl InferCtxt {
698698
}
699699
}
700700

701+
// [Note-Type-error-reporting]
702+
// An invariant is that anytime the expected or actual type is ty_err (the special
703+
// error type, meaning that an error occurred when typechecking this expression),
704+
// this is a derived error. The error cascaded from another error (that was already
705+
// reported), so it's not useful to display it to the user.
706+
// The following four methods -- type_error_message_str, type_error_message_str_with_expected,
707+
// type_error_message, and report_mismatched_types -- implement this logic.
708+
// They check if either the actual or expected type is ty_err, and don't print the error
709+
// in this case. The typechecker should only ever report type errors involving mismatched
710+
// types using one of these four methods, and should not call span_err directly for such
711+
// errors.
701712
pub fn type_error_message_str(@mut self,
702713
sp: span,
703714
mk_msg: &fn(Option<~str>, ~str) -> ~str,

src/test/compile-fail/pattern-error-continue.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ fn main() {
2929
_ => ()
3030
}
3131
match 'c' {
32-
S { _ } => (), //~ ERROR mismatched types: expected `char` but found struct
32+
S { _ } => (), //~ ERROR mismatched types: expected `char` but found a structure pattern
33+
3334
_ => ()
3435
}
3536
f(true); //~ ERROR mismatched types: expected `char` but found `bool`
36-
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct a {
12+
b: uint,
13+
c: uint
14+
}
15+
16+
impl a {
17+
fn foo(&self) {
18+
let a { x, y } = self.d; //~ ERROR attempted access of field `d`
19+
//~^ ERROR struct `a` does not have a field named `x`
20+
//~^^ ERROR struct `a` does not have a field named `y`
21+
//~^^^ ERROR pattern does not mention field `b`
22+
//~^^^^ ERROR pattern does not mention field `c`
23+
}
24+
}
25+
26+
fn main() {}

0 commit comments

Comments
 (0)