Auto merge of #32306 - nikomatsakis:issue-32278, r=eddyb

create fewer region variables in coercions

Fixes #32278.

r? @eddyb
This commit is contained in:
bors 2016-03-19 18:39:50 -07:00
commit 78e8a00514
23 changed files with 396 additions and 189 deletions

View File

@ -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<RegionResolutionError<'tcx>>);
fn process_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>)
-> Vec<RegionResolutionError<'tcx>>;
-> Option<Vec<RegionResolutionError<'tcx>>>;
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<String>;
@ -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<RegionResolutionError<'tcx>>) {
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<RegionResolutionError<'tcx>>)
-> Vec<RegionResolutionError<'tcx>> {
-> Option<Vec<RegionResolutionError<'tcx>>> {
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<SameRegions>,
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();
}
}

View File

@ -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<T>(

View File

@ -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<RegionVariableOrigin>,
Vec<(TypeTrace<'tcx>, TypeError<'tcx>)>,
ProcessedErrors(Vec<ProcessedErrorOrigin<'tcx>>,
Vec<SameRegions>),
}
#[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
}
_ => {

View File

@ -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<T>` to `&'b mut [T]`.
// In the autoderef loop for `&'a mut Vec<T>`, we would get
// three callbacks:
//
// - `&'a mut Vec<T>` -- 0 derefs, just ignore it
// - `Vec<T>` -- 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<T>` 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<T>`
// 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

View File

@ -11,8 +11,7 @@
fn test<'x>(x: &'x isize) {
// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
drop::<Box<for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
x
//~^ ERROR cannot infer an appropriate lifetime
x //~ ERROR E0312
}));
}

View File

@ -36,9 +36,5 @@ fn check<'r, I: Iterator<Item=usize>, 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
}

View File

@ -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);

View File

@ -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() { }

View File

@ -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
}
}

View File

@ -35,14 +35,14 @@ pub fn opt_str2<'a>(maybestr: &'a Option<String>) -> &'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<String>) -> &'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)"
}

View File

@ -37,8 +37,7 @@ pub fn opt_str2<'a>(maybestr: &'a Option<String>) -> &'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<String>) -> &'static str {
match *maybestr {
Some(ref s) => {
let s: &'a str = s;
s
//~^ ERROR cannot infer an appropriate lifetime
s //~ ERROR E0312
}
None => "(none)",
}

View File

@ -34,8 +34,7 @@ fn load1<'a,'b>(a: &'a MyBox<SomeTrait>,
b: &'b MyBox<SomeTrait>)
-> &'b MyBox<SomeTrait>
{
a
//~^ ERROR cannot infer
a //~ ERROR E0312
}
fn load2<'a>(ss: &MyBox<SomeTrait+'a>) -> MyBox<SomeTrait+'a> {

View File

@ -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) {

View File

@ -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) {

View File

@ -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

View File

@ -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() {

View File

@ -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
}

View File

@ -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() {

View File

@ -14,16 +14,16 @@ fn ignore<T>(t: T) {}
fn nested<'x>(x: &'x isize) {
let y = 3;
let mut ay = &y;
let mut ay = &y; //~ ERROR E0495
ignore::<Box<for<'z> FnMut(&'z isize)>>(Box::new(|z| {
ay = x; //~ ERROR cannot infer
ay = x;
ay = &y;
ay = z;
}));
ignore::< Box<for<'z> 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;
}));

View File

@ -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: &()) {

View File

@ -24,6 +24,6 @@ fn doit<T,F>(val: T, f: &F)
pub fn main() {
doit(0, &|x, y| {
x.set(y); //~ ERROR cannot infer
x.set(y); //~ ERROR E0312
});
}

View File

@ -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
}
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<String>` and the type
// from `&rc` should be `&'x &'a Rc<String>`, where `'x` is something
// small.
use std::rc::Rc;
#[derive(Clone)]
enum CachedMir<'mir> {
Ref(&'mir String),
Owned(Rc<String>),
}
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() { }