diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 2f1af4184e549..089eae89d0492 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -68,6 +68,7 @@ use super::region_inference::SubSupConflict; use super::region_inference::GenericBoundFailure; use super::region_inference::GenericKind; use super::region_inference::ProcessedErrors; +use super::region_inference::ProcessedErrorOrigin; use super::region_inference::SameRegions; use std::collections::HashSet; @@ -232,7 +233,7 @@ pub trait ErrorReporting<'tcx> { errors: &Vec>); fn process_errors(&self, errors: &Vec>) - -> Vec>; + -> Option>>; fn report_type_error(&self, trace: TypeTrace<'tcx>, @@ -246,7 +247,8 @@ pub trait ErrorReporting<'tcx> { fn report_and_explain_type_error(&self, trace: TypeTrace<'tcx>, - terr: &TypeError<'tcx>); + terr: &TypeError<'tcx>) + -> DiagnosticBuilder<'tcx>; fn values_str(&self, values: &ValuePairs<'tcx>) -> Option; @@ -258,7 +260,8 @@ pub trait ErrorReporting<'tcx> { fn report_concrete_failure(&self, origin: SubregionOrigin<'tcx>, sub: Region, - sup: Region); + sup: Region) + -> DiagnosticBuilder<'tcx>; fn report_generic_bound_failure(&self, origin: SubregionOrigin<'tcx>, @@ -273,8 +276,7 @@ pub trait ErrorReporting<'tcx> { sup_region: Region); fn report_processed_errors(&self, - var_origin: &[RegionVariableOrigin], - trace_origin: &[(TypeTrace<'tcx>, TypeError<'tcx>)], + origins: &[ProcessedErrorOrigin<'tcx>], same_regions: &[SameRegions]); fn give_suggestion(&self, err: &mut DiagnosticBuilder, same_regions: &[SameRegions]); @@ -303,12 +305,19 @@ trait ErrorReportingHelpers<'tcx> { impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { fn report_region_errors(&self, errors: &Vec>) { - let p_errors = self.process_errors(errors); - let errors = if p_errors.is_empty() { errors } else { &p_errors }; + debug!("report_region_errors(): {} errors to start", errors.len()); + + // try to pre-process the errors, which will group some of them + // together into a `ProcessedErrors` group: + let processed_errors = self.process_errors(errors); + let errors = processed_errors.as_ref().unwrap_or(errors); + + debug!("report_region_errors: {} errors after preprocessing", errors.len()); + for error in errors { match error.clone() { ConcreteFailure(origin, sub, sup) => { - self.report_concrete_failure(origin, sub, sup); + self.report_concrete_failure(origin, sub, sup).emit(); } GenericBoundFailure(kind, param_ty, sub) => { @@ -323,13 +332,10 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { sup_origin, sup_r); } - ProcessedErrors(ref var_origins, - ref trace_origins, + ProcessedErrors(ref origins, ref same_regions) => { if !same_regions.is_empty() { - self.report_processed_errors(&var_origins[..], - &trace_origins[..], - &same_regions[..]); + self.report_processed_errors(origins, same_regions); } } } @@ -341,46 +347,73 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { // parameters to the user. This is done so that we can have a more // complete view of what lifetimes should be the same. // If the return value is an empty vector, it means that processing - // failed (so the return value of this method should not be used) + // failed (so the return value of this method should not be used). + // + // The method also attempts to weed out messages that seem like + // duplicates that will be unhelpful to the end-user. But + // obviously it never weeds out ALL errors. fn process_errors(&self, errors: &Vec>) - -> Vec> { + -> Option>> { debug!("process_errors()"); - let mut var_origins = Vec::new(); - let mut trace_origins = Vec::new(); + let mut origins = Vec::new(); + + // we collect up ConcreteFailures and SubSupConflicts that are + // relating free-regions bound on the fn-header and group them + // together into this vector let mut same_regions = Vec::new(); - let mut processed_errors = Vec::new(); + + // here we put errors that we will not be able to process nicely + let mut other_errors = Vec::new(); + + // we collect up GenericBoundFailures in here. + let mut bound_failures = Vec::new(); + for error in errors { - match error.clone() { - ConcreteFailure(origin, sub, sup) => { + match *error { + ConcreteFailure(ref origin, sub, sup) => { debug!("processing ConcreteFailure"); - let trace = match origin { - infer::Subtype(trace) => Some(trace), - _ => None, - }; match free_regions_from_same_fn(self.tcx, sub, sup) { - Some(ref same_frs) if trace.is_some() => { - let trace = trace.unwrap(); - let terr = TypeError::RegionsDoesNotOutlive(sup, - sub); - trace_origins.push((trace, terr)); + Some(ref same_frs) => { + origins.push( + ProcessedErrorOrigin::ConcreteFailure( + origin.clone(), + sub, + sup)); append_to_same_regions(&mut same_regions, same_frs); } - _ => processed_errors.push((*error).clone()), + _ => { + other_errors.push(error.clone()); + } } } - SubSupConflict(var_origin, _, sub_r, _, sup_r) => { + SubSupConflict(ref var_origin, _, sub_r, _, sup_r) => { debug!("processing SubSupConflict sub: {:?} sup: {:?}", sub_r, sup_r); match free_regions_from_same_fn(self.tcx, sub_r, sup_r) { Some(ref same_frs) => { - var_origins.push(var_origin); + origins.push( + ProcessedErrorOrigin::VariableFailure( + var_origin.clone())); append_to_same_regions(&mut same_regions, same_frs); } - None => processed_errors.push((*error).clone()), + None => { + other_errors.push(error.clone()); + } } } - _ => () // This shouldn't happen + GenericBoundFailure(ref origin, ref kind, region) => { + bound_failures.push((origin.clone(), kind.clone(), region)); + } + ProcessedErrors(..) => { + panic!("should not encounter a `ProcessedErrors` yet: {:?}", error) + } } } + + // ok, let's pull together the errors, sorted in an order that + // we think will help user the best + let mut processed_errors = vec![]; + + // first, put the processed errors, if any if !same_regions.is_empty() { let common_scope_id = same_regions[0].scope_id; for sr in &same_regions { @@ -390,16 +423,39 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { if sr.scope_id != common_scope_id { debug!("returning empty result from process_errors because {} != {}", sr.scope_id, common_scope_id); - return vec!(); + return None; } } - let pe = ProcessedErrors(var_origins, trace_origins, same_regions); + assert!(origins.len() > 0); + let pe = ProcessedErrors(origins, same_regions); debug!("errors processed: {:?}", pe); processed_errors.push(pe); } - return processed_errors; + // next, put the other misc errors + processed_errors.extend(other_errors); + + // finally, put the `T: 'a` errors, but only if there were no + // other errors. otherwise, these have a very high rate of + // being unhelpful in practice. This is because they are + // basically secondary checks that test the state of the + // region graph after the rest of inference is done, and the + // other kinds of errors indicate that the region constraint + // graph is internally inconsistent, so these test results are + // likely to be meaningless. + if processed_errors.is_empty() { + for (origin, kind, region) in bound_failures { + processed_errors.push(GenericBoundFailure(origin, kind, region)); + } + } + + // we should always wind up with SOME errors, unless there were no + // errors to start + assert!(if errors.len() > 0 {processed_errors.len() > 0} else {true}); + return Some(processed_errors); + + #[derive(Debug)] struct FreeRegionsFromSameFn { sub_fr: ty::FreeRegion, sup_fr: ty::FreeRegion, @@ -459,11 +515,12 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { fn append_to_same_regions(same_regions: &mut Vec, same_frs: &FreeRegionsFromSameFn) { + debug!("append_to_same_regions(same_regions={:?}, same_frs={:?})", + same_regions, same_frs); let scope_id = same_frs.scope_id; let (sub_fr, sup_fr) = (same_frs.sub_fr, same_frs.sup_fr); - for sr in &mut *same_regions { - if sr.contains(&sup_fr.bound_region) - && scope_id == sr.scope_id { + for sr in same_regions.iter_mut() { + if sr.contains(&sup_fr.bound_region) && scope_id == sr.scope_id { sr.push(sub_fr.bound_region); return } @@ -569,11 +626,12 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { fn report_and_explain_type_error(&self, trace: TypeTrace<'tcx>, - terr: &TypeError<'tcx>) { + terr: &TypeError<'tcx>) + -> DiagnosticBuilder<'tcx> { let span = trace.origin.span(); let mut err = self.report_type_error(trace, terr); self.tcx.note_and_explain_type_err(&mut err, terr, span); - err.emit(); + err } /// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived @@ -678,11 +736,12 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { fn report_concrete_failure(&self, origin: SubregionOrigin<'tcx>, sub: Region, - sup: Region) { + sup: Region) + -> DiagnosticBuilder<'tcx> { match origin { infer::Subtype(trace) => { let terr = TypeError::RegionsDoesNotOutlive(sup, sub); - self.report_and_explain_type_error(trace, &terr); + self.report_and_explain_type_error(trace, &terr) } infer::Reborrow(span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0312, @@ -696,7 +755,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "...but the borrowed content is only valid for ", sup, ""); - err.emit(); + err } infer::ReborrowUpvar(span, ref upvar_id) => { let mut err = struct_span_err!(self.tcx.sess, span, E0313, @@ -712,7 +771,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { self.tcx.local_var_name_str(upvar_id.var_id)), sup, ""); - err.emit(); + err } infer::InfStackClosure(span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0314, @@ -725,7 +784,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "...but the closure's stack frame is only valid for ", sup, ""); - err.emit(); + err } infer::InvokeClosure(span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0315, @@ -734,7 +793,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "the closure is only valid for ", sup, ""); - err.emit(); + err } infer::DerefPointer(span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0473, @@ -743,7 +802,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "the reference is only valid for ", sup, ""); - err.emit(); + err } infer::FreeVariable(span, id) => { let mut err = struct_span_err!(self.tcx.sess, span, E0474, @@ -757,7 +816,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "closure is valid for ", sub, ""); - err.emit(); + err } infer::IndexSlice(span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0475, @@ -766,7 +825,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "the slice is only valid for ", sup, ""); - err.emit(); + err } infer::RelateObjectBound(span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0476, @@ -780,7 +839,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "source pointer is only valid for ", sup, ""); - err.emit(); + err } infer::RelateParamBound(span, ty) => { let mut err = struct_span_err!(self.tcx.sess, span, E0477, @@ -790,7 +849,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "type must outlive ", sub, ""); - err.emit(); + err } infer::RelateRegionParamBound(span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0478, @@ -803,7 +862,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "but lifetime parameter must outlive ", sub, ""); - err.emit(); + err } infer::RelateDefaultParamBound(span, ty) => { let mut err = struct_span_err!(self.tcx.sess, span, E0479, @@ -814,7 +873,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "type must outlive ", sub, ""); - err.emit(); + err } infer::CallRcvr(span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0480, @@ -824,7 +883,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "the receiver is only valid for ", sup, ""); - err.emit(); + err } infer::CallArg(span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0481, @@ -834,7 +893,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "the function argument is only valid for ", sup, ""); - err.emit(); + err } infer::CallReturn(span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0482, @@ -844,7 +903,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "the return value is only valid for ", sup, ""); - err.emit(); + err } infer::Operand(span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0483, @@ -854,7 +913,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "the operand is only valid for ", sup, ""); - err.emit(); + err } infer::AddrOf(span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0484, @@ -863,7 +922,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "the borrow is only valid for ", sup, ""); - err.emit(); + err } infer::AutoBorrow(span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0485, @@ -873,7 +932,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "the automatic borrow is only valid for ", sup, ""); - err.emit(); + err } infer::ExprTypeIsNotInScope(t, span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0486, @@ -884,7 +943,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "type is only valid for ", sup, ""); - err.emit(); + err } infer::SafeDestructor(span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0487, @@ -899,7 +958,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "subregion: ", sub, ""); - err.emit(); + err } infer::BindingTypeIsNotValidAtDecl(span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0488, @@ -908,7 +967,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "the variable is only valid for ", sup, ""); - err.emit(); + err } infer::ParameterInScope(_, span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0489, @@ -917,7 +976,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "the parameter is only valid for ", sub, ""); - err.emit(); + err } infer::DataBorrowed(ty, span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0490, @@ -925,7 +984,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { self.ty_to_string(ty)); self.tcx.note_and_explain_region(&mut err, "the type is valid for ", sub, ""); self.tcx.note_and_explain_region(&mut err, "but the borrow lasts for ", sup, ""); - err.emit(); + err } infer::ReferenceOutlivesReferent(ty, span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0491, @@ -940,7 +999,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { "but the referenced data is only valid for ", sup, ""); - err.emit(); + err } } } @@ -970,19 +1029,22 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { } fn report_processed_errors(&self, - var_origins: &[RegionVariableOrigin], - trace_origins: &[(TypeTrace<'tcx>, TypeError<'tcx>)], + origins: &[ProcessedErrorOrigin<'tcx>], same_regions: &[SameRegions]) { - for (i, vo) in var_origins.iter().enumerate() { - let mut err = self.report_inference_failure(vo.clone()); - if i == var_origins.len() - 1 { + for (i, origin) in origins.iter().enumerate() { + let mut err = match *origin { + ProcessedErrorOrigin::VariableFailure(ref var_origin) => + self.report_inference_failure(var_origin.clone()), + ProcessedErrorOrigin::ConcreteFailure(ref sr_origin, sub, sup) => + self.report_concrete_failure(sr_origin.clone(), sub, sup), + }; + + // attach the suggestion to the last such error + if i == origins.len() - 1 { self.give_suggestion(&mut err, same_regions); } - err.emit(); - } - for &(ref trace, ref terr) in trace_origins { - self.report_and_explain_type_error(trace.clone(), terr); + err.emit(); } } diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 4ff1de422117b..290d9afa44981 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -407,7 +407,7 @@ pub fn common_supertype<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, match result { Ok(t) => t, Err(ref err) => { - cx.report_and_explain_type_error(trace, err); + cx.report_and_explain_type_error(trace, err).emit(); cx.tcx.types.err } } @@ -1396,7 +1396,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { found: actual }) }; - self.report_and_explain_type_error(trace, &err); + self.report_and_explain_type_error(trace, &err).emit(); } pub fn report_conflicting_default_types(&self, @@ -1411,11 +1411,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }) }; - self.report_and_explain_type_error(trace, + self.report_and_explain_type_error( + trace, &TypeError::TyParamDefaultMismatch(ExpectedFound { expected: expected, found: actual - })); + })) + .emit(); } pub fn replace_late_bound_regions_with_fresh_var( diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index 36462b68288c9..7bba495e46779 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -17,7 +17,7 @@ pub use self::CombineMapType::*; pub use self::RegionResolutionError::*; pub use self::VarValue::*; -use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable}; +use super::{RegionVariableOrigin, SubregionOrigin, MiscVariable}; use super::unify_key; use rustc_data_structures::graph::{self, Direction, NodeIndex}; @@ -27,7 +27,6 @@ use middle::ty::{self, Ty, TyCtxt}; use middle::ty::{BoundRegion, Region, RegionVid}; use middle::ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound}; use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh}; -use middle::ty::error::TypeError; use util::common::indenter; use util::nodemap::{FnvHashMap, FnvHashSet}; @@ -152,11 +151,16 @@ pub enum RegionResolutionError<'tcx> { /// more specific errors message by suggesting to the user where they /// should put a lifetime. In those cases we process and put those errors /// into `ProcessedErrors` before we do any reporting. - ProcessedErrors(Vec, - Vec<(TypeTrace<'tcx>, TypeError<'tcx>)>, + ProcessedErrors(Vec>, Vec), } +#[derive(Clone, Debug)] +pub enum ProcessedErrorOrigin<'tcx> { + ConcreteFailure(SubregionOrigin<'tcx>, Region, Region), + VariableFailure(RegionVariableOrigin), +} + /// SameRegions is used to group regions that we think are the same and would /// like to indicate so to the user. /// For example, the following function @@ -530,16 +534,14 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { assert!(self.values_are_none()); debug!("RegionVarBindings: lub_regions({:?}, {:?})", a, b); - match (a, b) { - (ReStatic, _) | (_, ReStatic) => { - ReStatic // nothing lives longer than static - } - - _ => { - self.combine_vars(Lub, a, b, origin.clone(), |this, old_r, new_r| { - this.make_subregion(origin.clone(), old_r, new_r) - }) - } + if a == ty::ReStatic || b == ty::ReStatic { + ReStatic // nothing lives longer than static + } else if a == b { + a // LUB(a,a) = a + } else { + self.combine_vars(Lub, a, b, origin.clone(), |this, old_r, new_r| { + this.make_subregion(origin.clone(), old_r, new_r) + }) } } @@ -550,8 +552,11 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { debug!("RegionVarBindings: glb_regions({:?}, {:?})", a, b); match (a, b) { (ReStatic, r) | (r, ReStatic) => { - // static lives longer than everything else - r + r // static lives longer than everything else + } + + _ if a == b => { + a // GLB(a,a) = a } _ => { diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index aa359c95e2d14..bb27333025e07 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -71,7 +71,7 @@ use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; use middle::ty::{self, LvaluePreference, TypeAndMut, Ty, TyCtxt}; use middle::ty::fold::TypeFoldable; use middle::ty::error::TypeError; -use middle::ty::relate::{relate_substs, RelateResult, TypeRelation}; +use middle::ty::relate::{relate_substs, Relate, RelateResult, TypeRelation}; use util::common::indent; use std::cell::RefCell; @@ -112,8 +112,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.fcx.tcx() } - /// Unify two types (using sub or lub) and produce a noop coercion. - fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { + fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { let infcx = self.fcx.infcx(); infcx.commit_if_ok(|_| { let trace = TypeTrace::types(self.origin, false, a, b); @@ -122,7 +121,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } else { infcx.sub(false, trace).relate(&a, &b) } - }).and_then(|ty| self.identity(ty)) + }) + } + + /// Unify two types (using sub or lub) and produce a noop coercion. + fn unify_and_identity(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { + self.unify(&a, &b).and_then(|ty| self.identity(ty)) } /// Synthesize an identity adjustment. @@ -166,8 +170,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return self.coerce_unsafe_ptr(a, b, mt_b.mutbl); } - ty::TyRef(_, mt_b) => { - return self.coerce_borrowed_pointer(exprs, a, b, mt_b.mutbl); + ty::TyRef(r_b, mt_b) => { + return self.coerce_borrowed_pointer(exprs, a, b, r_b, mt_b); } _ => {} @@ -187,7 +191,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } _ => { // Otherwise, just use unification rules. - self.unify(a, b) + self.unify_and_identity(a, b) } } } @@ -199,7 +203,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>, - mutbl_b: hir::Mutability) + r_b: &'tcx ty::Region, + mt_b: TypeAndMut<'tcx>) -> CoerceResult<'tcx> // FIXME(eddyb) use copyable iterators when that becomes ergonomic. where E: Fn() -> I, @@ -213,57 +218,171 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // to type check, we will construct the type that `&M*expr` would // yield. - match a.sty { - ty::TyRef(_, mt_a) => { - try!(coerce_mutbls(mt_a.mutbl, mutbl_b)); + let (r_a, mt_a) = match a.sty { + ty::TyRef(r_a, mt_a) => { + try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl)); + (r_a, mt_a) } - _ => return self.unify(a, b) - } + _ => return self.unify_and_identity(a, b) + }; let span = self.origin.span(); - let coercion = Coercion(span); - let r_borrow = self.fcx.infcx().next_region_var(coercion); - let r_borrow = self.tcx().mk_region(r_borrow); - let autoref = Some(AutoPtr(r_borrow, mutbl_b)); - let lvalue_pref = LvaluePreference::from_mutbl(mutbl_b); + let lvalue_pref = LvaluePreference::from_mutbl(mt_b.mutbl); let mut first_error = None; + let mut r_borrow_var = None; let (_, autoderefs, success) = autoderef(self.fcx, span, a, exprs, UnresolvedTypeAction::Ignore, lvalue_pref, - |inner_ty, autoderef| { + |referent_ty, autoderef| + { if autoderef == 0 { // Don't let this pass, otherwise it would cause // &T to autoref to &&T. return None; } - let ty = self.tcx().mk_ref(r_borrow, - TypeAndMut {ty: inner_ty, mutbl: mutbl_b}); - match self.unify(ty, b) { + + // At this point, we have deref'd `a` to `referent_ty`. So + // imagine we are coercing from `&'a mut Vec` to `&'b mut [T]`. + // In the autoderef loop for `&'a mut Vec`, we would get + // three callbacks: + // + // - `&'a mut Vec` -- 0 derefs, just ignore it + // - `Vec` -- 1 deref + // - `[T]` -- 2 deref + // + // At each point after the first callback, we want to + // check to see whether this would match out target type + // (`&'b mut [T]`) if we autoref'd it. We can't just + // compare the referent types, though, because we still + // have to consider the mutability. E.g., in the case + // we've been considering, we have an `&mut` reference, so + // the `T` in `[T]` needs to be unified with equality. + // + // Therefore, we construct reference types reflecting what + // the types will be after we do the final auto-ref and + // compare those. Note that this means we use the target + // mutability [1], since it may be that we are coercing + // from `&mut T` to `&U`. + // + // One fine point concerns the region that we use. We + // choose the region such that the region of the final + // type that results from `unify` will be the region we + // want for the autoref: + // + // - if in sub mode, that means we want to use `'b` (the + // region from the target reference) for both + // pointers [2]. This is because sub mode (somewhat + // arbitrarily) returns the subtype region. In the case + // where we are coercing to a target type, we know we + // want to use that target type region (`'b`) because -- + // for the program to type-check -- it must be the + // smaller of the two. + // - One fine point. It may be surprising that we can + // use `'b` without relating `'a` and `'b`. The reason + // that this is ok is that what we produce is + // effectively a `&'b *x` expression (if you could + // annotate the region of a borrow), and regionck has + // code that adds edges from the region of a borrow + // (`'b`, here) into the regions in the borrowed + // expression (`*x`, here). (Search for "link".) + // - if in lub mode, things can get fairly complicated. The + // easiest thing is just to make a fresh + // region variable [4], which effectively means we defer + // the decision to region inference (and regionck, which will add + // some more edges to this variable). However, this can wind up + // creating a crippling number of variables in some cases -- + // e.g. #32278 -- so we optimize one particular case [3]. + // Let me try to explain with some examples: + // - The "running example" above represents the simple case, + // where we have one `&` reference at the outer level and + // ownership all the rest of the way down. In this case, + // we want `LUB('a, 'b)` as the resulting region. + // - However, if there are nested borrows, that region is + // too strong. Consider a coercion from `&'a &'x Rc` to + // `&'b T`. In this case, `'a` is actually irrelevant. + // The pointer we want is `LUB('x, 'b`). If we choose `LUB('a,'b)` + // we get spurious errors (`run-pass/regions-lub-ref-ref-rc.rs`). + // (The errors actually show up in borrowck, typically, because + // this extra edge causes the region `'a` to be inferred to something + // too big, which then results in borrowck errors.) + // - We could track the innermost shared reference, but there is already + // code in regionck that has the job of creating links between + // the region of a borrow and the regions in the thing being + // borrowed (here, `'a` and `'x`), and it knows how to handle + // all the various cases. So instead we just make a region variable + // and let regionck figure it out. + let r = if !self.use_lub { + r_b // [2] above + } else if autoderef == 1 { + r_a // [3] above + } else { + if r_borrow_var.is_none() { // create var lazilly, at most once + let coercion = Coercion(span); + let r = self.fcx.infcx().next_region_var(coercion); + r_borrow_var = Some(self.tcx().mk_region(r)); // [4] above + } + r_borrow_var.unwrap() + }; + let derefd_ty_a = self.tcx().mk_ref(r, TypeAndMut { + ty: referent_ty, + mutbl: mt_b.mutbl // [1] above + }); + match self.unify(derefd_ty_a, b) { + Ok(ty) => Some(ty), Err(err) => { if first_error.is_none() { first_error = Some(err); } None } - Ok((ty, _)) => Some(ty) } }); - match success { - Some(ty) => { - Ok((ty, AdjustDerefRef(AutoDerefRef { - autoderefs: autoderefs, - autoref: autoref, - unsize: None - }))) - } + // Extract type or return an error. We return the first error + // we got, which should be from relating the "base" type + // (e.g., in example above, the failure from relating `Vec` + // to the target type), since that should be the least + // confusing. + let ty = match success { + Some(ty) => ty, None => { - // Return original error as if overloaded deref was never - // attempted, to avoid irrelevant/confusing error messages. - Err(first_error.expect("coerce_borrowed_pointer failed with no error?")) + let err = first_error.expect("coerce_borrowed_pointer had no error"); + debug!("coerce_borrowed_pointer: failed with err = {:?}", err); + return Err(err); } + }; + + // Now apply the autoref. We have to extract the region out of + // the final ref type we got. + if ty == a && mt_a.mutbl == hir::MutImmutable && autoderefs == 1 { + // As a special case, if we would produce `&'a *x`, that's + // a total no-op. We end up with the type `&'a T` just as + // we started with. In that case, just skip it + // altogether. This is just an optimization. + // + // Note that for `&mut`, we DO want to reborrow -- + // otherwise, this would be a move, which might be an + // error. For example `foo(self.x)` where `self` and + // `self.x` both have `&mut `type would be a move of + // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`, + // which is a borrow. + assert_eq!(mt_b.mutbl, hir::MutImmutable); // can only coerce &T -> &U + return self.identity(ty); } + let r_borrow = match ty.sty { + ty::TyRef(r_borrow, _) => r_borrow, + _ => self.tcx().sess.span_bug(span, + &format!("expected a ref type, got {:?}", ty)) + }; + let autoref = Some(AutoPtr(r_borrow, mt_b.mutbl)); + debug!("coerce_borrowed_pointer: succeeded ty={:?} autoderefs={:?} autoref={:?}", + ty, autoderefs, autoref); + Ok((ty, AdjustDerefRef(AutoDerefRef { + autoderefs: autoderefs, + autoref: autoref, + unsize: None + }))) } @@ -392,14 +511,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match (fn_ty_a.unsafety, fn_ty_b.unsafety) { (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a); - return self.unify(unsafe_a, b).map(|(ty, _)| { + return self.unify_and_identity(unsafe_a, b).map(|(ty, _)| { (ty, AdjustUnsafeFnPointer) }); } _ => {} } } - self.unify(a, b) + self.unify_and_identity(a, b) } fn coerce_from_fn_item(&self, @@ -418,11 +537,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match b.sty { ty::TyFnPtr(_) => { let a_fn_pointer = self.tcx().mk_ty(ty::TyFnPtr(fn_ty_a)); - self.unify(a_fn_pointer, b).map(|(ty, _)| { + self.unify_and_identity(a_fn_pointer, b).map(|(ty, _)| { (ty, AdjustReifyFnPointer) }) } - _ => self.unify(a, b) + _ => self.unify_and_identity(a, b) } } @@ -439,13 +558,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::TyRef(_, mt) => (true, mt), ty::TyRawPtr(mt) => (false, mt), _ => { - return self.unify(a, b); + return self.unify_and_identity(a, b); } }; // Check that the types which they point at are compatible. let a_unsafe = self.tcx().mk_ptr(ty::TypeAndMut{ mutbl: mutbl_b, ty: mt_a.ty }); - let (ty, noop) = try!(self.unify(a_unsafe, b)); + let (ty, noop) = try!(self.unify_and_identity(a_unsafe, b)); try!(coerce_mutbls(mt_a.mutbl, mutbl_b)); // Although references and unsafe ptrs have the same diff --git a/src/test/compile-fail/issue-10291.rs b/src/test/compile-fail/issue-10291.rs index 9711d760ae666..43255db2ff3ab 100644 --- a/src/test/compile-fail/issue-10291.rs +++ b/src/test/compile-fail/issue-10291.rs @@ -11,8 +11,7 @@ fn test<'x>(x: &'x isize) { // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. drop:: FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { - x - //~^ ERROR cannot infer an appropriate lifetime + x //~ ERROR E0312 })); } diff --git a/src/test/compile-fail/issue-13058.rs b/src/test/compile-fail/issue-13058.rs index 503ccbd1cabfe..b552d7678d563 100644 --- a/src/test/compile-fail/issue-13058.rs +++ b/src/test/compile-fail/issue-13058.rs @@ -36,9 +36,5 @@ fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &T) -> bool fn main() { check((3, 5)); //~^ ERROR mismatched types -//~| expected `&_` -//~| found `(_, _)` -//~| expected &-ptr -//~| found tuple //~| HELP run `rustc --explain E0308` to see a detailed explanation } diff --git a/src/test/compile-fail/issue-7573.rs b/src/test/compile-fail/issue-7573.rs index 2d1cea1d44b74..d13da1d9fd948 100644 --- a/src/test/compile-fail/issue-7573.rs +++ b/src/test/compile-fail/issue-7573.rs @@ -24,11 +24,9 @@ impl CrateId { } pub fn remove_package_from_database() { - let mut lines_to_use: Vec<&CrateId> = Vec::new(); + let mut lines_to_use: Vec<&CrateId> = Vec::new(); //~ ERROR E0495 let push_id = |installed_id: &CrateId| { lines_to_use.push(installed_id); - //~^ ERROR cannot infer an appropriate lifetime for automatic coercion due to - // conflicting requirements }; list_database(push_id); diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-3.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-3.rs index 66d8927ee51b7..e0ea1ed743407 100644 --- a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-3.rs +++ b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-3.rs @@ -14,19 +14,19 @@ use std::marker::PhantomData; struct Bar<'x, 'y, 'z> { bar: &'y i32, baz: i32, marker: PhantomData<(&'x(),&'y(),&'z())> } fn bar1<'a>(x: &Bar) -> (&'a i32, &'a i32, &'a i32) { -//~^ HELP: consider using an explicit lifetime parameter as shown: fn bar1<'b, 'c, 'a>(x: &'a Bar<'b, 'a, 'c>) -> (&'a i32, &'a i32, &'a i32) + //~^ HELP: consider using an explicit lifetime parameter as shown: fn bar1<'a>(x: &'a Bar) -> (&'a i32, &'a i32, &'a i32) (x.bar, &x.baz, &x.baz) - //~^ ERROR: cannot infer - //~^^ ERROR: cannot infer - //~^^^ ERROR: cannot infer + //~^ ERROR E0312 + //~| ERROR cannot infer + //~| ERROR cannot infer } fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&'a i32, &'a i32, &'a i32) { -//~^ HELP: consider using an explicit lifetime parameter as shown: fn bar2<'a, 'c>(x: &'a Bar<'a, 'a, 'c>) -> (&'a i32, &'a i32, &'a i32) + //~^ HELP: consider using an explicit lifetime parameter as shown: fn bar2<'a, 'c>(x: &'a Bar<'a, 'a, 'c>) -> (&'a i32, &'a i32, &'a i32) (x.bar, &x.baz, &x.baz) - //~^ ERROR: cannot infer - //~^^ ERROR: cannot infer - //~^^^ ERROR: cannot infer + //~^ ERROR E0312 + //~| ERROR cannot infer + //~| ERROR cannot infer } fn main() { } diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs index e32ed1c42a090..73d89beb2202f 100644 --- a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs +++ b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs @@ -39,8 +39,8 @@ struct Cat<'x, T> { cat: &'x isize, t: T } struct Dog<'y> { dog: &'y isize } fn cat2<'x, 'y>(x: Cat<'x, Dog<'y>>) -> &'x isize { -//~^ HELP: consider using an explicit lifetime parameter as shown: fn cat2<'x>(x: Cat<'x, Dog<'x>>) -> &'x isize - x.t.dog //~ ERROR: cannot infer + //~^ HELP consider using an explicit lifetime parameter as shown: fn cat2<'x>(x: Cat<'x, Dog<'x>>) -> &'x isize + x.t.dog //~ ERROR E0312 } struct Baz<'x> { @@ -49,11 +49,9 @@ struct Baz<'x> { impl<'a> Baz<'a> { fn baz2<'b>(&self, x: &isize) -> (&'b isize, &'b isize) { - //~^ HELP: parameter as shown: fn baz2<'b>(&self, x: &'b isize) -> (&'a isize, &'a isize) - // The lifetime that gets assigned to `x` seems somewhat random. - // I have disabled this test for the time being. --pcwalton - (self.bar, x) //~ ERROR: cannot infer - //~^ ERROR: cannot infer + //~^ HELP consider using an explicit lifetime parameter as shown: fn baz2<'b>(&self, x: &'b isize) -> (&'a isize, &'a isize) + (self.bar, x) //~ ERROR E0312 + //~^ ERROR E0312 } } diff --git a/src/test/compile-fail/lub-if.rs b/src/test/compile-fail/lub-if.rs index 06af8ac8719e5..8d2a0fd07e80a 100644 --- a/src/test/compile-fail/lub-if.rs +++ b/src/test/compile-fail/lub-if.rs @@ -35,14 +35,14 @@ pub fn opt_str2<'a>(maybestr: &'a Option) -> &'static str { "(none)" } else { let s: &'a str = maybestr.as_ref().unwrap(); - s //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to conflicting + s //~ ERROR E0312 } } pub fn opt_str3<'a>(maybestr: &'a Option) -> &'static str { if maybestr.is_some() { let s: &'a str = maybestr.as_ref().unwrap(); - s //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to conflicting + s //~ ERROR E0312 } else { "(none)" } diff --git a/src/test/compile-fail/lub-match.rs b/src/test/compile-fail/lub-match.rs index 1b5824964a8eb..b9423feb5c1cd 100644 --- a/src/test/compile-fail/lub-match.rs +++ b/src/test/compile-fail/lub-match.rs @@ -37,8 +37,7 @@ pub fn opt_str2<'a>(maybestr: &'a Option) -> &'static str { None => "(none)", Some(ref s) => { let s: &'a str = s; - s - //~^ ERROR cannot infer an appropriate lifetime + s //~ ERROR E0312 } } } @@ -47,8 +46,7 @@ pub fn opt_str3<'a>(maybestr: &'a Option) -> &'static str { match *maybestr { Some(ref s) => { let s: &'a str = s; - s - //~^ ERROR cannot infer an appropriate lifetime + s //~ ERROR E0312 } None => "(none)", } diff --git a/src/test/compile-fail/object-lifetime-default-mybox.rs b/src/test/compile-fail/object-lifetime-default-mybox.rs index 80dbee3c481e6..014b0c1e80e71 100644 --- a/src/test/compile-fail/object-lifetime-default-mybox.rs +++ b/src/test/compile-fail/object-lifetime-default-mybox.rs @@ -34,8 +34,7 @@ fn load1<'a,'b>(a: &'a MyBox, b: &'b MyBox) -> &'b MyBox { - a - //~^ ERROR cannot infer + a //~ ERROR E0312 } fn load2<'a>(ss: &MyBox) -> MyBox { diff --git a/src/test/compile-fail/region-lifetime-bounds-on-fns-where-clause.rs b/src/test/compile-fail/region-lifetime-bounds-on-fns-where-clause.rs index ee05ba676ac70..6364db1f4b49c 100644 --- a/src/test/compile-fail/region-lifetime-bounds-on-fns-where-clause.rs +++ b/src/test/compile-fail/region-lifetime-bounds-on-fns-where-clause.rs @@ -15,7 +15,7 @@ fn a<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) where 'b: 'a { fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) { // Illegal now because there is no `'b:'a` declaration. - *x = *y; //~ ERROR cannot infer + *x = *y; //~ ERROR E0312 } fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) { diff --git a/src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs b/src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs index 30e6a4e12773f..154135eba38ba 100644 --- a/src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs +++ b/src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs @@ -16,8 +16,8 @@ fn a<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) where fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) { // Illegal now because there is no `'b:'a` declaration. - *x = *y; //~ ERROR cannot infer - *z = *y; //~ ERROR cannot infer + *x = *y; //~ ERROR E0312 + *z = *y; //~ ERROR E0312 } fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) { diff --git a/src/test/compile-fail/regions-early-bound-error-method.rs b/src/test/compile-fail/regions-early-bound-error-method.rs index 4a3ca01c8496d..8cc35272282c4 100644 --- a/src/test/compile-fail/regions-early-bound-error-method.rs +++ b/src/test/compile-fail/regions-early-bound-error-method.rs @@ -28,8 +28,7 @@ impl<'a> GetRef<'a> for Box<'a> { impl<'a> Box<'a> { fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a isize { g2.get() - //~^ ERROR cannot infer an appropriate lifetime for automatic coercion due to - //~| ERROR mismatched types + //~^ ERROR mismatched types //~| expected `&'a isize` //~| found `&'b isize` //~| lifetime mismatch diff --git a/src/test/compile-fail/regions-early-bound-error.rs b/src/test/compile-fail/regions-early-bound-error.rs index 57c8e3f1170aa..1fc3b4b3c6a62 100644 --- a/src/test/compile-fail/regions-early-bound-error.rs +++ b/src/test/compile-fail/regions-early-bound-error.rs @@ -27,11 +27,7 @@ impl<'a,T:Clone> GetRef<'a,T> for Box<'a,T> { fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize { g1.get() - //~^ ERROR cannot infer an appropriate lifetime for automatic coercion due to - //~| ERROR mismatched types - //~| expected `&'b isize` - //~| found `&'a isize` - //~| lifetime mismatch + //~^ ERROR mismatched types } fn main() { diff --git a/src/test/compile-fail/regions-glb-free-free.rs b/src/test/compile-fail/regions-glb-free-free.rs index 323d5360029c5..c2e4fbac3c941 100644 --- a/src/test/compile-fail/regions-glb-free-free.rs +++ b/src/test/compile-fail/regions-glb-free-free.rs @@ -22,9 +22,9 @@ mod argparse { impl<'a> Flag<'a> { pub fn set_desc(self, s: &str) -> Flag<'a> { - Flag { + Flag { //~ ERROR cannot infer name: self.name, - desc: s, //~ ERROR cannot infer an appropriate lifetime for automatic coercion due t + desc: s, max_count: self.max_count, value: self.value } diff --git a/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs b/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs index 43940d499d210..89254516ac600 100644 --- a/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs +++ b/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs @@ -15,13 +15,13 @@ fn a<'a, 'b:'a>(x: &mut &'a isize, y: &mut &'b isize) { fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) { // Illegal now because there is no `'b:'a` declaration. - *x = *y; //~ ERROR cannot infer + *x = *y; //~ ERROR E0312 } fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) { // Here we try to call `foo` but do not know that `'a` and `'b` are // related as required. - a(x, y); //~ ERROR cannot infer + a(x, y); //~ ERROR E0495 } fn d() { diff --git a/src/test/compile-fail/regions-nested-fns.rs b/src/test/compile-fail/regions-nested-fns.rs index f114a8bc7ce66..5ef2a701a6005 100644 --- a/src/test/compile-fail/regions-nested-fns.rs +++ b/src/test/compile-fail/regions-nested-fns.rs @@ -14,16 +14,16 @@ fn ignore(t: T) {} fn nested<'x>(x: &'x isize) { let y = 3; - let mut ay = &y; + let mut ay = &y; //~ ERROR E0495 ignore:: FnMut(&'z isize)>>(Box::new(|z| { - ay = x; //~ ERROR cannot infer + ay = x; ay = &y; ay = z; })); ignore::< Box FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { - if false { return x; } //~ ERROR cannot infer an appropriate lifetime for automatic + if false { return x; } //~ ERROR E0312 if false { return ay; } return z; })); diff --git a/src/test/compile-fail/regions-static-bound.rs b/src/test/compile-fail/regions-static-bound.rs index 297b6a866da3a..de695e72d07e4 100644 --- a/src/test/compile-fail/regions-static-bound.rs +++ b/src/test/compile-fail/regions-static-bound.rs @@ -13,7 +13,7 @@ fn static_id<'a,'b>(t: &'a ()) -> &'static () fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () where 'a: 'b, 'b: 'static { t } fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { - t //~ ERROR cannot infer an appropriate lifetime + t //~ ERROR E0312 } fn error(u: &(), v: &()) { diff --git a/src/test/compile-fail/unboxed-closures-infer-argument-types-two-region-pointers.rs b/src/test/compile-fail/unboxed-closures-infer-argument-types-two-region-pointers.rs index 3dd5779914d06..1e2b01856e71b 100644 --- a/src/test/compile-fail/unboxed-closures-infer-argument-types-two-region-pointers.rs +++ b/src/test/compile-fail/unboxed-closures-infer-argument-types-two-region-pointers.rs @@ -24,6 +24,6 @@ fn doit(val: T, f: &F) pub fn main() { doit(0, &|x, y| { - x.set(y); //~ ERROR cannot infer + x.set(y); //~ ERROR E0312 }); } diff --git a/src/test/compile-fail/wf-static-method.rs b/src/test/compile-fail/wf-static-method.rs index 6c6522fe658d2..e99957c791427 100644 --- a/src/test/compile-fail/wf-static-method.rs +++ b/src/test/compile-fail/wf-static-method.rs @@ -24,7 +24,7 @@ struct Evil<'a, 'b: 'a>(Option<&'a &'b ()>); impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () { fn make_me() -> Self { } fn static_evil(u: &'b u32) -> &'a u32 { - u //~ ERROR cannot infer an appropriate lifetime + u //~ ERROR E0312 } } @@ -40,7 +40,7 @@ impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> { impl<'a, 'b> Evil<'a, 'b> { fn inherent_evil(u: &'b u32) -> &'a u32 { - u //~ ERROR cannot infer an appropriate lifetime + u //~ ERROR E0312 } } diff --git a/src/test/run-pass/regions-lub-ref-ref-rc.rs b/src/test/run-pass/regions-lub-ref-ref-rc.rs new file mode 100644 index 0000000000000..41c64197acbe8 --- /dev/null +++ b/src/test/run-pass/regions-lub-ref-ref-rc.rs @@ -0,0 +1,36 @@ +// 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 a corner case of LUB coercion. In this case, one arm of the +// match requires a deref coercion and other other doesn't, and there +// is an extra `&` on the `rc`. We want to be sure that the lifetime +// assigned to this `&rc` value is not `'a` but something smaller. In +// other words, the type from `rc` is `&'a Rc` and the type +// from `&rc` should be `&'x &'a Rc`, where `'x` is something +// small. + +use std::rc::Rc; + +#[derive(Clone)] +enum CachedMir<'mir> { + Ref(&'mir String), + Owned(Rc), +} + +impl<'mir> CachedMir<'mir> { + fn get_ref<'a>(&'a self) -> &'a String { + match *self { + CachedMir::Ref(r) => r, + CachedMir::Owned(ref rc) => &rc, + } + } +} + +fn main() { }