2013-05-23 21:37:37 -04:00
|
|
|
// Copyright 2012-2013 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.
|
|
|
|
|
2014-11-25 21:17:11 -05:00
|
|
|
//! Error Reporting Code for the inference engine
|
|
|
|
//!
|
|
|
|
//! Because of the way inference, and in particular region inference,
|
|
|
|
//! works, it often happens that errors are not detected until far after
|
|
|
|
//! the relevant line of code has been type-checked. Therefore, there is
|
|
|
|
//! an elaborate system to track why a particular constraint in the
|
|
|
|
//! inference graph arose so that we can explain to the user what gave
|
|
|
|
//! rise to a particular error.
|
|
|
|
//!
|
|
|
|
//! The basis of the system are the "origin" types. An "origin" is the
|
|
|
|
//! reason that a constraint or inference variable arose. There are
|
|
|
|
//! different "origin" enums for different kinds of constraints/variables
|
|
|
|
//! (e.g., `TypeOrigin`, `RegionVariableOrigin`). An origin always has
|
|
|
|
//! a span, but also more information so that we can generate a meaningful
|
|
|
|
//! error message.
|
|
|
|
//!
|
|
|
|
//! Having a catalogue of all the different reasons an error can arise is
|
|
|
|
//! also useful for other reasons, like cross-referencing FAQs etc, though
|
|
|
|
//! we are not really taking advantage of this yet.
|
|
|
|
//!
|
|
|
|
//! # Region Inference
|
|
|
|
//!
|
|
|
|
//! Region inference is particularly tricky because it always succeeds "in
|
|
|
|
//! the moment" and simply registers a constraint. Then, at the end, we
|
|
|
|
//! can compute the full graph and report errors, so we need to be able to
|
|
|
|
//! store and later report what gave rise to the conflicting constraints.
|
|
|
|
//!
|
|
|
|
//! # Subtype Trace
|
|
|
|
//!
|
2015-01-06 20:53:18 -05:00
|
|
|
//! Determining whether `T1 <: T2` often involves a number of subtypes and
|
2014-11-25 21:17:11 -05:00
|
|
|
//! subconstraints along the way. A "TypeTrace" is an extended version
|
|
|
|
//! of an origin that traces the types and other values that were being
|
|
|
|
//! compared. It is not necessarily comprehensive (in fact, at the time of
|
|
|
|
//! this writing it only tracks the root values being compared) but I'd
|
|
|
|
//! like to extend it to include significant "waypoints". For example, if
|
|
|
|
//! you are comparing `(T1, T2) <: (T3, T4)`, and the problem is that `T2
|
|
|
|
//! <: T4` fails, I'd like the trace to include enough information to say
|
|
|
|
//! "in the 2nd element of the tuple". Similarly, failures when comparing
|
|
|
|
//! arguments or return types in fn types should be able to cite the
|
|
|
|
//! specific position, etc.
|
|
|
|
//!
|
|
|
|
//! # Reality vs plan
|
|
|
|
//!
|
|
|
|
//! Of course, there is still a LOT of code in typeck that has yet to be
|
|
|
|
//! ported to this system, and which relies on string concatenation at the
|
|
|
|
//! time of error detection.
|
|
|
|
|
2014-11-06 00:05:53 -08:00
|
|
|
use self::FreshOrKept::*;
|
2013-05-23 21:37:37 -04:00
|
|
|
|
2014-11-25 16:59:02 -05:00
|
|
|
use super::InferCtxt;
|
|
|
|
use super::TypeTrace;
|
|
|
|
use super::SubregionOrigin;
|
|
|
|
use super::RegionVariableOrigin;
|
|
|
|
use super::ValuePairs;
|
|
|
|
use super::region_inference::RegionResolutionError;
|
|
|
|
use super::region_inference::ConcreteFailure;
|
|
|
|
use super::region_inference::SubSupConflict;
|
2015-01-03 04:40:33 -05:00
|
|
|
use super::region_inference::GenericBoundFailure;
|
|
|
|
use super::region_inference::GenericKind;
|
2014-11-25 16:59:02 -05:00
|
|
|
use super::region_inference::ProcessedErrors;
|
2016-03-18 14:47:40 -04:00
|
|
|
use super::region_inference::ProcessedErrorOrigin;
|
2014-11-25 16:59:02 -05:00
|
|
|
use super::region_inference::SameRegions;
|
|
|
|
|
2014-05-29 19:03:06 -07:00
|
|
|
use std::collections::HashSet;
|
2015-07-31 00:04:06 -07:00
|
|
|
|
2016-03-29 08:50:44 +03:00
|
|
|
use hir::map as ast_map;
|
|
|
|
use hir;
|
|
|
|
use hir::print as pprust;
|
2015-07-31 00:04:06 -07:00
|
|
|
|
2016-04-21 05:15:53 -04:00
|
|
|
use lint;
|
2016-03-29 12:54:26 +03:00
|
|
|
use hir::def::Def;
|
|
|
|
use hir::def_id::DefId;
|
2016-11-07 13:25:06 -05:00
|
|
|
use infer;
|
2015-06-16 01:10:55 +03:00
|
|
|
use middle::region;
|
2016-11-07 13:25:06 -05:00
|
|
|
use traits::{ObligationCause, ObligationCauseCode};
|
2016-07-16 23:18:20 +03:00
|
|
|
use ty::{self, TyCtxt, TypeFoldable};
|
2016-03-22 17:30:57 +02:00
|
|
|
use ty::{Region, ReFree};
|
|
|
|
use ty::error::TypeError;
|
2015-06-18 20:25:05 +03:00
|
|
|
|
2014-02-15 01:26:51 -05:00
|
|
|
use std::cell::{Cell, RefCell};
|
|
|
|
use std::char::from_u32;
|
2015-06-18 20:25:05 +03:00
|
|
|
use std::fmt;
|
2014-02-15 01:26:51 -05:00
|
|
|
use syntax::ast;
|
2014-09-07 20:09:06 +03:00
|
|
|
use syntax::ptr::P;
|
2016-11-16 08:21:52 +00:00
|
|
|
use syntax::symbol::Symbol;
|
2016-06-21 18:08:13 -04:00
|
|
|
use syntax_pos::{self, Pos, Span};
|
2016-08-05 15:58:31 -07:00
|
|
|
use errors::DiagnosticBuilder;
|
2013-05-23 21:37:37 -04:00
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
2016-05-03 04:56:42 +03:00
|
|
|
pub fn note_and_explain_region(self,
|
2015-12-21 10:00:43 +13:00
|
|
|
err: &mut DiagnosticBuilder,
|
2015-06-25 23:42:17 +03:00
|
|
|
prefix: &str,
|
2016-08-25 23:58:52 +03:00
|
|
|
region: &'tcx ty::Region,
|
2015-06-25 23:42:17 +03:00
|
|
|
suffix: &str) {
|
2015-07-31 00:04:06 -07:00
|
|
|
fn item_scope_tag(item: &hir::Item) -> &'static str {
|
2015-06-25 23:42:17 +03:00
|
|
|
match item.node {
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ItemImpl(..) => "impl",
|
|
|
|
hir::ItemStruct(..) => "struct",
|
2016-08-10 21:00:17 +03:00
|
|
|
hir::ItemUnion(..) => "union",
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ItemEnum(..) => "enum",
|
|
|
|
hir::ItemTrait(..) => "trait",
|
|
|
|
hir::ItemFn(..) => "function body",
|
2015-06-25 23:42:17 +03:00
|
|
|
_ => "item"
|
|
|
|
}
|
2015-06-16 01:10:55 +03:00
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
fn explain_span<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
|
|
|
heading: &str, span: Span)
|
|
|
|
-> (String, Option<Span>) {
|
2015-06-25 23:42:17 +03:00
|
|
|
let lo = tcx.sess.codemap().lookup_char_pos_adj(span.lo);
|
|
|
|
(format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize()),
|
|
|
|
Some(span))
|
2015-06-16 01:10:55 +03:00
|
|
|
}
|
|
|
|
|
2016-08-25 23:58:52 +03:00
|
|
|
let (description, span) = match *region {
|
2015-06-25 23:42:17 +03:00
|
|
|
ty::ReScope(scope) => {
|
|
|
|
let new_string;
|
|
|
|
let unknown_scope = || {
|
|
|
|
format!("{}unknown scope: {:?}{}. Please report a bug.",
|
|
|
|
prefix, scope, suffix)
|
|
|
|
};
|
2015-08-20 01:46:28 +03:00
|
|
|
let span = match scope.span(&self.region_maps, &self.map) {
|
2015-06-25 23:42:17 +03:00
|
|
|
Some(s) => s,
|
2015-12-21 10:00:43 +13:00
|
|
|
None => {
|
|
|
|
err.note(&unknown_scope());
|
|
|
|
return;
|
|
|
|
}
|
2015-06-25 23:42:17 +03:00
|
|
|
};
|
2015-08-20 01:46:28 +03:00
|
|
|
let tag = match self.map.find(scope.node_id(&self.region_maps)) {
|
2015-06-25 23:42:17 +03:00
|
|
|
Some(ast_map::NodeBlock(_)) => "block",
|
|
|
|
Some(ast_map::NodeExpr(expr)) => match expr.node {
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprCall(..) => "call",
|
|
|
|
hir::ExprMethodCall(..) => "method call",
|
2016-08-26 19:23:42 +03:00
|
|
|
hir::ExprMatch(.., hir::MatchSource::IfLetDesugar { .. }) => "if let",
|
|
|
|
hir::ExprMatch(.., hir::MatchSource::WhileLetDesugar) => "while let",
|
|
|
|
hir::ExprMatch(.., hir::MatchSource::ForLoopDesugar) => "for",
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ExprMatch(..) => "match",
|
2015-06-25 23:42:17 +03:00
|
|
|
_ => "expression",
|
|
|
|
},
|
|
|
|
Some(ast_map::NodeStmt(_)) => "statement",
|
2016-02-09 22:00:20 +01:00
|
|
|
Some(ast_map::NodeItem(it)) => item_scope_tag(&it),
|
2015-06-25 23:42:17 +03:00
|
|
|
Some(_) | None => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(span, &unknown_scope());
|
|
|
|
return;
|
2015-06-25 23:42:17 +03:00
|
|
|
}
|
|
|
|
};
|
2015-08-20 01:46:28 +03:00
|
|
|
let scope_decorated_tag = match self.region_maps.code_extent_data(scope) {
|
|
|
|
region::CodeExtentData::Misc(_) => tag,
|
2015-12-08 23:38:36 +01:00
|
|
|
region::CodeExtentData::CallSiteScope { .. } => {
|
|
|
|
"scope of call-site for function"
|
|
|
|
}
|
2015-08-20 01:46:28 +03:00
|
|
|
region::CodeExtentData::ParameterScope { .. } => {
|
2016-04-26 13:36:18 +08:00
|
|
|
"scope of function body"
|
2015-06-25 23:42:17 +03:00
|
|
|
}
|
2015-08-20 01:46:28 +03:00
|
|
|
region::CodeExtentData::DestructionScope(_) => {
|
2015-06-25 23:42:17 +03:00
|
|
|
new_string = format!("destruction scope surrounding {}", tag);
|
|
|
|
&new_string[..]
|
|
|
|
}
|
2015-08-20 01:46:28 +03:00
|
|
|
region::CodeExtentData::Remainder(r) => {
|
2015-06-25 23:42:17 +03:00
|
|
|
new_string = format!("block suffix following statement {}",
|
|
|
|
r.first_statement_index);
|
|
|
|
&new_string[..]
|
|
|
|
}
|
|
|
|
};
|
|
|
|
explain_span(self, scope_decorated_tag, span)
|
|
|
|
}
|
2015-06-16 01:10:55 +03:00
|
|
|
|
2015-06-25 23:42:17 +03:00
|
|
|
ty::ReFree(ref fr) => {
|
|
|
|
let prefix = match fr.bound_region {
|
|
|
|
ty::BrAnon(idx) => {
|
|
|
|
format!("the anonymous lifetime #{} defined on", idx + 1)
|
|
|
|
}
|
|
|
|
ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(),
|
|
|
|
_ => {
|
|
|
|
format!("the lifetime {} as defined on",
|
|
|
|
fr.bound_region)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-08-22 17:39:21 +03:00
|
|
|
match self.map.find(fr.scope.node_id(&self.region_maps)) {
|
2015-06-25 23:42:17 +03:00
|
|
|
Some(ast_map::NodeBlock(ref blk)) => {
|
|
|
|
let (msg, opt_span) = explain_span(self, "block", blk.span);
|
|
|
|
(format!("{} {}", prefix, msg), opt_span)
|
|
|
|
}
|
|
|
|
Some(ast_map::NodeItem(it)) => {
|
2016-02-09 22:00:20 +01:00
|
|
|
let tag = item_scope_tag(&it);
|
2015-06-25 23:42:17 +03:00
|
|
|
let (msg, opt_span) = explain_span(self, tag, it.span);
|
|
|
|
(format!("{} {}", prefix, msg), opt_span)
|
|
|
|
}
|
|
|
|
Some(_) | None => {
|
2015-08-22 17:39:21 +03:00
|
|
|
// this really should not happen, but it does:
|
|
|
|
// FIXME(#27942)
|
2015-06-25 23:42:17 +03:00
|
|
|
(format!("{} unknown free region bounded by scope {:?}",
|
|
|
|
prefix, fr.scope), None)
|
|
|
|
}
|
2015-06-16 01:10:55 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-25 23:42:17 +03:00
|
|
|
ty::ReStatic => ("the static lifetime".to_owned(), None),
|
2015-06-16 01:10:55 +03:00
|
|
|
|
2015-06-25 23:42:17 +03:00
|
|
|
ty::ReEmpty => ("the empty lifetime".to_owned(), None),
|
2015-06-16 01:10:55 +03:00
|
|
|
|
2015-07-28 18:07:20 +02:00
|
|
|
ty::ReEarlyBound(ref data) => (data.name.to_string(), None),
|
2015-06-16 01:10:55 +03:00
|
|
|
|
2015-08-18 23:21:29 +03:00
|
|
|
// FIXME(#13998) ReSkolemized should probably print like
|
|
|
|
// ReFree rather than dumping Debug output on the user.
|
|
|
|
//
|
|
|
|
// We shouldn't really be having unification failures with ReVar
|
2015-08-24 21:30:39 +03:00
|
|
|
// and ReLateBound though.
|
2016-06-01 15:10:44 +03:00
|
|
|
ty::ReSkolemized(..) |
|
|
|
|
ty::ReVar(_) |
|
|
|
|
ty::ReLateBound(..) |
|
|
|
|
ty::ReErased => {
|
2015-06-25 23:42:17 +03:00
|
|
|
(format!("lifetime {:?}", region), None)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let message = format!("{}{}{}", prefix, description, suffix);
|
|
|
|
if let Some(span) = span {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(span, &message);
|
2015-06-25 23:42:17 +03:00
|
|
|
} else {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.note(&message);
|
2015-06-16 01:10:55 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|
|
|
pub fn report_region_errors(&self,
|
|
|
|
errors: &Vec<RegionResolutionError<'tcx>>) {
|
2016-03-18 14:47:40 -04:00
|
|
|
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());
|
|
|
|
|
2015-01-31 12:20:46 -05:00
|
|
|
for error in errors {
|
2016-10-05 10:17:14 -04:00
|
|
|
debug!("report_region_errors: error = {:?}", error);
|
2014-04-22 02:21:52 +03:00
|
|
|
match error.clone() {
|
2013-05-23 21:37:37 -04:00
|
|
|
ConcreteFailure(origin, sub, sup) => {
|
2016-03-18 14:47:40 -04:00
|
|
|
self.report_concrete_failure(origin, sub, sup).emit();
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
|
2015-08-07 10:28:51 -04:00
|
|
|
GenericBoundFailure(kind, param_ty, sub) => {
|
|
|
|
self.report_generic_bound_failure(kind, param_ty, sub);
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
|
|
|
|
2013-05-23 21:37:37 -04:00
|
|
|
SubSupConflict(var_origin,
|
|
|
|
sub_origin, sub_r,
|
|
|
|
sup_origin, sup_r) => {
|
|
|
|
self.report_sub_sup_conflict(var_origin,
|
|
|
|
sub_origin, sub_r,
|
|
|
|
sup_origin, sup_r);
|
|
|
|
}
|
|
|
|
|
2016-03-18 14:47:40 -04:00
|
|
|
ProcessedErrors(ref origins,
|
2014-02-15 01:26:51 -05:00
|
|
|
ref same_regions) => {
|
|
|
|
if !same_regions.is_empty() {
|
2016-03-18 14:47:40 -04:00
|
|
|
self.report_processed_errors(origins, same_regions);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-15 01:26:51 -05:00
|
|
|
// This method goes through all the errors and try to group certain types
|
|
|
|
// of error together, for the purpose of suggesting explicit lifetime
|
|
|
|
// 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
|
2016-03-18 14:47:40 -04:00
|
|
|
// 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.
|
2014-09-29 22:11:30 +03:00
|
|
|
fn process_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>)
|
2016-03-18 14:47:40 -04:00
|
|
|
-> Option<Vec<RegionResolutionError<'tcx>>> {
|
2014-03-22 04:24:42 -04:00
|
|
|
debug!("process_errors()");
|
2016-03-18 14:47:40 -04:00
|
|
|
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
|
2014-02-15 01:26:51 -05:00
|
|
|
let mut same_regions = Vec::new();
|
2016-03-18 14:47:40 -04:00
|
|
|
|
|
|
|
// 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();
|
|
|
|
|
2015-01-31 12:20:46 -05:00
|
|
|
for error in errors {
|
2016-10-05 10:17:14 -04:00
|
|
|
// Check whether we can process this error into some other
|
|
|
|
// form; if not, fall through.
|
2016-03-18 14:47:40 -04:00
|
|
|
match *error {
|
|
|
|
ConcreteFailure(ref origin, sub, sup) => {
|
2014-11-14 09:18:10 -08:00
|
|
|
debug!("processing ConcreteFailure");
|
2016-10-05 10:17:14 -04:00
|
|
|
if let SubregionOrigin::CompareImplMethodObligation { .. } = *origin {
|
|
|
|
// When comparing an impl method against a
|
|
|
|
// trait method, it is not helpful to suggest
|
|
|
|
// changes to the impl method. This is
|
|
|
|
// because the impl method signature is being
|
|
|
|
// checked using the trait's environment, so
|
|
|
|
// usually the changes we suggest would
|
|
|
|
// actually have to be applied to the *trait*
|
|
|
|
// method (and it's not clear that the trait
|
|
|
|
// method is even under the user's control).
|
|
|
|
} else if let Some(same_frs) = free_regions_from_same_fn(self.tcx, sub, sup) {
|
|
|
|
origins.push(
|
|
|
|
ProcessedErrorOrigin::ConcreteFailure(
|
|
|
|
origin.clone(),
|
|
|
|
sub,
|
|
|
|
sup));
|
|
|
|
append_to_same_regions(&mut same_regions, &same_frs);
|
|
|
|
continue;
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
2016-10-05 10:17:14 -04:00
|
|
|
SubSupConflict(ref var_origin, ref sub_origin, sub, ref sup_origin, sup) => {
|
|
|
|
debug!("processing SubSupConflict sub: {:?} sup: {:?}", sub, sup);
|
2016-10-19 17:19:00 -04:00
|
|
|
match (sub_origin, sup_origin) {
|
|
|
|
(&SubregionOrigin::CompareImplMethodObligation { .. }, _) => {
|
|
|
|
// As above, when comparing an impl method
|
|
|
|
// against a trait method, it is not helpful
|
|
|
|
// to suggest changes to the impl method.
|
|
|
|
}
|
|
|
|
(_, &SubregionOrigin::CompareImplMethodObligation { .. }) => {
|
|
|
|
// See above.
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
if let Some(same_frs) = free_regions_from_same_fn(self.tcx, sub, sup) {
|
|
|
|
origins.push(
|
|
|
|
ProcessedErrorOrigin::VariableFailure(
|
|
|
|
var_origin.clone()));
|
|
|
|
append_to_same_regions(&mut same_regions, &same_frs);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
2016-03-18 14:47:40 -04:00
|
|
|
GenericBoundFailure(ref origin, ref kind, region) => {
|
|
|
|
bound_failures.push((origin.clone(), kind.clone(), region));
|
2016-10-05 10:17:14 -04:00
|
|
|
continue;
|
2016-03-18 14:47:40 -04:00
|
|
|
}
|
|
|
|
ProcessedErrors(..) => {
|
2016-03-26 19:59:04 +01:00
|
|
|
bug!("should not encounter a `ProcessedErrors` yet: {:?}", error)
|
2016-03-18 14:47:40 -04:00
|
|
|
}
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2016-10-05 10:17:14 -04:00
|
|
|
|
|
|
|
// No changes to this error.
|
|
|
|
other_errors.push(error.clone());
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2016-03-18 14:47:40 -04:00
|
|
|
|
|
|
|
// 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
|
2014-02-15 01:26:51 -05:00
|
|
|
if !same_regions.is_empty() {
|
2014-10-14 23:05:01 -07:00
|
|
|
let common_scope_id = same_regions[0].scope_id;
|
2015-01-31 12:20:46 -05:00
|
|
|
for sr in &same_regions {
|
2014-02-15 01:26:51 -05:00
|
|
|
// Since ProcessedErrors is used to reconstruct the function
|
|
|
|
// declaration, we want to make sure that they are, in fact,
|
|
|
|
// from the same scope
|
|
|
|
if sr.scope_id != common_scope_id {
|
2014-03-22 04:24:42 -04:00
|
|
|
debug!("returning empty result from process_errors because
|
|
|
|
{} != {}", sr.scope_id, common_scope_id);
|
2016-03-18 14:47:40 -04:00
|
|
|
return None;
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
2016-03-18 14:47:40 -04:00
|
|
|
assert!(origins.len() > 0);
|
|
|
|
let pe = ProcessedErrors(origins, same_regions);
|
2014-12-20 00:09:35 -08:00
|
|
|
debug!("errors processed: {:?}", pe);
|
2014-02-15 01:26:51 -05:00
|
|
|
processed_errors.push(pe);
|
|
|
|
}
|
|
|
|
|
2016-03-18 14:47:40 -04:00
|
|
|
// 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});
|
2014-02-15 01:26:51 -05:00
|
|
|
|
2016-03-18 14:47:40 -04:00
|
|
|
return Some(processed_errors);
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2014-02-15 01:26:51 -05:00
|
|
|
struct FreeRegionsFromSameFn {
|
|
|
|
sub_fr: ty::FreeRegion,
|
|
|
|
sup_fr: ty::FreeRegion,
|
|
|
|
scope_id: ast::NodeId
|
|
|
|
}
|
|
|
|
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
impl FreeRegionsFromSameFn {
|
|
|
|
fn new(sub_fr: ty::FreeRegion,
|
|
|
|
sup_fr: ty::FreeRegion,
|
|
|
|
scope_id: ast::NodeId)
|
|
|
|
-> FreeRegionsFromSameFn {
|
|
|
|
FreeRegionsFromSameFn {
|
|
|
|
sub_fr: sub_fr,
|
|
|
|
sup_fr: sup_fr,
|
|
|
|
scope_id: scope_id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
fn free_regions_from_same_fn<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
2016-08-25 23:58:52 +03:00
|
|
|
sub: &'tcx Region,
|
|
|
|
sup: &'tcx Region)
|
2016-04-29 06:00:23 +03:00
|
|
|
-> Option<FreeRegionsFromSameFn> {
|
2014-12-20 00:09:35 -08:00
|
|
|
debug!("free_regions_from_same_fn(sub={:?}, sup={:?})", sub, sup);
|
2014-02-15 01:26:51 -05:00
|
|
|
let (scope_id, fr1, fr2) = match (sub, sup) {
|
2016-08-25 23:58:52 +03:00
|
|
|
(&ReFree(fr1), &ReFree(fr2)) => {
|
2014-11-18 14:22:59 +01:00
|
|
|
if fr1.scope != fr2.scope {
|
2014-02-15 01:26:51 -05:00
|
|
|
return None
|
|
|
|
}
|
2014-11-18 14:22:59 +01:00
|
|
|
assert!(fr1.scope == fr2.scope);
|
2015-08-22 17:39:21 +03:00
|
|
|
(fr1.scope.node_id(&tcx.region_maps), fr1, fr2)
|
2014-02-15 01:26:51 -05:00
|
|
|
},
|
|
|
|
_ => return None
|
|
|
|
};
|
|
|
|
let parent = tcx.map.get_parent(scope_id);
|
|
|
|
let parent_node = tcx.map.find(parent);
|
|
|
|
match parent_node {
|
|
|
|
Some(node) => match node {
|
|
|
|
ast_map::NodeItem(item) => match item.node {
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ItemFn(..) => {
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
Some(FreeRegionsFromSameFn::new(fr1, fr2, scope_id))
|
2014-02-15 01:26:51 -05:00
|
|
|
},
|
|
|
|
_ => None
|
|
|
|
},
|
2014-08-04 13:56:56 -07:00
|
|
|
ast_map::NodeImplItem(..) |
|
|
|
|
ast_map::NodeTraitItem(..) => {
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
Some(FreeRegionsFromSameFn::new(fr1, fr2, scope_id))
|
|
|
|
},
|
2014-02-15 01:26:51 -05:00
|
|
|
_ => None
|
|
|
|
},
|
2014-03-22 04:24:42 -04:00
|
|
|
None => {
|
2014-11-14 09:18:10 -08:00
|
|
|
debug!("no parent node of scope_id {}", scope_id);
|
2014-03-22 04:24:42 -04:00
|
|
|
None
|
|
|
|
}
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn append_to_same_regions(same_regions: &mut Vec<SameRegions>,
|
|
|
|
same_frs: &FreeRegionsFromSameFn) {
|
2016-03-18 14:47:40 -04:00
|
|
|
debug!("append_to_same_regions(same_regions={:?}, same_frs={:?})",
|
|
|
|
same_regions, same_frs);
|
2014-02-15 01:26:51 -05:00
|
|
|
let scope_id = same_frs.scope_id;
|
|
|
|
let (sub_fr, sup_fr) = (same_frs.sub_fr, same_frs.sup_fr);
|
2016-03-18 14:47:40 -04:00
|
|
|
for sr in same_regions.iter_mut() {
|
|
|
|
if sr.contains(&sup_fr.bound_region) && scope_id == sr.scope_id {
|
2014-02-15 01:26:51 -05:00
|
|
|
sr.push(sub_fr.bound_region);
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
same_regions.push(SameRegions {
|
|
|
|
scope_id: scope_id,
|
2016-10-29 22:54:04 +01:00
|
|
|
regions: vec![sub_fr.bound_region, sup_fr.bound_region]
|
2014-02-15 01:26:51 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-08 19:48:56 +05:30
|
|
|
/// Adds a note if the types come from similarly named crates
|
2015-12-21 10:00:43 +13:00
|
|
|
fn check_and_note_conflicting_crates(&self,
|
|
|
|
err: &mut DiagnosticBuilder,
|
|
|
|
terr: &TypeError<'tcx>,
|
|
|
|
sp: Span) {
|
|
|
|
let report_path_match = |err: &mut DiagnosticBuilder, did1: DefId, did2: DefId| {
|
2015-09-08 22:21:20 +05:30
|
|
|
// Only external crates, if either is from a local
|
|
|
|
// module we could have false positives
|
2015-09-08 23:57:24 +05:30
|
|
|
if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate {
|
2016-04-06 13:51:55 +03:00
|
|
|
let exp_path = self.tcx.item_path_str(did1);
|
|
|
|
let found_path = self.tcx.item_path_str(did2);
|
|
|
|
// We compare strings because DefPath can be different
|
2015-09-08 22:21:20 +05:30
|
|
|
// for imported and non-imported crates
|
|
|
|
if exp_path == found_path {
|
2015-11-21 01:08:09 +02:00
|
|
|
let crate_name = self.tcx.sess.cstore.crate_name(did1.krate);
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(sp, &format!("Perhaps two different versions \
|
|
|
|
of crate `{}` are being used?",
|
|
|
|
crate_name));
|
2015-09-08 22:21:20 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2015-09-08 19:48:56 +05:30
|
|
|
match *terr {
|
2015-09-06 21:51:58 +03:00
|
|
|
TypeError::Sorts(ref exp_found) => {
|
2015-09-08 19:48:56 +05:30
|
|
|
// if they are both "path types", there's a chance of ambiguity
|
|
|
|
// due to different versions of the same crate
|
|
|
|
match (&exp_found.expected.sty, &exp_found.found.sty) {
|
2016-09-06 01:26:02 +03:00
|
|
|
(&ty::TyAdt(exp_adt, _), &ty::TyAdt(found_adt, _)) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
report_path_match(err, exp_adt.did, found_adt.did);
|
2015-09-08 19:48:56 +05:30
|
|
|
},
|
|
|
|
_ => ()
|
|
|
|
}
|
2015-09-08 22:21:20 +05:30
|
|
|
},
|
2015-09-06 21:51:58 +03:00
|
|
|
TypeError::Traits(ref exp_found) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
report_path_match(err, exp_found.expected, exp_found.found);
|
2015-09-08 22:21:20 +05:30
|
|
|
},
|
2015-09-08 23:57:24 +05:30
|
|
|
_ => () // FIXME(#22750) handle traits and stuff
|
2015-09-08 19:48:56 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-16 23:18:20 +03:00
|
|
|
fn note_error_origin(&self,
|
|
|
|
err: &mut DiagnosticBuilder<'tcx>,
|
2016-11-07 13:25:06 -05:00
|
|
|
cause: &ObligationCause<'tcx>)
|
2016-07-16 23:18:20 +03:00
|
|
|
{
|
2016-11-07 13:25:06 -05:00
|
|
|
match cause.code {
|
|
|
|
ObligationCauseCode::MatchExpressionArm { arm_span, source } => match source {
|
2016-07-16 23:18:20 +03:00
|
|
|
hir::MatchSource::IfLetDesugar {..} => {
|
|
|
|
err.span_note(arm_span, "`if let` arm with an incompatible type");
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
err.span_note(arm_span, "match arm with an incompatible type");
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-21 20:12:30 +03:00
|
|
|
pub fn note_type_err(&self,
|
|
|
|
diag: &mut DiagnosticBuilder<'tcx>,
|
2016-11-07 13:25:06 -05:00
|
|
|
cause: &ObligationCause<'tcx>,
|
2016-08-10 01:43:12 -07:00
|
|
|
secondary_span: Option<(Span, String)>,
|
2016-07-21 20:12:30 +03:00
|
|
|
values: Option<ValuePairs<'tcx>>,
|
|
|
|
terr: &TypeError<'tcx>)
|
2016-07-16 23:18:20 +03:00
|
|
|
{
|
2016-07-19 01:02:47 +03:00
|
|
|
let expected_found = match values {
|
|
|
|
None => None,
|
|
|
|
Some(values) => match self.values_str(&values) {
|
|
|
|
Some((expected, found)) => Some((expected, found)),
|
2016-07-21 20:12:30 +03:00
|
|
|
None => {
|
|
|
|
// Derived error. Cancel the emitter.
|
|
|
|
self.tcx.sess.diagnostic().cancel(diag);
|
|
|
|
return
|
|
|
|
}
|
2016-07-19 01:02:47 +03:00
|
|
|
}
|
2016-07-16 23:18:20 +03:00
|
|
|
};
|
|
|
|
|
2016-11-07 13:25:06 -05:00
|
|
|
let span = cause.span;
|
2016-07-16 23:18:20 +03:00
|
|
|
|
2016-07-19 01:02:47 +03:00
|
|
|
if let Some((expected, found)) = expected_found {
|
2016-08-05 15:58:31 -07:00
|
|
|
let is_simple_error = if let &TypeError::Sorts(ref values) = terr {
|
2016-07-19 01:02:47 +03:00
|
|
|
values.expected.is_primitive() && values.found.is_primitive()
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
};
|
2016-07-16 23:18:20 +03:00
|
|
|
|
2016-08-05 15:58:31 -07:00
|
|
|
if !is_simple_error {
|
2016-09-07 18:40:31 -07:00
|
|
|
if expected == found {
|
|
|
|
if let &TypeError::Sorts(ref values) = terr {
|
|
|
|
diag.note_expected_found_extra(
|
|
|
|
&"type", &expected, &found,
|
|
|
|
&format!(" ({})", values.expected.sort_string(self.tcx)),
|
|
|
|
&format!(" ({})", values.found.sort_string(self.tcx)));
|
|
|
|
} else {
|
|
|
|
diag.note_expected_found(&"type", &expected, &found);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
diag.note_expected_found(&"type", &expected, &found);
|
|
|
|
}
|
2016-07-19 01:02:47 +03:00
|
|
|
}
|
2016-07-16 23:18:20 +03:00
|
|
|
}
|
|
|
|
|
2016-08-05 15:58:31 -07:00
|
|
|
diag.span_label(span, &terr);
|
2016-08-10 01:43:12 -07:00
|
|
|
if let Some((sp, msg)) = secondary_span {
|
|
|
|
diag.span_label(sp, &msg);
|
|
|
|
}
|
2016-07-16 23:18:20 +03:00
|
|
|
|
2016-11-07 13:25:06 -05:00
|
|
|
self.note_error_origin(diag, &cause);
|
2016-07-21 20:12:30 +03:00
|
|
|
self.check_and_note_conflicting_crates(diag, terr, span);
|
|
|
|
self.tcx.note_and_explain_type_err(diag, terr, span);
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
|
2016-07-16 23:18:20 +03:00
|
|
|
pub fn report_and_explain_type_error(&self,
|
|
|
|
trace: TypeTrace<'tcx>,
|
|
|
|
terr: &TypeError<'tcx>)
|
|
|
|
-> DiagnosticBuilder<'tcx>
|
|
|
|
{
|
2016-11-07 13:25:06 -05:00
|
|
|
let span = trace.cause.span;
|
|
|
|
let failure_str = trace.cause.as_failure_str();
|
|
|
|
let mut diag = match trace.cause.code {
|
|
|
|
ObligationCauseCode::IfExpressionWithNoElse => {
|
2016-10-03 09:28:46 -07:00
|
|
|
struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str)
|
|
|
|
},
|
|
|
|
};
|
2016-11-07 13:25:06 -05:00
|
|
|
self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr);
|
2016-07-21 20:12:30 +03:00
|
|
|
diag
|
2016-07-16 23:18:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a string of the form "expected `{}`, found `{}`".
|
2016-04-20 15:00:05 -04:00
|
|
|
fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> {
|
2013-05-23 21:37:37 -04:00
|
|
|
match *values {
|
Improve the readability of diagnostics that involve unresolved type variables
Diagnostics such as the following
```
mismatched types: expected `core::result::Result<uint,()>`, found `core::option::Option<<generic #1>>`
<anon>:6 let a: Result<uint, ()> = None;
^~~~
mismatched types: expected `&mut <generic #2>`, found `uint`
<anon>:7 f(42u);
^~~
```
tend to be fairly unappealing to new users. While specific type var IDs are valuable in
diagnostics that deal with more than one such variable, in practice many messages
only mention one. In those cases, leaving out the specific number makes the messages
slightly less terrifying.
In addition, type variables have been changed to use the type hole syntax `_` in diagnostics.
With a variable ID, they're printed as `_#id` (e.g. `_#1`). In cases where the ID is left out,
it's simply `_`. Integer and float variables have an additional suffix after the number, e.g.
`_#1i` or `_#3f`.
2014-10-23 22:35:19 +02:00
|
|
|
infer::Types(ref exp_found) => self.expected_found_str(exp_found),
|
2014-12-14 07:17:23 -05:00
|
|
|
infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found),
|
2016-07-16 23:18:20 +03:00
|
|
|
infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found),
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-16 23:18:20 +03:00
|
|
|
fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
|
2014-02-07 00:38:33 +02:00
|
|
|
&self,
|
2015-09-06 21:51:58 +03:00
|
|
|
exp_found: &ty::error::ExpectedFound<T>)
|
2016-04-20 15:00:05 -04:00
|
|
|
-> Option<(String, String)>
|
2013-05-23 21:37:37 -04:00
|
|
|
{
|
2016-07-16 23:18:20 +03:00
|
|
|
let exp_found = self.resolve_type_vars_if_possible(exp_found);
|
|
|
|
if exp_found.references_error() {
|
2013-05-23 21:37:37 -04:00
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2016-07-16 23:18:20 +03:00
|
|
|
Some((format!("{}", exp_found.expected), format!("{}", exp_found.found)))
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
|
2015-01-03 04:40:33 -05:00
|
|
|
fn report_generic_bound_failure(&self,
|
|
|
|
origin: SubregionOrigin<'tcx>,
|
|
|
|
bound_kind: GenericKind<'tcx>,
|
2016-08-25 23:58:52 +03:00
|
|
|
sub: &'tcx Region)
|
2015-01-03 04:40:33 -05:00
|
|
|
{
|
2014-08-27 21:46:52 -04:00
|
|
|
// FIXME: it would be better to report the first error message
|
|
|
|
// with the span of the parameter itself, rather than the span
|
|
|
|
// where the error was detected. But that span is not readily
|
|
|
|
// accessible.
|
|
|
|
|
2015-01-03 04:40:33 -05:00
|
|
|
let labeled_user_string = match bound_kind {
|
|
|
|
GenericKind::Param(ref p) =>
|
2015-06-18 20:25:05 +03:00
|
|
|
format!("the parameter type `{}`", p),
|
2015-01-03 04:40:33 -05:00
|
|
|
GenericKind::Projection(ref p) =>
|
2015-06-18 20:25:05 +03:00
|
|
|
format!("the associated type `{}`", p),
|
2015-01-03 04:40:33 -05:00
|
|
|
};
|
|
|
|
|
2016-10-05 10:17:14 -04:00
|
|
|
if let SubregionOrigin::CompareImplMethodObligation {
|
2016-10-12 16:38:58 -04:00
|
|
|
span, item_name, impl_item_def_id, trait_item_def_id, lint_id
|
2016-10-05 10:17:14 -04:00
|
|
|
} = origin {
|
|
|
|
self.report_extra_impl_obligation(span,
|
|
|
|
item_name,
|
|
|
|
impl_item_def_id,
|
|
|
|
trait_item_def_id,
|
2016-10-12 16:38:58 -04:00
|
|
|
&format!("`{}: {}`", bound_kind, sub),
|
|
|
|
lint_id)
|
2016-10-05 10:17:14 -04:00
|
|
|
.emit();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-08-25 23:58:52 +03:00
|
|
|
let mut err = match *sub {
|
2014-08-27 21:46:52 -04:00
|
|
|
ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
|
|
|
|
// Does the required lifetime have a nice name we can print?
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess,
|
|
|
|
origin.span(),
|
|
|
|
E0309,
|
|
|
|
"{} may not live long enough",
|
|
|
|
labeled_user_string);
|
2016-04-20 14:49:16 -04:00
|
|
|
err.help(&format!("consider adding an explicit lifetime bound `{}: {}`...",
|
|
|
|
bound_kind,
|
|
|
|
sub));
|
2015-12-21 10:00:43 +13:00
|
|
|
err
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
ty::ReStatic => {
|
|
|
|
// Does the required lifetime have a nice name we can print?
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess,
|
|
|
|
origin.span(),
|
|
|
|
E0310,
|
|
|
|
"{} may not live long enough",
|
|
|
|
labeled_user_string);
|
2016-04-20 14:49:16 -04:00
|
|
|
err.help(&format!("consider adding an explicit lifetime \
|
|
|
|
bound `{}: 'static`...",
|
|
|
|
bound_kind));
|
2015-12-21 10:00:43 +13:00
|
|
|
err
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
_ => {
|
|
|
|
// If not, be less specific.
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess,
|
|
|
|
origin.span(),
|
|
|
|
E0311,
|
|
|
|
"{} may not live long enough",
|
|
|
|
labeled_user_string);
|
2016-04-20 14:49:16 -04:00
|
|
|
err.help(&format!("consider adding an explicit lifetime bound for `{}`",
|
|
|
|
bound_kind));
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.note_and_explain_region(
|
2015-12-21 10:00:43 +13:00
|
|
|
&mut err,
|
2015-02-20 14:08:14 -05:00
|
|
|
&format!("{} must be valid for ", labeled_user_string),
|
2014-08-27 21:46:52 -04:00
|
|
|
sub,
|
|
|
|
"...");
|
2015-12-21 10:00:43 +13:00
|
|
|
err
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
2015-12-21 10:00:43 +13:00
|
|
|
};
|
2014-08-27 21:46:52 -04:00
|
|
|
|
2015-12-21 10:00:43 +13:00
|
|
|
self.note_region_origin(&mut err, &origin);
|
|
|
|
err.emit();
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
|
|
|
|
2014-02-07 00:38:33 +02:00
|
|
|
fn report_concrete_failure(&self,
|
2014-09-29 22:11:30 +03:00
|
|
|
origin: SubregionOrigin<'tcx>,
|
2016-08-25 23:58:52 +03:00
|
|
|
sub: &'tcx Region,
|
|
|
|
sup: &'tcx Region)
|
2016-03-18 14:47:40 -04:00
|
|
|
-> DiagnosticBuilder<'tcx> {
|
2013-05-23 21:37:37 -04:00
|
|
|
match origin {
|
2015-07-14 19:36:15 -04:00
|
|
|
infer::Subtype(trace) => {
|
2015-07-10 15:40:04 -07:00
|
|
|
let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
|
2016-03-18 14:47:40 -04:00
|
|
|
self.report_and_explain_type_error(trace, &terr)
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
infer::Reborrow(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0312,
|
2016-05-08 22:33:03 +10:00
|
|
|
"lifetime of reference outlives \
|
2013-05-23 21:37:37 -04:00
|
|
|
lifetime of borrowed content...");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2014-01-07 18:49:13 -08:00
|
|
|
"...the reference is valid for ",
|
2013-05-23 21:37:37 -04:00
|
|
|
sub,
|
|
|
|
"...");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-05-23 21:37:37 -04:00
|
|
|
"...but the borrowed content is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
2014-02-07 14:43:48 -05:00
|
|
|
infer::ReborrowUpvar(span, ref upvar_id) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0313,
|
2015-01-18 16:58:25 -08:00
|
|
|
"lifetime of borrowed pointer outlives \
|
2014-02-07 14:43:48 -05:00
|
|
|
lifetime of captured variable `{}`...",
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.local_var_name_str(upvar_id.var_id));
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2014-02-07 14:43:48 -05:00
|
|
|
"...the borrowed pointer is valid for ",
|
|
|
|
sub,
|
|
|
|
"...");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("...but `{}` is only valid for ",
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.local_var_name_str(upvar_id.var_id)),
|
2014-02-07 14:43:48 -05:00
|
|
|
sup,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2014-02-07 14:43:48 -05:00
|
|
|
}
|
2013-06-25 12:04:50 -04:00
|
|
|
infer::InfStackClosure(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0314,
|
2013-06-25 12:04:50 -04:00
|
|
|
"closure outlives stack frame");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-06-25 12:04:50 -04:00
|
|
|
"...the closure must be valid for ",
|
|
|
|
sub,
|
|
|
|
"...");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-06-25 12:04:50 -04:00
|
|
|
"...but the closure's stack frame is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2013-06-25 12:04:50 -04:00
|
|
|
}
|
2013-05-23 21:37:37 -04:00
|
|
|
infer::InvokeClosure(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0315,
|
2013-05-23 21:37:37 -04:00
|
|
|
"cannot invoke closure outside of its lifetime");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-05-23 21:37:37 -04:00
|
|
|
"the closure is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
infer::DerefPointer(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0473,
|
2015-09-11 16:17:15 +02:00
|
|
|
"dereference of reference outside its lifetime");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-05-23 21:37:37 -04:00
|
|
|
"the reference is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
2014-02-07 14:43:48 -05:00
|
|
|
infer::FreeVariable(span, id) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0474,
|
2015-09-11 16:17:15 +02:00
|
|
|
"captured variable `{}` does not outlive the enclosing closure",
|
|
|
|
self.tcx.local_var_name_str(id));
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-05-23 21:37:37 -04:00
|
|
|
"captured variable is valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-05-23 21:37:37 -04:00
|
|
|
"closure is valid for ",
|
|
|
|
sub,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
infer::IndexSlice(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0475,
|
2015-09-11 16:17:15 +02:00
|
|
|
"index of slice outside its lifetime");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-05-23 21:37:37 -04:00
|
|
|
"the slice is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
infer::RelateObjectBound(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0476,
|
2015-09-11 16:17:15 +02:00
|
|
|
"lifetime of the source pointer does not outlive \
|
|
|
|
lifetime bound of the object type");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-05-23 21:37:37 -04:00
|
|
|
"object type is valid for ",
|
|
|
|
sub,
|
|
|
|
"");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-05-23 21:37:37 -04:00
|
|
|
"source pointer is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
2014-11-15 17:25:05 -05:00
|
|
|
infer::RelateParamBound(span, ty) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0477,
|
2015-09-11 16:17:15 +02:00
|
|
|
"the type `{}` does not fulfill the required lifetime",
|
|
|
|
self.ty_to_string(ty));
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2014-08-27 21:46:52 -04:00
|
|
|
"type must outlive ",
|
|
|
|
sub,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
|
|
|
infer::RelateRegionParamBound(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0478,
|
2015-09-11 16:17:15 +02:00
|
|
|
"lifetime bound not satisfied");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2014-08-27 21:46:52 -04:00
|
|
|
"lifetime parameter instantiated with ",
|
|
|
|
sup,
|
|
|
|
"");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2014-08-27 21:46:52 -04:00
|
|
|
"but lifetime parameter must outlive ",
|
|
|
|
sub,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
|
|
|
infer::RelateDefaultParamBound(span, ty) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0479,
|
2015-09-11 16:17:15 +02:00
|
|
|
"the type `{}` (provided as the value of \
|
|
|
|
a type parameter) is not valid at this point",
|
|
|
|
self.ty_to_string(ty));
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2014-08-27 21:46:52 -04:00
|
|
|
"type must outlive ",
|
|
|
|
sub,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
2013-05-23 21:37:37 -04:00
|
|
|
infer::CallRcvr(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0480,
|
2015-09-11 16:17:15 +02:00
|
|
|
"lifetime of method receiver does not outlive \
|
|
|
|
the method call");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-05-23 21:37:37 -04:00
|
|
|
"the receiver is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
infer::CallArg(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0481,
|
2015-09-11 16:17:15 +02:00
|
|
|
"lifetime of function argument does not outlive \
|
|
|
|
the function call");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-05-23 21:37:37 -04:00
|
|
|
"the function argument is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
infer::CallReturn(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0482,
|
2015-09-11 16:17:15 +02:00
|
|
|
"lifetime of return value does not outlive \
|
|
|
|
the function call");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-05-23 21:37:37 -04:00
|
|
|
"the return value is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
2015-02-12 12:48:54 -05:00
|
|
|
infer::Operand(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0483,
|
2015-09-11 16:17:15 +02:00
|
|
|
"lifetime of operand does not outlive \
|
|
|
|
the operation");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2015-02-12 12:48:54 -05:00
|
|
|
"the operand is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2015-02-12 12:48:54 -05:00
|
|
|
}
|
2013-05-23 21:37:37 -04:00
|
|
|
infer::AddrOf(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0484,
|
2015-09-11 16:17:15 +02:00
|
|
|
"reference is not valid at the time of borrow");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-05-23 21:37:37 -04:00
|
|
|
"the borrow is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
infer::AutoBorrow(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0485,
|
2015-09-11 16:17:15 +02:00
|
|
|
"automatically reference is not valid \
|
|
|
|
at the time of borrow");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-05-23 21:37:37 -04:00
|
|
|
"the automatic borrow is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
2014-08-27 21:46:52 -04:00
|
|
|
infer::ExprTypeIsNotInScope(t, span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0486,
|
2015-09-11 16:17:15 +02:00
|
|
|
"type of expression contains references \
|
|
|
|
that are not valid during the expression: `{}`",
|
|
|
|
self.ty_to_string(t));
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2014-08-27 21:46:52 -04:00
|
|
|
"type is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
2014-10-27 12:55:16 +01:00
|
|
|
infer::SafeDestructor(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0487,
|
2015-09-11 16:17:15 +02:00
|
|
|
"unsafe use of destructor: destructor might be called \
|
|
|
|
while references are dead");
|
2014-10-27 12:55:16 +01:00
|
|
|
// FIXME (22171): terms "super/subregion" are suboptimal
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2014-10-27 12:55:16 +01:00
|
|
|
"superregion: ",
|
|
|
|
sup,
|
|
|
|
"");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2014-10-27 12:55:16 +01:00
|
|
|
"subregion: ",
|
|
|
|
sub,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2014-10-27 12:55:16 +01:00
|
|
|
}
|
2013-05-23 21:37:37 -04:00
|
|
|
infer::BindingTypeIsNotValidAtDecl(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0488,
|
2015-09-11 16:17:15 +02:00
|
|
|
"lifetime of variable does not enclose its declaration");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-05-23 21:37:37 -04:00
|
|
|
"the variable is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
2015-08-07 10:28:51 -04:00
|
|
|
infer::ParameterInScope(_, span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0489,
|
2015-09-11 16:17:15 +02:00
|
|
|
"type/lifetime parameter not in scope here");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2015-08-07 10:28:51 -04:00
|
|
|
"the parameter is only valid for ",
|
|
|
|
sub,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2015-08-07 10:28:51 -04:00
|
|
|
}
|
|
|
|
infer::DataBorrowed(ty, span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0490,
|
2015-09-11 16:17:15 +02:00
|
|
|
"a value of type `{}` is borrowed for too long",
|
|
|
|
self.ty_to_string(ty));
|
2015-12-21 10:00:43 +13:00
|
|
|
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, "");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2015-08-07 10:28:51 -04:00
|
|
|
}
|
2013-07-10 10:04:22 -04:00
|
|
|
infer::ReferenceOutlivesReferent(ty, span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = struct_span_err!(self.tcx.sess, span, E0491,
|
2015-09-11 16:17:15 +02:00
|
|
|
"in type `{}`, reference has a longer lifetime \
|
|
|
|
than the data it references",
|
|
|
|
self.ty_to_string(ty));
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-05-23 21:37:37 -04:00
|
|
|
"the pointer is valid for ",
|
|
|
|
sub,
|
|
|
|
"");
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-05-23 21:37:37 -04:00
|
|
|
"but the referenced data is only valid for ",
|
|
|
|
sup,
|
|
|
|
"");
|
2016-03-18 14:47:40 -04:00
|
|
|
err
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
2016-10-05 10:17:14 -04:00
|
|
|
infer::CompareImplMethodObligation { span,
|
|
|
|
item_name,
|
|
|
|
impl_item_def_id,
|
2016-10-12 16:38:58 -04:00
|
|
|
trait_item_def_id,
|
|
|
|
lint_id } => {
|
2016-10-05 10:17:14 -04:00
|
|
|
self.report_extra_impl_obligation(span,
|
|
|
|
item_name,
|
|
|
|
impl_item_def_id,
|
|
|
|
trait_item_def_id,
|
2016-10-12 16:38:58 -04:00
|
|
|
&format!("`{}: {}`", sup, sub),
|
|
|
|
lint_id)
|
2016-10-05 10:17:14 -04:00
|
|
|
}
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-07 00:38:33 +02:00
|
|
|
fn report_sub_sup_conflict(&self,
|
2013-05-23 21:37:37 -04:00
|
|
|
var_origin: RegionVariableOrigin,
|
2014-09-29 22:11:30 +03:00
|
|
|
sub_origin: SubregionOrigin<'tcx>,
|
2016-08-25 23:58:52 +03:00
|
|
|
sub_region: &'tcx Region,
|
2014-09-29 22:11:30 +03:00
|
|
|
sup_origin: SubregionOrigin<'tcx>,
|
2016-08-25 23:58:52 +03:00
|
|
|
sup_region: &'tcx Region) {
|
2015-12-21 10:00:43 +13:00
|
|
|
let mut err = self.report_inference_failure(var_origin);
|
2013-05-23 21:37:37 -04:00
|
|
|
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-05-23 21:37:37 -04:00
|
|
|
"first, the lifetime cannot outlive ",
|
|
|
|
sup_region,
|
|
|
|
"...");
|
|
|
|
|
2015-12-21 10:00:43 +13:00
|
|
|
self.note_region_origin(&mut err, &sup_origin);
|
2013-05-23 21:37:37 -04:00
|
|
|
|
2015-12-21 10:00:43 +13:00
|
|
|
self.tcx.note_and_explain_region(&mut err,
|
2013-05-23 21:37:37 -04:00
|
|
|
"but, the lifetime must be valid for ",
|
|
|
|
sub_region,
|
|
|
|
"...");
|
|
|
|
|
2015-12-21 10:00:43 +13:00
|
|
|
self.note_region_origin(&mut err, &sub_origin);
|
|
|
|
err.emit();
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
|
2014-02-15 01:26:51 -05:00
|
|
|
fn report_processed_errors(&self,
|
2016-03-18 14:47:40 -04:00
|
|
|
origins: &[ProcessedErrorOrigin<'tcx>],
|
2014-02-15 01:26:51 -05:00
|
|
|
same_regions: &[SameRegions]) {
|
2016-03-18 14:47:40 -04:00
|
|
|
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 {
|
2015-12-21 10:00:43 +13:00
|
|
|
self.give_suggestion(&mut err, same_regions);
|
|
|
|
}
|
|
|
|
|
2016-03-18 14:47:40 -04:00
|
|
|
err.emit();
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-21 10:00:43 +13:00
|
|
|
fn give_suggestion(&self, err: &mut DiagnosticBuilder, same_regions: &[SameRegions]) {
|
2014-02-15 01:26:51 -05:00
|
|
|
let scope_id = same_regions[0].scope_id;
|
|
|
|
let parent = self.tcx.map.get_parent(scope_id);
|
|
|
|
let parent_node = self.tcx.map.find(parent);
|
2015-01-26 13:38:33 +01:00
|
|
|
let taken = lifetimes_in_scope(self.tcx, scope_id);
|
2015-02-18 14:48:57 -05:00
|
|
|
let life_giver = LifeGiver::with_taken(&taken[..]);
|
2014-02-15 01:26:51 -05:00
|
|
|
let node_inner = match parent_node {
|
2014-04-23 18:16:23 +02:00
|
|
|
Some(ref node) => match *node {
|
|
|
|
ast_map::NodeItem(ref item) => {
|
|
|
|
match item.node {
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, _) => {
|
2016-05-08 21:19:29 +03:00
|
|
|
Some((fn_decl, gen, unsafety, constness, item.name, item.span))
|
2016-10-29 22:57:23 -07:00
|
|
|
}
|
|
|
|
_ => None,
|
2014-04-23 18:16:23 +02:00
|
|
|
}
|
|
|
|
}
|
2015-03-10 12:28:44 +02:00
|
|
|
ast_map::NodeImplItem(item) => {
|
2016-10-29 22:57:23 -07:00
|
|
|
let id = self.tcx.map.get_parent(item.id);
|
|
|
|
if let Some(ast_map::NodeItem(parent_scope)) = self.tcx.map.find(id) {
|
|
|
|
if let hir::ItemImpl(_, _, _, None, _, _) = parent_scope.node {
|
|
|
|
// this impl scope implements a trait, do not recomend
|
|
|
|
// using explicit lifetimes (#37363)
|
|
|
|
return;
|
2014-08-04 13:56:56 -07:00
|
|
|
}
|
2016-10-29 22:57:23 -07:00
|
|
|
}
|
|
|
|
if let hir::ImplItemKind::Method(ref sig, _) = item.node {
|
|
|
|
Some((&sig.decl,
|
|
|
|
&sig.generics,
|
|
|
|
sig.unsafety,
|
|
|
|
sig.constness,
|
|
|
|
item.name,
|
|
|
|
item.span))
|
|
|
|
} else {
|
|
|
|
None
|
2014-08-04 13:56:56 -07:00
|
|
|
}
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
},
|
2015-03-10 12:28:44 +02:00
|
|
|
ast_map::NodeTraitItem(item) => {
|
|
|
|
match item.node {
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::MethodTraitItem(ref sig, Some(_)) => {
|
2015-03-11 23:38:58 +02:00
|
|
|
Some((&sig.decl,
|
|
|
|
&sig.generics,
|
|
|
|
sig.unsafety,
|
2015-02-25 22:05:07 +02:00
|
|
|
sig.constness,
|
2015-09-20 04:50:30 +03:00
|
|
|
item.name,
|
2015-03-10 12:28:44 +02:00
|
|
|
item.span))
|
2014-10-03 22:35:16 -07:00
|
|
|
}
|
2016-10-29 22:57:23 -07:00
|
|
|
_ => None,
|
2014-10-03 22:35:16 -07:00
|
|
|
}
|
|
|
|
}
|
2016-10-29 22:57:23 -07:00
|
|
|
_ => None,
|
2014-02-15 01:26:51 -05:00
|
|
|
},
|
2016-10-29 22:57:23 -07:00
|
|
|
None => None,
|
2014-02-15 01:26:51 -05:00
|
|
|
};
|
2016-05-08 21:19:29 +03:00
|
|
|
let (fn_decl, generics, unsafety, constness, name, span)
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
= node_inner.expect("expect item fn");
|
2016-05-08 21:19:29 +03:00
|
|
|
let rebuilder = Rebuilder::new(self.tcx, fn_decl, generics, same_regions, &life_giver);
|
|
|
|
let (fn_decl, generics) = rebuilder.rebuild();
|
2016-08-10 16:20:12 -07:00
|
|
|
self.give_expl_lifetime_param(
|
|
|
|
err, &fn_decl, unsafety, constness, name, &generics, span);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2016-04-21 05:15:53 -04:00
|
|
|
|
|
|
|
pub fn issue_32330_warnings(&self, span: Span, issue32330s: &[ty::Issue32330]) {
|
|
|
|
for issue32330 in issue32330s {
|
|
|
|
match *issue32330 {
|
|
|
|
ty::Issue32330::WontChange => { }
|
|
|
|
ty::Issue32330::WillChange { fn_def_id, region_name } => {
|
|
|
|
self.tcx.sess.add_lint(
|
|
|
|
lint::builtin::HR_LIFETIME_IN_ASSOC_TYPE,
|
|
|
|
ast::CRATE_NODE_ID,
|
|
|
|
span,
|
|
|
|
format!("lifetime parameter `{0}` declared on fn `{1}` \
|
|
|
|
appears only in the return type, \
|
|
|
|
but here is required to be higher-ranked, \
|
|
|
|
which means that `{0}` must appear in both \
|
|
|
|
argument and return types",
|
|
|
|
region_name,
|
|
|
|
self.tcx.item_path_str(fn_def_id)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
|
2014-03-24 19:11:44 -04:00
|
|
|
struct RebuildPathInfo<'a> {
|
2015-07-31 00:04:06 -07:00
|
|
|
path: &'a hir::Path,
|
2014-03-24 19:11:44 -04:00
|
|
|
// indexes to insert lifetime on path.lifetimes
|
2014-12-04 12:06:42 -08:00
|
|
|
indexes: Vec<u32>,
|
2014-03-24 19:11:44 -04:00
|
|
|
// number of lifetimes we expect to see on the type referred by `path`
|
|
|
|
// (e.g., expected=1 for struct Foo<'a>)
|
2014-12-04 12:06:42 -08:00
|
|
|
expected: u32,
|
|
|
|
anon_nums: &'a HashSet<u32>,
|
2014-03-24 19:11:44 -04:00
|
|
|
region_names: &'a HashSet<ast::Name>
|
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
struct Rebuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
|
|
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
2015-07-31 00:04:06 -07:00
|
|
|
fn_decl: &'a hir::FnDecl,
|
|
|
|
generics: &'a hir::Generics,
|
2014-02-15 01:26:51 -05:00
|
|
|
same_regions: &'a [SameRegions],
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
life_giver: &'a LifeGiver,
|
2014-12-04 12:06:42 -08:00
|
|
|
cur_anon: Cell<u32>,
|
|
|
|
inserted_anons: RefCell<HashSet<u32>>,
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
enum FreshOrKept {
|
|
|
|
Fresh,
|
|
|
|
Kept
|
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
|
|
|
|
fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
2015-07-31 00:04:06 -07:00
|
|
|
fn_decl: &'a hir::FnDecl,
|
|
|
|
generics: &'a hir::Generics,
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
same_regions: &'a [SameRegions],
|
|
|
|
life_giver: &'a LifeGiver)
|
2016-04-29 06:00:23 +03:00
|
|
|
-> Rebuilder<'a, 'gcx, 'tcx> {
|
2014-02-15 01:26:51 -05:00
|
|
|
Rebuilder {
|
|
|
|
tcx: tcx,
|
|
|
|
fn_decl: fn_decl,
|
|
|
|
generics: generics,
|
|
|
|
same_regions: same_regions,
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
life_giver: life_giver,
|
2014-02-15 01:26:51 -05:00
|
|
|
cur_anon: Cell::new(0),
|
|
|
|
inserted_anons: RefCell::new(HashSet::new()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-08 21:19:29 +03:00
|
|
|
fn rebuild(&self) -> (hir::FnDecl, hir::Generics) {
|
2014-02-15 01:26:51 -05:00
|
|
|
let mut inputs = self.fn_decl.inputs.clone();
|
2014-09-07 20:09:06 +03:00
|
|
|
let mut output = self.fn_decl.output.clone();
|
2014-03-24 19:11:44 -04:00
|
|
|
let mut ty_params = self.generics.ty_params.clone();
|
2014-08-11 09:32:26 -07:00
|
|
|
let where_clause = self.generics.where_clause.clone();
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
let mut kept_lifetimes = HashSet::new();
|
2015-01-31 12:20:46 -05:00
|
|
|
for sr in self.same_regions {
|
2014-02-15 01:26:51 -05:00
|
|
|
self.cur_anon.set(0);
|
|
|
|
self.offset_cur_anon();
|
|
|
|
let (anon_nums, region_names) =
|
|
|
|
self.extract_anon_nums_and_names(sr);
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
let (lifetime, fresh_or_kept) = self.pick_lifetime(®ion_names);
|
|
|
|
match fresh_or_kept {
|
|
|
|
Kept => { kept_lifetimes.insert(lifetime.name); }
|
|
|
|
_ => ()
|
|
|
|
}
|
2015-02-18 14:48:57 -05:00
|
|
|
inputs = self.rebuild_args_ty(&inputs[..], lifetime,
|
2014-02-15 01:26:51 -05:00
|
|
|
&anon_nums, ®ion_names);
|
2014-11-09 16:14:15 +01:00
|
|
|
output = self.rebuild_output(&output, lifetime, &anon_nums, ®ion_names);
|
2014-03-24 19:11:44 -04:00
|
|
|
ty_params = self.rebuild_ty_params(ty_params, lifetime,
|
|
|
|
®ion_names);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
let fresh_lifetimes = self.life_giver.get_generated_lifetimes();
|
2014-02-15 01:26:51 -05:00
|
|
|
let all_region_names = self.extract_all_region_names();
|
|
|
|
let generics = self.rebuild_generics(self.generics,
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
&fresh_lifetimes,
|
|
|
|
&kept_lifetimes,
|
|
|
|
&all_region_names,
|
2014-08-11 09:32:26 -07:00
|
|
|
ty_params,
|
|
|
|
where_clause);
|
2015-07-31 00:04:06 -07:00
|
|
|
let new_fn_decl = hir::FnDecl {
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
inputs: inputs,
|
|
|
|
output: output,
|
|
|
|
variadic: self.fn_decl.variadic
|
|
|
|
};
|
2016-05-08 21:19:29 +03:00
|
|
|
(new_fn_decl, generics)
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn pick_lifetime(&self,
|
|
|
|
region_names: &HashSet<ast::Name>)
|
2015-07-31 00:04:06 -07:00
|
|
|
-> (hir::Lifetime, FreshOrKept) {
|
2015-03-24 16:54:09 -07:00
|
|
|
if !region_names.is_empty() {
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
// It's not necessary to convert the set of region names to a
|
|
|
|
// vector of string and then sort them. However, it makes the
|
|
|
|
// choice of lifetime name deterministic and thus easier to test.
|
|
|
|
let mut names = Vec::new();
|
2015-01-31 12:20:46 -05:00
|
|
|
for rn in region_names {
|
2015-07-28 18:07:20 +02:00
|
|
|
let lt_name = rn.to_string();
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
names.push(lt_name);
|
|
|
|
}
|
|
|
|
names.sort();
|
2016-11-16 08:21:52 +00:00
|
|
|
let name = Symbol::intern(&names[0]);
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
return (name_to_dummy_lifetime(name), Kept);
|
|
|
|
}
|
|
|
|
return (self.life_giver.give_lifetime(), Fresh);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn extract_anon_nums_and_names(&self, same_regions: &SameRegions)
|
2014-12-04 12:06:42 -08:00
|
|
|
-> (HashSet<u32>, HashSet<ast::Name>) {
|
2014-02-15 01:26:51 -05:00
|
|
|
let mut anon_nums = HashSet::new();
|
|
|
|
let mut region_names = HashSet::new();
|
2015-01-31 12:20:46 -05:00
|
|
|
for br in &same_regions.regions {
|
2014-02-15 01:26:51 -05:00
|
|
|
match *br {
|
|
|
|
ty::BrAnon(i) => {
|
|
|
|
anon_nums.insert(i);
|
|
|
|
}
|
2016-04-21 05:10:10 -04:00
|
|
|
ty::BrNamed(_, name, _) => {
|
2014-02-15 01:26:51 -05:00
|
|
|
region_names.insert(name);
|
|
|
|
}
|
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(anon_nums, region_names)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn extract_all_region_names(&self) -> HashSet<ast::Name> {
|
|
|
|
let mut all_region_names = HashSet::new();
|
2015-01-31 12:20:46 -05:00
|
|
|
for sr in self.same_regions {
|
|
|
|
for br in &sr.regions {
|
2014-02-15 01:26:51 -05:00
|
|
|
match *br {
|
2016-04-21 05:10:10 -04:00
|
|
|
ty::BrNamed(_, name, _) => {
|
2014-02-15 01:26:51 -05:00
|
|
|
all_region_names.insert(name);
|
|
|
|
}
|
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
all_region_names
|
|
|
|
}
|
|
|
|
|
2014-12-04 12:06:42 -08:00
|
|
|
fn inc_cur_anon(&self, n: u32) {
|
2014-02-15 01:26:51 -05:00
|
|
|
let anon = self.cur_anon.get();
|
|
|
|
self.cur_anon.set(anon+n);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn offset_cur_anon(&self) {
|
|
|
|
let mut anon = self.cur_anon.get();
|
2014-03-20 19:49:20 -07:00
|
|
|
while self.inserted_anons.borrow().contains(&anon) {
|
2014-02-15 01:26:51 -05:00
|
|
|
anon += 1;
|
|
|
|
}
|
|
|
|
self.cur_anon.set(anon);
|
|
|
|
}
|
|
|
|
|
2014-12-04 12:06:42 -08:00
|
|
|
fn inc_and_offset_cur_anon(&self, n: u32) {
|
2014-02-15 01:26:51 -05:00
|
|
|
self.inc_cur_anon(n);
|
|
|
|
self.offset_cur_anon();
|
|
|
|
}
|
|
|
|
|
2014-12-04 12:06:42 -08:00
|
|
|
fn track_anon(&self, anon: u32) {
|
2014-03-20 19:49:20 -07:00
|
|
|
self.inserted_anons.borrow_mut().insert(anon);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
|
2014-03-24 19:11:44 -04:00
|
|
|
fn rebuild_ty_params(&self,
|
2015-12-19 04:20:11 +03:00
|
|
|
ty_params: hir::HirVec<hir::TyParam>,
|
2015-07-31 00:04:06 -07:00
|
|
|
lifetime: hir::Lifetime,
|
2014-03-24 19:11:44 -04:00
|
|
|
region_names: &HashSet<ast::Name>)
|
2015-12-19 04:20:11 +03:00
|
|
|
-> hir::HirVec<hir::TyParam> {
|
2016-10-11 16:06:43 +02:00
|
|
|
ty_params.into_iter().map(|ty_param| {
|
|
|
|
let bounds = self.rebuild_ty_param_bounds(ty_param.bounds,
|
2014-03-24 19:11:44 -04:00
|
|
|
lifetime,
|
|
|
|
region_names);
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::TyParam {
|
2015-09-20 16:47:24 +03:00
|
|
|
name: ty_param.name,
|
2014-03-24 19:11:44 -04:00
|
|
|
id: ty_param.id,
|
|
|
|
bounds: bounds,
|
2016-10-11 16:06:43 +02:00
|
|
|
default: ty_param.default,
|
2014-04-03 13:38:45 +13:00
|
|
|
span: ty_param.span,
|
2016-10-11 16:06:43 +02:00
|
|
|
pure_wrt_drop: ty_param.pure_wrt_drop,
|
2014-03-24 19:11:44 -04:00
|
|
|
}
|
2015-12-19 04:20:11 +03:00
|
|
|
}).collect()
|
2014-03-24 19:11:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn rebuild_ty_param_bounds(&self,
|
2015-12-16 21:44:33 +03:00
|
|
|
ty_param_bounds: hir::TyParamBounds,
|
2015-07-31 00:04:06 -07:00
|
|
|
lifetime: hir::Lifetime,
|
2014-03-24 19:11:44 -04:00
|
|
|
region_names: &HashSet<ast::Name>)
|
2015-12-16 21:44:33 +03:00
|
|
|
-> hir::TyParamBounds {
|
2015-12-19 04:20:11 +03:00
|
|
|
ty_param_bounds.iter().map(|tpb| {
|
2014-03-24 19:11:44 -04:00
|
|
|
match tpb {
|
2015-07-31 00:04:06 -07:00
|
|
|
&hir::RegionTyParamBound(lt) => {
|
2014-08-27 21:46:52 -04:00
|
|
|
// FIXME -- it's unclear whether I'm supposed to
|
|
|
|
// substitute lifetime here. I suspect we need to
|
|
|
|
// be passing down a map.
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::RegionTyParamBound(lt)
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
&hir::TraitTyParamBound(ref poly_tr, modifier) => {
|
2014-11-07 06:53:45 -05:00
|
|
|
let tr = &poly_tr.trait_ref;
|
2014-03-24 19:11:44 -04:00
|
|
|
let last_seg = tr.path.segments.last().unwrap();
|
|
|
|
let mut insert = Vec::new();
|
2014-11-03 21:52:52 -05:00
|
|
|
let lifetimes = last_seg.parameters.lifetimes();
|
|
|
|
for (i, lt) in lifetimes.iter().enumerate() {
|
2014-03-24 19:11:44 -04:00
|
|
|
if region_names.contains(<.name) {
|
2014-12-04 12:06:42 -08:00
|
|
|
insert.push(i as u32);
|
2014-03-24 19:11:44 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
let rebuild_info = RebuildPathInfo {
|
|
|
|
path: &tr.path,
|
|
|
|
indexes: insert,
|
2014-12-04 12:06:42 -08:00
|
|
|
expected: lifetimes.len() as u32,
|
2014-03-24 19:11:44 -04:00
|
|
|
anon_nums: &HashSet::new(),
|
|
|
|
region_names: region_names
|
|
|
|
};
|
|
|
|
let new_path = self.rebuild_path(rebuild_info, lifetime);
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::TraitTyParamBound(hir::PolyTraitRef {
|
2014-11-07 06:53:45 -05:00
|
|
|
bound_lifetimes: poly_tr.bound_lifetimes.clone(),
|
2015-07-31 00:04:06 -07:00
|
|
|
trait_ref: hir::TraitRef {
|
2014-11-07 06:53:45 -05:00
|
|
|
path: new_path,
|
|
|
|
ref_id: tr.ref_id,
|
2015-02-05 21:46:01 +13:00
|
|
|
},
|
|
|
|
span: poly_tr.span,
|
2014-12-24 19:38:10 +13:00
|
|
|
}, modifier)
|
2014-03-24 19:11:44 -04:00
|
|
|
}
|
|
|
|
}
|
2015-12-19 04:20:11 +03:00
|
|
|
}).collect()
|
2014-03-24 19:11:44 -04:00
|
|
|
}
|
|
|
|
|
2014-02-15 01:26:51 -05:00
|
|
|
fn rebuild_generics(&self,
|
2015-07-31 00:04:06 -07:00
|
|
|
generics: &hir::Generics,
|
|
|
|
add: &Vec<hir::Lifetime>,
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
keep: &HashSet<ast::Name>,
|
2014-03-24 19:11:44 -04:00
|
|
|
remove: &HashSet<ast::Name>,
|
2015-12-19 04:20:11 +03:00
|
|
|
ty_params: hir::HirVec<hir::TyParam>,
|
2015-07-31 00:04:06 -07:00
|
|
|
where_clause: hir::WhereClause)
|
|
|
|
-> hir::Generics {
|
2014-02-15 01:26:51 -05:00
|
|
|
let mut lifetimes = Vec::new();
|
2015-01-31 12:20:46 -05:00
|
|
|
for lt in add {
|
2016-10-17 16:22:24 +02:00
|
|
|
lifetimes.push(hir::LifetimeDef {
|
|
|
|
lifetime: *lt,
|
|
|
|
bounds: hir::HirVec::new(),
|
|
|
|
pure_wrt_drop: false,
|
2016-10-11 16:06:43 +02:00
|
|
|
});
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2015-01-31 12:20:46 -05:00
|
|
|
for lt in &generics.lifetimes {
|
2014-08-05 22:59:24 -04:00
|
|
|
if keep.contains(<.lifetime.name) ||
|
2014-08-11 09:32:26 -07:00
|
|
|
!remove.contains(<.lifetime.name) {
|
2014-02-15 01:26:51 -05:00
|
|
|
lifetimes.push((*lt).clone());
|
|
|
|
}
|
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::Generics {
|
2015-12-17 20:41:28 +03:00
|
|
|
lifetimes: lifetimes.into(),
|
2014-08-11 09:32:26 -07:00
|
|
|
ty_params: ty_params,
|
|
|
|
where_clause: where_clause,
|
2016-08-10 19:39:12 +02:00
|
|
|
span: generics.span,
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn rebuild_args_ty(&self,
|
2015-07-31 00:04:06 -07:00
|
|
|
inputs: &[hir::Arg],
|
|
|
|
lifetime: hir::Lifetime,
|
2014-12-04 12:06:42 -08:00
|
|
|
anon_nums: &HashSet<u32>,
|
2014-02-15 01:26:51 -05:00
|
|
|
region_names: &HashSet<ast::Name>)
|
2015-12-17 20:41:28 +03:00
|
|
|
-> hir::HirVec<hir::Arg> {
|
2014-02-15 01:26:51 -05:00
|
|
|
let mut new_inputs = Vec::new();
|
2015-01-31 12:20:46 -05:00
|
|
|
for arg in inputs {
|
2016-02-09 22:00:20 +01:00
|
|
|
let new_ty = self.rebuild_arg_ty_or_output(&arg.ty, lifetime,
|
2014-02-15 01:26:51 -05:00
|
|
|
anon_nums, region_names);
|
2015-07-31 00:04:06 -07:00
|
|
|
let possibly_new_arg = hir::Arg {
|
2014-02-15 01:26:51 -05:00
|
|
|
ty: new_ty,
|
2014-09-07 20:09:06 +03:00
|
|
|
pat: arg.pat.clone(),
|
2014-02-15 01:26:51 -05:00
|
|
|
id: arg.id
|
|
|
|
};
|
|
|
|
new_inputs.push(possibly_new_arg);
|
|
|
|
}
|
2015-12-17 20:41:28 +03:00
|
|
|
new_inputs.into()
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
fn rebuild_output(&self, ty: &hir::FunctionRetTy,
|
|
|
|
lifetime: hir::Lifetime,
|
2014-12-04 12:06:42 -08:00
|
|
|
anon_nums: &HashSet<u32>,
|
2015-07-31 00:04:06 -07:00
|
|
|
region_names: &HashSet<ast::Name>) -> hir::FunctionRetTy {
|
2014-11-09 16:14:15 +01:00
|
|
|
match *ty {
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::Return(ref ret_ty) => hir::Return(
|
2016-02-09 22:00:20 +01:00
|
|
|
self.rebuild_arg_ty_or_output(&ret_ty, lifetime, anon_nums, region_names)
|
2014-11-09 16:14:15 +01:00
|
|
|
),
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::DefaultReturn(span) => hir::DefaultReturn(span),
|
2014-11-09 16:14:15 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-15 01:26:51 -05:00
|
|
|
fn rebuild_arg_ty_or_output(&self,
|
2015-07-31 00:04:06 -07:00
|
|
|
ty: &hir::Ty,
|
|
|
|
lifetime: hir::Lifetime,
|
2014-12-04 12:06:42 -08:00
|
|
|
anon_nums: &HashSet<u32>,
|
2014-02-15 01:26:51 -05:00
|
|
|
region_names: &HashSet<ast::Name>)
|
2015-07-31 00:04:06 -07:00
|
|
|
-> P<hir::Ty> {
|
2014-09-07 20:09:06 +03:00
|
|
|
let mut new_ty = P(ty.clone());
|
2016-10-29 22:54:04 +01:00
|
|
|
let mut ty_queue = vec![ty];
|
2014-02-15 01:26:51 -05:00
|
|
|
while !ty_queue.is_empty() {
|
2014-12-30 10:51:18 -08:00
|
|
|
let cur_ty = ty_queue.remove(0);
|
2014-02-15 01:26:51 -05:00
|
|
|
match cur_ty.node {
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::TyRptr(lt_opt, ref mut_ty) => {
|
2014-09-07 20:09:06 +03:00
|
|
|
let rebuild = match lt_opt {
|
|
|
|
Some(lt) => region_names.contains(<.name),
|
2014-02-15 01:26:51 -05:00
|
|
|
None => {
|
|
|
|
let anon = self.cur_anon.get();
|
2014-09-07 20:09:06 +03:00
|
|
|
let rebuild = anon_nums.contains(&anon);
|
|
|
|
if rebuild {
|
2014-02-15 01:26:51 -05:00
|
|
|
self.track_anon(anon);
|
|
|
|
}
|
|
|
|
self.inc_and_offset_cur_anon(1);
|
2014-09-07 20:09:06 +03:00
|
|
|
rebuild
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2014-09-07 20:09:06 +03:00
|
|
|
};
|
|
|
|
if rebuild {
|
2015-07-31 00:04:06 -07:00
|
|
|
let to = hir::Ty {
|
2014-09-07 20:09:06 +03:00
|
|
|
id: cur_ty.id,
|
2015-07-31 00:04:06 -07:00
|
|
|
node: hir::TyRptr(Some(lifetime), mut_ty.clone()),
|
2014-09-07 20:09:06 +03:00
|
|
|
span: cur_ty.span
|
|
|
|
};
|
|
|
|
new_ty = self.rebuild_ty(new_ty, P(to));
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2016-02-09 22:00:20 +01:00
|
|
|
ty_queue.push(&mut_ty.ty);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2016-10-27 05:17:42 +03:00
|
|
|
hir::TyPath(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
|
2016-11-25 13:21:19 +02:00
|
|
|
match path.def {
|
2016-08-10 21:00:17 +03:00
|
|
|
Def::Enum(did) | Def::TyAlias(did) |
|
|
|
|
Def::Struct(did) | Def::Union(did) => {
|
2016-11-10 16:49:53 +02:00
|
|
|
let generics = self.tcx.item_generics(did);
|
2014-02-15 01:26:51 -05:00
|
|
|
|
2014-05-31 18:53:13 -04:00
|
|
|
let expected =
|
2016-08-10 20:39:09 +03:00
|
|
|
generics.regions.len() as u32;
|
2014-05-31 18:53:13 -04:00
|
|
|
let lifetimes =
|
2014-11-03 21:52:52 -05:00
|
|
|
path.segments.last().unwrap().parameters.lifetimes();
|
2014-02-15 01:26:51 -05:00
|
|
|
let mut insert = Vec::new();
|
2015-03-24 16:53:34 -07:00
|
|
|
if lifetimes.is_empty() {
|
2014-02-15 01:26:51 -05:00
|
|
|
let anon = self.cur_anon.get();
|
2015-01-26 16:05:07 -05:00
|
|
|
for (i, a) in (anon..anon+expected).enumerate() {
|
2014-02-15 01:26:51 -05:00
|
|
|
if anon_nums.contains(&a) {
|
2014-12-04 12:06:42 -08:00
|
|
|
insert.push(i as u32);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
self.track_anon(a);
|
|
|
|
}
|
|
|
|
self.inc_and_offset_cur_anon(expected);
|
|
|
|
} else {
|
|
|
|
for (i, lt) in lifetimes.iter().enumerate() {
|
|
|
|
if region_names.contains(<.name) {
|
2014-12-04 12:06:42 -08:00
|
|
|
insert.push(i as u32);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-03-24 19:11:44 -04:00
|
|
|
let rebuild_info = RebuildPathInfo {
|
|
|
|
path: path,
|
|
|
|
indexes: insert,
|
|
|
|
expected: expected,
|
|
|
|
anon_nums: anon_nums,
|
|
|
|
region_names: region_names
|
|
|
|
};
|
2014-09-07 20:09:06 +03:00
|
|
|
let new_path = self.rebuild_path(rebuild_info, lifetime);
|
2015-02-17 19:29:13 +02:00
|
|
|
let qself = maybe_qself.as_ref().map(|qself| {
|
2016-10-27 05:17:42 +03:00
|
|
|
self.rebuild_arg_ty_or_output(qself, lifetime,
|
|
|
|
anon_nums, region_names)
|
2015-02-17 19:29:13 +02:00
|
|
|
});
|
2015-07-31 00:04:06 -07:00
|
|
|
let to = hir::Ty {
|
2014-09-07 20:09:06 +03:00
|
|
|
id: cur_ty.id,
|
2016-10-27 05:17:42 +03:00
|
|
|
node: hir::TyPath(hir::QPath::Resolved(qself, P(new_path))),
|
2014-09-07 20:09:06 +03:00
|
|
|
span: cur_ty.span
|
|
|
|
};
|
|
|
|
new_ty = self.rebuild_ty(new_ty, P(to));
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
_ => ()
|
|
|
|
}
|
|
|
|
}
|
2014-09-07 20:09:06 +03:00
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::TyPtr(ref mut_ty) => {
|
2016-02-09 22:00:20 +01:00
|
|
|
ty_queue.push(&mut_ty.ty);
|
2014-09-07 20:09:06 +03:00
|
|
|
}
|
2016-09-20 02:14:46 +02:00
|
|
|
hir::TySlice(ref ty) |
|
|
|
|
hir::TyArray(ref ty, _) => {
|
2016-02-09 22:00:20 +01:00
|
|
|
ty_queue.push(&ty);
|
2014-09-07 20:09:06 +03:00
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::TyTup(ref tys) => ty_queue.extend(tys.iter().map(|ty| &**ty)),
|
2014-09-07 20:09:06 +03:00
|
|
|
_ => {}
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
new_ty
|
|
|
|
}
|
|
|
|
|
|
|
|
fn rebuild_ty(&self,
|
2015-07-31 00:04:06 -07:00
|
|
|
from: P<hir::Ty>,
|
|
|
|
to: P<hir::Ty>)
|
|
|
|
-> P<hir::Ty> {
|
2014-09-07 20:09:06 +03:00
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
fn build_to(from: P<hir::Ty>,
|
|
|
|
to: &mut Option<P<hir::Ty>>)
|
|
|
|
-> P<hir::Ty> {
|
2014-09-07 20:09:06 +03:00
|
|
|
if Some(from.id) == to.as_ref().map(|ty| ty.id) {
|
|
|
|
return to.take().expect("`to` type found more than once during rebuild");
|
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
from.map(|hir::Ty {id, node, span}| {
|
2014-09-07 20:09:06 +03:00
|
|
|
let new_node = match node {
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::TyRptr(lifetime, mut_ty) => {
|
|
|
|
hir::TyRptr(lifetime, hir::MutTy {
|
2014-09-07 20:09:06 +03:00
|
|
|
mutbl: mut_ty.mutbl,
|
|
|
|
ty: build_to(mut_ty.ty, to),
|
|
|
|
})
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::TyPtr(mut_ty) => {
|
|
|
|
hir::TyPtr(hir::MutTy {
|
2014-09-07 20:09:06 +03:00
|
|
|
mutbl: mut_ty.mutbl,
|
|
|
|
ty: build_to(mut_ty.ty, to),
|
|
|
|
})
|
|
|
|
}
|
2016-09-20 02:14:46 +02:00
|
|
|
hir::TySlice(ty) => hir::TySlice(build_to(ty, to)),
|
|
|
|
hir::TyArray(ty, e) => {
|
|
|
|
hir::TyArray(build_to(ty, to), e)
|
2014-09-07 20:09:06 +03:00
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::TyTup(tys) => {
|
|
|
|
hir::TyTup(tys.into_iter().map(|ty| build_to(ty, to)).collect())
|
2014-09-07 20:09:06 +03:00
|
|
|
}
|
|
|
|
other => other
|
|
|
|
};
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::Ty { id: id, node: new_node, span: span }
|
2014-09-07 20:09:06 +03:00
|
|
|
})
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
|
2014-09-07 20:09:06 +03:00
|
|
|
build_to(from, &mut Some(to))
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn rebuild_path(&self,
|
2014-03-24 19:11:44 -04:00
|
|
|
rebuild_info: RebuildPathInfo,
|
2015-07-31 00:04:06 -07:00
|
|
|
lifetime: hir::Lifetime)
|
|
|
|
-> hir::Path
|
2014-11-03 21:52:52 -05:00
|
|
|
{
|
2014-03-24 19:11:44 -04:00
|
|
|
let RebuildPathInfo {
|
2014-10-06 13:36:53 +13:00
|
|
|
path,
|
|
|
|
indexes,
|
|
|
|
expected,
|
|
|
|
anon_nums,
|
|
|
|
region_names,
|
2014-03-24 19:11:44 -04:00
|
|
|
} = rebuild_info;
|
|
|
|
|
2014-02-15 01:26:51 -05:00
|
|
|
let last_seg = path.segments.last().unwrap();
|
2014-11-03 21:52:52 -05:00
|
|
|
let new_parameters = match last_seg.parameters {
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::ParenthesizedParameters(..) => {
|
2014-11-03 21:52:52 -05:00
|
|
|
last_seg.parameters.clone()
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2014-11-03 21:52:52 -05:00
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::AngleBracketedParameters(ref data) => {
|
2014-11-03 21:52:52 -05:00
|
|
|
let mut new_lts = Vec::new();
|
2015-03-24 16:53:34 -07:00
|
|
|
if data.lifetimes.is_empty() {
|
2014-11-03 21:52:52 -05:00
|
|
|
// traverse once to see if there's a need to insert lifetime
|
2015-01-26 15:44:22 -05:00
|
|
|
let need_insert = (0..expected).any(|i| {
|
2014-11-03 21:52:52 -05:00
|
|
|
indexes.contains(&i)
|
|
|
|
});
|
|
|
|
if need_insert {
|
2015-01-26 15:46:12 -05:00
|
|
|
for i in 0..expected {
|
2014-11-03 21:52:52 -05:00
|
|
|
if indexes.contains(&i) {
|
|
|
|
new_lts.push(lifetime);
|
|
|
|
} else {
|
|
|
|
new_lts.push(self.life_giver.give_lifetime());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-02-15 01:26:51 -05:00
|
|
|
} else {
|
2014-11-03 21:52:52 -05:00
|
|
|
for (i, lt) in data.lifetimes.iter().enumerate() {
|
2014-12-04 12:06:42 -08:00
|
|
|
if indexes.contains(&(i as u32)) {
|
2014-11-03 21:52:52 -05:00
|
|
|
new_lts.push(lifetime);
|
|
|
|
} else {
|
|
|
|
new_lts.push(*lt);
|
|
|
|
}
|
|
|
|
}
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2015-12-19 04:20:11 +03:00
|
|
|
let new_types = data.types.iter().map(|t| {
|
2016-02-09 22:00:20 +01:00
|
|
|
self.rebuild_arg_ty_or_output(&t, lifetime, anon_nums, region_names)
|
2015-12-19 04:20:11 +03:00
|
|
|
}).collect();
|
|
|
|
let new_bindings = data.bindings.iter().map(|b| {
|
2015-12-07 17:17:41 +03:00
|
|
|
hir::TypeBinding {
|
2014-11-29 17:08:30 +13:00
|
|
|
id: b.id,
|
2015-09-20 16:47:24 +03:00
|
|
|
name: b.name,
|
2016-02-09 22:00:20 +01:00
|
|
|
ty: self.rebuild_arg_ty_or_output(&b.ty,
|
2014-11-29 17:08:30 +13:00
|
|
|
lifetime,
|
|
|
|
anon_nums,
|
|
|
|
region_names),
|
|
|
|
span: b.span
|
2015-12-07 17:17:41 +03:00
|
|
|
}
|
2015-12-19 04:20:11 +03:00
|
|
|
}).collect();
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::AngleBracketedParameters(hir::AngleBracketedParameterData {
|
2015-12-17 20:41:28 +03:00
|
|
|
lifetimes: new_lts.into(),
|
2014-11-29 17:08:30 +13:00
|
|
|
types: new_types,
|
2016-10-17 06:02:23 +03:00
|
|
|
infer_types: data.infer_types,
|
2014-11-29 17:08:30 +13:00
|
|
|
bindings: new_bindings,
|
|
|
|
})
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2014-11-03 21:52:52 -05:00
|
|
|
};
|
2015-07-31 00:04:06 -07:00
|
|
|
let new_seg = hir::PathSegment {
|
2016-03-06 15:54:44 +03:00
|
|
|
name: last_seg.name,
|
2014-11-03 21:52:52 -05:00
|
|
|
parameters: new_parameters
|
2014-02-15 01:26:51 -05:00
|
|
|
};
|
|
|
|
let mut new_segs = Vec::new();
|
2015-12-02 17:31:49 -08:00
|
|
|
new_segs.extend_from_slice(path.segments.split_last().unwrap().1);
|
2014-02-15 01:26:51 -05:00
|
|
|
new_segs.push(new_seg);
|
2015-07-31 00:04:06 -07:00
|
|
|
hir::Path {
|
2014-02-15 01:26:51 -05:00
|
|
|
span: path.span,
|
2016-11-25 13:21:19 +02:00
|
|
|
def: path.def,
|
2015-12-17 20:41:28 +03:00
|
|
|
segments: new_segs.into()
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
2014-02-15 01:26:51 -05:00
|
|
|
fn give_expl_lifetime_param(&self,
|
2015-12-21 10:00:43 +13:00
|
|
|
err: &mut DiagnosticBuilder,
|
2015-07-31 00:04:06 -07:00
|
|
|
decl: &hir::FnDecl,
|
|
|
|
unsafety: hir::Unsafety,
|
|
|
|
constness: hir::Constness,
|
2015-09-20 04:50:30 +03:00
|
|
|
name: ast::Name,
|
2015-07-31 00:04:06 -07:00
|
|
|
generics: &hir::Generics,
|
2015-06-16 01:10:55 +03:00
|
|
|
span: Span) {
|
2016-05-08 21:19:29 +03:00
|
|
|
let suggested_fn = pprust::fun_to_string(decl, unsafety, constness, name, generics);
|
2014-02-15 01:26:51 -05:00
|
|
|
let msg = format!("consider using an explicit lifetime \
|
|
|
|
parameter as shown: {}", suggested_fn);
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_help(span, &msg[..]);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
|
2014-02-07 00:38:33 +02:00
|
|
|
fn report_inference_failure(&self,
|
2015-12-21 10:00:43 +13:00
|
|
|
var_origin: RegionVariableOrigin)
|
|
|
|
-> DiagnosticBuilder<'tcx> {
|
2015-06-14 06:46:04 +03:00
|
|
|
let br_string = |br: ty::BoundRegion| {
|
2015-06-18 20:25:05 +03:00
|
|
|
let mut s = br.to_string();
|
2015-06-14 06:46:04 +03:00
|
|
|
if !s.is_empty() {
|
|
|
|
s.push_str(" ");
|
|
|
|
}
|
|
|
|
s
|
|
|
|
};
|
2013-10-29 06:12:50 -04:00
|
|
|
let var_description = match var_origin {
|
2014-05-25 03:17:19 -07:00
|
|
|
infer::MiscVariable(_) => "".to_string(),
|
|
|
|
infer::PatternRegion(_) => " for pattern".to_string(),
|
|
|
|
infer::AddrOfRegion(_) => " for borrow expression".to_string(),
|
|
|
|
infer::Autoref(_) => " for autoref".to_string(),
|
|
|
|
infer::Coercion(_) => " for automatic coercion".to_string(),
|
2014-11-05 22:06:04 -05:00
|
|
|
infer::LateBoundRegion(_, br, infer::FnCall) => {
|
2015-06-14 06:46:04 +03:00
|
|
|
format!(" for lifetime parameter {}in function call",
|
|
|
|
br_string(br))
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
2014-11-15 16:22:22 -05:00
|
|
|
infer::LateBoundRegion(_, br, infer::HigherRankedType) => {
|
2015-06-14 06:46:04 +03:00
|
|
|
format!(" for lifetime parameter {}in generic type", br_string(br))
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
2014-12-17 14:16:28 -05:00
|
|
|
infer::LateBoundRegion(_, br, infer::AssocTypeProjection(type_name)) => {
|
2015-06-14 06:46:04 +03:00
|
|
|
format!(" for lifetime parameter {}in trait containing associated type `{}`",
|
2015-07-28 18:07:20 +02:00
|
|
|
br_string(br), type_name)
|
2014-12-17 14:16:28 -05:00
|
|
|
}
|
2014-03-07 08:43:39 +01:00
|
|
|
infer::EarlyBoundRegion(_, name) => {
|
2014-07-22 05:27:46 -04:00
|
|
|
format!(" for lifetime parameter `{}`",
|
2015-07-28 18:07:20 +02:00
|
|
|
name)
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
2014-03-07 08:43:39 +01:00
|
|
|
infer::BoundRegionInCoherence(name) => {
|
2014-07-22 05:27:46 -04:00
|
|
|
format!(" for lifetime parameter `{}` in coherence check",
|
2015-07-28 18:07:20 +02:00
|
|
|
name)
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
2014-02-07 14:43:48 -05:00
|
|
|
infer::UpvarRegion(ref upvar_id, _) => {
|
|
|
|
format!(" for capture of `{}` by closure",
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.local_var_name_str(upvar_id.var_id).to_string())
|
2014-02-07 14:43:48 -05:00
|
|
|
}
|
2013-10-29 06:12:50 -04:00
|
|
|
};
|
|
|
|
|
2015-12-21 10:00:43 +13:00
|
|
|
struct_span_err!(self.tcx.sess, var_origin.span(), E0495,
|
2015-09-14 21:25:04 +02:00
|
|
|
"cannot infer an appropriate lifetime{} \
|
|
|
|
due to conflicting requirements",
|
2015-12-21 10:00:43 +13:00
|
|
|
var_description)
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
|
|
|
|
2015-12-21 10:00:43 +13:00
|
|
|
fn note_region_origin(&self, err: &mut DiagnosticBuilder, origin: &SubregionOrigin<'tcx>) {
|
2014-08-27 21:46:52 -04:00
|
|
|
match *origin {
|
2015-07-14 19:36:15 -04:00
|
|
|
infer::Subtype(ref trace) => {
|
2016-07-16 23:18:20 +03:00
|
|
|
if let Some((expected, found)) = self.values_str(&trace.values) {
|
|
|
|
// FIXME: do we want a "the" here?
|
|
|
|
err.span_note(
|
2016-11-07 13:25:06 -05:00
|
|
|
trace.cause.span,
|
2016-07-16 23:18:20 +03:00
|
|
|
&format!("...so that {} (expected {}, found {})",
|
2016-11-07 13:25:06 -05:00
|
|
|
trace.cause.as_requirement_str(), expected, found));
|
2016-07-16 23:18:20 +03:00
|
|
|
} else {
|
|
|
|
// FIXME: this really should be handled at some earlier stage. Our
|
|
|
|
// handling of region checking when type errors are present is
|
|
|
|
// *terrible*.
|
|
|
|
|
|
|
|
err.span_note(
|
2016-11-07 13:25:06 -05:00
|
|
|
trace.cause.span,
|
2016-07-16 23:18:20 +03:00
|
|
|
&format!("...so that {}",
|
2016-11-07 13:25:06 -05:00
|
|
|
trace.cause.as_requirement_str()));
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
infer::Reborrow(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2013-10-29 06:12:50 -04:00
|
|
|
span,
|
2014-01-07 18:49:13 -08:00
|
|
|
"...so that reference does not outlive \
|
2013-10-29 06:12:50 -04:00
|
|
|
borrowed content");
|
|
|
|
}
|
2014-02-07 14:43:48 -05:00
|
|
|
infer::ReborrowUpvar(span, ref upvar_id) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2014-02-07 14:43:48 -05:00
|
|
|
span,
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!(
|
2014-05-16 10:45:16 -07:00
|
|
|
"...so that closure can access `{}`",
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.local_var_name_str(upvar_id.var_id)
|
2015-12-21 10:00:43 +13:00
|
|
|
.to_string()));
|
2014-02-07 14:43:48 -05:00
|
|
|
}
|
2013-10-29 06:12:50 -04:00
|
|
|
infer::InfStackClosure(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2013-10-29 06:12:50 -04:00
|
|
|
span,
|
|
|
|
"...so that closure does not outlive its stack frame");
|
|
|
|
}
|
|
|
|
infer::InvokeClosure(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2013-10-29 06:12:50 -04:00
|
|
|
span,
|
|
|
|
"...so that closure is not invoked outside its lifetime");
|
|
|
|
}
|
|
|
|
infer::DerefPointer(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2013-10-29 06:12:50 -04:00
|
|
|
span,
|
|
|
|
"...so that pointer is not dereferenced \
|
|
|
|
outside its lifetime");
|
|
|
|
}
|
2014-02-07 14:43:48 -05:00
|
|
|
infer::FreeVariable(span, id) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2013-10-29 06:12:50 -04:00
|
|
|
span,
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("...so that captured variable `{}` \
|
2014-02-07 14:43:48 -05:00
|
|
|
does not outlive the enclosing closure",
|
2015-06-25 23:42:17 +03:00
|
|
|
self.tcx.local_var_name_str(id)));
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
|
|
|
infer::IndexSlice(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2013-10-29 06:12:50 -04:00
|
|
|
span,
|
|
|
|
"...so that slice is not indexed outside the lifetime");
|
|
|
|
}
|
|
|
|
infer::RelateObjectBound(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2013-10-29 06:12:50 -04:00
|
|
|
span,
|
2014-08-27 21:46:52 -04:00
|
|
|
"...so that it can be closed over into an object");
|
|
|
|
}
|
2013-10-29 06:12:50 -04:00
|
|
|
infer::CallRcvr(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2013-10-29 06:12:50 -04:00
|
|
|
span,
|
|
|
|
"...so that method receiver is valid for the method call");
|
|
|
|
}
|
|
|
|
infer::CallArg(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2013-10-29 06:12:50 -04:00
|
|
|
span,
|
|
|
|
"...so that argument is valid for the call");
|
|
|
|
}
|
|
|
|
infer::CallReturn(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2013-10-29 06:12:50 -04:00
|
|
|
span,
|
|
|
|
"...so that return value is valid for the call");
|
|
|
|
}
|
2015-02-12 12:48:54 -05:00
|
|
|
infer::Operand(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2015-02-12 12:48:54 -05:00
|
|
|
span,
|
|
|
|
"...so that operand is valid for operation");
|
|
|
|
}
|
2013-10-29 06:12:50 -04:00
|
|
|
infer::AddrOf(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2013-10-29 06:12:50 -04:00
|
|
|
span,
|
2014-01-07 18:49:13 -08:00
|
|
|
"...so that reference is valid \
|
2013-10-29 06:12:50 -04:00
|
|
|
at the time of borrow");
|
|
|
|
}
|
|
|
|
infer::AutoBorrow(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2013-10-29 06:12:50 -04:00
|
|
|
span,
|
2014-07-22 05:27:46 -04:00
|
|
|
"...so that auto-reference is valid \
|
|
|
|
at the time of borrow");
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
2014-08-27 21:46:52 -04:00
|
|
|
infer::ExprTypeIsNotInScope(t, span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2014-08-27 21:46:52 -04:00
|
|
|
span,
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("...so type `{}` of expression is valid during the \
|
2014-08-27 21:46:52 -04:00
|
|
|
expression",
|
2015-02-20 14:08:14 -05:00
|
|
|
self.ty_to_string(t)));
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
2013-10-29 06:12:50 -04:00
|
|
|
infer::BindingTypeIsNotValidAtDecl(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2013-10-29 06:12:50 -04:00
|
|
|
span,
|
|
|
|
"...so that variable is valid at time of its declaration");
|
|
|
|
}
|
2015-08-07 10:28:51 -04:00
|
|
|
infer::ParameterInScope(_, span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2015-08-07 10:28:51 -04:00
|
|
|
span,
|
2015-11-05 15:30:32 +01:00
|
|
|
"...so that a type/lifetime parameter is in scope here");
|
2015-08-07 10:28:51 -04:00
|
|
|
}
|
|
|
|
infer::DataBorrowed(ty, span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2015-08-07 10:28:51 -04:00
|
|
|
span,
|
|
|
|
&format!("...so that the type `{}` is not borrowed for too long",
|
|
|
|
self.ty_to_string(ty)));
|
|
|
|
}
|
2014-08-27 21:46:52 -04:00
|
|
|
infer::ReferenceOutlivesReferent(ty, span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2014-08-27 21:46:52 -04:00
|
|
|
span,
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("...so that the reference type `{}` \
|
2014-08-27 21:46:52 -04:00
|
|
|
does not outlive the data it points at",
|
2015-02-20 14:08:14 -05:00
|
|
|
self.ty_to_string(ty)));
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
2014-11-15 17:25:05 -05:00
|
|
|
infer::RelateParamBound(span, t) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2014-08-27 21:46:52 -04:00
|
|
|
span,
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("...so that the type `{}` \
|
2015-02-16 11:58:47 -05:00
|
|
|
will meet its required lifetime bounds",
|
2015-02-20 14:08:14 -05:00
|
|
|
self.ty_to_string(t)));
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
|
|
|
infer::RelateDefaultParamBound(span, t) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2014-08-27 21:46:52 -04:00
|
|
|
span,
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("...so that type parameter \
|
2014-08-27 21:46:52 -04:00
|
|
|
instantiated with `{}`, \
|
2014-11-28 19:01:41 +13:00
|
|
|
will meet its declared lifetime bounds",
|
2015-02-20 14:08:14 -05:00
|
|
|
self.ty_to_string(t)));
|
2014-08-27 21:46:52 -04:00
|
|
|
}
|
|
|
|
infer::RelateRegionParamBound(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2013-10-29 06:12:50 -04:00
|
|
|
span,
|
2015-03-24 20:59:17 -07:00
|
|
|
"...so that the declared lifetime parameter bounds \
|
|
|
|
are satisfied");
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
2014-10-27 12:55:16 +01:00
|
|
|
infer::SafeDestructor(span) => {
|
2015-12-21 10:00:43 +13:00
|
|
|
err.span_note(
|
2014-10-27 12:55:16 +01:00
|
|
|
span,
|
|
|
|
"...so that references are valid when the destructor \
|
2015-12-21 10:00:43 +13:00
|
|
|
runs");
|
2014-10-27 12:55:16 +01:00
|
|
|
}
|
2016-10-05 10:17:14 -04:00
|
|
|
infer::CompareImplMethodObligation { span, .. } => {
|
|
|
|
err.span_note(
|
|
|
|
span,
|
|
|
|
"...so that the definition in impl matches the definition from the trait");
|
|
|
|
}
|
2013-10-29 06:12:50 -04:00
|
|
|
}
|
2013-05-23 21:37:37 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
|
|
|
scope_id: ast::NodeId)
|
|
|
|
-> Vec<hir::LifetimeDef> {
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
let mut taken = Vec::new();
|
|
|
|
let parent = tcx.map.get_parent(scope_id);
|
|
|
|
let method_id_opt = match tcx.map.find(parent) {
|
|
|
|
Some(node) => match node {
|
|
|
|
ast_map::NodeItem(item) => match item.node {
|
2016-08-26 19:23:42 +03:00
|
|
|
hir::ItemFn(.., ref gen, _) => {
|
2015-12-02 17:31:49 -08:00
|
|
|
taken.extend_from_slice(&gen.lifetimes);
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
None
|
|
|
|
},
|
|
|
|
_ => None
|
|
|
|
},
|
2014-08-04 13:56:56 -07:00
|
|
|
ast_map::NodeImplItem(ii) => {
|
2015-03-10 12:28:44 +02:00
|
|
|
match ii.node {
|
2015-11-12 15:57:51 +01:00
|
|
|
hir::ImplItemKind::Method(ref sig, _) => {
|
2015-12-02 17:31:49 -08:00
|
|
|
taken.extend_from_slice(&sig.generics.lifetimes);
|
2015-03-10 12:28:44 +02:00
|
|
|
Some(ii.id)
|
2014-08-04 13:56:56 -07:00
|
|
|
}
|
2015-03-14 12:05:00 -06:00
|
|
|
_ => None,
|
2014-08-04 13:56:56 -07:00
|
|
|
}
|
|
|
|
}
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
_ => None
|
|
|
|
},
|
|
|
|
None => None
|
|
|
|
};
|
2016-06-13 22:43:30 -07:00
|
|
|
if let Some(method_id) = method_id_opt {
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
let parent = tcx.map.get_parent(method_id);
|
2016-06-13 22:43:30 -07:00
|
|
|
if let Some(node) = tcx.map.find(parent) {
|
|
|
|
match node {
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
ast_map::NodeItem(item) => match item.node {
|
2016-08-26 19:23:42 +03:00
|
|
|
hir::ItemImpl(_, _, ref gen, ..) => {
|
2015-12-02 17:31:49 -08:00
|
|
|
taken.extend_from_slice(&gen.lifetimes);
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
}
|
|
|
|
_ => ()
|
|
|
|
},
|
|
|
|
_ => ()
|
2016-06-13 22:43:30 -07:00
|
|
|
}
|
Support lifetime suggestion for method
This includes a change to the way lifetime names are generated. Say we
figure that `[#0, 'a, 'b]` have to be the same lifetimes, then instead
of just generating a new lifetime `'c` like before to replace them, we
would reuse `'a`. This is done so that when the lifetime name comes
from an impl, we don't give something that's completely off, and we
don't have to do much work to figure out where the name came from. For
example, for the following code snippet:
```rust
struct Baz<'x> {
bar: &'x int
}
impl<'x> Baz<'x> {
fn baz1(&self) -> &int {
self.bar
}
}
```
`[#1, 'x]` (where `#1` is BrAnon(1) and refers to lifetime of `&int`)
have to be marked the same lifetime. With the old method, we would
generate a new lifetime `'a` and suggest `fn baz1(&self) -> &'a int`
or `fn baz1<'a>(&self) -> &'a int`, both of which are wrong.
2014-03-26 19:12:50 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return taken;
|
|
|
|
}
|
|
|
|
|
2014-02-15 01:26:51 -05:00
|
|
|
// LifeGiver is responsible for generating fresh lifetime names
|
|
|
|
struct LifeGiver {
|
2014-05-22 16:57:53 -07:00
|
|
|
taken: HashSet<String>,
|
2015-03-25 17:06:52 -07:00
|
|
|
counter: Cell<usize>,
|
2015-07-31 00:04:06 -07:00
|
|
|
generated: RefCell<Vec<hir::Lifetime>>,
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl LifeGiver {
|
2015-07-31 00:04:06 -07:00
|
|
|
fn with_taken(taken: &[hir::LifetimeDef]) -> LifeGiver {
|
2014-02-15 01:26:51 -05:00
|
|
|
let mut taken_ = HashSet::new();
|
2015-01-31 12:20:46 -05:00
|
|
|
for lt in taken {
|
2015-07-28 18:07:20 +02:00
|
|
|
let lt_name = lt.lifetime.name.to_string();
|
2014-02-15 01:26:51 -05:00
|
|
|
taken_.insert(lt_name);
|
|
|
|
}
|
|
|
|
LifeGiver {
|
|
|
|
taken: taken_,
|
|
|
|
counter: Cell::new(0),
|
|
|
|
generated: RefCell::new(Vec::new()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn inc_counter(&self) {
|
|
|
|
let c = self.counter.get();
|
|
|
|
self.counter.set(c+1);
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
fn give_lifetime(&self) -> hir::Lifetime {
|
2015-06-18 01:02:58 +03:00
|
|
|
let lifetime;
|
2014-02-15 01:26:51 -05:00
|
|
|
loop {
|
2015-06-08 16:55:35 +02:00
|
|
|
let mut s = String::from("'");
|
2015-02-20 14:08:14 -05:00
|
|
|
s.push_str(&num_to_string(self.counter.get()));
|
2014-02-15 01:26:51 -05:00
|
|
|
if !self.taken.contains(&s) {
|
2016-11-16 08:21:52 +00:00
|
|
|
lifetime = name_to_dummy_lifetime(Symbol::intern(&s));
|
2014-03-20 19:49:20 -07:00
|
|
|
self.generated.borrow_mut().push(lifetime);
|
2014-02-15 01:26:51 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
self.inc_counter();
|
|
|
|
}
|
|
|
|
self.inc_counter();
|
|
|
|
return lifetime;
|
|
|
|
|
|
|
|
// 0 .. 25 generates a .. z, 26 .. 51 generates aa .. zz, and so on
|
2015-03-25 17:06:52 -07:00
|
|
|
fn num_to_string(counter: usize) -> String {
|
2014-05-22 16:57:53 -07:00
|
|
|
let mut s = String::new();
|
2014-02-15 01:26:51 -05:00
|
|
|
let (n, r) = (counter/26 + 1, counter % 26);
|
|
|
|
let letter: char = from_u32((r+97) as u32).unwrap();
|
2015-01-26 15:46:12 -05:00
|
|
|
for _ in 0..n {
|
2014-10-14 23:05:01 -07:00
|
|
|
s.push(letter);
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
2014-05-09 18:45:36 -07:00
|
|
|
s
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:04:06 -07:00
|
|
|
fn get_generated_lifetimes(&self) -> Vec<hir::Lifetime> {
|
2014-03-28 10:29:55 -07:00
|
|
|
self.generated.borrow().clone()
|
2014-02-15 01:26:51 -05:00
|
|
|
}
|
|
|
|
}
|
2015-07-31 00:04:06 -07:00
|
|
|
|
|
|
|
fn name_to_dummy_lifetime(name: ast::Name) -> hir::Lifetime {
|
|
|
|
hir::Lifetime { id: ast::DUMMY_NODE_ID,
|
2016-06-21 18:08:13 -04:00
|
|
|
span: syntax_pos::DUMMY_SP,
|
2015-07-31 00:04:06 -07:00
|
|
|
name: name }
|
|
|
|
}
|
2016-11-07 13:25:06 -05:00
|
|
|
|
|
|
|
impl<'tcx> ObligationCause<'tcx> {
|
|
|
|
fn as_failure_str(&self) -> &'static str {
|
|
|
|
use traits::ObligationCauseCode::*;
|
|
|
|
match self.code {
|
|
|
|
CompareImplMethodObligation { .. } => "method not compatible with trait",
|
|
|
|
MatchExpressionArm { source, .. } => match source {
|
|
|
|
hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types",
|
|
|
|
_ => "match arms have incompatible types",
|
|
|
|
},
|
|
|
|
IfExpression => "if and else have incompatible types",
|
|
|
|
IfExpressionWithNoElse => "if may be missing an else clause",
|
|
|
|
EquatePredicate => "equality predicate not satisfied",
|
|
|
|
MainFunctionType => "main function has wrong type",
|
|
|
|
StartFunctionType => "start function has wrong type",
|
|
|
|
IntrinsicType => "intrinsic has wrong type",
|
|
|
|
MethodReceiver => "mismatched method receiver",
|
|
|
|
_ => "mismatched types",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn as_requirement_str(&self) -> &'static str {
|
|
|
|
use traits::ObligationCauseCode::*;
|
|
|
|
match self.code {
|
|
|
|
CompareImplMethodObligation { .. } => "method type is compatible with trait",
|
|
|
|
ExprAssignable => "expression is assignable",
|
|
|
|
MatchExpressionArm { source, .. } => match source {
|
|
|
|
hir::MatchSource::IfLetDesugar{..} => "`if let` arms have compatible types",
|
|
|
|
_ => "match arms have compatible types",
|
|
|
|
},
|
|
|
|
IfExpression => "if and else have compatible types",
|
|
|
|
IfExpressionWithNoElse => "if missing an else returns ()",
|
|
|
|
EquatePredicate => "equality where clause is satisfied",
|
|
|
|
MainFunctionType => "`main` function has the correct type",
|
|
|
|
StartFunctionType => "`start` function has the correct type",
|
|
|
|
IntrinsicType => "intrinsic has the correct type",
|
|
|
|
MethodReceiver => "method receiver has the correct type",
|
|
|
|
_ => "types are compatible",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|