Change:
For the input file below, the two distinct invocations of (but with identical arguments) are non-deterministically deciding whether or not to prompt with the "consider using an explicit lifetime parameter" hint. Input file (): Transcript: (See also for a problem with the suggestion actually provided by when it chooses to actually provide one.)
I tested it a bit, and the issue seems to be is fed slightly different information each time. In the first case we have a and in the second . In the constraint graph for some node we are trying to infer, there are multiple incoming edges and outgoing edges to and from . From my understanding the compiler only picks one node from these incoming edges and one node from these outgoing edges, and it doesn't pick the same pair each time (what I don't understand is why I didn't see the and variations).
I'm getting a non-deterministic error message using the latest nightlies: It's non-deterministic on my Fedora 20 machine but not my OSX machine.

Discussion:
// failed (so the return value of this method should not be used) fn process_errors(&self, errors: &Vec<RegionResolutionError>) -> Vec<RegionResolutionError> { <ins> debug!("process_errors()"); </ins> let mut var_origins = Vec::new(); let mut trace_origins = Vec::new(); let mut same_regions = Vec::new();

for error in errors.iter() { match *error { ConcreteFailure(origin, sub, sup) => { <ins> debug!("processing ConcreteFailure") </ins> let trace = match origin { infer::Subtype(trace) => Some(trace), _ => None,

} } SubSupConflict(var_origin, _, sub_r, _, sup_r) => { <ins> debug!("processing SubSupConflict") </ins> match free_regions_from_same_fn(self.tcx, sub_r, sup_r) { Some(ref same_frs) => { var_origins.push(var_origin);

// declaration, we want to make sure that they are, in fact, // from the same scope if sr.scope_id != common_scope_id { <ins> debug!("returning empty result from process_errors because {} != {}", sr.scope_id, common_scope_id); </ins> return vec!(); } } let pe = ProcessedErrors(var_origins, trace_origins, same_regions); <ins> debug!("errors processed: {:?}", pe); </ins> processed_errors.push(pe); } return processed_errors;

sub: Region, sup: Region) -> Option<FreeRegionsFromSameFn> { <ins> debug!("free_regions_from_same_fn(sub={:?}, sup={:?})", sub, sup); </ins> let (scope_id, fr1, fr2) = match (sub, sup) { (ReFree(fr1), ReFree(fr2)) => { if fr1.scope_id != fr2.scope_id {

}, _ => None }, <del> None => None </del> <ins> None => { debug!("no parent node of scope_id {}", scope_id) None } </ins> } }

{ // Errors in expanding nodes result from a lower-bound that is // not contained by an upper-bound. <del> let (lower_bounds, lower_dup) = </del> <ins> let (mut lower_bounds, lower_dup) = </ins> self.collect_concrete_regions(graph, var_data, node_idx, graph::Incoming, dup_vec); <del> let (upper_bounds, upper_dup) = </del> <ins> let (mut upper_bounds, upper_dup) = </ins> self.collect_concrete_regions(graph, var_data, node_idx, graph::Outgoing, dup_vec);

return; } <ins> // We place free regions first because we are special casing // SubSupConflict(ReFree, ReFree) when reporting error, and so // the user will more likely get a specific suggestion. fn free_regions_first(a: &RegionAndOrigin, b: &RegionAndOrigin) -> Ordering { match (a.region, b.region) { (ReFree(..), ReFree(..)) => Equal, (ReFree(..), _) => Less, (_, ReFree(..)) => Greater, (_, _) => Equal, } } lower_bounds.sort_by(|a, b| { free_regions_first(a, b) }); upper_bounds.sort_by(|a, b| { free_regions_first(a, b) }); </ins> for lower_bound in lower_bounds.iter() { for upper_bound in upper_bounds.iter() { if !self.is_subregion_of(lower_bound.region,