diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 96acb708315e4..312a446d44091 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -35,7 +35,7 @@ use ty::fold::TypeFoldable; use ty::relate::{Relate, RelateResult, TypeRelation}; use traits::{self, PredicateObligations, ProjectionMode}; use rustc_data_structures::unify::{self, UnificationTable}; -use std::cell::{RefCell, Ref}; +use std::cell::{Cell, RefCell, Ref}; use std::fmt; use syntax::ast; use syntax::codemap; @@ -110,6 +110,25 @@ pub struct InferCtxt<'a, 'tcx: 'a> { // documentation for `ProjectionMode`. projection_mode: ProjectionMode, + // When an error occurs, we want to avoid reporting "derived" + // errors that are due to this original failure. Normally, we + // handle this with the `err_count_on_creation` count, which + // basically just tracks how many errors were reported when we + // started type-checking a fn and checks to see if any new errors + // have been reported since then. Not great, but it works. + // + // However, when errors originated in other passes -- notably + // resolve -- this heuristic breaks down. Therefore, we have this + // auxiliary flag that one can set whenever one creates a + // type-error that is due to an error in a prior pass. + // + // Don't read this flag directly, call `is_tainted_by_errors()` + // and `set_tainted_by_errors()`. + tainted_by_errors_flag: Cell, + + // Track how many errors were reported when this infcx is created. + // If the number of errors increases, that's also a sign (line + // `tained_by_errors`) to avoid reporting certain kinds of errors. err_count_on_creation: usize, } @@ -379,6 +398,7 @@ pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a TyCtxt<'tcx>, reported_trait_errors: RefCell::new(FnvHashSet()), normalize: false, projection_mode: projection_mode, + tainted_by_errors_flag: Cell::new(false), err_count_on_creation: tcx.sess.err_count() } } @@ -1128,15 +1148,36 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .map(|method| resolve_ty(method.ty))) } - pub fn errors_since_creation(&self) -> bool { - self.tcx.sess.err_count() - self.err_count_on_creation != 0 + /// True if errors have been reported since this infcx was + /// created. This is sometimes used as a heuristic to skip + /// reporting errors that often occur as a result of earlier + /// errors, but where it's hard to be 100% sure (e.g., unresolved + /// inference variables, regionck errors). + pub fn is_tainted_by_errors(&self) -> bool { + debug!("is_tainted_by_errors(err_count={}, err_count_on_creation={}, \ + tainted_by_errors_flag={})", + self.tcx.sess.err_count(), + self.err_count_on_creation, + self.tainted_by_errors_flag.get()); + + if self.tcx.sess.err_count() > self.err_count_on_creation { + return true; // errors reported since this infcx was made + } + self.tainted_by_errors_flag.get() + } + + /// Set the "tainted by errors" flag to true. We call this when we + /// observe an error from a prior pass. + pub fn set_tainted_by_errors(&self) { + debug!("set_tainted_by_errors()"); + self.tainted_by_errors_flag.set(true) } pub fn node_type(&self, id: ast::NodeId) -> Ty<'tcx> { match self.tables.borrow().node_types.get(&id) { Some(&t) => t, // FIXME - None if self.errors_since_creation() => + None if self.is_tainted_by_errors() => self.tcx.types.err, None => { bug!("no type for node {}: {} in fcx", @@ -1158,7 +1199,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { free_regions: &FreeRegionMap, subject_node_id: ast::NodeId) { let errors = self.region_vars.resolve_regions(free_regions, subject_node_id); - if !self.errors_since_creation() { + if !self.is_tainted_by_errors() { // As a heuristic, just skip reporting region errors // altogether if other errors have been reported while // this infcx was in use. This is totally hokey but diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index ece8c0c696af8..71e1efe220f03 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -91,6 +91,7 @@ impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> { } (&ty::TyError, _) | (_, &ty::TyError) => { + infcx.set_tainted_by_errors(); Ok(self.tcx().types.err) } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 3b5bdd734b4ce..d7ddfc9f1a6d0 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -624,6 +624,12 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, predicate, obligation); + // Ambiguity errors are often caused as fallout from earlier + // errors. So just ignore them if this infcx is tainted. + if infcx.is_tainted_by_errors() { + return; + } + match predicate { ty::Predicate::Trait(ref data) => { let trait_ref = data.to_poly_trait_ref(); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index d6e64ccd259e6..1110e193e579b 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -155,6 +155,12 @@ pub trait AstConv<'tcx> { _trait_ref: ty::TraitRef<'tcx>, _item_name: ast::Name) -> Ty<'tcx>; + + /// Invoked when we encounter an error from some prior pass + /// (e.g. resolve) that is translated into a ty-error. This is + /// used to help suppress derived errors typeck might otherwise + /// report. + fn set_tainted_by_errors(&self); } pub fn ast_region_to_region(tcx: &TyCtxt, lifetime: &hir::Lifetime) @@ -1533,6 +1539,7 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>, prim_ty_to_ty(tcx, base_segments, prim_ty) } Def::Err => { + this.set_tainted_by_errors(); return this.tcx().types.err; } _ => { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 8dbd6496b6fb0..a7a04f4a85fe8 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -209,6 +209,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let self_ty = fcx.to_ty(&qself.ty); let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) { if d.base_def == Def::Err { + fcx.infcx().set_tainted_by_errors(); fcx.write_error(pat.id); return; } @@ -628,6 +629,7 @@ fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let path_res = match tcx.def_map.borrow().get(&pat.id) { Some(&path_res) if path_res.base_def != Def::Err => path_res, _ => { + fcx.infcx().set_tainted_by_errors(); fcx.write_error(pat.id); if let Some(subpats) = subpats { diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 91cdb8d966d41..922c411ce8cd8 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -45,12 +45,13 @@ use super::structurally_resolved_type; use lint; use hir::def_id::DefId; +use rustc::hir; +use rustc::traits; use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::cast::{CastKind, CastTy}; -use syntax::codemap::Span; -use rustc::hir; use syntax::ast; - +use syntax::codemap::Span; +use util::common::ErrorReported; /// Reifies a cast check to be checked once we have full type information for /// a function context. @@ -58,6 +59,7 @@ pub struct CastCheck<'tcx> { expr: &'tcx hir::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, + cast_span: Span, span: Span, } @@ -111,17 +113,37 @@ enum CastError { } impl<'tcx> CastCheck<'tcx> { - pub fn new(expr: &'tcx hir::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span) - -> CastCheck<'tcx> { - CastCheck { + pub fn new<'a>(fcx: &FnCtxt<'a, 'tcx>, + expr: &'tcx hir::Expr, + expr_ty: Ty<'tcx>, + cast_ty: Ty<'tcx>, + cast_span: Span, + span: Span) + -> Result, ErrorReported> { + let check = CastCheck { expr: expr, expr_ty: expr_ty, cast_ty: cast_ty, + cast_span: cast_span, span: span, + }; + + // For better error messages, check for some obviously unsized + // cases now. We do a more thorough check at the end, once + // inference is more completely known. + match cast_ty.sty { + ty::TyTrait(..) | ty::TySlice(..) => { + check.report_cast_to_unsized_type(fcx); + Err(ErrorReported) + } + _ => { + Ok(check) + } } } - fn report_cast_error<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, + fn report_cast_error<'a>(&self, + fcx: &FnCtxt<'a, 'tcx>, e: CastError) { match e { CastError::NeedViaPtr | @@ -186,6 +208,61 @@ impl<'tcx> CastCheck<'tcx> { } } + fn report_cast_to_unsized_type<'a>(&self, + fcx: &FnCtxt<'a, 'tcx>) { + if + self.cast_ty.references_error() || + self.expr_ty.references_error() + { + return; + } + + let tstr = fcx.infcx().ty_to_string(self.cast_ty); + let mut err = fcx.type_error_struct(self.span, |actual| { + format!("cast to unsized type: `{}` as `{}`", actual, tstr) + }, self.expr_ty, None); + match self.expr_ty.sty { + ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => { + let mtstr = match mt { + hir::MutMutable => "mut ", + hir::MutImmutable => "" + }; + if self.cast_ty.is_trait() { + match fcx.tcx().sess.codemap().span_to_snippet(self.cast_span) { + Ok(s) => { + err.span_suggestion(self.cast_span, + "try casting to a reference instead:", + format!("&{}{}", mtstr, s)); + }, + Err(_) => + span_help!(err, self.cast_span, + "did you mean `&{}{}`?", mtstr, tstr), + } + } else { + span_help!(err, self.span, + "consider using an implicit coercion to `&{}{}` instead", + mtstr, tstr); + } + } + ty::TyBox(..) => { + match fcx.tcx().sess.codemap().span_to_snippet(self.cast_span) { + Ok(s) => { + err.span_suggestion(self.cast_span, + "try casting to a `Box` instead:", + format!("Box<{}>", s)); + }, + Err(_) => + span_help!(err, self.cast_span, "did you mean `Box<{}>`?", tstr), + } + } + _ => { + span_help!(err, self.expr.span, + "consider using a box or reference as appropriate"); + } + } + err.emit(); + } + fn trivial_cast_lint<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) { let t_cast = self.cast_ty; let t_expr = self.expr_ty; @@ -218,7 +295,9 @@ impl<'tcx> CastCheck<'tcx> { debug!("check_cast({}, {:?} as {:?})", self.expr.id, self.expr_ty, self.cast_ty); - if self.expr_ty.references_error() || self.cast_ty.references_error() { + if !fcx.type_is_known_to_be_sized(self.cast_ty, self.span) { + self.report_cast_to_unsized_type(fcx); + } else if self.expr_ty.references_error() || self.cast_ty.references_error() { // No sense in giving duplicate error messages } else if self.try_coercion_cast(fcx) { self.trivial_cast_lint(fcx); @@ -403,3 +482,17 @@ impl<'tcx> CastCheck<'tcx> { } } + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + fn type_is_known_to_be_sized(&self, + ty: Ty<'tcx>, + span: Span) + -> bool + { + traits::type_known_to_meet_builtin_bound(self.infcx(), + ty, + ty::BoundSized, + span) + } +} + diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 57f56530009eb..2d0505d9347d5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1076,64 +1076,6 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - span: Span, - t_span: Span, - e_span: Span, - t_cast: Ty<'tcx>, - t_expr: Ty<'tcx>, - id: ast::NodeId) { - if t_cast.references_error() || t_expr.references_error() { - return; - } - let tstr = fcx.infcx().ty_to_string(t_cast); - let mut err = fcx.type_error_struct(span, |actual| { - format!("cast to unsized type: `{}` as `{}`", actual, tstr) - }, t_expr, None); - match t_expr.sty { - ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => { - let mtstr = match mt { - hir::MutMutable => "mut ", - hir::MutImmutable => "" - }; - if t_cast.is_trait() { - match fcx.tcx().sess.codemap().span_to_snippet(t_span) { - Ok(s) => { - err.span_suggestion(t_span, - "try casting to a reference instead:", - format!("&{}{}", mtstr, s)); - }, - Err(_) => - span_help!(err, t_span, - "did you mean `&{}{}`?", mtstr, tstr), - } - } else { - span_help!(err, span, - "consider using an implicit coercion to `&{}{}` instead", - mtstr, tstr); - } - } - ty::TyBox(..) => { - match fcx.tcx().sess.codemap().span_to_snippet(t_span) { - Ok(s) => { - err.span_suggestion(t_span, - "try casting to a `Box` instead:", - format!("Box<{}>", s)); - }, - Err(_) => - span_help!(err, t_span, "did you mean `Box<{}>`?", tstr), - } - } - _ => { - span_help!(err, e_span, - "consider using a box or reference as appropriate"); - } - } - err.emit(); - fcx.write_error(id); -} - - impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { fn tcx(&self) -> &TyCtxt<'tcx> { self.ccx.tcx } @@ -1240,6 +1182,10 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { { self.normalize_associated_type(span, trait_ref, item_name) } + + fn set_tainted_by_errors(&self) { + self.infcx().set_tainted_by_errors() + } } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -1524,17 +1470,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.require_type_is_sized(self.expr_ty(expr), expr.span, code); } - pub fn type_is_known_to_be_sized(&self, - ty: Ty<'tcx>, - span: Span) - -> bool - { - traits::type_known_to_meet_builtin_bound(self.infcx(), - ty, - ty::BoundSized, - span) - } - pub fn register_builtin_bound(&self, ty: Ty<'tcx>, builtin_bound: ty::BuiltinBound, @@ -1771,16 +1706,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn default_type_parameters(&self) { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; + + // Defaulting inference variables becomes very dubious if we have + // encountered type-checking errors. Therefore, if we think we saw + // some errors in this function, just resolve all uninstanted type + // varibles to TyError. + if self.infcx().is_tainted_by_errors() { + for ty in &self.infcx().unsolved_variables() { + if let ty::TyInfer(_) = self.infcx().shallow_resolve(ty).sty { + debug!("default_type_parameters: defaulting `{:?}` to error", ty); + demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.err); + } + } + return; + } + for ty in &self.infcx().unsolved_variables() { let resolved = self.infcx().resolve_type_vars_if_possible(ty); if self.infcx().type_var_diverges(resolved) { + debug!("default_type_parameters: defaulting `{:?}` to `()` because it diverges", + resolved); demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); } else { match self.infcx().type_is_unconstrained_numeric(resolved) { UnconstrainedInt => { + debug!("default_type_parameters: defaulting `{:?}` to `i32`", + resolved); demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32) }, UnconstrainedFloat => { + debug!("default_type_parameters: defaulting `{:?}` to `f32`", + resolved); demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64) } Neither => { } @@ -3232,6 +3188,7 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Find the relevant variant let def = lookup_full_def(tcx, path.span, expr.id); if def == Def::Err { + fcx.infcx().set_tainted_by_errors(); check_struct_fields_on_error(fcx, expr.id, fields, base_expr); return; } @@ -3435,6 +3392,7 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr.span, id); } else { + fcx.infcx().set_tainted_by_errors(); fcx.write_ty(id, fcx.tcx().types.err); } } @@ -3560,7 +3518,7 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Find the type of `e`. Supply hints based on the type we are casting to, // if appropriate. let t_cast = fcx.to_ty(t); - let t_cast = structurally_resolved_type(fcx, expr.span, t_cast); + let t_cast = fcx.infcx().resolve_type_vars_if_possible(&t_cast); check_expr_with_expectation(fcx, e, ExpectCastableToType(t_cast)); let t_expr = fcx.expr_ty(e); let t_cast = fcx.infcx().resolve_type_vars_if_possible(&t_cast); @@ -3568,8 +3526,6 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Eagerly check for some obvious errors. if t_expr.references_error() || t_cast.references_error() { fcx.write_error(id); - } else if !fcx.type_is_known_to_be_sized(t_cast, expr.span) { - report_cast_to_unsized_type(fcx, expr.span, t.span, e.span, t_cast, t_expr, id); } else { // Write a type for the whole expression, assuming everything is going // to work out Ok. @@ -3577,8 +3533,14 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Defer other checks until we're done type checking. let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut(); - let cast_check = cast::CastCheck::new(e, t_expr, t_cast, expr.span); - deferred_cast_checks.push(cast_check); + match cast::CastCheck::new(fcx, e, t_expr, t_cast, t.span, expr.span) { + Ok(cast_check) => { + deferred_cast_checks.push(cast_check); + } + Err(ErrorReported) => { + fcx.write_error(id); + } + } } } hir::ExprType(ref e, ref t) => { @@ -4408,8 +4370,12 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Def::ForeignMod(..) | Def::Local(..) | Def::Label(..) | - Def::Upvar(..) | + Def::Upvar(..) => { + segment_spaces = vec![None; segments.len()]; + } + Def::Err => { + fcx.infcx().set_tainted_by_errors(); segment_spaces = vec![None; segments.len()]; } } @@ -4769,9 +4735,11 @@ fn structurally_resolve_type_or_else<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // If not, error. if alternative.is_ty_var() || alternative.references_error() { - fcx.type_error_message(sp, |_actual| { - "the type of this value must be known in this context".to_string() - }, ty, None); + if !fcx.infcx().is_tainted_by_errors() { + fcx.type_error_message(sp, |_actual| { + "the type of this value must be known in this context".to_string() + }, ty, None); + } demand::suptype(fcx, sp, fcx.tcx().types.err, ty); ty = fcx.tcx().types.err; } else { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 4a6f7a6a2ef48..e5e82ea7f5517 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -384,6 +384,10 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> { { self.tcx().mk_projection(trait_ref, item_name) } + + fn set_tainted_by_errors(&self) { + // no obvious place to track this, just let it go + } } /// Interface used to find the bounds on a type parameter from within diff --git a/src/test/compile-fail/cast-rfc0401-2.rs b/src/test/compile-fail/cast-rfc0401-2.rs new file mode 100644 index 0000000000000..1598a9aa1fc41 --- /dev/null +++ b/src/test/compile-fail/cast-rfc0401-2.rs @@ -0,0 +1,19 @@ +// Copyright 2015 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. + +// RFC 401 test extracted into distinct file. This is because some the +// change to suppress "derived" errors wound up suppressing this error +// message, since the fallback for `3` doesn't occur. + +fn main() { + let _ = 3 as bool; + //~^ ERROR cannot cast as `bool` + //~| HELP compare with zero +} diff --git a/src/test/compile-fail/cast-rfc0401.rs b/src/test/compile-fail/cast-rfc0401.rs index b81617abcf4b0..05c531e91f128 100644 --- a/src/test/compile-fail/cast-rfc0401.rs +++ b/src/test/compile-fail/cast-rfc0401.rs @@ -58,7 +58,7 @@ fn main() let _ = f as *const u8; //~^ ERROR casting //~^^ HELP through a usize first - let _ = 3 as bool; + let _ = 3_i32 as bool; //~^ ERROR cannot cast as `bool` //~| HELP compare with zero let _ = E::A as bool; diff --git a/src/test/compile-fail/issue-30580.rs b/src/test/compile-fail/derived-errors/issue-30580.rs similarity index 100% rename from src/test/compile-fail/issue-30580.rs rename to src/test/compile-fail/derived-errors/issue-30580.rs diff --git a/src/test/compile-fail/derived-errors/issue-31997-1.rs b/src/test/compile-fail/derived-errors/issue-31997-1.rs new file mode 100644 index 0000000000000..7d79c48c06ae2 --- /dev/null +++ b/src/test/compile-fail/derived-errors/issue-31997-1.rs @@ -0,0 +1,66 @@ +// Copyright 2012 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. + +// Regression test for this example from #31997 -- main goal is to +// emit as minimal and precise an error set as possible. Ideally, we'd +// only emit the E0433 error below, but right now we emit two. + +use std::io::prelude::*; +// use std::collections::HashMap; +use std::io; + +#[derive(Debug)] +struct Instance { + name: String, + start: Option, + end: Option, +} + +fn main() { + let input = io::stdin(); + let mut input = input.lock(); + + let mut map = HashMap::new(); + //~^ ERROR E0433 + + for line in input.lines() { + let line = line.unwrap(); + println!("process: {}", line); + let mut parts = line.splitn(2, ":"); + let _logfile = parts.next().unwrap(); + let rest = parts.next().unwrap(); + let mut parts = line.split(" [-] "); + + let stamp = parts.next().unwrap(); + + let rest = parts.next().unwrap(); + let words = rest.split_whitespace().collect::>(); + + let instance = words.iter().find(|a| a.starts_with("i-")).unwrap(); + let name = words[1].to_owned(); + let mut entry = map.entry(instance.to_owned()).or_insert(Instance { + name: name, + start: None, + end: None, + }); + + if rest.contains("terminating") { + assert!(entry.end.is_none()); + entry.end = Some(stamp.to_string()); + } + if rest.contains("waiting for") { + assert!(entry.start.is_none()); + entry.start = Some(stamp.to_string()); + } + + } + + println!("{:?}", map); +} diff --git a/src/test/compile-fail/derived-errors/issue-31997.rs b/src/test/compile-fail/derived-errors/issue-31997.rs new file mode 100644 index 0000000000000..cf283f6d3e4b5 --- /dev/null +++ b/src/test/compile-fail/derived-errors/issue-31997.rs @@ -0,0 +1,27 @@ +// Copyright 2012 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. + +// Test that the resolve failure does not lead to downstream type errors. +// See issue #31997. + +trait TheTrait { } + +fn closure(x: F) -> Result + where F: FnMut() -> T, T: TheTrait, +{ + unimplemented!() +} + +fn foo() -> Result<(), ()> { + try!(closure(|| bar(0 as *mut _))); //~ ERROR unresolved name `bar` + Ok(()) +} + +fn main() { } diff --git a/src/test/compile-fail/issue-13853.rs b/src/test/compile-fail/issue-13853.rs index 7643310298da3..86a6bdfd4dde4 100644 --- a/src/test/compile-fail/issue-13853.rs +++ b/src/test/compile-fail/issue-13853.rs @@ -35,7 +35,7 @@ impl Node for Stuff { fn iterate>(graph: &G) { for node in graph.iter() { //~ ERROR no method named `iter` found - node.zomg(); //~ error: the type of this value must be known in this context + node.zomg(); } } diff --git a/src/test/compile-fail/issue-19692.rs b/src/test/compile-fail/issue-19692.rs index 53ad241687894..ca1715445e526 100644 --- a/src/test/compile-fail/issue-19692.rs +++ b/src/test/compile-fail/issue-19692.rs @@ -12,7 +12,7 @@ struct Homura; fn akemi(homura: Homura) { let Some(ref madoka) = Some(homura.kaname()); //~ ERROR no method named `kaname` found - madoka.clone(); //~ ERROR the type of this value must be known + madoka.clone(); } fn main() { } diff --git a/src/test/compile-fail/issue-20261.rs b/src/test/compile-fail/issue-20261.rs index 09044b5b5055d..2f1910b26bbef 100644 --- a/src/test/compile-fail/issue-20261.rs +++ b/src/test/compile-fail/issue-20261.rs @@ -11,6 +11,5 @@ fn main() { for (ref i,) in [].iter() { //~ ERROR mismatched types i.clone(); - //~^ ERROR: the type of this value must be known in this context } } diff --git a/src/test/compile-fail/issue-26480.rs b/src/test/compile-fail/issue-26480.rs index 903df42291c63..23e4ffb1f3076 100644 --- a/src/test/compile-fail/issue-26480.rs +++ b/src/test/compile-fail/issue-26480.rs @@ -30,8 +30,7 @@ macro_rules! write { } macro_rules! cast { - ($x:expr) => ($x as ()) - //~^ ERROR non-scalar cast: `i32` as `()` + ($x:expr) => ($x as ()) //~ ERROR non-scalar cast } fn main() { diff --git a/src/test/compile-fail/issue-3973.rs b/src/test/compile-fail/issue-3973.rs index 54eb2a9082955..92456760b0508 100644 --- a/src/test/compile-fail/issue-3973.rs +++ b/src/test/compile-fail/issue-3973.rs @@ -31,5 +31,5 @@ impl ToString_ for Point { fn main() { let p = Point::new(0.0, 0.0); //~^ ERROR no associated item named `new` found for type `Point` in the current scope - println!("{}", p.to_string()); //~ ERROR type of this value must be known + println!("{}", p.to_string()); } diff --git a/src/test/compile-fail/issue-7092.rs b/src/test/compile-fail/issue-7092.rs index 4a278bbdeb04a..4acbcb165ff08 100644 --- a/src/test/compile-fail/issue-7092.rs +++ b/src/test/compile-fail/issue-7092.rs @@ -19,7 +19,7 @@ fn foo(x: Whatever) { //~| found `std::option::Option<_>` //~| expected enum `Whatever` //~| found enum `std::option::Option` - field.access(), //~ ERROR the type of this value must be known in this context + field.access(), } } diff --git a/src/test/run-pass/cast-to-infer-ty.rs b/src/test/run-pass/cast-to-infer-ty.rs new file mode 100644 index 0000000000000..2aa0d9c62fb41 --- /dev/null +++ b/src/test/run-pass/cast-to-infer-ty.rs @@ -0,0 +1,17 @@ +// Copyright 2012 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. + +// Check that we allow a cast to `_` so long as the target type can be +// inferred elsewhere. + +pub fn main() { + let i: *const i32 = 0 as _; + assert!(i.is_null()); +}