make suggestion stuff not swallow errors
The older code would sometimes swallow errors or fail to produce a suggestion. The newer code does not. However, just printing everything would produce a bunch of new and kind of annoying errors, so continue to swallow `T: 'a` errors so long as there are other things to show.
This commit is contained in:
parent
5abacd36f0
commit
bca07b5ebb
6 changed files with 155 additions and 89 deletions
|
@ -68,6 +68,7 @@ use super::region_inference::SubSupConflict;
|
||||||
use super::region_inference::GenericBoundFailure;
|
use super::region_inference::GenericBoundFailure;
|
||||||
use super::region_inference::GenericKind;
|
use super::region_inference::GenericKind;
|
||||||
use super::region_inference::ProcessedErrors;
|
use super::region_inference::ProcessedErrors;
|
||||||
|
use super::region_inference::ProcessedErrorOrigin;
|
||||||
use super::region_inference::SameRegions;
|
use super::region_inference::SameRegions;
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
@ -232,7 +233,7 @@ pub trait ErrorReporting<'tcx> {
|
||||||
errors: &Vec<RegionResolutionError<'tcx>>);
|
errors: &Vec<RegionResolutionError<'tcx>>);
|
||||||
|
|
||||||
fn process_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>)
|
fn process_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>)
|
||||||
-> Vec<RegionResolutionError<'tcx>>;
|
-> Option<Vec<RegionResolutionError<'tcx>>>;
|
||||||
|
|
||||||
fn report_type_error(&self,
|
fn report_type_error(&self,
|
||||||
trace: TypeTrace<'tcx>,
|
trace: TypeTrace<'tcx>,
|
||||||
|
@ -246,7 +247,8 @@ pub trait ErrorReporting<'tcx> {
|
||||||
|
|
||||||
fn report_and_explain_type_error(&self,
|
fn report_and_explain_type_error(&self,
|
||||||
trace: TypeTrace<'tcx>,
|
trace: TypeTrace<'tcx>,
|
||||||
terr: &TypeError<'tcx>);
|
terr: &TypeError<'tcx>)
|
||||||
|
-> DiagnosticBuilder<'tcx>;
|
||||||
|
|
||||||
fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<String>;
|
fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<String>;
|
||||||
|
|
||||||
|
@ -258,7 +260,8 @@ pub trait ErrorReporting<'tcx> {
|
||||||
fn report_concrete_failure(&self,
|
fn report_concrete_failure(&self,
|
||||||
origin: SubregionOrigin<'tcx>,
|
origin: SubregionOrigin<'tcx>,
|
||||||
sub: Region,
|
sub: Region,
|
||||||
sup: Region);
|
sup: Region)
|
||||||
|
-> DiagnosticBuilder<'tcx>;
|
||||||
|
|
||||||
fn report_generic_bound_failure(&self,
|
fn report_generic_bound_failure(&self,
|
||||||
origin: SubregionOrigin<'tcx>,
|
origin: SubregionOrigin<'tcx>,
|
||||||
|
@ -273,8 +276,7 @@ pub trait ErrorReporting<'tcx> {
|
||||||
sup_region: Region);
|
sup_region: Region);
|
||||||
|
|
||||||
fn report_processed_errors(&self,
|
fn report_processed_errors(&self,
|
||||||
var_origin: &[RegionVariableOrigin],
|
origins: &[ProcessedErrorOrigin<'tcx>],
|
||||||
trace_origin: &[(TypeTrace<'tcx>, TypeError<'tcx>)],
|
|
||||||
same_regions: &[SameRegions]);
|
same_regions: &[SameRegions]);
|
||||||
|
|
||||||
fn give_suggestion(&self, err: &mut DiagnosticBuilder, 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> {
|
impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
fn report_region_errors(&self,
|
fn report_region_errors(&self,
|
||||||
errors: &Vec<RegionResolutionError<'tcx>>) {
|
errors: &Vec<RegionResolutionError<'tcx>>) {
|
||||||
let p_errors = self.process_errors(errors);
|
debug!("report_region_errors(): {} errors to start", errors.len());
|
||||||
let errors = if p_errors.is_empty() { errors } else { &p_errors };
|
|
||||||
|
// 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 {
|
for error in errors {
|
||||||
match error.clone() {
|
match error.clone() {
|
||||||
ConcreteFailure(origin, sub, sup) => {
|
ConcreteFailure(origin, sub, sup) => {
|
||||||
self.report_concrete_failure(origin, sub, sup);
|
self.report_concrete_failure(origin, sub, sup).emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericBoundFailure(kind, param_ty, sub) => {
|
GenericBoundFailure(kind, param_ty, sub) => {
|
||||||
|
@ -323,13 +332,10 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
sup_origin, sup_r);
|
sup_origin, sup_r);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessedErrors(ref var_origins,
|
ProcessedErrors(ref origins,
|
||||||
ref trace_origins,
|
|
||||||
ref same_regions) => {
|
ref same_regions) => {
|
||||||
if !same_regions.is_empty() {
|
if !same_regions.is_empty() {
|
||||||
self.report_processed_errors(&var_origins[..],
|
self.report_processed_errors(origins, same_regions);
|
||||||
&trace_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
|
// parameters to the user. This is done so that we can have a more
|
||||||
// complete view of what lifetimes should be the same.
|
// complete view of what lifetimes should be the same.
|
||||||
// If the return value is an empty vector, it means that processing
|
// 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>>)
|
fn process_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>)
|
||||||
-> Vec<RegionResolutionError<'tcx>> {
|
-> Option<Vec<RegionResolutionError<'tcx>>> {
|
||||||
debug!("process_errors()");
|
debug!("process_errors()");
|
||||||
let mut var_origins = Vec::new();
|
let mut origins = Vec::new();
|
||||||
let mut trace_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 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 {
|
for error in errors {
|
||||||
match error.clone() {
|
match *error {
|
||||||
ConcreteFailure(origin, sub, sup) => {
|
ConcreteFailure(ref origin, sub, sup) => {
|
||||||
debug!("processing ConcreteFailure");
|
debug!("processing ConcreteFailure");
|
||||||
let trace = match origin {
|
|
||||||
infer::Subtype(trace) => Some(trace),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
match free_regions_from_same_fn(self.tcx, sub, sup) {
|
match free_regions_from_same_fn(self.tcx, sub, sup) {
|
||||||
Some(ref same_frs) if trace.is_some() => {
|
Some(ref same_frs) => {
|
||||||
let trace = trace.unwrap();
|
origins.push(
|
||||||
let terr = TypeError::RegionsDoesNotOutlive(sup,
|
ProcessedErrorOrigin::ConcreteFailure(
|
||||||
sub);
|
origin.clone(),
|
||||||
trace_origins.push((trace, terr));
|
sub,
|
||||||
|
sup));
|
||||||
append_to_same_regions(&mut same_regions, same_frs);
|
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);
|
debug!("processing SubSupConflict sub: {:?} sup: {:?}", sub_r, sup_r);
|
||||||
match free_regions_from_same_fn(self.tcx, sub_r, sup_r) {
|
match free_regions_from_same_fn(self.tcx, sub_r, sup_r) {
|
||||||
Some(ref same_frs) => {
|
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);
|
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() {
|
if !same_regions.is_empty() {
|
||||||
let common_scope_id = same_regions[0].scope_id;
|
let common_scope_id = same_regions[0].scope_id;
|
||||||
for sr in &same_regions {
|
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 {
|
if sr.scope_id != common_scope_id {
|
||||||
debug!("returning empty result from process_errors because
|
debug!("returning empty result from process_errors because
|
||||||
{} != {}", sr.scope_id, common_scope_id);
|
{} != {}", 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);
|
debug!("errors processed: {:?}", pe);
|
||||||
processed_errors.push(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 {
|
struct FreeRegionsFromSameFn {
|
||||||
sub_fr: ty::FreeRegion,
|
sub_fr: ty::FreeRegion,
|
||||||
sup_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>,
|
fn append_to_same_regions(same_regions: &mut Vec<SameRegions>,
|
||||||
same_frs: &FreeRegionsFromSameFn) {
|
same_frs: &FreeRegionsFromSameFn) {
|
||||||
|
debug!("append_to_same_regions(same_regions={:?}, same_frs={:?})",
|
||||||
|
same_regions, same_frs);
|
||||||
let scope_id = same_frs.scope_id;
|
let scope_id = same_frs.scope_id;
|
||||||
let (sub_fr, sup_fr) = (same_frs.sub_fr, same_frs.sup_fr);
|
let (sub_fr, sup_fr) = (same_frs.sub_fr, same_frs.sup_fr);
|
||||||
for sr in &mut *same_regions {
|
for sr in same_regions.iter_mut() {
|
||||||
if sr.contains(&sup_fr.bound_region)
|
if sr.contains(&sup_fr.bound_region) && scope_id == sr.scope_id {
|
||||||
&& scope_id == sr.scope_id {
|
|
||||||
sr.push(sub_fr.bound_region);
|
sr.push(sub_fr.bound_region);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -569,11 +626,12 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
fn report_and_explain_type_error(&self,
|
fn report_and_explain_type_error(&self,
|
||||||
trace: TypeTrace<'tcx>,
|
trace: TypeTrace<'tcx>,
|
||||||
terr: &TypeError<'tcx>) {
|
terr: &TypeError<'tcx>)
|
||||||
|
-> DiagnosticBuilder<'tcx> {
|
||||||
let span = trace.origin.span();
|
let span = trace.origin.span();
|
||||||
let mut err = self.report_type_error(trace, terr);
|
let mut err = self.report_type_error(trace, terr);
|
||||||
self.tcx.note_and_explain_type_err(&mut err, terr, span);
|
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
|
/// 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,
|
fn report_concrete_failure(&self,
|
||||||
origin: SubregionOrigin<'tcx>,
|
origin: SubregionOrigin<'tcx>,
|
||||||
sub: Region,
|
sub: Region,
|
||||||
sup: Region) {
|
sup: Region)
|
||||||
|
-> DiagnosticBuilder<'tcx> {
|
||||||
match origin {
|
match origin {
|
||||||
infer::Subtype(trace) => {
|
infer::Subtype(trace) => {
|
||||||
let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
|
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) => {
|
infer::Reborrow(span) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0312,
|
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 ",
|
"...but the borrowed content is only valid for ",
|
||||||
sup,
|
sup,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::ReborrowUpvar(span, ref upvar_id) => {
|
infer::ReborrowUpvar(span, ref upvar_id) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0313,
|
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)),
|
self.tcx.local_var_name_str(upvar_id.var_id)),
|
||||||
sup,
|
sup,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::InfStackClosure(span) => {
|
infer::InfStackClosure(span) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0314,
|
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 ",
|
"...but the closure's stack frame is only valid for ",
|
||||||
sup,
|
sup,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::InvokeClosure(span) => {
|
infer::InvokeClosure(span) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0315,
|
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 ",
|
"the closure is only valid for ",
|
||||||
sup,
|
sup,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::DerefPointer(span) => {
|
infer::DerefPointer(span) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0473,
|
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 ",
|
"the reference is only valid for ",
|
||||||
sup,
|
sup,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::FreeVariable(span, id) => {
|
infer::FreeVariable(span, id) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0474,
|
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 ",
|
"closure is valid for ",
|
||||||
sub,
|
sub,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::IndexSlice(span) => {
|
infer::IndexSlice(span) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0475,
|
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 ",
|
"the slice is only valid for ",
|
||||||
sup,
|
sup,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::RelateObjectBound(span) => {
|
infer::RelateObjectBound(span) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0476,
|
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 ",
|
"source pointer is only valid for ",
|
||||||
sup,
|
sup,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::RelateParamBound(span, ty) => {
|
infer::RelateParamBound(span, ty) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0477,
|
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 ",
|
"type must outlive ",
|
||||||
sub,
|
sub,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::RelateRegionParamBound(span) => {
|
infer::RelateRegionParamBound(span) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0478,
|
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 ",
|
"but lifetime parameter must outlive ",
|
||||||
sub,
|
sub,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::RelateDefaultParamBound(span, ty) => {
|
infer::RelateDefaultParamBound(span, ty) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0479,
|
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 ",
|
"type must outlive ",
|
||||||
sub,
|
sub,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::CallRcvr(span) => {
|
infer::CallRcvr(span) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0480,
|
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 ",
|
"the receiver is only valid for ",
|
||||||
sup,
|
sup,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::CallArg(span) => {
|
infer::CallArg(span) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0481,
|
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 ",
|
"the function argument is only valid for ",
|
||||||
sup,
|
sup,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::CallReturn(span) => {
|
infer::CallReturn(span) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0482,
|
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 ",
|
"the return value is only valid for ",
|
||||||
sup,
|
sup,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::Operand(span) => {
|
infer::Operand(span) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0483,
|
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 ",
|
"the operand is only valid for ",
|
||||||
sup,
|
sup,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::AddrOf(span) => {
|
infer::AddrOf(span) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0484,
|
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 ",
|
"the borrow is only valid for ",
|
||||||
sup,
|
sup,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::AutoBorrow(span) => {
|
infer::AutoBorrow(span) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0485,
|
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 ",
|
"the automatic borrow is only valid for ",
|
||||||
sup,
|
sup,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::ExprTypeIsNotInScope(t, span) => {
|
infer::ExprTypeIsNotInScope(t, span) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0486,
|
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 ",
|
"type is only valid for ",
|
||||||
sup,
|
sup,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::SafeDestructor(span) => {
|
infer::SafeDestructor(span) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0487,
|
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: ",
|
"subregion: ",
|
||||||
sub,
|
sub,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::BindingTypeIsNotValidAtDecl(span) => {
|
infer::BindingTypeIsNotValidAtDecl(span) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0488,
|
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 ",
|
"the variable is only valid for ",
|
||||||
sup,
|
sup,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::ParameterInScope(_, span) => {
|
infer::ParameterInScope(_, span) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0489,
|
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 ",
|
"the parameter is only valid for ",
|
||||||
sub,
|
sub,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::DataBorrowed(ty, span) => {
|
infer::DataBorrowed(ty, span) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0490,
|
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.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, "the type is valid for ", sub, "");
|
||||||
self.tcx.note_and_explain_region(&mut err, "but the borrow lasts for ", sup, "");
|
self.tcx.note_and_explain_region(&mut err, "but the borrow lasts for ", sup, "");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
infer::ReferenceOutlivesReferent(ty, span) => {
|
infer::ReferenceOutlivesReferent(ty, span) => {
|
||||||
let mut err = struct_span_err!(self.tcx.sess, span, E0491,
|
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 ",
|
"but the referenced data is only valid for ",
|
||||||
sup,
|
sup,
|
||||||
"");
|
"");
|
||||||
err.emit();
|
err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -970,19 +1029,22 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_processed_errors(&self,
|
fn report_processed_errors(&self,
|
||||||
var_origins: &[RegionVariableOrigin],
|
origins: &[ProcessedErrorOrigin<'tcx>],
|
||||||
trace_origins: &[(TypeTrace<'tcx>, TypeError<'tcx>)],
|
|
||||||
same_regions: &[SameRegions]) {
|
same_regions: &[SameRegions]) {
|
||||||
for (i, vo) in var_origins.iter().enumerate() {
|
for (i, origin) in origins.iter().enumerate() {
|
||||||
let mut err = self.report_inference_failure(vo.clone());
|
let mut err = match *origin {
|
||||||
if i == var_origins.len() - 1 {
|
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);
|
self.give_suggestion(&mut err, same_regions);
|
||||||
}
|
}
|
||||||
err.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
for &(ref trace, ref terr) in trace_origins {
|
err.emit();
|
||||||
self.report_and_explain_type_error(trace.clone(), terr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -407,7 +407,7 @@ pub fn common_supertype<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
|
||||||
match result {
|
match result {
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(ref err) => {
|
Err(ref err) => {
|
||||||
cx.report_and_explain_type_error(trace, err);
|
cx.report_and_explain_type_error(trace, err).emit();
|
||||||
cx.tcx.types.err
|
cx.tcx.types.err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1396,7 +1396,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
found: actual
|
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,
|
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 {
|
&TypeError::TyParamDefaultMismatch(ExpectedFound {
|
||||||
expected: expected,
|
expected: expected,
|
||||||
found: actual
|
found: actual
|
||||||
}));
|
}))
|
||||||
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn replace_late_bound_regions_with_fresh_var<T>(
|
pub fn replace_late_bound_regions_with_fresh_var<T>(
|
||||||
|
|
|
@ -17,7 +17,7 @@ pub use self::CombineMapType::*;
|
||||||
pub use self::RegionResolutionError::*;
|
pub use self::RegionResolutionError::*;
|
||||||
pub use self::VarValue::*;
|
pub use self::VarValue::*;
|
||||||
|
|
||||||
use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable};
|
use super::{RegionVariableOrigin, SubregionOrigin, MiscVariable};
|
||||||
use super::unify_key;
|
use super::unify_key;
|
||||||
|
|
||||||
use rustc_data_structures::graph::{self, Direction, NodeIndex};
|
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::{BoundRegion, Region, RegionVid};
|
||||||
use middle::ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound};
|
use middle::ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound};
|
||||||
use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
|
use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
|
||||||
use middle::ty::error::TypeError;
|
|
||||||
use util::common::indenter;
|
use util::common::indenter;
|
||||||
use util::nodemap::{FnvHashMap, FnvHashSet};
|
use util::nodemap::{FnvHashMap, FnvHashSet};
|
||||||
|
|
||||||
|
@ -152,11 +151,16 @@ pub enum RegionResolutionError<'tcx> {
|
||||||
/// more specific errors message by suggesting to the user where they
|
/// more specific errors message by suggesting to the user where they
|
||||||
/// should put a lifetime. In those cases we process and put those errors
|
/// should put a lifetime. In those cases we process and put those errors
|
||||||
/// into `ProcessedErrors` before we do any reporting.
|
/// into `ProcessedErrors` before we do any reporting.
|
||||||
ProcessedErrors(Vec<RegionVariableOrigin>,
|
ProcessedErrors(Vec<ProcessedErrorOrigin<'tcx>>,
|
||||||
Vec<(TypeTrace<'tcx>, TypeError<'tcx>)>,
|
|
||||||
Vec<SameRegions>),
|
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
|
/// SameRegions is used to group regions that we think are the same and would
|
||||||
/// like to indicate so to the user.
|
/// like to indicate so to the user.
|
||||||
/// For example, the following function
|
/// For example, the following function
|
||||||
|
|
|
@ -36,9 +36,5 @@ fn check<'r, I: Iterator<Item=usize>, T: Itble<'r, usize, I>>(cont: &T) -> bool
|
||||||
fn main() {
|
fn main() {
|
||||||
check((3, 5));
|
check((3, 5));
|
||||||
//~^ ERROR mismatched types
|
//~^ ERROR mismatched types
|
||||||
//~| expected `&_`
|
|
||||||
//~| found `(_, _)`
|
|
||||||
//~| expected &-ptr
|
|
||||||
//~| found tuple
|
|
||||||
//~| HELP run `rustc --explain E0308` to see a detailed explanation
|
//~| HELP run `rustc --explain E0308` to see a detailed explanation
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ fn bar1<'a>(x: &Bar) -> (&'a i32, &'a i32, &'a i32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&'a i32, &'a i32, &'a i32) {
|
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, 'b, 'c>(x: &'a 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)
|
||||||
(x.bar, &x.baz, &x.baz)
|
(x.bar, &x.baz, &x.baz)
|
||||||
//~^ ERROR E0312
|
//~^ ERROR E0312
|
||||||
//~| ERROR cannot infer
|
//~| ERROR cannot infer
|
||||||
|
|
|
@ -39,6 +39,7 @@ struct Cat<'x, T> { cat: &'x isize, t: T }
|
||||||
struct Dog<'y> { dog: &'y isize }
|
struct Dog<'y> { dog: &'y isize }
|
||||||
|
|
||||||
fn cat2<'x, 'y>(x: Cat<'x, Dog<'y>>) -> &'x 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 E0312
|
x.t.dog //~ ERROR E0312
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +49,7 @@ struct Baz<'x> {
|
||||||
|
|
||||||
impl<'a> Baz<'a> {
|
impl<'a> Baz<'a> {
|
||||||
fn baz2<'b>(&self, x: &isize) -> (&'b isize, &'b isize) {
|
fn baz2<'b>(&self, x: &isize) -> (&'b isize, &'b isize) {
|
||||||
|
//~^ 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
|
(self.bar, x) //~ ERROR E0312
|
||||||
//~^ ERROR E0312
|
//~^ ERROR E0312
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue