From edc11a9f09060b355010b8cc71da45c4f35eadf0 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Wed, 17 Apr 2013 19:36:59 -0700 Subject: [PATCH] rustc: Suppress derived pattern-match-checking errors typeck::check::_match wasn't suppressing derived errors properly. Fixed it. --- src/librustc/middle/typeck/check/_match.rs | 174 ++++++++++++--------- src/librustc/middle/typeck/infer/mod.rs | 25 +-- src/test/compile-fail/issue-5100.rs | 44 ++++++ 3 files changed, 164 insertions(+), 79 deletions(-) create mode 100644 src/test/compile-fail/issue-5100.rs diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 7f0066a1aa2..7d2fd51cefe 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -175,11 +175,18 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: @ast::Path, kind_name = "structure"; } _ => { - tcx.sess.span_fatal( - pat.span, - fmt!("mismatched types: expected `%s` but found enum or \ - structure", - fcx.infcx().ty_to_str(expected))); + let resolved_expected = + fcx.infcx().ty_to_str(fcx.infcx().resolve_type_vars_if_possible(expected)); + fcx.infcx().type_error_message_str(pat.span, + |actual| { + fmt!("mismatched types: expected `%s` but found %s", + resolved_expected, actual)}, + ~"an enum or structure pattern", + None); + fcx.write_error(pat.id); + kind_name = "[error]"; + arg_types = (copy subpats).get_or_default(~[]).map(|_| + ty::mk_err()); } } @@ -486,74 +493,44 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { } ast::pat_tup(ref elts) => { let s = structure_of(fcx, pat.span, expected); - let ex_elts = match s { - ty::ty_tup(ref elts) => elts, - _ => { - tcx.sess.span_fatal - (pat.span, - fmt!("mismatched types: expected `%s`, found tuple", - fcx.infcx().ty_to_str(expected))); - } - }; let e_count = elts.len(); - if e_count != ex_elts.len() { - tcx.sess.span_fatal - (pat.span, fmt!("mismatched types: expected a tuple \ - with %u fields, found one with %u \ - fields", ex_elts.len(), e_count)); + match s { + ty::ty_tup(ref ex_elts) if e_count == ex_elts.len() => { + for elts.eachi |i, elt| { + check_pat(pcx, *elt, ex_elts[i]); + } + fcx.write_ty(pat.id, expected); + } + _ => { + for elts.each |elt| { + check_pat(pcx, *elt, ty::mk_err()); + } + let actual = ty::mk_tup(tcx, elts.map(|pat_var| { + fcx.node_ty(pat_var.id) + })); + // use terr_tuple_size if both types are tuples + let type_error = match s { + ty::ty_tup(ref ex_elts) => + ty::terr_tuple_size(ty::expected_found{expected: ex_elts.len(), + found: e_count}), + _ => ty::terr_mismatch + }; + fcx.infcx().report_mismatched_types(pat.span, + expected, + actual, + &type_error); + fcx.write_error(pat.id); + } } - let mut i = 0u; - for elts.each |elt| { - check_pat(pcx, *elt, ex_elts[i]); - i += 1u; - } - - fcx.write_ty(pat.id, expected); } ast::pat_box(inner) => { - match structure_of(fcx, pat.span, expected) { - ty::ty_box(e_inner) => { - check_pat(pcx, inner, e_inner.ty); - fcx.write_ty(pat.id, expected); - } - _ => { - tcx.sess.span_fatal( - pat.span, - ~"mismatched types: expected `" + - fcx.infcx().ty_to_str(expected) + - ~"` found box"); - } - } + check_pointer_pat(pcx, At, inner, pat.id, pat.span, expected); } ast::pat_uniq(inner) => { - match structure_of(fcx, pat.span, expected) { - ty::ty_uniq(e_inner) => { - check_pat(pcx, inner, e_inner.ty); - fcx.write_ty(pat.id, expected); - } - _ => { - tcx.sess.span_fatal( - pat.span, - ~"mismatched types: expected `" + - fcx.infcx().ty_to_str(expected) + - ~"` found uniq"); - } - } + check_pointer_pat(pcx, Uniq, inner, pat.id, pat.span, expected); } ast::pat_region(inner) => { - match structure_of(fcx, pat.span, expected) { - ty::ty_rptr(_, e_inner) => { - check_pat(pcx, inner, e_inner.ty); - fcx.write_ty(pat.id, expected); - } - _ => { - tcx.sess.span_fatal( - pat.span, - ~"mismatched types: expected `" + - fcx.infcx().ty_to_str(expected) + - ~"` found borrowed pointer"); - } - } + check_pointer_pat(pcx, Borrowed, inner, pat.id, pat.span, expected); } ast::pat_vec(ref before, slice, ref after) => { let default_region_var = @@ -577,11 +554,25 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { (mt, default_region_var) }, _ => { - tcx.sess.span_fatal( - pat.span, - fmt!("mismatched type: expected `%s` but found vector", - fcx.infcx().ty_to_str(expected)) - ); + for before.each |&elt| { + check_pat(pcx, elt, ty::mk_err()); + } + for slice.each |&elt| { + check_pat(pcx, elt, ty::mk_err()); + } + for after.each |&elt| { + check_pat(pcx, elt, ty::mk_err()); + } + let resolved_expected = + fcx.infcx().ty_to_str(fcx.infcx().resolve_type_vars_if_possible(expected)); + fcx.infcx().type_error_message_str(pat.span, + |actual| { + fmt!("mismatched types: expected `%s` but found %s", + resolved_expected, actual)}, + ~"a vector pattern", + None); + fcx.write_error(pat.id); + return; } }; for before.each |elt| { @@ -605,3 +596,46 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { } } +// Helper function to check @, ~ and & patterns +pub fn check_pointer_pat(pcx: &pat_ctxt, + pointer_kind: PointerKind, + inner: @ast::pat, + pat_id: ast::node_id, + span: span, + expected: ty::t) { + let fcx = pcx.fcx; + let check_inner: &fn(ty::mt) = |e_inner| { + check_pat(pcx, inner, e_inner.ty); + fcx.write_ty(pat_id, expected); + }; + match structure_of(fcx, span, expected) { + ty::ty_box(e_inner) if pointer_kind == At => { + check_inner(e_inner); + } + ty::ty_uniq(e_inner) if pointer_kind == Uniq => { + check_inner(e_inner); + } + ty::ty_rptr(_, e_inner) if pointer_kind == Borrowed => { + check_inner(e_inner); + } + _ => { + check_pat(pcx, inner, ty::mk_err()); + let resolved_expected = + fcx.infcx().ty_to_str(fcx.infcx().resolve_type_vars_if_possible(expected)); + fcx.infcx().type_error_message_str(span, |actual| { + fmt!("mismatched types: expected `%s` but found %s", + resolved_expected, actual)}, + fmt!("an %s pattern", match pointer_kind { + At => "@-box", + Uniq => "~-box", + Borrowed => "&-pointer" + }), + None); + fcx.write_error(pat_id); + } + } +} + +#[deriving(Eq)] +enum PointerKind { At, Uniq, Borrowed } + diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 7b5a93d4cad..8f709e7cd5a 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -749,6 +749,19 @@ pub impl InferCtxt { } } + + fn type_error_message_str(@mut self, sp: span, mk_msg: &fn(~str) -> ~str, + actual_ty: ~str, err: Option<&ty::type_err>) { + let error_str = err.map_default(~"", |t_err| + fmt!(" (%s)", + ty::type_err_to_str(self.tcx, *t_err))); + self.tcx.sess.span_err(sp, + fmt!("%s%s", mk_msg(actual_ty), error_str)); + for err.each |err| { + ty::note_and_explain_type_err(self.tcx, *err) + } + } + fn type_error_message(@mut self, sp: span, mk_msg: &fn(~str) -> ~str, actual_ty: ty::t, err: Option<&ty::type_err>) { let actual_ty = self.resolve_type_vars_if_possible(actual_ty); @@ -757,15 +770,9 @@ pub impl InferCtxt { if ty::type_is_error(actual_ty) { return; } - let error_str = err.map_default(~"", |t_err| - fmt!(" (%s)", - ty::type_err_to_str(self.tcx, *t_err))); - self.tcx.sess.span_err(sp, - fmt!("%s%s", mk_msg(self.ty_to_str(actual_ty)), - error_str)); - for err.each |err| { - ty::note_and_explain_type_err(self.tcx, *err) - } + + self.type_error_message_str(sp, mk_msg, self.ty_to_str(actual_ty), + err); } fn report_mismatched_types(@mut self, sp: span, e: ty::t, a: ty::t, diff --git a/src/test/compile-fail/issue-5100.rs b/src/test/compile-fail/issue-5100.rs new file mode 100644 index 00000000000..dbfdb38f721 --- /dev/null +++ b/src/test/compile-fail/issue-5100.rs @@ -0,0 +1,44 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum A { B, C } + +fn main() { + match (true, false) { + B => (), //~ ERROR expected `(bool,bool)` but found an enum or structure pattern + _ => () + } + + match (true, false) { + (true, false, false) => () //~ ERROR mismatched types: expected `(bool,bool)` but found `(bool,bool,bool)` (expected a tuple with 2 elements but found one with 3 elements) + } + + match (true, false) { + @(true, false) => () //~ ERROR mismatched types: expected `(bool,bool)` but found an @-box pattern + } + + match (true, false) { + ~(true, false) => () //~ ERROR mismatched types: expected `(bool,bool)` but found a ~-box pattern + } + + match (true, false) { + &(true, false) => () //~ ERROR mismatched types: expected `(bool,bool)` but found an &-pointer pattern + } + + + let v = [('a', 'b') //~ ERROR expected function but found `(char,char)` + ('c', 'd'), + ('e', 'f')]; + + for v.each |&(x,y)| {} // should be OK + + // Make sure none of the errors above were fatal + let x: char = true; //~ ERROR expected `char` but found `bool` +}