Auto merge of #54453 - nikomatsakis:nll-issue-53121-shred-outlives, r=pnkfelix
rework how we handle outlives relationships When we encounter an outlives relationship involving a projection, we use to over-constrain in some cases with region constraints. We also used to evaluate whether the where-clauses in the environment might apply **before** running inference. We now avoid doing both of those things: - If there are where-clauses in the environment that might be useful, we add no constraints. - After inference is done, we check if we wound up inferring values compatible with the where-clause, and make use of them if so. I realize now that this PR includes some meandering commits and refactorings from when I expected to go in a different direction. If desired, I could try to remove some of those. Fixes #53121 Fixes #53789 r? @pnkfelix
This commit is contained in:
commit
c7df1f530b
44 changed files with 2574 additions and 1604 deletions
|
@ -55,23 +55,22 @@
|
|||
//! ported to this system, and which relies on string concatenation at the
|
||||
//! time of error detection.
|
||||
|
||||
use infer;
|
||||
use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
|
||||
use super::region_constraints::GenericKind;
|
||||
use super::lexical_region_resolve::RegionResolutionError;
|
||||
use super::region_constraints::GenericKind;
|
||||
use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
|
||||
use infer::{self, SuppressRegionErrors};
|
||||
|
||||
use std::{cmp, fmt};
|
||||
use errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
|
||||
use hir;
|
||||
use hir::Node;
|
||||
use hir::def_id::DefId;
|
||||
use hir::Node;
|
||||
use middle::region;
|
||||
use traits::{ObligationCause, ObligationCauseCode};
|
||||
use ty::{self, subst::Subst, Region, Ty, TyCtxt, TypeFoldable, TyKind};
|
||||
use ty::error::TypeError;
|
||||
use session::config::BorrowckMode;
|
||||
use std::{cmp, fmt};
|
||||
use syntax::ast::DUMMY_NODE_ID;
|
||||
use syntax_pos::{Pos, Span};
|
||||
use errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
|
||||
use traits::{ObligationCause, ObligationCauseCode};
|
||||
use ty::error::TypeError;
|
||||
use ty::{self, subst::Subst, Region, Ty, TyCtxt, TyKind, TypeFoldable};
|
||||
|
||||
mod note;
|
||||
|
||||
|
@ -153,8 +152,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
// We shouldn't encounter an error message with ReClosureBound.
|
||||
ty::ReCanonical(..) |
|
||||
ty::ReClosureBound(..) => {
|
||||
ty::ReCanonical(..) | ty::ReClosureBound(..) => {
|
||||
bug!("encountered unexpected ReClosureBound: {:?}", region,);
|
||||
}
|
||||
};
|
||||
|
@ -176,9 +174,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
|
||||
fn msg_span_from_free_region(self, region: ty::Region<'tcx>) -> (String, Option<Span>) {
|
||||
match *region {
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) => {
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) => {
|
||||
self.msg_span_from_early_bound_and_free_regions(region)
|
||||
},
|
||||
}
|
||||
ty::ReStatic => ("the static lifetime".to_owned(), None),
|
||||
_ => bug!("{:?}", region),
|
||||
}
|
||||
|
@ -197,25 +195,28 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
Some(Node::Item(it)) => Self::item_scope_tag(&it),
|
||||
Some(Node::TraitItem(it)) => Self::trait_item_scope_tag(&it),
|
||||
Some(Node::ImplItem(it)) => Self::impl_item_scope_tag(&it),
|
||||
_ => unreachable!()
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let (prefix, span) = match *region {
|
||||
ty::ReEarlyBound(ref br) => {
|
||||
let mut sp = cm.def_span(self.hir.span(node));
|
||||
if let Some(param) = self.hir.get_generics(scope).and_then(|generics| {
|
||||
generics.get_named(&br.name)
|
||||
}) {
|
||||
if let Some(param) = self.hir
|
||||
.get_generics(scope)
|
||||
.and_then(|generics| generics.get_named(&br.name))
|
||||
{
|
||||
sp = param.span;
|
||||
}
|
||||
(format!("the lifetime {} as defined on", br.name), sp)
|
||||
}
|
||||
ty::ReFree(ty::FreeRegion {
|
||||
bound_region: ty::BoundRegion::BrNamed(_, ref name), ..
|
||||
bound_region: ty::BoundRegion::BrNamed(_, ref name),
|
||||
..
|
||||
}) => {
|
||||
let mut sp = cm.def_span(self.hir.span(node));
|
||||
if let Some(param) = self.hir.get_generics(scope).and_then(|generics| {
|
||||
generics.get_named(&name)
|
||||
}) {
|
||||
if let Some(param) = self.hir
|
||||
.get_generics(scope)
|
||||
.and_then(|generics| generics.get_named(&name))
|
||||
{
|
||||
sp = param.span;
|
||||
}
|
||||
(format!("the lifetime {} as defined on", name), sp)
|
||||
|
@ -278,9 +279,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
fn impl_item_scope_tag(item: &hir::ImplItem) -> &'static str {
|
||||
match item.node {
|
||||
hir::ImplItemKind::Method(..) => "method body",
|
||||
hir::ImplItemKind::Const(..) |
|
||||
hir::ImplItemKind::Existential(..) |
|
||||
hir::ImplItemKind::Type(..) => "associated item",
|
||||
hir::ImplItemKind::Const(..)
|
||||
| hir::ImplItemKind::Existential(..)
|
||||
| hir::ImplItemKind::Type(..) => "associated item",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,20 +299,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
&self,
|
||||
region_scope_tree: ®ion::ScopeTree,
|
||||
errors: &Vec<RegionResolutionError<'tcx>>,
|
||||
will_later_be_reported_by_nll: bool,
|
||||
suppress: SuppressRegionErrors,
|
||||
) {
|
||||
debug!("report_region_errors(): {} errors to start", errors.len());
|
||||
debug!(
|
||||
"report_region_errors(): {} errors to start, suppress = {:?}",
|
||||
errors.len(),
|
||||
suppress
|
||||
);
|
||||
|
||||
// If the errors will later be reported by NLL, choose wether to display them or not based
|
||||
// on the borrowck mode
|
||||
if will_later_be_reported_by_nll {
|
||||
match self.tcx.borrowck_mode() {
|
||||
// If we're on AST or Migrate mode, report AST region errors
|
||||
BorrowckMode::Ast | BorrowckMode::Migrate => {},
|
||||
// If we're on MIR or Compare mode, don't report AST region errors as they should
|
||||
// be reported by NLL
|
||||
BorrowckMode::Compare | BorrowckMode::Mir => return,
|
||||
}
|
||||
if suppress.suppressed() {
|
||||
return;
|
||||
}
|
||||
|
||||
// try to pre-process the errors, which will group some of them
|
||||
|
@ -482,17 +479,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
} else {
|
||||
err.span_label(arm_span, msg);
|
||||
}
|
||||
},
|
||||
hir::MatchSource::TryDesugar => { // Issue #51632
|
||||
}
|
||||
hir::MatchSource::TryDesugar => {
|
||||
// Issue #51632
|
||||
if let Ok(try_snippet) = self.tcx.sess.source_map().span_to_snippet(arm_span) {
|
||||
err.span_suggestion_with_applicability(
|
||||
arm_span,
|
||||
"try wrapping with a success variant",
|
||||
format!("Ok({})", try_snippet),
|
||||
Applicability::MachineApplicable
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
let msg = "match arm with an incompatible type";
|
||||
if self.tcx.sess.source_map().is_multiline(arm_span) {
|
||||
|
@ -641,16 +639,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
fn strip_generic_default_params(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
substs: &ty::subst::Substs<'tcx>
|
||||
substs: &ty::subst::Substs<'tcx>,
|
||||
) -> &'tcx ty::subst::Substs<'tcx> {
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
let mut num_supplied_defaults = 0;
|
||||
let mut type_params = generics.params.iter().rev().filter_map(|param| match param.kind {
|
||||
ty::GenericParamDefKind::Lifetime => None,
|
||||
ty::GenericParamDefKind::Type { has_default, .. } => {
|
||||
Some((param.def_id, has_default))
|
||||
}
|
||||
}).peekable();
|
||||
let mut type_params = generics
|
||||
.params
|
||||
.iter()
|
||||
.rev()
|
||||
.filter_map(|param| match param.kind {
|
||||
ty::GenericParamDefKind::Lifetime => None,
|
||||
ty::GenericParamDefKind::Type { has_default, .. } => {
|
||||
Some((param.def_id, has_default))
|
||||
}
|
||||
})
|
||||
.peekable();
|
||||
let has_default = {
|
||||
let has_default = type_params.peek().map(|(_, has_default)| has_default);
|
||||
*has_default.unwrap_or(&false)
|
||||
|
@ -684,10 +687,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
| (&ty::Infer(ty::InferTy::IntVar(_)), &ty::Infer(ty::InferTy::IntVar(_)))
|
||||
| (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_)))
|
||||
| (&ty::Infer(ty::InferTy::FloatVar(_)), &ty::Float(_))
|
||||
| (
|
||||
&ty::Infer(ty::InferTy::FloatVar(_)),
|
||||
&ty::Infer(ty::InferTy::FloatVar(_)),
|
||||
) => true,
|
||||
| (&ty::Infer(ty::InferTy::FloatVar(_)), &ty::Infer(ty::InferTy::FloatVar(_))) => {
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -703,11 +705,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
"&{}{}{}",
|
||||
r,
|
||||
if r == "" { "" } else { " " },
|
||||
if mutbl == hir::MutMutable {
|
||||
"mut "
|
||||
} else {
|
||||
""
|
||||
}
|
||||
if mutbl == hir::MutMutable { "mut " } else { "" }
|
||||
));
|
||||
s.push_normal(ty.to_string());
|
||||
}
|
||||
|
@ -738,9 +736,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
let common_len = cmp::min(len1, len2);
|
||||
let remainder1: Vec<_> = sub1.types().skip(common_len).collect();
|
||||
let remainder2: Vec<_> = sub2.types().skip(common_len).collect();
|
||||
let common_default_params =
|
||||
remainder1.iter().rev().zip(remainder2.iter().rev())
|
||||
.filter(|(a, b)| a == b).count();
|
||||
let common_default_params = remainder1
|
||||
.iter()
|
||||
.rev()
|
||||
.zip(remainder2.iter().rev())
|
||||
.filter(|(a, b)| a == b)
|
||||
.count();
|
||||
let len = sub1.len() - common_default_params;
|
||||
|
||||
// Only draw `<...>` if there're lifetime/type arguments.
|
||||
|
@ -866,8 +867,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
// When encountering &T != &mut T, highlight only the borrow
|
||||
(&ty::Ref(r1, ref_ty1, mutbl1),
|
||||
&ty::Ref(r2, ref_ty2, mutbl2)) if equals(&ref_ty1, &ref_ty2) => {
|
||||
(&ty::Ref(r1, ref_ty1, mutbl1), &ty::Ref(r2, ref_ty2, mutbl2))
|
||||
if equals(&ref_ty1, &ref_ty2) =>
|
||||
{
|
||||
let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
|
||||
push_ty_ref(&r1, ref_ty1, mutbl1, &mut values.0);
|
||||
push_ty_ref(&r2, ref_ty2, mutbl2, &mut values.1);
|
||||
|
@ -1068,11 +1070,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
bound_kind: GenericKind<'tcx>,
|
||||
sub: Region<'tcx>,
|
||||
) {
|
||||
self.construct_generic_bound_failure(region_scope_tree,
|
||||
span,
|
||||
origin,
|
||||
bound_kind,
|
||||
sub)
|
||||
self.construct_generic_bound_failure(region_scope_tree, span, origin, bound_kind, sub)
|
||||
.emit()
|
||||
}
|
||||
|
||||
|
@ -1083,8 +1081,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
origin: Option<SubregionOrigin<'tcx>>,
|
||||
bound_kind: GenericKind<'tcx>,
|
||||
sub: Region<'tcx>,
|
||||
) -> DiagnosticBuilder<'a>
|
||||
{
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
// Attempt to obtain the span of the parameter so we can
|
||||
// suggest adding an explicit lifetime bound to it.
|
||||
let type_param_span = match (self.in_progress_tables, bound_kind) {
|
||||
|
@ -1161,8 +1158,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
let tail = if has_lifetimes { " + " } else { "" };
|
||||
let suggestion = format!("{}: {}{}", bound_kind, sub, tail);
|
||||
err.span_suggestion_short_with_applicability(
|
||||
sp, consider, suggestion,
|
||||
Applicability::MaybeIncorrect // Issue #41966
|
||||
sp,
|
||||
consider,
|
||||
suggestion,
|
||||
Applicability::MaybeIncorrect, // Issue #41966
|
||||
);
|
||||
} else {
|
||||
err.help(consider);
|
||||
|
@ -1358,12 +1357,10 @@ impl<'tcx> ObligationCause<'tcx> {
|
|||
match self.code {
|
||||
CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"),
|
||||
MatchExpressionArm { source, .. } => Error0308(match source {
|
||||
hir::MatchSource::IfLetDesugar { .. } => {
|
||||
"`if let` arms have incompatible types"
|
||||
},
|
||||
hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have incompatible types",
|
||||
hir::MatchSource::TryDesugar => {
|
||||
"try expression alternatives have incompatible types"
|
||||
},
|
||||
}
|
||||
_ => "match arms have incompatible types",
|
||||
}),
|
||||
IfExpression => Error0308("if and else have incompatible types"),
|
||||
|
|
|
@ -10,23 +10,26 @@
|
|||
|
||||
//! The code to do lexical region resolution.
|
||||
|
||||
use infer::SubregionOrigin;
|
||||
use infer::RegionVariableOrigin;
|
||||
use infer::region_constraints::Constraint;
|
||||
use infer::region_constraints::GenericKind;
|
||||
use infer::region_constraints::RegionConstraintData;
|
||||
use infer::region_constraints::VarInfos;
|
||||
use infer::region_constraints::VerifyBound;
|
||||
use infer::RegionVariableOrigin;
|
||||
use infer::SubregionOrigin;
|
||||
use middle::free_region::RegionRelations;
|
||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::graph::implementation::{Graph, Direction, NodeIndex, INCOMING, OUTGOING};
|
||||
use rustc_data_structures::graph::implementation::{
|
||||
Direction, Graph, NodeIndex, INCOMING, OUTGOING,
|
||||
};
|
||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||
use std::fmt;
|
||||
use std::u32;
|
||||
use ty::{self, TyCtxt};
|
||||
use ty::{Region, RegionVid};
|
||||
use ty::fold::TypeFoldable;
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
|
||||
use ty::{ReLateBound, ReScope, ReSkolemized, ReVar};
|
||||
use ty::{Region, RegionVid};
|
||||
|
||||
mod graphviz;
|
||||
|
||||
|
@ -108,11 +111,15 @@ struct LexicalResolver<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
|
|||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
|
||||
self.region_rels.tcx
|
||||
}
|
||||
|
||||
fn infer_variable_values(
|
||||
&mut self,
|
||||
errors: &mut Vec<RegionResolutionError<'tcx>>,
|
||||
) -> LexicalRegionResolutions<'tcx> {
|
||||
let mut var_data = self.construct_var_data(self.region_rels.tcx);
|
||||
let mut var_data = self.construct_var_data(self.tcx());
|
||||
|
||||
// Dorky hack to cause `dump_constraints` to only get called
|
||||
// if debug mode is enabled:
|
||||
|
@ -239,9 +246,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
|
||||
debug!(
|
||||
"Expanding value of {:?} from {:?} to {:?}",
|
||||
b_vid,
|
||||
cur_region,
|
||||
lub
|
||||
b_vid, cur_region, lub
|
||||
);
|
||||
|
||||
*b_data = VarValue::Value(lub);
|
||||
|
@ -254,18 +259,17 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
|
||||
let tcx = self.region_rels.tcx;
|
||||
let tcx = self.tcx();
|
||||
match (a, b) {
|
||||
(&ty::ReCanonical(..), _) |
|
||||
(_, &ty::ReCanonical(..)) |
|
||||
(&ty::ReClosureBound(..), _) |
|
||||
(_, &ty::ReClosureBound(..)) |
|
||||
(&ReLateBound(..), _) |
|
||||
(_, &ReLateBound(..)) |
|
||||
(&ReErased, _) |
|
||||
(_, &ReErased) => {
|
||||
(&ty::ReCanonical(..), _)
|
||||
| (_, &ty::ReCanonical(..))
|
||||
| (&ty::ReClosureBound(..), _)
|
||||
| (_, &ty::ReClosureBound(..))
|
||||
| (&ReLateBound(..), _)
|
||||
| (_, &ReLateBound(..))
|
||||
| (&ReErased, _)
|
||||
| (_, &ReErased) => {
|
||||
bug!("cannot relate region: LUB({:?}, {:?})", a, b);
|
||||
}
|
||||
|
||||
|
@ -287,20 +291,20 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
(&ReEarlyBound(_), &ReScope(s_id)) |
|
||||
(&ReScope(s_id), &ReEarlyBound(_)) |
|
||||
(&ReFree(_), &ReScope(s_id)) |
|
||||
(&ReScope(s_id), &ReFree(_)) => {
|
||||
(&ReEarlyBound(_), &ReScope(s_id))
|
||||
| (&ReScope(s_id), &ReEarlyBound(_))
|
||||
| (&ReFree(_), &ReScope(s_id))
|
||||
| (&ReScope(s_id), &ReFree(_)) => {
|
||||
// A "free" region can be interpreted as "some region
|
||||
// at least as big as fr.scope". So, we can
|
||||
// reasonably compare free regions and scopes:
|
||||
let fr_scope = match (a, b) {
|
||||
(&ReEarlyBound(ref br), _) | (_, &ReEarlyBound(ref br)) => self.region_rels
|
||||
.region_scope_tree
|
||||
.early_free_scope(self.region_rels.tcx, br),
|
||||
.early_free_scope(self.tcx(), br),
|
||||
(&ReFree(ref fr), _) | (_, &ReFree(ref fr)) => self.region_rels
|
||||
.region_scope_tree
|
||||
.free_scope(self.region_rels.tcx, fr),
|
||||
.free_scope(self.tcx(), fr),
|
||||
_ => bug!(),
|
||||
};
|
||||
let r_id = self.region_rels
|
||||
|
@ -332,10 +336,10 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
tcx.mk_region(ReScope(lub))
|
||||
}
|
||||
|
||||
(&ReEarlyBound(_), &ReEarlyBound(_)) |
|
||||
(&ReFree(_), &ReEarlyBound(_)) |
|
||||
(&ReEarlyBound(_), &ReFree(_)) |
|
||||
(&ReFree(_), &ReFree(_)) => self.region_rels.lub_free_regions(a, b),
|
||||
(&ReEarlyBound(_), &ReEarlyBound(_))
|
||||
| (&ReFree(_), &ReEarlyBound(_))
|
||||
| (&ReEarlyBound(_), &ReFree(_))
|
||||
| (&ReFree(_), &ReFree(_)) => self.region_rels.lub_free_regions(a, b),
|
||||
|
||||
// For these types, we cannot define any additional
|
||||
// relationship:
|
||||
|
@ -358,8 +362,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
for (constraint, origin) in &self.data.constraints {
|
||||
debug!(
|
||||
"collect_errors: constraint={:?} origin={:?}",
|
||||
constraint,
|
||||
origin
|
||||
constraint, origin
|
||||
);
|
||||
match *constraint {
|
||||
Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
|
||||
|
@ -374,9 +377,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
debug!(
|
||||
"collect_errors: region error at {:?}: \
|
||||
cannot verify that {:?} <= {:?}",
|
||||
origin,
|
||||
sub,
|
||||
sup
|
||||
origin, sub, sup
|
||||
);
|
||||
|
||||
errors.push(RegionResolutionError::ConcreteFailure(
|
||||
|
@ -402,10 +403,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
debug!(
|
||||
"collect_errors: region error at {:?}: \
|
||||
cannot verify that {:?}={:?} <= {:?}",
|
||||
origin,
|
||||
a_vid,
|
||||
a_region,
|
||||
b_region
|
||||
origin, a_vid, a_region, b_region
|
||||
);
|
||||
*a_data = VarValue::ErrorValue;
|
||||
}
|
||||
|
@ -415,7 +413,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
|
||||
for verify in &self.data.verifys {
|
||||
debug!("collect_errors: verify={:?}", verify);
|
||||
let sub = var_data.normalize(verify.region);
|
||||
let sub = var_data.normalize(self.tcx(), verify.region);
|
||||
|
||||
// This was an inference variable which didn't get
|
||||
// constrained, therefore it can be assume to hold.
|
||||
|
@ -423,16 +421,15 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
continue;
|
||||
}
|
||||
|
||||
if self.bound_is_met(&verify.bound, var_data, sub) {
|
||||
let verify_kind_ty = verify.kind.to_ty(self.tcx());
|
||||
if self.bound_is_met(&verify.bound, var_data, verify_kind_ty, sub) {
|
||||
continue;
|
||||
}
|
||||
|
||||
debug!(
|
||||
"collect_errors: region error at {:?}: \
|
||||
cannot verify that {:?} <= {:?}",
|
||||
verify.origin,
|
||||
verify.region,
|
||||
verify.bound
|
||||
verify.origin, verify.region, verify.bound
|
||||
);
|
||||
|
||||
errors.push(RegionResolutionError::GenericBoundFailure(
|
||||
|
@ -580,10 +577,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
debug!(
|
||||
"region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \
|
||||
sup: {:?}",
|
||||
origin,
|
||||
node_idx,
|
||||
lower_bound.region,
|
||||
upper_bound.region
|
||||
origin, node_idx, lower_bound.region, upper_bound.region
|
||||
);
|
||||
errors.push(RegionResolutionError::SubSupConflict(
|
||||
origin,
|
||||
|
@ -645,8 +639,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
|
||||
debug!(
|
||||
"collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})",
|
||||
orig_node_idx,
|
||||
node_idx
|
||||
orig_node_idx, node_idx
|
||||
);
|
||||
|
||||
process_edges(&self.data, &mut state, graph, node_idx, dir);
|
||||
|
@ -721,20 +714,26 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
&self,
|
||||
bound: &VerifyBound<'tcx>,
|
||||
var_values: &LexicalRegionResolutions<'tcx>,
|
||||
generic_ty: Ty<'tcx>,
|
||||
min: ty::Region<'tcx>,
|
||||
) -> bool {
|
||||
match bound {
|
||||
VerifyBound::AnyRegion(rs) => rs.iter()
|
||||
.map(|&r| var_values.normalize(r))
|
||||
.any(|r| self.region_rels.is_subregion_of(min, r)),
|
||||
VerifyBound::IfEq(k, b) => {
|
||||
(var_values.normalize(self.region_rels.tcx, *k) == generic_ty)
|
||||
&& self.bound_is_met(b, var_values, generic_ty, min)
|
||||
}
|
||||
|
||||
VerifyBound::AllRegions(rs) => rs.iter()
|
||||
.map(|&r| var_values.normalize(r))
|
||||
.all(|r| self.region_rels.is_subregion_of(min, r)),
|
||||
VerifyBound::OutlivedBy(r) =>
|
||||
self.region_rels.is_subregion_of(
|
||||
min,
|
||||
var_values.normalize(self.tcx(), r),
|
||||
),
|
||||
|
||||
VerifyBound::AnyBound(bs) => bs.iter().any(|b| self.bound_is_met(b, var_values, min)),
|
||||
VerifyBound::AnyBound(bs) => bs.iter()
|
||||
.any(|b| self.bound_is_met(b, var_values, generic_ty, min)),
|
||||
|
||||
VerifyBound::AllBounds(bs) => bs.iter().all(|b| self.bound_is_met(b, var_values, min)),
|
||||
VerifyBound::AllBounds(bs) => bs.iter()
|
||||
.all(|b| self.bound_is_met(b, var_values, generic_ty, min)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -745,13 +744,15 @@ impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'tcx> LexicalRegionResolutions<'tcx> {
|
||||
fn normalize(&self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
match *r {
|
||||
ty::ReVar(rid) => self.resolve_var(rid),
|
||||
fn normalize<T>(&self, tcx: TyCtxt<'_, '_, 'tcx>, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
tcx.fold_regions(&value, &mut false, |r, _db| match r {
|
||||
ty::ReVar(rid) => self.resolve_var(*rid),
|
||||
_ => r,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn value(&self, rid: RegionVid) -> &VarValue<'tcx> {
|
||||
|
|
|
@ -24,6 +24,7 @@ use middle::free_region::RegionRelations;
|
|||
use middle::lang_items;
|
||||
use middle::region;
|
||||
use rustc_data_structures::unify as ut;
|
||||
use session::config::BorrowckMode;
|
||||
use std::cell::{Cell, Ref, RefCell, RefMut};
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
|
@ -80,6 +81,38 @@ pub type Bound<T> = Option<T>;
|
|||
pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
|
||||
pub type FixupResult<T> = Result<T, FixupError>; // "fixup result"
|
||||
|
||||
/// A flag that is used to suppress region errors. This is normally
|
||||
/// false, but sometimes -- when we are doing region checks that the
|
||||
/// NLL borrow checker will also do -- it might be set to true.
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
pub struct SuppressRegionErrors {
|
||||
suppressed: bool
|
||||
}
|
||||
|
||||
impl SuppressRegionErrors {
|
||||
pub fn suppressed(self) -> bool {
|
||||
self.suppressed
|
||||
}
|
||||
|
||||
/// Indicates that the MIR borrowck will repeat these region
|
||||
/// checks, so we should ignore errors if NLL is (unconditionally)
|
||||
/// enabled.
|
||||
pub fn when_nll_is_enabled(tcx: TyCtxt<'_, '_, '_>) -> Self {
|
||||
match tcx.borrowck_mode() {
|
||||
// If we're on AST or Migrate mode, report AST region errors
|
||||
BorrowckMode::Ast | BorrowckMode::Migrate => SuppressRegionErrors {
|
||||
suppressed: false
|
||||
},
|
||||
|
||||
// If we're on MIR or Compare mode, don't report AST region errors as they should
|
||||
// be reported by NLL
|
||||
BorrowckMode::Compare | BorrowckMode::Mir => SuppressRegionErrors {
|
||||
suppressed: true
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InferCtxt<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
|
||||
|
@ -408,7 +441,7 @@ pub enum FixupError {
|
|||
pub struct RegionObligation<'tcx> {
|
||||
pub sub_region: ty::Region<'tcx>,
|
||||
pub sup_type: Ty<'tcx>,
|
||||
pub cause: ObligationCause<'tcx>,
|
||||
pub origin: SubregionOrigin<'tcx>,
|
||||
}
|
||||
|
||||
impl fmt::Display for FixupError {
|
||||
|
@ -1039,34 +1072,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
region_context: DefId,
|
||||
region_map: ®ion::ScopeTree,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
) {
|
||||
self.resolve_regions_and_report_errors_inner(
|
||||
region_context,
|
||||
region_map,
|
||||
outlives_env,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
/// Like `resolve_regions_and_report_errors`, but skips error
|
||||
/// reporting if NLL is enabled. This is used for fn bodies where
|
||||
/// the same error may later be reported by the NLL-based
|
||||
/// inference.
|
||||
pub fn resolve_regions_and_report_errors_unless_nll(
|
||||
&self,
|
||||
region_context: DefId,
|
||||
region_map: ®ion::ScopeTree,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
) {
|
||||
self.resolve_regions_and_report_errors_inner(region_context, region_map, outlives_env, true)
|
||||
}
|
||||
|
||||
fn resolve_regions_and_report_errors_inner(
|
||||
&self,
|
||||
region_context: DefId,
|
||||
region_map: ®ion::ScopeTree,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
will_later_be_reported_by_nll: bool,
|
||||
suppress: SuppressRegionErrors,
|
||||
) {
|
||||
assert!(
|
||||
self.is_tainted_by_errors() || self.region_obligations.borrow().is_empty(),
|
||||
|
@ -1098,7 +1104,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
// this infcx was in use. This is totally hokey but
|
||||
// otherwise we have a hard time separating legit region
|
||||
// errors from silly ones.
|
||||
self.report_region_errors(region_map, &errors, will_later_be_reported_by_nll);
|
||||
self.report_region_errors(region_map, &errors, suppress);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use infer::{GenericKind, InferCtxt};
|
||||
use infer::outlives::free_region_map::FreeRegionMap;
|
||||
use traits::query::outlives_bounds::{self, OutlivesBound};
|
||||
use ty::{self, Ty};
|
||||
|
||||
use infer::{GenericKind, InferCtxt};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
use traits::query::outlives_bounds::{self, OutlivesBound};
|
||||
use ty::{self, Ty};
|
||||
|
||||
/// The `OutlivesEnvironment` collects information about what outlives
|
||||
/// what in a given type-checking setting. For example, if we have a
|
||||
|
@ -39,15 +39,51 @@ use syntax_pos::Span;
|
|||
pub struct OutlivesEnvironment<'tcx> {
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
free_region_map: FreeRegionMap<'tcx>,
|
||||
region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>,
|
||||
|
||||
// Contains, for each body B that we are checking (that is, the fn
|
||||
// item, but also any nested closures), the set of implied region
|
||||
// bounds that are in scope in that particular body.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// ```
|
||||
// fn foo<'a, 'b, T>(x: &'a T, y: &'b ()) {
|
||||
// bar(x, y, |y: &'b T| { .. } // body B1)
|
||||
// } // body B0
|
||||
// ```
|
||||
//
|
||||
// Here, for body B0, the list would be `[T: 'a]`, because we
|
||||
// infer that `T` must outlive `'a` from the implied bounds on the
|
||||
// fn declaration.
|
||||
//
|
||||
// For the body B1, the list would be `[T: 'a, T: 'b]`, because we
|
||||
// also can see that -- within the closure body! -- `T` must
|
||||
// outlive `'b`. This is not necessarily true outside the closure
|
||||
// body, since the closure may never be called.
|
||||
//
|
||||
// We collect this map as we descend the tree. We then use the
|
||||
// results when proving outlives obligations like `T: 'x` later
|
||||
// (e.g., if `T: 'x` must be proven within the body B1, then we
|
||||
// know it is true if either `'a: 'x` or `'b: 'x`).
|
||||
region_bound_pairs_map: FxHashMap<ast::NodeId, RegionBoundPairs<'tcx>>,
|
||||
|
||||
// Used to compute `region_bound_pairs_map`: contains the set of
|
||||
// in-scope region-bound pairs thus far.
|
||||
region_bound_pairs_accum: RegionBoundPairs<'tcx>,
|
||||
}
|
||||
|
||||
/// "Region-bound pairs" tracks outlives relations that are known to
|
||||
/// be true, either because of explicit where clauses like `T: 'a` or
|
||||
/// because of implied bounds.
|
||||
pub type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>;
|
||||
|
||||
impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
|
||||
pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
|
||||
let mut env = OutlivesEnvironment {
|
||||
param_env,
|
||||
free_region_map: FreeRegionMap::new(),
|
||||
region_bound_pairs: vec![],
|
||||
region_bound_pairs_map: FxHashMap::default(),
|
||||
region_bound_pairs_accum: vec![],
|
||||
};
|
||||
|
||||
env.add_outlives_bounds(None, outlives_bounds::explicit_outlives_bounds(param_env));
|
||||
|
@ -61,8 +97,8 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
|
|||
}
|
||||
|
||||
/// Borrows current value of the `region_bound_pairs`.
|
||||
pub fn region_bound_pairs(&self) -> &[(ty::Region<'tcx>, GenericKind<'tcx>)] {
|
||||
&self.region_bound_pairs
|
||||
pub fn region_bound_pairs_map(&self) -> &FxHashMap<ast::NodeId, RegionBoundPairs<'tcx>> {
|
||||
&self.region_bound_pairs_map
|
||||
}
|
||||
|
||||
/// Returns ownership of the `free_region_map`.
|
||||
|
@ -108,12 +144,12 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
|
|||
/// similar leaks around givens that seem equally suspicious, to
|
||||
/// be honest. --nmatsakis
|
||||
pub fn push_snapshot_pre_closure(&self) -> usize {
|
||||
self.region_bound_pairs.len()
|
||||
self.region_bound_pairs_accum.len()
|
||||
}
|
||||
|
||||
/// See `push_snapshot_pre_closure`.
|
||||
pub fn pop_snapshot_post_closure(&mut self, len: usize) {
|
||||
self.region_bound_pairs.truncate(len);
|
||||
self.region_bound_pairs_accum.truncate(len);
|
||||
}
|
||||
|
||||
/// This method adds "implied bounds" into the outlives environment.
|
||||
|
@ -149,6 +185,15 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Save the current set of region-bound pairs under the given `body_id`.
|
||||
pub fn save_implied_bounds(&mut self, body_id: ast::NodeId) {
|
||||
let old = self.region_bound_pairs_map.insert(
|
||||
body_id,
|
||||
self.region_bound_pairs_accum.clone(),
|
||||
);
|
||||
assert!(old.is_none());
|
||||
}
|
||||
|
||||
/// Processes outlives bounds that are known to hold, whether from implied or other sources.
|
||||
///
|
||||
/// The `infcx` parameter is optional; if the implied bounds may
|
||||
|
@ -167,16 +212,18 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
|
|||
for outlives_bound in outlives_bounds {
|
||||
debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
|
||||
match outlives_bound {
|
||||
OutlivesBound::RegionSubRegion(r_a @ &ty::ReEarlyBound(_), &ty::ReVar(vid_b)) |
|
||||
OutlivesBound::RegionSubRegion(r_a @ &ty::ReFree(_), &ty::ReVar(vid_b)) => {
|
||||
infcx.expect("no infcx provided but region vars found").add_given(r_a, vid_b);
|
||||
OutlivesBound::RegionSubRegion(r_a @ &ty::ReEarlyBound(_), &ty::ReVar(vid_b))
|
||||
| OutlivesBound::RegionSubRegion(r_a @ &ty::ReFree(_), &ty::ReVar(vid_b)) => {
|
||||
infcx
|
||||
.expect("no infcx provided but region vars found")
|
||||
.add_given(r_a, vid_b);
|
||||
}
|
||||
OutlivesBound::RegionSubParam(r_a, param_b) => {
|
||||
self.region_bound_pairs
|
||||
self.region_bound_pairs_accum
|
||||
.push((r_a, GenericKind::Param(param_b)));
|
||||
}
|
||||
OutlivesBound::RegionSubProjection(r_a, projection_b) => {
|
||||
self.region_bound_pairs
|
||||
self.region_bound_pairs_accum
|
||||
.push((r_a, GenericKind::Projection(projection_b)));
|
||||
}
|
||||
OutlivesBound::RegionSubRegion(r_a, r_b) => {
|
||||
|
|
|
@ -13,3 +13,4 @@
|
|||
pub mod env;
|
||||
pub mod free_region_map;
|
||||
pub mod obligations;
|
||||
pub mod verify;
|
||||
|
|
|
@ -69,13 +69,14 @@
|
|||
//! might later infer `?U` to something like `&'b u32`, which would
|
||||
//! imply that `'b: 'a`.
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use infer::outlives::env::RegionBoundPairs;
|
||||
use infer::outlives::verify::VerifyBoundCx;
|
||||
use infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use syntax::ast;
|
||||
use traits;
|
||||
use traits::ObligationCause;
|
||||
use ty::outlives::Component;
|
||||
use ty::subst::{Subst, Substs};
|
||||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use ty::{self, Region, Ty, TyCtxt, TypeFoldable};
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
||||
/// Registers that the given region obligation must be resolved
|
||||
|
@ -98,6 +99,26 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
|||
.push((body_id, obligation));
|
||||
}
|
||||
|
||||
pub fn register_region_obligation_with_cause(
|
||||
&self,
|
||||
sup_type: Ty<'tcx>,
|
||||
sub_region: Region<'tcx>,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
) {
|
||||
let origin = SubregionOrigin::from_obligation_cause(cause, || {
|
||||
infer::RelateParamBound(cause.span, sup_type)
|
||||
});
|
||||
|
||||
self.register_region_obligation(
|
||||
cause.body_id,
|
||||
RegionObligation {
|
||||
sup_type,
|
||||
sub_region,
|
||||
origin,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Trait queries just want to pass back type obligations "as is"
|
||||
pub fn take_registered_region_obligations(&self) -> Vec<(ast::NodeId, RegionObligation<'tcx>)> {
|
||||
::std::mem::replace(&mut *self.region_obligations.borrow_mut(), vec![])
|
||||
|
@ -138,10 +159,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
|||
/// processed.
|
||||
pub fn process_registered_region_obligations(
|
||||
&self,
|
||||
region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
region_bound_pairs_map: &FxHashMap<ast::NodeId, RegionBoundPairs<'tcx>>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body_id: ast::NodeId,
|
||||
) {
|
||||
assert!(
|
||||
!self.in_snapshot.get(),
|
||||
|
@ -150,41 +170,39 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
|||
|
||||
debug!("process_registered_region_obligations()");
|
||||
|
||||
// pull out the region obligations with the given `body_id` (leaving the rest)
|
||||
let mut my_region_obligations = Vec::with_capacity(self.region_obligations.borrow().len());
|
||||
{
|
||||
let mut r_o = self.region_obligations.borrow_mut();
|
||||
my_region_obligations.extend(
|
||||
r_o.drain_filter(|(ro_body_id, _)| *ro_body_id == body_id)
|
||||
.map(|(_, obligation)| obligation)
|
||||
);
|
||||
}
|
||||
let my_region_obligations = self.take_registered_region_obligations();
|
||||
|
||||
let outlives = &mut TypeOutlives::new(
|
||||
self,
|
||||
self.tcx,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
);
|
||||
|
||||
for RegionObligation {
|
||||
sup_type,
|
||||
sub_region,
|
||||
cause,
|
||||
} in my_region_obligations
|
||||
for (
|
||||
body_id,
|
||||
RegionObligation {
|
||||
sup_type,
|
||||
sub_region,
|
||||
origin,
|
||||
},
|
||||
) in my_region_obligations
|
||||
{
|
||||
debug!(
|
||||
"process_registered_region_obligations: sup_type={:?} sub_region={:?} cause={:?}",
|
||||
sup_type, sub_region, cause
|
||||
"process_registered_region_obligations: sup_type={:?} sub_region={:?} origin={:?}",
|
||||
sup_type, sub_region, origin
|
||||
);
|
||||
|
||||
let origin = SubregionOrigin::from_obligation_cause(&cause, || {
|
||||
infer::RelateParamBound(cause.span, sup_type)
|
||||
});
|
||||
|
||||
let sup_type = self.resolve_type_vars_if_possible(&sup_type);
|
||||
outlives.type_must_outlive(origin, sup_type, sub_region);
|
||||
|
||||
if let Some(region_bound_pairs) = region_bound_pairs_map.get(&body_id) {
|
||||
let outlives = &mut TypeOutlives::new(
|
||||
self,
|
||||
self.tcx,
|
||||
®ion_bound_pairs,
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
);
|
||||
outlives.type_must_outlive(origin, sup_type, sub_region);
|
||||
} else {
|
||||
self.tcx.sess.delay_span_bug(
|
||||
origin.span(),
|
||||
&format!("no region-bound-pairs for {:?}", body_id),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,7 +210,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
|||
/// registered in advance.
|
||||
pub fn type_must_outlive(
|
||||
&self,
|
||||
region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
region_bound_pairs: &RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
origin: infer::SubregionOrigin<'tcx>,
|
||||
|
@ -225,9 +243,7 @@ where
|
|||
// of these fields.
|
||||
delegate: D,
|
||||
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
||||
region_bound_pairs: &'cx [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
verify_bound: VerifyBoundCx<'cx, 'gcx, 'tcx>,
|
||||
}
|
||||
|
||||
pub trait TypeOutlivesDelegate<'tcx> {
|
||||
|
@ -254,16 +270,19 @@ where
|
|||
pub fn new(
|
||||
delegate: D,
|
||||
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
||||
region_bound_pairs: &'cx [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
region_bound_pairs: &'cx RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Self {
|
||||
Self {
|
||||
delegate,
|
||||
tcx,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
verify_bound: VerifyBoundCx::new(
|
||||
tcx,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -302,7 +321,8 @@ where
|
|||
let origin = origin.clone();
|
||||
match component {
|
||||
Component::Region(region1) => {
|
||||
self.delegate.push_sub_region_constraint(origin, region, region1);
|
||||
self.delegate
|
||||
.push_sub_region_constraint(origin, region, region1);
|
||||
}
|
||||
Component::Param(param_ty) => {
|
||||
self.param_ty_must_outlive(origin, region, param_ty);
|
||||
|
@ -337,8 +357,8 @@ where
|
|||
region, param_ty, origin
|
||||
);
|
||||
|
||||
let verify_bound = self.param_bound(param_ty);
|
||||
let generic = GenericKind::Param(param_ty);
|
||||
let verify_bound = self.verify_bound.generic_bound(generic);
|
||||
self.delegate
|
||||
.push_verify(origin, generic, region, verify_bound);
|
||||
}
|
||||
|
@ -368,19 +388,22 @@ where
|
|||
// rule might not apply (but another rule might). For now, we err
|
||||
// on the side of adding too few edges into the graph.
|
||||
|
||||
// Compute the bounds we can derive from the environment or trait
|
||||
// definition. We know that the projection outlives all the
|
||||
// regions in this list.
|
||||
let env_bounds = self.projection_declared_bounds(projection_ty);
|
||||
// Compute the bounds we can derive from the environment. This
|
||||
// is an "approximate" match -- in some cases, these bounds
|
||||
// may not apply.
|
||||
let approx_env_bounds = self.verify_bound
|
||||
.projection_approx_declared_bounds_from_env(projection_ty);
|
||||
debug!(
|
||||
"projection_must_outlive: approx_env_bounds={:?}",
|
||||
approx_env_bounds
|
||||
);
|
||||
|
||||
debug!("projection_must_outlive: env_bounds={:?}", env_bounds);
|
||||
|
||||
// If we know that the projection outlives 'static, then we're
|
||||
// done here.
|
||||
if env_bounds.contains(&&ty::ReStatic) {
|
||||
debug!("projection_must_outlive: 'static as declared bound");
|
||||
return;
|
||||
}
|
||||
// Compute the bounds we can derive from the trait definition.
|
||||
// These are guaranteed to apply, no matter the inference
|
||||
// results.
|
||||
let trait_bounds: Vec<_> = self.verify_bound
|
||||
.projection_declared_bounds_from_trait(projection_ty)
|
||||
.collect();
|
||||
|
||||
// If declared bounds list is empty, the only applicable rule is
|
||||
// OutlivesProjectionComponent. If there are inference variables,
|
||||
|
@ -397,7 +420,7 @@ where
|
|||
// inference variables, we use a verify constraint instead of adding
|
||||
// edges, which winds up enforcing the same condition.
|
||||
let needs_infer = projection_ty.needs_infer();
|
||||
if env_bounds.is_empty() && needs_infer {
|
||||
if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer {
|
||||
debug!("projection_must_outlive: no declared bounds");
|
||||
|
||||
for component_ty in projection_ty.substs.types() {
|
||||
|
@ -405,36 +428,38 @@ where
|
|||
}
|
||||
|
||||
for r in projection_ty.substs.regions() {
|
||||
self.delegate.push_sub_region_constraint(origin.clone(), region, r);
|
||||
self.delegate
|
||||
.push_sub_region_constraint(origin.clone(), region, r);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If we find that there is a unique declared bound `'b`, and this bound
|
||||
// appears in the trait reference, then the best action is to require that `'b:'r`,
|
||||
// so do that. This is best no matter what rule we use:
|
||||
// If we found a unique bound `'b` from the trait, and we
|
||||
// found nothing else from the environment, then the best
|
||||
// action is to require that `'b: 'r`, so do that.
|
||||
//
|
||||
// - OutlivesProjectionEnv or OutlivesProjectionTraitDef: these would translate to
|
||||
// the requirement that `'b:'r`
|
||||
// - OutlivesProjectionComponent: this would require `'b:'r` in addition to
|
||||
// other conditions
|
||||
if !env_bounds.is_empty() && env_bounds[1..].iter().all(|b| *b == env_bounds[0]) {
|
||||
let unique_bound = env_bounds[0];
|
||||
// This is best no matter what rule we use:
|
||||
//
|
||||
// - OutlivesProjectionEnv: these would translate to the requirement that `'b:'r`
|
||||
// - OutlivesProjectionTraitDef: these would translate to the requirement that `'b:'r`
|
||||
// - OutlivesProjectionComponent: this would require `'b:'r`
|
||||
// in addition to other conditions
|
||||
if !trait_bounds.is_empty()
|
||||
&& trait_bounds[1..]
|
||||
.iter()
|
||||
.chain(approx_env_bounds.iter().map(|b| &b.1))
|
||||
.all(|b| *b == trait_bounds[0])
|
||||
{
|
||||
let unique_bound = trait_bounds[0];
|
||||
debug!(
|
||||
"projection_must_outlive: unique declared bound = {:?}",
|
||||
"projection_must_outlive: unique trait bound = {:?}",
|
||||
unique_bound
|
||||
);
|
||||
if projection_ty
|
||||
.substs
|
||||
.regions()
|
||||
.any(|r| env_bounds.contains(&r))
|
||||
{
|
||||
debug!("projection_must_outlive: unique declared bound appears in trait ref");
|
||||
self.delegate
|
||||
.push_sub_region_constraint(origin.clone(), region, unique_bound);
|
||||
return;
|
||||
}
|
||||
debug!("projection_must_outlive: unique declared bound appears in trait ref");
|
||||
self.delegate
|
||||
.push_sub_region_constraint(origin.clone(), region, unique_bound);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback to verifying after the fact that there exists a
|
||||
|
@ -442,216 +467,11 @@ where
|
|||
// projection outlive; in some cases, this may add insufficient
|
||||
// edges into the inference graph, leading to inference failures
|
||||
// even though a satisfactory solution exists.
|
||||
let verify_bound = self.projection_bound(env_bounds, projection_ty);
|
||||
let generic = GenericKind::Projection(projection_ty);
|
||||
let verify_bound = self.verify_bound.generic_bound(generic);
|
||||
self.delegate
|
||||
.push_verify(origin, generic.clone(), region, verify_bound);
|
||||
}
|
||||
|
||||
fn type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
|
||||
match ty.sty {
|
||||
ty::Param(p) => self.param_bound(p),
|
||||
ty::Projection(data) => {
|
||||
let declared_bounds = self.projection_declared_bounds(data);
|
||||
self.projection_bound(declared_bounds, data)
|
||||
}
|
||||
_ => self.recursive_type_bound(ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
|
||||
debug!("param_bound(param_ty={:?})", param_ty);
|
||||
|
||||
let mut param_bounds = self.declared_generic_bounds_from_env(GenericKind::Param(param_ty));
|
||||
|
||||
// Add in the default bound of fn body that applies to all in
|
||||
// scope type parameters:
|
||||
param_bounds.extend(self.implicit_region_bound);
|
||||
|
||||
VerifyBound::AnyRegion(param_bounds)
|
||||
}
|
||||
|
||||
fn projection_declared_bounds(
|
||||
&self,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
) -> Vec<ty::Region<'tcx>> {
|
||||
// First assemble bounds from where clauses and traits.
|
||||
|
||||
let mut declared_bounds =
|
||||
self.declared_generic_bounds_from_env(GenericKind::Projection(projection_ty));
|
||||
|
||||
declared_bounds
|
||||
.extend_from_slice(&self.declared_projection_bounds_from_trait(projection_ty));
|
||||
|
||||
declared_bounds
|
||||
}
|
||||
|
||||
fn projection_bound(
|
||||
&self,
|
||||
declared_bounds: Vec<ty::Region<'tcx>>,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
) -> VerifyBound<'tcx> {
|
||||
debug!(
|
||||
"projection_bound(declared_bounds={:?}, projection_ty={:?})",
|
||||
declared_bounds, projection_ty
|
||||
);
|
||||
|
||||
// see the extensive comment in projection_must_outlive
|
||||
let ty = self
|
||||
.tcx
|
||||
.mk_projection(projection_ty.item_def_id, projection_ty.substs);
|
||||
let recursive_bound = self.recursive_type_bound(ty);
|
||||
|
||||
VerifyBound::AnyRegion(declared_bounds).or(recursive_bound)
|
||||
}
|
||||
|
||||
fn recursive_type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
|
||||
let mut bounds = ty.walk_shallow().map(|subty| self.type_bound(subty)).collect::<Vec<_>>();
|
||||
|
||||
let mut regions = ty.regions();
|
||||
regions.retain(|r| !r.is_late_bound()); // ignore late-bound regions
|
||||
bounds.push(VerifyBound::AllRegions(regions));
|
||||
|
||||
// remove bounds that must hold, since they are not interesting
|
||||
bounds.retain(|b| !b.must_hold());
|
||||
|
||||
if bounds.len() == 1 {
|
||||
bounds.pop().unwrap()
|
||||
} else {
|
||||
VerifyBound::AllBounds(bounds)
|
||||
}
|
||||
}
|
||||
|
||||
fn declared_generic_bounds_from_env(
|
||||
&self,
|
||||
generic: GenericKind<'tcx>,
|
||||
) -> Vec<ty::Region<'tcx>> {
|
||||
let tcx = self.tcx;
|
||||
|
||||
// To start, collect bounds from user environment. Note that
|
||||
// parameter environments are already elaborated, so we don't
|
||||
// have to worry about that. Comparing using `==` is a bit
|
||||
// dubious for projections, but it will work for simple cases
|
||||
// like `T` and `T::Item`. It may not work as well for things
|
||||
// like `<T as Foo<'a>>::Item`.
|
||||
let generic_ty = generic.to_ty(tcx);
|
||||
let c_b = self.param_env.caller_bounds;
|
||||
let mut param_bounds = self.collect_outlives_from_predicate_list(generic_ty, c_b);
|
||||
|
||||
// Next, collect regions we scraped from the well-formedness
|
||||
// constraints in the fn signature. To do that, we walk the list
|
||||
// of known relations from the fn ctxt.
|
||||
//
|
||||
// This is crucial because otherwise code like this fails:
|
||||
//
|
||||
// fn foo<'a, A>(x: &'a A) { x.bar() }
|
||||
//
|
||||
// The problem is that the type of `x` is `&'a A`. To be
|
||||
// well-formed, then, A must be lower-generic by `'a`, but we
|
||||
// don't know that this holds from first principles.
|
||||
for &(r, p) in self.region_bound_pairs {
|
||||
debug!("generic={:?} p={:?}", generic, p);
|
||||
if generic == p {
|
||||
param_bounds.push(r);
|
||||
}
|
||||
}
|
||||
|
||||
param_bounds
|
||||
}
|
||||
|
||||
/// Given a projection like `<T as Foo<'x>>::Bar`, returns any bounds
|
||||
/// declared in the trait definition. For example, if the trait were
|
||||
///
|
||||
/// ```rust
|
||||
/// trait Foo<'a> {
|
||||
/// type Bar: 'a;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// then this function would return `'x`. This is subject to the
|
||||
/// limitations around higher-ranked bounds described in
|
||||
/// `region_bounds_declared_on_associated_item`.
|
||||
fn declared_projection_bounds_from_trait(
|
||||
&self,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
) -> Vec<ty::Region<'tcx>> {
|
||||
debug!("projection_bounds(projection_ty={:?})", projection_ty);
|
||||
let mut bounds = self.region_bounds_declared_on_associated_item(projection_ty.item_def_id);
|
||||
for r in &mut bounds {
|
||||
*r = r.subst(self.tcx, projection_ty.substs);
|
||||
}
|
||||
bounds
|
||||
}
|
||||
|
||||
/// Given the def-id of an associated item, returns any region
|
||||
/// bounds attached to that associated item from the trait definition.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
/// ```rust
|
||||
/// trait Foo<'a> {
|
||||
/// type Bar: 'a;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// If we were given the def-id of `Foo::Bar`, we would return
|
||||
/// `'a`. You could then apply the substitutions from the
|
||||
/// projection to convert this into your namespace. This also
|
||||
/// works if the user writes `where <Self as Foo<'a>>::Bar: 'a` on
|
||||
/// the trait. In fact, it works by searching for just such a
|
||||
/// where-clause.
|
||||
///
|
||||
/// It will not, however, work for higher-ranked bounds like:
|
||||
///
|
||||
/// ```rust
|
||||
/// trait Foo<'a, 'b>
|
||||
/// where for<'x> <Self as Foo<'x, 'b>>::Bar: 'x
|
||||
/// {
|
||||
/// type Bar;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This is for simplicity, and because we are not really smart
|
||||
/// enough to cope with such bounds anywhere.
|
||||
fn region_bounds_declared_on_associated_item(
|
||||
&self,
|
||||
assoc_item_def_id: DefId,
|
||||
) -> Vec<ty::Region<'tcx>> {
|
||||
let tcx = self.tcx;
|
||||
let assoc_item = tcx.associated_item(assoc_item_def_id);
|
||||
let trait_def_id = assoc_item.container.assert_trait();
|
||||
let trait_predicates = tcx.predicates_of(trait_def_id);
|
||||
let identity_substs = Substs::identity_for_item(tcx, assoc_item_def_id);
|
||||
let identity_proj = tcx.mk_projection(assoc_item_def_id, identity_substs);
|
||||
self.collect_outlives_from_predicate_list(
|
||||
identity_proj,
|
||||
traits::elaborate_predicates(tcx, trait_predicates.predicates),
|
||||
)
|
||||
}
|
||||
|
||||
/// Searches through a predicate list for a predicate `T: 'a`.
|
||||
///
|
||||
/// Careful: does not elaborate predicates, and just uses `==`
|
||||
/// when comparing `ty` for equality, so `ty` must be something
|
||||
/// that does not involve inference variables and where you
|
||||
/// otherwise want a precise match.
|
||||
fn collect_outlives_from_predicate_list<I, P>(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
predicates: I,
|
||||
) -> Vec<ty::Region<'tcx>>
|
||||
where
|
||||
I: IntoIterator<Item = P>,
|
||||
P: AsRef<ty::Predicate<'tcx>>,
|
||||
{
|
||||
predicates
|
||||
.into_iter()
|
||||
.filter_map(|p| p.as_ref().to_opt_type_outlives())
|
||||
.filter_map(|p| p.no_late_bound_regions())
|
||||
.filter(|p| p.0 == ty)
|
||||
.map(|p| p.1)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'gcx, 'tcx> {
|
||||
|
@ -674,4 +494,3 @@ impl<'cx, 'gcx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'gcx, '
|
|||
self.verify_generic_bound(origin, kind, a, bound)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
326
src/librustc/infer/outlives/verify.rs
Normal file
326
src/librustc/infer/outlives/verify.rs
Normal file
|
@ -0,0 +1,326 @@
|
|||
// Copyright 2012-2014 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.
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use infer::outlives::env::RegionBoundPairs;
|
||||
use infer::{GenericKind, VerifyBound};
|
||||
use traits;
|
||||
use ty::subst::{Subst, Substs};
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use util::captures::Captures;
|
||||
|
||||
/// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
|
||||
/// obligation into a series of `'a: 'b` constraints and "verifys", as
|
||||
/// described on the module comment. The final constraints are emitted
|
||||
/// via a "delegate" of type `D` -- this is usually the `infcx`, which
|
||||
/// accrues them into the `region_obligations` code, but for NLL we
|
||||
/// use something else.
|
||||
pub struct VerifyBoundCx<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
|
||||
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
||||
region_bound_pairs: &'cx RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
|
||||
pub fn new(
|
||||
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
||||
region_bound_pairs: &'cx RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Self {
|
||||
Self {
|
||||
tcx,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a "verify bound" that encodes what we know about
|
||||
/// `generic` and the regions it outlives.
|
||||
pub fn generic_bound(&self, generic: GenericKind<'tcx>) -> VerifyBound<'tcx> {
|
||||
match generic {
|
||||
GenericKind::Param(param_ty) => self.param_bound(param_ty),
|
||||
GenericKind::Projection(projection_ty) => self.projection_bound(projection_ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
|
||||
match ty.sty {
|
||||
ty::Param(p) => self.param_bound(p),
|
||||
ty::Projection(data) => self.projection_bound(data),
|
||||
_ => self.recursive_type_bound(ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
|
||||
debug!("param_bound(param_ty={:?})", param_ty);
|
||||
|
||||
// Start with anything like `T: 'a` we can scrape from the
|
||||
// environment
|
||||
let param_bounds = self.declared_generic_bounds_from_env(GenericKind::Param(param_ty))
|
||||
.into_iter()
|
||||
.map(|outlives| outlives.1);
|
||||
|
||||
// Add in the default bound of fn body that applies to all in
|
||||
// scope type parameters:
|
||||
let param_bounds = param_bounds.chain(self.implicit_region_bound);
|
||||
|
||||
VerifyBound::AnyBound(param_bounds.map(|r| VerifyBound::OutlivedBy(r)).collect())
|
||||
}
|
||||
|
||||
/// Given a projection like `T::Item`, searches the environment
|
||||
/// for where-clauses like `T::Item: 'a`. Returns the set of
|
||||
/// regions `'a` that it finds.
|
||||
///
|
||||
/// This is an "approximate" check -- it may not find all
|
||||
/// applicable bounds, and not all the bounds it returns can be
|
||||
/// relied upon. In particular, this check ignores region
|
||||
/// identity. So, for example, if we have `<T as
|
||||
/// Trait<'0>>::Item` where `'0` is a region variable, and the
|
||||
/// user has `<T as Trait<'a>>::Item: 'b` in the environment, then
|
||||
/// the clause from the environment only applies if `'0 = 'a`,
|
||||
/// which we don't know yet. But we would still include `'b` in
|
||||
/// this list.
|
||||
pub fn projection_approx_declared_bounds_from_env(
|
||||
&self,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
|
||||
let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx);
|
||||
let erased_projection_ty = self.tcx.erase_regions(&projection_ty);
|
||||
self.declared_generic_bounds_from_env_with_compare_fn(|ty| {
|
||||
if let ty::Projection(..) = ty.sty {
|
||||
let erased_ty = self.tcx.erase_regions(&ty);
|
||||
erased_ty == erased_projection_ty
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Searches the where clauses in scope for regions that
|
||||
/// `projection_ty` is known to outlive. Currently requires an
|
||||
/// exact match.
|
||||
pub fn projection_declared_bounds_from_trait(
|
||||
&self,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'gcx> {
|
||||
self.declared_projection_bounds_from_trait(projection_ty)
|
||||
}
|
||||
|
||||
pub fn projection_bound(&self, projection_ty: ty::ProjectionTy<'tcx>) -> VerifyBound<'tcx> {
|
||||
debug!("projection_bound(projection_ty={:?})", projection_ty);
|
||||
|
||||
let projection_ty_as_ty =
|
||||
self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
|
||||
|
||||
// Search the env for where clauses like `P: 'a`.
|
||||
let env_bounds = self.projection_approx_declared_bounds_from_env(projection_ty)
|
||||
.into_iter()
|
||||
.map(|ty::OutlivesPredicate(ty, r)| {
|
||||
let vb = VerifyBound::OutlivedBy(r);
|
||||
if ty == projection_ty_as_ty {
|
||||
// Micro-optimize if this is an exact match (this
|
||||
// occurs often when there are no region variables
|
||||
// involved).
|
||||
vb
|
||||
} else {
|
||||
VerifyBound::IfEq(ty, Box::new(vb))
|
||||
}
|
||||
});
|
||||
|
||||
// Extend with bounds that we can find from the trait.
|
||||
let trait_bounds = self.projection_declared_bounds_from_trait(projection_ty)
|
||||
.into_iter()
|
||||
.map(|r| VerifyBound::OutlivedBy(r));
|
||||
|
||||
// see the extensive comment in projection_must_outlive
|
||||
let ty = self.tcx
|
||||
.mk_projection(projection_ty.item_def_id, projection_ty.substs);
|
||||
let recursive_bound = self.recursive_type_bound(ty);
|
||||
|
||||
VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound)
|
||||
}
|
||||
|
||||
fn recursive_type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
|
||||
let mut bounds = ty.walk_shallow()
|
||||
.map(|subty| self.type_bound(subty))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut regions = ty.regions();
|
||||
regions.retain(|r| !r.is_late_bound()); // ignore late-bound regions
|
||||
bounds.push(VerifyBound::AllBounds(
|
||||
regions
|
||||
.into_iter()
|
||||
.map(|r| VerifyBound::OutlivedBy(r))
|
||||
.collect(),
|
||||
));
|
||||
|
||||
// remove bounds that must hold, since they are not interesting
|
||||
bounds.retain(|b| !b.must_hold());
|
||||
|
||||
if bounds.len() == 1 {
|
||||
bounds.pop().unwrap()
|
||||
} else {
|
||||
VerifyBound::AllBounds(bounds)
|
||||
}
|
||||
}
|
||||
|
||||
/// Searches the environment for where-clauses like `G: 'a` where
|
||||
/// `G` is either some type parameter `T` or a projection like
|
||||
/// `T::Item`. Returns a vector of the `'a` bounds it can find.
|
||||
///
|
||||
/// This is a conservative check -- it may not find all applicable
|
||||
/// bounds, but all the bounds it returns can be relied upon.
|
||||
fn declared_generic_bounds_from_env(
|
||||
&self,
|
||||
generic: GenericKind<'tcx>,
|
||||
) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
|
||||
let generic_ty = generic.to_ty(self.tcx);
|
||||
self.declared_generic_bounds_from_env_with_compare_fn(|ty| ty == generic_ty)
|
||||
}
|
||||
|
||||
fn declared_generic_bounds_from_env_with_compare_fn(
|
||||
&self,
|
||||
compare_ty: impl Fn(Ty<'tcx>) -> bool,
|
||||
) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
|
||||
let tcx = self.tcx;
|
||||
|
||||
// To start, collect bounds from user environment. Note that
|
||||
// parameter environments are already elaborated, so we don't
|
||||
// have to worry about that. Comparing using `==` is a bit
|
||||
// dubious for projections, but it will work for simple cases
|
||||
// like `T` and `T::Item`. It may not work as well for things
|
||||
// like `<T as Foo<'a>>::Item`.
|
||||
let c_b = self.param_env.caller_bounds;
|
||||
let param_bounds = self.collect_outlives_from_predicate_list(&compare_ty, c_b);
|
||||
|
||||
// Next, collect regions we scraped from the well-formedness
|
||||
// constraints in the fn signature. To do that, we walk the list
|
||||
// of known relations from the fn ctxt.
|
||||
//
|
||||
// This is crucial because otherwise code like this fails:
|
||||
//
|
||||
// fn foo<'a, A>(x: &'a A) { x.bar() }
|
||||
//
|
||||
// The problem is that the type of `x` is `&'a A`. To be
|
||||
// well-formed, then, A must be lower-generic by `'a`, but we
|
||||
// don't know that this holds from first principles.
|
||||
let from_region_bound_pairs = self.region_bound_pairs.iter().filter_map(|&(r, p)| {
|
||||
debug!(
|
||||
"declared_generic_bounds_from_env_with_compare_fn: region_bound_pair = {:?}",
|
||||
(r, p)
|
||||
);
|
||||
let p_ty = p.to_ty(tcx);
|
||||
if compare_ty(p_ty) {
|
||||
Some(ty::OutlivesPredicate(p_ty, r))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
param_bounds
|
||||
.chain(from_region_bound_pairs)
|
||||
.inspect(|bound| {
|
||||
debug!(
|
||||
"declared_generic_bounds_from_env_with_compare_fn: result predicate = {:?}",
|
||||
bound
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Given a projection like `<T as Foo<'x>>::Bar`, returns any bounds
|
||||
/// declared in the trait definition. For example, if the trait were
|
||||
///
|
||||
/// ```rust
|
||||
/// trait Foo<'a> {
|
||||
/// type Bar: 'a;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// then this function would return `'x`. This is subject to the
|
||||
/// limitations around higher-ranked bounds described in
|
||||
/// `region_bounds_declared_on_associated_item`.
|
||||
fn declared_projection_bounds_from_trait(
|
||||
&self,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'gcx> {
|
||||
debug!("projection_bounds(projection_ty={:?})", projection_ty);
|
||||
let tcx = self.tcx;
|
||||
self.region_bounds_declared_on_associated_item(projection_ty.item_def_id)
|
||||
.map(move |r| r.subst(tcx, projection_ty.substs))
|
||||
}
|
||||
|
||||
/// Given the def-id of an associated item, returns any region
|
||||
/// bounds attached to that associated item from the trait definition.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
/// ```rust
|
||||
/// trait Foo<'a> {
|
||||
/// type Bar: 'a;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// If we were given the def-id of `Foo::Bar`, we would return
|
||||
/// `'a`. You could then apply the substitutions from the
|
||||
/// projection to convert this into your namespace. This also
|
||||
/// works if the user writes `where <Self as Foo<'a>>::Bar: 'a` on
|
||||
/// the trait. In fact, it works by searching for just such a
|
||||
/// where-clause.
|
||||
///
|
||||
/// It will not, however, work for higher-ranked bounds like:
|
||||
///
|
||||
/// ```rust
|
||||
/// trait Foo<'a, 'b>
|
||||
/// where for<'x> <Self as Foo<'x, 'b>>::Bar: 'x
|
||||
/// {
|
||||
/// type Bar;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This is for simplicity, and because we are not really smart
|
||||
/// enough to cope with such bounds anywhere.
|
||||
fn region_bounds_declared_on_associated_item(
|
||||
&self,
|
||||
assoc_item_def_id: DefId,
|
||||
) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'gcx> {
|
||||
let tcx = self.tcx;
|
||||
let assoc_item = tcx.associated_item(assoc_item_def_id);
|
||||
let trait_def_id = assoc_item.container.assert_trait();
|
||||
let trait_predicates = tcx.predicates_of(trait_def_id);
|
||||
let identity_substs = Substs::identity_for_item(tcx, assoc_item_def_id);
|
||||
let identity_proj = tcx.mk_projection(assoc_item_def_id, identity_substs);
|
||||
self.collect_outlives_from_predicate_list(
|
||||
move |ty| ty == identity_proj,
|
||||
traits::elaborate_predicates(tcx, trait_predicates.predicates),
|
||||
).map(|b| b.1)
|
||||
}
|
||||
|
||||
/// Searches through a predicate list for a predicate `T: 'a`.
|
||||
///
|
||||
/// Careful: does not elaborate predicates, and just uses `==`
|
||||
/// when comparing `ty` for equality, so `ty` must be something
|
||||
/// that does not involve inference variables and where you
|
||||
/// otherwise want a precise match.
|
||||
fn collect_outlives_from_predicate_list(
|
||||
&self,
|
||||
compare_ty: impl Fn(Ty<'tcx>) -> bool,
|
||||
predicates: impl IntoIterator<Item = impl AsRef<ty::Predicate<'tcx>>>,
|
||||
) -> impl Iterator<Item = ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
|
||||
predicates
|
||||
.into_iter()
|
||||
.filter_map(|p| p.as_ref().to_opt_type_outlives())
|
||||
.filter_map(|p| p.no_late_bound_regions())
|
||||
.filter(move |p| compare_ty(p.0))
|
||||
}
|
||||
}
|
|
@ -155,29 +155,94 @@ pub enum GenericKind<'tcx> {
|
|||
Projection(ty::ProjectionTy<'tcx>),
|
||||
}
|
||||
|
||||
/// When we introduce a verification step, we wish to test that a
|
||||
/// particular region (let's call it `'min`) meets some bound.
|
||||
/// The bound is described the by the following grammar:
|
||||
EnumTypeFoldableImpl! {
|
||||
impl<'tcx> TypeFoldable<'tcx> for GenericKind<'tcx> {
|
||||
(GenericKind::Param)(a),
|
||||
(GenericKind::Projection)(a),
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes the things that some `GenericKind` value G is known to
|
||||
/// outlive. Each variant of `VerifyBound` can be thought of as a
|
||||
/// function:
|
||||
///
|
||||
/// fn(min: Region) -> bool { .. }
|
||||
///
|
||||
/// where `true` means that the region `min` meets that `G: min`.
|
||||
/// (False means nothing.)
|
||||
///
|
||||
/// So, for example, if we have the type `T` and we have in scope that
|
||||
/// `T: 'a` and `T: 'b`, then the verify bound might be:
|
||||
///
|
||||
/// fn(min: Region) -> bool {
|
||||
/// ('a: min) || ('b: min)
|
||||
/// }
|
||||
///
|
||||
/// This is described with a `AnyRegion('a, 'b)` node.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum VerifyBound<'tcx> {
|
||||
/// B = exists {R} --> some 'r in {R} must outlive 'min
|
||||
/// Given a kind K and a bound B, expands to a function like the
|
||||
/// following, where `G` is the generic for which this verify
|
||||
/// bound was created:
|
||||
///
|
||||
/// Put another way, the subject value is known to outlive all
|
||||
/// regions in {R}, so if any of those outlives 'min, then the
|
||||
/// bound is met.
|
||||
AnyRegion(Vec<Region<'tcx>>),
|
||||
|
||||
/// B = forall {R} --> all 'r in {R} must outlive 'min
|
||||
/// fn(min) -> bool {
|
||||
/// if G == K {
|
||||
/// B(min)
|
||||
/// } else {
|
||||
/// false
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// Put another way, the subject value is known to outlive some
|
||||
/// region in {R}, so if all of those outlives 'min, then the bound
|
||||
/// is met.
|
||||
AllRegions(Vec<Region<'tcx>>),
|
||||
/// In other words, if the generic `G` that we are checking is
|
||||
/// equal to `K`, then check the associated verify bound
|
||||
/// (otherwise, false).
|
||||
///
|
||||
/// This is used when we have something in the environment that
|
||||
/// may or may not be relevant, depending on the region inference
|
||||
/// results. For example, we may have `where <T as
|
||||
/// Trait<'a>>::Item: 'b` in our where clauses. If we are
|
||||
/// generating the verify-bound for `<T as Trait<'0>>::Item`, then
|
||||
/// this where-clause is only relevant if `'0` winds up inferred
|
||||
/// to `'a`.
|
||||
///
|
||||
/// So we would compile to a verify-bound like
|
||||
///
|
||||
/// IfEq(<T as Trait<'a>>::Item, AnyRegion('a))
|
||||
///
|
||||
/// meaning, if the subject G is equal to `<T as Trait<'a>>::Item`
|
||||
/// (after inference), and `'a: min`, then `G: min`.
|
||||
IfEq(Ty<'tcx>, Box<VerifyBound<'tcx>>),
|
||||
|
||||
/// B = exists {B} --> 'min must meet some bound b in {B}
|
||||
/// Given a region `R`, expands to the function:
|
||||
///
|
||||
/// fn(min) -> bool {
|
||||
/// R: min
|
||||
/// }
|
||||
///
|
||||
/// This is used when we can establish that `G: R` -- therefore,
|
||||
/// if `R: min`, then by transitivity `G: min`.
|
||||
OutlivedBy(Region<'tcx>),
|
||||
|
||||
/// Given a set of bounds `B`, expands to the function:
|
||||
///
|
||||
/// fn(min) -> bool {
|
||||
/// exists (b in B) { b(min) }
|
||||
/// }
|
||||
///
|
||||
/// In other words, if we meet some bound in `B`, that suffices.
|
||||
/// This is used when all the bounds in `B` are known to apply to
|
||||
/// G.
|
||||
AnyBound(Vec<VerifyBound<'tcx>>),
|
||||
|
||||
/// B = forall {B} --> 'min must meet all bounds b in {B}
|
||||
/// Given a set of bounds `B`, expands to the function:
|
||||
///
|
||||
/// fn(min) -> bool {
|
||||
/// forall (b in B) { b(min) }
|
||||
/// }
|
||||
///
|
||||
/// In other words, if we meet *all* bounds in `B`, that suffices.
|
||||
/// This is used when *some* bound in `B` is known to suffice, but
|
||||
/// we don't know which.
|
||||
AllBounds(Vec<VerifyBound<'tcx>>),
|
||||
}
|
||||
|
||||
|
@ -882,33 +947,23 @@ impl<'a, 'gcx, 'tcx> GenericKind<'tcx> {
|
|||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> VerifyBound<'tcx> {
|
||||
fn for_each_region(&self, f: &mut dyn FnMut(ty::Region<'tcx>)) {
|
||||
match self {
|
||||
&VerifyBound::AnyRegion(ref rs) | &VerifyBound::AllRegions(ref rs) => for &r in rs {
|
||||
f(r);
|
||||
},
|
||||
|
||||
&VerifyBound::AnyBound(ref bs) | &VerifyBound::AllBounds(ref bs) => for b in bs {
|
||||
b.for_each_region(f);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn must_hold(&self) -> bool {
|
||||
match self {
|
||||
&VerifyBound::AnyRegion(ref bs) => bs.contains(&&ty::ReStatic),
|
||||
&VerifyBound::AllRegions(ref bs) => bs.is_empty(),
|
||||
&VerifyBound::AnyBound(ref bs) => bs.iter().any(|b| b.must_hold()),
|
||||
&VerifyBound::AllBounds(ref bs) => bs.iter().all(|b| b.must_hold()),
|
||||
VerifyBound::IfEq(..) => false,
|
||||
VerifyBound::OutlivedBy(ty::ReStatic) => true,
|
||||
VerifyBound::OutlivedBy(_) => false,
|
||||
VerifyBound::AnyBound(bs) => bs.iter().any(|b| b.must_hold()),
|
||||
VerifyBound::AllBounds(bs) => bs.iter().all(|b| b.must_hold()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cannot_hold(&self) -> bool {
|
||||
match self {
|
||||
&VerifyBound::AnyRegion(ref bs) => bs.is_empty(),
|
||||
&VerifyBound::AllRegions(ref bs) => bs.contains(&&ty::ReEmpty),
|
||||
&VerifyBound::AnyBound(ref bs) => bs.iter().all(|b| b.cannot_hold()),
|
||||
&VerifyBound::AllBounds(ref bs) => bs.iter().any(|b| b.cannot_hold()),
|
||||
VerifyBound::IfEq(_, b) => b.cannot_hold(),
|
||||
VerifyBound::OutlivedBy(ty::ReEmpty) => true,
|
||||
VerifyBound::OutlivedBy(_) => false,
|
||||
VerifyBound::AnyBound(bs) => bs.iter().all(|b| b.cannot_hold()),
|
||||
VerifyBound::AllBounds(bs) => bs.iter().any(|b| b.cannot_hold()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,34 +13,39 @@ use super::*;
|
|||
#[derive(Debug)]
|
||||
pub(super) struct TaintSet<'tcx> {
|
||||
directions: TaintDirections,
|
||||
regions: FxHashSet<ty::Region<'tcx>>
|
||||
regions: FxHashSet<ty::Region<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> TaintSet<'tcx> {
|
||||
pub(super) fn new(directions: TaintDirections,
|
||||
initial_region: ty::Region<'tcx>)
|
||||
-> Self {
|
||||
pub(super) fn new(directions: TaintDirections, initial_region: ty::Region<'tcx>) -> Self {
|
||||
let mut regions = FxHashSet();
|
||||
regions.insert(initial_region);
|
||||
TaintSet { directions: directions, regions: regions }
|
||||
TaintSet {
|
||||
directions: directions,
|
||||
regions: regions,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn fixed_point(&mut self,
|
||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||
undo_log: &[UndoLogEntry<'tcx>],
|
||||
verifys: &[Verify<'tcx>]) {
|
||||
pub(super) fn fixed_point(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||
undo_log: &[UndoLogEntry<'tcx>],
|
||||
verifys: &[Verify<'tcx>],
|
||||
) {
|
||||
let mut prev_len = 0;
|
||||
while prev_len < self.len() {
|
||||
debug!("tainted: prev_len = {:?} new_len = {:?}",
|
||||
prev_len, self.len());
|
||||
debug!(
|
||||
"tainted: prev_len = {:?} new_len = {:?}",
|
||||
prev_len,
|
||||
self.len()
|
||||
);
|
||||
|
||||
prev_len = self.len();
|
||||
|
||||
for undo_entry in undo_log {
|
||||
match undo_entry {
|
||||
&AddConstraint(Constraint::VarSubVar(a, b)) => {
|
||||
self.add_edge(tcx.mk_region(ReVar(a)),
|
||||
tcx.mk_region(ReVar(b)));
|
||||
self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
|
||||
}
|
||||
&AddConstraint(Constraint::RegSubVar(a, b)) => {
|
||||
self.add_edge(a, tcx.mk_region(ReVar(b)));
|
||||
|
@ -55,15 +60,13 @@ impl<'tcx> TaintSet<'tcx> {
|
|||
self.add_edge(a, tcx.mk_region(ReVar(b)));
|
||||
}
|
||||
&AddVerify(i) => {
|
||||
verifys[i].bound.for_each_region(&mut |b| {
|
||||
self.add_edge(verifys[i].region, b);
|
||||
});
|
||||
span_bug!(
|
||||
verifys[i].origin.span(),
|
||||
"we never add verifications while doing higher-ranked things",
|
||||
)
|
||||
}
|
||||
&Purged |
|
||||
&AddCombination(..) |
|
||||
&AddVar(..) |
|
||||
&OpenSnapshot |
|
||||
&CommitedSnapshot => {}
|
||||
&Purged | &AddCombination(..) | &AddVar(..) | &OpenSnapshot
|
||||
| &CommitedSnapshot => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,9 +80,7 @@ impl<'tcx> TaintSet<'tcx> {
|
|||
self.regions.len()
|
||||
}
|
||||
|
||||
fn add_edge(&mut self,
|
||||
source: ty::Region<'tcx>,
|
||||
target: ty::Region<'tcx>) {
|
||||
fn add_edge(&mut self, source: ty::Region<'tcx>, target: ty::Region<'tcx>) {
|
||||
if self.directions.incoming {
|
||||
if self.regions.contains(&target) {
|
||||
self.regions.insert(source);
|
||||
|
@ -93,4 +94,3 @@ impl<'tcx> TaintSet<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,10 +16,9 @@ use super::*;
|
|||
use std::collections::hash_map::Entry;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
|
||||
use infer::region_constraints::{Constraint, RegionConstraintData};
|
||||
use infer::{InferCtxt, RegionObligation};
|
||||
use infer::InferCtxt;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
|
||||
use ty::fold::TypeFolder;
|
||||
use ty::{Region, RegionVid};
|
||||
|
@ -227,20 +226,18 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
.iter()
|
||||
.filter_map(|param| match param.kind {
|
||||
ty::GenericParamDefKind::Lifetime => Some(param.name.to_string()),
|
||||
_ => None
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
let body_ids: FxHashSet<_> = infcx
|
||||
let body_id_map: FxHashMap<_, _> = infcx
|
||||
.region_obligations
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|&(id, _)| id)
|
||||
.map(|&(id, _)| (id, vec![]))
|
||||
.collect();
|
||||
|
||||
for id in body_ids {
|
||||
infcx.process_registered_region_obligations(&[], None, full_env.clone(), id);
|
||||
}
|
||||
infcx.process_registered_region_obligations(&body_id_map, None, full_env.clone());
|
||||
|
||||
let region_data = infcx
|
||||
.borrow_region_constraints()
|
||||
|
@ -359,8 +356,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
&Err(SelectionError::Unimplemented) => {
|
||||
if self.is_of_param(pred.skip_binder().trait_ref.substs) {
|
||||
already_visited.remove(&pred);
|
||||
self.add_user_pred(&mut user_computed_preds,
|
||||
ty::Predicate::Trait(pred.clone()));
|
||||
self.add_user_pred(
|
||||
&mut user_computed_preds,
|
||||
ty::Predicate::Trait(pred.clone()),
|
||||
);
|
||||
predicates.push_back(pred);
|
||||
} else {
|
||||
debug!(
|
||||
|
@ -418,8 +417,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
// under which a type implements an auto trait. A trait predicate involving
|
||||
// a HRTB means that the type needs to work with any choice of lifetime,
|
||||
// not just one specific lifetime (e.g. 'static).
|
||||
fn add_user_pred<'c>(&self, user_computed_preds: &mut FxHashSet<ty::Predicate<'c>>,
|
||||
new_pred: ty::Predicate<'c>) {
|
||||
fn add_user_pred<'c>(
|
||||
&self,
|
||||
user_computed_preds: &mut FxHashSet<ty::Predicate<'c>>,
|
||||
new_pred: ty::Predicate<'c>,
|
||||
) {
|
||||
let mut should_add_new = true;
|
||||
user_computed_preds.retain(|&old_pred| {
|
||||
match (&new_pred, old_pred) {
|
||||
|
@ -431,20 +433,19 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
if !new_substs.types().eq(old_substs.types()) {
|
||||
// We can't compare lifetimes if the types are different,
|
||||
// so skip checking old_pred
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
|
||||
for (new_region, old_region) in new_substs
|
||||
.regions()
|
||||
.zip(old_substs.regions()) {
|
||||
|
||||
for (new_region, old_region) in
|
||||
new_substs.regions().zip(old_substs.regions())
|
||||
{
|
||||
match (new_region, old_region) {
|
||||
// If both predicates have an 'ReLateBound' (a HRTB) in the
|
||||
// same spot, we do nothing
|
||||
(
|
||||
ty::RegionKind::ReLateBound(_, _),
|
||||
ty::RegionKind::ReLateBound(_, _)
|
||||
) => {},
|
||||
ty::RegionKind::ReLateBound(_, _),
|
||||
) => {}
|
||||
|
||||
(ty::RegionKind::ReLateBound(_, _), _) => {
|
||||
// The new predicate has a HRTB in a spot where the old
|
||||
|
@ -458,7 +459,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
// so we return 'false' to remove the old predicate from
|
||||
// user_computed_preds
|
||||
return false;
|
||||
},
|
||||
}
|
||||
(_, ty::RegionKind::ReLateBound(_, _)) => {
|
||||
// This is the opposite situation as the previous arm - the
|
||||
// old predicate has a HRTB lifetime in a place where the
|
||||
|
@ -471,10 +472,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
return true
|
||||
return true;
|
||||
});
|
||||
|
||||
if should_add_new {
|
||||
|
@ -513,28 +514,20 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
match constraint {
|
||||
&Constraint::VarSubVar(r1, r2) => {
|
||||
{
|
||||
let deps1 = vid_map
|
||||
.entry(RegionTarget::RegionVid(r1))
|
||||
.or_default();
|
||||
let deps1 = vid_map.entry(RegionTarget::RegionVid(r1)).or_default();
|
||||
deps1.larger.insert(RegionTarget::RegionVid(r2));
|
||||
}
|
||||
|
||||
let deps2 = vid_map
|
||||
.entry(RegionTarget::RegionVid(r2))
|
||||
.or_default();
|
||||
let deps2 = vid_map.entry(RegionTarget::RegionVid(r2)).or_default();
|
||||
deps2.smaller.insert(RegionTarget::RegionVid(r1));
|
||||
}
|
||||
&Constraint::RegSubVar(region, vid) => {
|
||||
{
|
||||
let deps1 = vid_map
|
||||
.entry(RegionTarget::Region(region))
|
||||
.or_default();
|
||||
let deps1 = vid_map.entry(RegionTarget::Region(region)).or_default();
|
||||
deps1.larger.insert(RegionTarget::RegionVid(vid));
|
||||
}
|
||||
|
||||
let deps2 = vid_map
|
||||
.entry(RegionTarget::RegionVid(vid))
|
||||
.or_default();
|
||||
let deps2 = vid_map.entry(RegionTarget::RegionVid(vid)).or_default();
|
||||
deps2.smaller.insert(RegionTarget::Region(region));
|
||||
}
|
||||
&Constraint::VarSubReg(vid, region) => {
|
||||
|
@ -542,15 +535,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
}
|
||||
&Constraint::RegSubReg(r1, r2) => {
|
||||
{
|
||||
let deps1 = vid_map
|
||||
.entry(RegionTarget::Region(r1))
|
||||
.or_default();
|
||||
let deps1 = vid_map.entry(RegionTarget::Region(r1)).or_default();
|
||||
deps1.larger.insert(RegionTarget::Region(r2));
|
||||
}
|
||||
|
||||
let deps2 = vid_map
|
||||
.entry(RegionTarget::Region(r2))
|
||||
.or_default();
|
||||
let deps2 = vid_map.entry(RegionTarget::Region(r2)).or_default();
|
||||
deps2.smaller.insert(RegionTarget::Region(r1));
|
||||
}
|
||||
}
|
||||
|
@ -683,7 +672,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
&ty::Predicate::RegionOutlives(ref binder) => {
|
||||
if select.infcx().region_outlives_predicate(&dummy_cause, binder).is_err() {
|
||||
if select
|
||||
.infcx()
|
||||
.region_outlives_predicate(&dummy_cause, binder)
|
||||
.is_err()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -693,23 +686,17 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||
binder.map_bound_ref(|pred| pred.0).no_late_bound_regions(),
|
||||
) {
|
||||
(None, Some(t_a)) => {
|
||||
select.infcx().register_region_obligation(
|
||||
ast::DUMMY_NODE_ID,
|
||||
RegionObligation {
|
||||
sup_type: t_a,
|
||||
sub_region: select.infcx().tcx.types.re_static,
|
||||
cause: dummy_cause.clone(),
|
||||
},
|
||||
select.infcx().register_region_obligation_with_cause(
|
||||
t_a,
|
||||
select.infcx().tcx.types.re_static,
|
||||
&dummy_cause,
|
||||
);
|
||||
}
|
||||
(Some(ty::OutlivesPredicate(t_a, r_b)), _) => {
|
||||
select.infcx().register_region_obligation(
|
||||
ast::DUMMY_NODE_ID,
|
||||
RegionObligation {
|
||||
sup_type: t_a,
|
||||
sub_region: r_b,
|
||||
cause: dummy_cause.clone(),
|
||||
},
|
||||
select.infcx().register_region_obligation_with_cause(
|
||||
t_a,
|
||||
r_b,
|
||||
&dummy_cause,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use infer::{RegionObligation, InferCtxt};
|
||||
use infer::InferCtxt;
|
||||
use mir::interpret::GlobalId;
|
||||
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate};
|
||||
use ty::error::ExpectedFound;
|
||||
|
@ -372,13 +372,11 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
|
|||
Some(t_a) => {
|
||||
let r_static = self.selcx.tcx().types.re_static;
|
||||
if self.register_region_obligations {
|
||||
self.selcx.infcx().register_region_obligation(
|
||||
obligation.cause.body_id,
|
||||
RegionObligation {
|
||||
sup_type: t_a,
|
||||
sub_region: r_static,
|
||||
cause: obligation.cause.clone(),
|
||||
});
|
||||
self.selcx.infcx().register_region_obligation_with_cause(
|
||||
t_a,
|
||||
r_static,
|
||||
&obligation.cause,
|
||||
);
|
||||
}
|
||||
ProcessResult::Changed(vec![])
|
||||
}
|
||||
|
@ -387,13 +385,11 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
|
|||
// If there aren't, register the obligation.
|
||||
Some(ty::OutlivesPredicate(t_a, r_b)) => {
|
||||
if self.register_region_obligations {
|
||||
self.selcx.infcx().register_region_obligation(
|
||||
obligation.cause.body_id,
|
||||
RegionObligation {
|
||||
sup_type: t_a,
|
||||
sub_region: r_b,
|
||||
cause: obligation.cause.clone()
|
||||
});
|
||||
self.selcx.infcx().register_region_obligation_with_cause(
|
||||
t_a,
|
||||
r_b,
|
||||
&obligation.cause,
|
||||
);
|
||||
}
|
||||
ProcessResult::Changed(vec![])
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ pub use self::ObligationCauseCode::*;
|
|||
use chalk_engine;
|
||||
use hir;
|
||||
use hir::def_id::DefId;
|
||||
use infer::SuppressRegionErrors;
|
||||
use infer::outlives::env::OutlivesEnvironment;
|
||||
use middle::region;
|
||||
use mir::interpret::ConstEvalErr;
|
||||
|
@ -715,7 +716,12 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
// cares about declarations like `'a: 'b`.
|
||||
let outlives_env = OutlivesEnvironment::new(elaborated_env);
|
||||
|
||||
infcx.resolve_regions_and_report_errors(region_context, ®ion_scope_tree, &outlives_env);
|
||||
infcx.resolve_regions_and_report_errors(
|
||||
region_context,
|
||||
®ion_scope_tree,
|
||||
&outlives_env,
|
||||
SuppressRegionErrors::default(),
|
||||
);
|
||||
|
||||
let predicates = match infcx.fully_resolve(&predicates) {
|
||||
Ok(predicates) => predicates,
|
||||
|
|
|
@ -535,6 +535,13 @@ impl<I: Idx, T> IndexVec<I, T> {
|
|||
self.raw.len()
|
||||
}
|
||||
|
||||
/// Gives the next index that will be assigned when `push` is
|
||||
/// called.
|
||||
#[inline]
|
||||
pub fn next_index(&self) -> I {
|
||||
I::new(self.len())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.raw.is_empty()
|
||||
|
|
|
@ -14,29 +14,29 @@ use std::path::PathBuf;
|
|||
use std::sync::mpsc;
|
||||
|
||||
use driver;
|
||||
use rustc_lint;
|
||||
use rustc_resolve::MakeGlobMap;
|
||||
use rustc::middle::region;
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::traits::ObligationCause;
|
||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc::ty::query::OnDiskCache;
|
||||
use rustc::infer::{self, InferOk, InferResult};
|
||||
use rustc::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc::infer::type_variable::TypeVariableOrigin;
|
||||
use rustc_metadata::cstore::CStore;
|
||||
use rustc::hir::map as hir_map;
|
||||
use rustc::session::{self, config};
|
||||
use rustc::session::config::{OutputFilenames, OutputTypes};
|
||||
use rustc_data_structures::sync::{self, Lrc};
|
||||
use syntax;
|
||||
use syntax::ast;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use syntax::source_map::{SourceMap, FilePathMapping, FileName};
|
||||
use errors;
|
||||
use errors::emitter::Emitter;
|
||||
use errors::{Level, DiagnosticBuilder};
|
||||
use errors::{DiagnosticBuilder, Level};
|
||||
use rustc::hir::map as hir_map;
|
||||
use rustc::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc::infer::type_variable::TypeVariableOrigin;
|
||||
use rustc::infer::{self, InferOk, InferResult, SuppressRegionErrors};
|
||||
use rustc::middle::region;
|
||||
use rustc::session::config::{OutputFilenames, OutputTypes};
|
||||
use rustc::session::{self, config};
|
||||
use rustc::traits::ObligationCause;
|
||||
use rustc::ty::query::OnDiskCache;
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_data_structures::sync::{self, Lrc};
|
||||
use rustc_lint;
|
||||
use rustc_metadata::cstore::CStore;
|
||||
use rustc_resolve::MakeGlobMap;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use syntax;
|
||||
use syntax::ast;
|
||||
use syntax::feature_gate::UnstableFeatures;
|
||||
use syntax::source_map::{FileName, FilePathMapping, SourceMap};
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax_pos::DUMMY_SP;
|
||||
|
||||
|
@ -90,13 +90,15 @@ impl Emitter for ExpectErrorEmitter {
|
|||
|
||||
fn errors(msgs: &[&str]) -> (Box<dyn Emitter + sync::Send>, usize) {
|
||||
let v = msgs.iter().map(|m| m.to_string()).collect();
|
||||
(box ExpectErrorEmitter { messages: v } as Box<dyn Emitter + sync::Send>, msgs.len())
|
||||
(
|
||||
box ExpectErrorEmitter { messages: v } as Box<dyn Emitter + sync::Send>,
|
||||
msgs.len(),
|
||||
)
|
||||
}
|
||||
|
||||
fn test_env<F>(source_string: &str,
|
||||
args: (Box<dyn Emitter + sync::Send>, usize),
|
||||
body: F)
|
||||
where F: FnOnce(Env)
|
||||
fn test_env<F>(source_string: &str, args: (Box<dyn Emitter + sync::Send>, usize), body: F)
|
||||
where
|
||||
F: FnOnce(Env),
|
||||
{
|
||||
syntax::with_globals(|| {
|
||||
let mut options = config::Options::default();
|
||||
|
@ -113,34 +115,41 @@ fn test_env_with_pool<F>(
|
|||
options: config::Options,
|
||||
source_string: &str,
|
||||
(emitter, expected_err_count): (Box<dyn Emitter + sync::Send>, usize),
|
||||
body: F
|
||||
)
|
||||
where F: FnOnce(Env)
|
||||
body: F,
|
||||
) where
|
||||
F: FnOnce(Env),
|
||||
{
|
||||
let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);
|
||||
let sess = session::build_session_(options,
|
||||
None,
|
||||
diagnostic_handler,
|
||||
Lrc::new(SourceMap::new(FilePathMapping::empty())));
|
||||
let sess = session::build_session_(
|
||||
options,
|
||||
None,
|
||||
diagnostic_handler,
|
||||
Lrc::new(SourceMap::new(FilePathMapping::empty())),
|
||||
);
|
||||
let cstore = CStore::new(::get_codegen_backend(&sess).metadata_loader());
|
||||
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
|
||||
let input = config::Input::Str {
|
||||
name: FileName::Anon,
|
||||
input: source_string.to_string(),
|
||||
};
|
||||
let krate = driver::phase_1_parse_input(&driver::CompileController::basic(),
|
||||
&sess,
|
||||
&input).unwrap();
|
||||
let driver::ExpansionResult { defs, resolutions, mut hir_forest, .. } = {
|
||||
driver::phase_2_configure_and_expand(&sess,
|
||||
&cstore,
|
||||
krate,
|
||||
None,
|
||||
"test",
|
||||
None,
|
||||
MakeGlobMap::No,
|
||||
|_| Ok(()))
|
||||
.expect("phase 2 aborted")
|
||||
let krate =
|
||||
driver::phase_1_parse_input(&driver::CompileController::basic(), &sess, &input).unwrap();
|
||||
let driver::ExpansionResult {
|
||||
defs,
|
||||
resolutions,
|
||||
mut hir_forest,
|
||||
..
|
||||
} = {
|
||||
driver::phase_2_configure_and_expand(
|
||||
&sess,
|
||||
&cstore,
|
||||
krate,
|
||||
None,
|
||||
"test",
|
||||
None,
|
||||
MakeGlobMap::No,
|
||||
|_| Ok(()),
|
||||
).expect("phase 2 aborted")
|
||||
};
|
||||
|
||||
let arenas = ty::AllArenas::new();
|
||||
|
@ -155,32 +164,39 @@ fn test_env_with_pool<F>(
|
|||
extra: String::new(),
|
||||
outputs: OutputTypes::new(&[]),
|
||||
};
|
||||
TyCtxt::create_and_enter(&sess,
|
||||
&cstore,
|
||||
ty::query::Providers::default(),
|
||||
ty::query::Providers::default(),
|
||||
&arenas,
|
||||
resolutions,
|
||||
hir_map,
|
||||
OnDiskCache::new_empty(sess.source_map()),
|
||||
"test_crate",
|
||||
tx,
|
||||
&outputs,
|
||||
|tcx| {
|
||||
tcx.infer_ctxt().enter(|infcx| {
|
||||
let mut region_scope_tree = region::ScopeTree::default();
|
||||
let param_env = ty::ParamEnv::empty();
|
||||
body(Env {
|
||||
infcx: &infcx,
|
||||
region_scope_tree: &mut region_scope_tree,
|
||||
param_env: param_env,
|
||||
TyCtxt::create_and_enter(
|
||||
&sess,
|
||||
&cstore,
|
||||
ty::query::Providers::default(),
|
||||
ty::query::Providers::default(),
|
||||
&arenas,
|
||||
resolutions,
|
||||
hir_map,
|
||||
OnDiskCache::new_empty(sess.source_map()),
|
||||
"test_crate",
|
||||
tx,
|
||||
&outputs,
|
||||
|tcx| {
|
||||
tcx.infer_ctxt().enter(|infcx| {
|
||||
let mut region_scope_tree = region::ScopeTree::default();
|
||||
let param_env = ty::ParamEnv::empty();
|
||||
body(Env {
|
||||
infcx: &infcx,
|
||||
region_scope_tree: &mut region_scope_tree,
|
||||
param_env: param_env,
|
||||
});
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
let def_id = tcx.hir.local_def_id(ast::CRATE_NODE_ID);
|
||||
infcx.resolve_regions_and_report_errors(
|
||||
def_id,
|
||||
®ion_scope_tree,
|
||||
&outlives_env,
|
||||
SuppressRegionErrors::default(),
|
||||
);
|
||||
assert_eq!(tcx.sess.err_count(), expected_err_count);
|
||||
});
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
let def_id = tcx.hir.local_def_id(ast::CRATE_NODE_ID);
|
||||
infcx.resolve_regions_and_report_errors(def_id, ®ion_scope_tree, &outlives_env);
|
||||
assert_eq!(tcx.sess.err_count(), expected_err_count);
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn d1() -> ty::DebruijnIndex {
|
||||
|
@ -196,9 +212,15 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
self.infcx.tcx
|
||||
}
|
||||
|
||||
pub fn create_region_hierarchy(&mut self, rh: &RH,
|
||||
parent: (region::Scope, region::ScopeDepth)) {
|
||||
let me = region::Scope { id: rh.id, data: region::ScopeData::Node };
|
||||
pub fn create_region_hierarchy(
|
||||
&mut self,
|
||||
rh: &RH,
|
||||
parent: (region::Scope, region::ScopeDepth),
|
||||
) {
|
||||
let me = region::Scope {
|
||||
id: rh.id,
|
||||
data: region::ScopeData::Node,
|
||||
};
|
||||
self.region_scope_tree.record_scope_parent(me, Some(parent));
|
||||
for child_rh in rh.sub {
|
||||
self.create_region_hierarchy(child_rh, (me, parent.1 + 1));
|
||||
|
@ -211,20 +233,25 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
|
||||
let dscope = region::Scope {
|
||||
id: hir::ItemLocalId(1),
|
||||
data: region::ScopeData::Destruction
|
||||
data: region::ScopeData::Destruction,
|
||||
};
|
||||
self.region_scope_tree.record_scope_parent(dscope, None);
|
||||
self.create_region_hierarchy(&RH {
|
||||
id: hir::ItemLocalId(1),
|
||||
sub: &[RH {
|
||||
id: hir::ItemLocalId(10),
|
||||
sub: &[],
|
||||
self.create_region_hierarchy(
|
||||
&RH {
|
||||
id: hir::ItemLocalId(1),
|
||||
sub: &[
|
||||
RH {
|
||||
id: hir::ItemLocalId(10),
|
||||
sub: &[],
|
||||
},
|
||||
RH {
|
||||
id: hir::ItemLocalId(11),
|
||||
sub: &[],
|
||||
},
|
||||
],
|
||||
},
|
||||
RH {
|
||||
id: hir::ItemLocalId(11),
|
||||
sub: &[],
|
||||
}],
|
||||
}, (dscope, 1));
|
||||
(dscope, 1),
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // this seems like it could be useful, even if we don't use it now
|
||||
|
@ -236,11 +263,12 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
fn search_mod(this: &Env,
|
||||
m: &hir::Mod,
|
||||
idx: usize,
|
||||
names: &[String])
|
||||
-> Option<ast::NodeId> {
|
||||
fn search_mod(
|
||||
this: &Env,
|
||||
m: &hir::Mod,
|
||||
idx: usize,
|
||||
names: &[String],
|
||||
) -> Option<ast::NodeId> {
|
||||
assert!(idx < names.len());
|
||||
for item in &m.item_ids {
|
||||
let item = this.infcx.tcx.hir.expect_item(item.id);
|
||||
|
@ -257,22 +285,22 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
return match it.node {
|
||||
hir::ItemKind::Use(..) |
|
||||
hir::ItemKind::ExternCrate(..) |
|
||||
hir::ItemKind::Const(..) |
|
||||
hir::ItemKind::Static(..) |
|
||||
hir::ItemKind::Fn(..) |
|
||||
hir::ItemKind::ForeignMod(..) |
|
||||
hir::ItemKind::GlobalAsm(..) |
|
||||
hir::ItemKind::Existential(..) |
|
||||
hir::ItemKind::Ty(..) => None,
|
||||
hir::ItemKind::Use(..)
|
||||
| hir::ItemKind::ExternCrate(..)
|
||||
| hir::ItemKind::Const(..)
|
||||
| hir::ItemKind::Static(..)
|
||||
| hir::ItemKind::Fn(..)
|
||||
| hir::ItemKind::ForeignMod(..)
|
||||
| hir::ItemKind::GlobalAsm(..)
|
||||
| hir::ItemKind::Existential(..)
|
||||
| hir::ItemKind::Ty(..) => None,
|
||||
|
||||
hir::ItemKind::Enum(..) |
|
||||
hir::ItemKind::Struct(..) |
|
||||
hir::ItemKind::Union(..) |
|
||||
hir::ItemKind::Trait(..) |
|
||||
hir::ItemKind::TraitAlias(..) |
|
||||
hir::ItemKind::Impl(..) => None,
|
||||
hir::ItemKind::Enum(..)
|
||||
| hir::ItemKind::Struct(..)
|
||||
| hir::ItemKind::Union(..)
|
||||
| hir::ItemKind::Trait(..)
|
||||
| hir::ItemKind::TraitAlias(..)
|
||||
| hir::ItemKind::Impl(..) => None,
|
||||
|
||||
hir::ItemKind::Mod(ref m) => search_mod(this, m, idx, names),
|
||||
};
|
||||
|
@ -280,7 +308,10 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn make_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
|
||||
match self.infcx.at(&ObligationCause::dummy(), self.param_env).sub(a, b) {
|
||||
match self.infcx
|
||||
.at(&ObligationCause::dummy(), self.param_env)
|
||||
.sub(a, b)
|
||||
{
|
||||
Ok(_) => true,
|
||||
Err(ref e) => panic!("Encountered error: {}", e),
|
||||
}
|
||||
|
@ -302,13 +333,15 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn t_fn(&self, input_tys: &[Ty<'tcx>], output_ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
self.infcx.tcx.mk_fn_ptr(ty::Binder::bind(self.infcx.tcx.mk_fn_sig(
|
||||
input_tys.iter().cloned(),
|
||||
output_ty,
|
||||
false,
|
||||
hir::Unsafety::Normal,
|
||||
Abi::Rust
|
||||
)))
|
||||
self.infcx
|
||||
.tcx
|
||||
.mk_fn_ptr(ty::Binder::bind(self.infcx.tcx.mk_fn_sig(
|
||||
input_tys.iter().cloned(),
|
||||
output_ty,
|
||||
false,
|
||||
hir::Unsafety::Normal,
|
||||
Abi::Rust,
|
||||
)))
|
||||
}
|
||||
|
||||
pub fn t_nil(&self) -> Ty<'tcx> {
|
||||
|
@ -321,23 +354,30 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
|
||||
pub fn t_param(&self, index: u32) -> Ty<'tcx> {
|
||||
let name = format!("T{}", index);
|
||||
self.infcx.tcx.mk_ty_param(index, Symbol::intern(&name).as_interned_str())
|
||||
self.infcx
|
||||
.tcx
|
||||
.mk_ty_param(index, Symbol::intern(&name).as_interned_str())
|
||||
}
|
||||
|
||||
pub fn re_early_bound(&self, index: u32, name: &'static str) -> ty::Region<'tcx> {
|
||||
let name = Symbol::intern(name).as_interned_str();
|
||||
self.infcx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
|
||||
def_id: self.infcx.tcx.hir.local_def_id(ast::CRATE_NODE_ID),
|
||||
index,
|
||||
name,
|
||||
}))
|
||||
self.infcx
|
||||
.tcx
|
||||
.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
|
||||
def_id: self.infcx.tcx.hir.local_def_id(ast::CRATE_NODE_ID),
|
||||
index,
|
||||
name,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn re_late_bound_with_debruijn(&self,
|
||||
id: u32,
|
||||
debruijn: ty::DebruijnIndex)
|
||||
-> ty::Region<'tcx> {
|
||||
self.infcx.tcx.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(id)))
|
||||
pub fn re_late_bound_with_debruijn(
|
||||
&self,
|
||||
id: u32,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
) -> ty::Region<'tcx> {
|
||||
self.infcx
|
||||
.tcx
|
||||
.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(id)))
|
||||
}
|
||||
|
||||
pub fn t_rptr(&self, r: ty::Region<'tcx>) -> Ty<'tcx> {
|
||||
|
@ -349,10 +389,11 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
|
||||
}
|
||||
|
||||
pub fn t_rptr_late_bound_with_debruijn(&self,
|
||||
id: u32,
|
||||
debruijn: ty::DebruijnIndex)
|
||||
-> Ty<'tcx> {
|
||||
pub fn t_rptr_late_bound_with_debruijn(
|
||||
&self,
|
||||
id: u32,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
) -> Ty<'tcx> {
|
||||
let r = self.re_late_bound_with_debruijn(id, debruijn);
|
||||
self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
|
||||
}
|
||||
|
@ -360,9 +401,11 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
pub fn t_rptr_scope(&self, id: u32) -> Ty<'tcx> {
|
||||
let r = ty::ReScope(region::Scope {
|
||||
id: hir::ItemLocalId(id),
|
||||
data: region::ScopeData::Node
|
||||
data: region::ScopeData::Node,
|
||||
});
|
||||
self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
|
||||
self.infcx
|
||||
.tcx
|
||||
.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
|
||||
}
|
||||
|
||||
pub fn re_free(&self, id: u32) -> ty::Region<'tcx> {
|
||||
|
@ -378,14 +421,19 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, ()> {
|
||||
self.infcx.at(&ObligationCause::dummy(), self.param_env).sub(t1, t2)
|
||||
self.infcx
|
||||
.at(&ObligationCause::dummy(), self.param_env)
|
||||
.sub(t1, t2)
|
||||
}
|
||||
|
||||
/// Checks that `t1 <: t2` is true (this may register additional
|
||||
/// region checks).
|
||||
pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
|
||||
match self.sub(t1, t2) {
|
||||
Ok(InferOk { obligations, value: () }) => {
|
||||
Ok(InferOk {
|
||||
obligations,
|
||||
value: (),
|
||||
}) => {
|
||||
// None of these tests should require nested obligations:
|
||||
assert!(obligations.is_empty());
|
||||
}
|
||||
|
@ -445,8 +493,10 @@ fn sub_free_bound_false() {
|
|||
env.create_simple_region_hierarchy();
|
||||
let t_rptr_free1 = env.t_rptr_free(1);
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
env.check_not_sub(env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
|
||||
env.check_not_sub(
|
||||
env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -462,8 +512,10 @@ fn sub_bound_free_true() {
|
|||
env.create_simple_region_hierarchy();
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
let t_rptr_free1 = env.t_rptr_free(1);
|
||||
env.check_sub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_free1], env.tcx().types.isize));
|
||||
env.check_sub(
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -476,10 +528,13 @@ fn sub_free_bound_false_infer() {
|
|||
//! does NOT hold for any instantiation of `_#1`.
|
||||
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
|
||||
let t_infer1 = env.infcx
|
||||
.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
env.check_not_sub(env.t_fn(&[t_infer1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
|
||||
env.check_not_sub(
|
||||
env.t_fn(&[t_infer1], env.tcx().types.isize),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -487,7 +542,6 @@ fn sub_free_bound_false_infer() {
|
|||
/// This requires adjusting the Debruijn index.
|
||||
#[test]
|
||||
fn subst_ty_renumber_bound() {
|
||||
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
// Situation:
|
||||
// Theta = [A -> &'a foo]
|
||||
|
@ -509,11 +563,10 @@ fn subst_ty_renumber_bound() {
|
|||
env.t_fn(&[t_ptr_bound2], env.t_nil())
|
||||
};
|
||||
|
||||
debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
|
||||
t_source,
|
||||
substs,
|
||||
t_substituted,
|
||||
t_expected);
|
||||
debug!(
|
||||
"subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
|
||||
t_source, substs, t_substituted, t_expected
|
||||
);
|
||||
|
||||
assert_eq!(t_substituted, t_expected);
|
||||
})
|
||||
|
@ -546,11 +599,10 @@ fn subst_ty_renumber_some_bounds() {
|
|||
env.t_pair(t_rptr_bound1, env.t_fn(&[t_rptr_bound2], env.t_nil()))
|
||||
};
|
||||
|
||||
debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
|
||||
t_source,
|
||||
substs,
|
||||
t_substituted,
|
||||
t_expected);
|
||||
debug!(
|
||||
"subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
|
||||
t_source, substs, t_substituted, t_expected
|
||||
);
|
||||
|
||||
assert_eq!(t_substituted, t_expected);
|
||||
})
|
||||
|
@ -559,7 +611,6 @@ fn subst_ty_renumber_some_bounds() {
|
|||
/// Test that we correctly compute whether a type has escaping regions or not.
|
||||
#[test]
|
||||
fn escaping() {
|
||||
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
|
||||
// Situation:
|
||||
// Theta = [A -> &'a foo]
|
||||
|
@ -608,11 +659,10 @@ fn subst_region_renumber_region() {
|
|||
env.t_fn(&[t_rptr_bound2], env.t_nil())
|
||||
};
|
||||
|
||||
debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
|
||||
t_source,
|
||||
substs,
|
||||
t_substituted,
|
||||
t_expected);
|
||||
debug!(
|
||||
"subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
|
||||
t_source, substs, t_substituted, t_expected
|
||||
);
|
||||
|
||||
assert_eq!(t_substituted, t_expected);
|
||||
})
|
||||
|
@ -627,9 +677,13 @@ fn walk_ty() {
|
|||
let tup1_ty = tcx.intern_tup(&[int_ty, usize_ty, int_ty, usize_ty]);
|
||||
let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, usize_ty]);
|
||||
let walked: Vec<_> = tup2_ty.walk().collect();
|
||||
assert_eq!(walked,
|
||||
[tup2_ty, tup1_ty, int_ty, usize_ty, int_ty, usize_ty, tup1_ty, int_ty,
|
||||
usize_ty, int_ty, usize_ty, usize_ty]);
|
||||
assert_eq!(
|
||||
walked,
|
||||
[
|
||||
tup2_ty, tup1_ty, int_ty, usize_ty, int_ty, usize_ty, tup1_ty, int_ty, usize_ty,
|
||||
int_ty, usize_ty, usize_ty
|
||||
]
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -644,14 +698,16 @@ fn walk_ty_skip_subtree() {
|
|||
|
||||
// types we expect to see (in order), plus a boolean saying
|
||||
// whether to skip the subtree.
|
||||
let mut expected = vec![(tup2_ty, false),
|
||||
(tup1_ty, false),
|
||||
(int_ty, false),
|
||||
(usize_ty, false),
|
||||
(int_ty, false),
|
||||
(usize_ty, false),
|
||||
(tup1_ty, true), // skip the isize/usize/isize/usize
|
||||
(usize_ty, false)];
|
||||
let mut expected = vec![
|
||||
(tup2_ty, false),
|
||||
(tup1_ty, false),
|
||||
(int_ty, false),
|
||||
(usize_ty, false),
|
||||
(int_ty, false),
|
||||
(usize_ty, false),
|
||||
(tup1_ty, true), // skip the isize/usize/isize/usize
|
||||
(usize_ty, false),
|
||||
];
|
||||
expected.reverse();
|
||||
|
||||
let mut walker = tup2_ty.walk();
|
||||
|
|
|
@ -10,15 +10,13 @@
|
|||
|
||||
use super::universal_regions::UniversalRegions;
|
||||
use borrow_check::nll::constraints::graph::NormalConstraintGraph;
|
||||
use borrow_check::nll::constraints::{
|
||||
ConstraintSccIndex, ConstraintSet, OutlivesConstraint,
|
||||
};
|
||||
use borrow_check::nll::constraints::{ConstraintSccIndex, ConstraintSet, OutlivesConstraint};
|
||||
use borrow_check::nll::region_infer::values::{RegionElement, ToElementIndex};
|
||||
use borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations;
|
||||
use borrow_check::nll::type_check::Locations;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::infer::canonical::QueryRegionConstraint;
|
||||
use rustc::infer::region_constraints::{GenericKind, VarInfos};
|
||||
use rustc::infer::region_constraints::{GenericKind, VarInfos, VerifyBound};
|
||||
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin, RegionVariableOrigin};
|
||||
use rustc::mir::{
|
||||
ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, Local, Location,
|
||||
|
@ -29,7 +27,7 @@ use rustc::util::common;
|
|||
use rustc_data_structures::bit_set::BitSet;
|
||||
use rustc_data_structures::graph::scc::Sccs;
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use rustc_errors::{DiagnosticBuilder, Diagnostic};
|
||||
use rustc_errors::{Diagnostic, DiagnosticBuilder};
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
|
@ -71,6 +69,15 @@ pub struct RegionInferenceContext<'tcx> {
|
|||
/// visible from this index.
|
||||
scc_universes: IndexVec<ConstraintSccIndex, ty::UniverseIndex>,
|
||||
|
||||
/// Contains a "representative" from each SCC. This will be the
|
||||
/// minimal RegionVid belonging to that universe. It is used as a
|
||||
/// kind of hacky way to manage checking outlives relationships,
|
||||
/// since we can 'canonicalize' each region to the representative
|
||||
/// of its SCC and be sure that -- if they have the same repr --
|
||||
/// they *must* be equal (though not having the same repr does not
|
||||
/// mean they are unequal).
|
||||
scc_representatives: IndexVec<ConstraintSccIndex, ty::RegionVid>,
|
||||
|
||||
/// The final inferred values of the region variables; we compute
|
||||
/// one value per SCC. To get the value for any given *region*,
|
||||
/// you first find which scc it is a part of.
|
||||
|
@ -162,42 +169,7 @@ pub struct TypeTest<'tcx> {
|
|||
|
||||
/// A test which, if met by the region `'x`, proves that this type
|
||||
/// constraint is satisfied.
|
||||
pub test: RegionTest,
|
||||
}
|
||||
|
||||
/// A "test" that can be applied to some "subject region" `'x`. These are used to
|
||||
/// describe type constraints. Tests do not presently affect the
|
||||
/// region values that get inferred for each variable; they only
|
||||
/// examine the results *after* inference. This means they can
|
||||
/// conveniently include disjuction ("a or b must be true").
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum RegionTest {
|
||||
/// The subject region `'x` must by outlived by *some* region in
|
||||
/// the given set of regions.
|
||||
///
|
||||
/// This test comes from e.g. a where clause like `T: 'a + 'b`,
|
||||
/// which implies that we know that `T: 'a` and that `T:
|
||||
/// 'b`. Therefore, if we are trying to prove that `T: 'x`, we can
|
||||
/// do so by showing that `'a: 'x` *or* `'b: 'x`.
|
||||
IsOutlivedByAnyRegionIn(Vec<RegionVid>),
|
||||
|
||||
/// The subject region `'x` must by outlived by *all* regions in
|
||||
/// the given set of regions.
|
||||
///
|
||||
/// This test comes from e.g. a projection type like `T = <u32 as
|
||||
/// Trait<'a, 'b>>::Foo`, which must outlive `'a` or `'b`, and
|
||||
/// maybe both. Therefore we can prove that `T: 'x` if we know
|
||||
/// that `'a: 'x` *and* `'b: 'x`.
|
||||
IsOutlivedByAllRegionsIn(Vec<RegionVid>),
|
||||
|
||||
/// Any of the given tests are true.
|
||||
///
|
||||
/// This arises from projections, for which there are multiple
|
||||
/// ways to prove an outlives relationship.
|
||||
Any(Vec<RegionTest>),
|
||||
|
||||
/// All of the given tests are true.
|
||||
All(Vec<RegionTest>),
|
||||
pub verify_bound: VerifyBound<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
|
@ -245,6 +217,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
|
||||
let scc_universes = Self::compute_scc_universes(&constraint_sccs, &definitions);
|
||||
|
||||
let scc_representatives = Self::compute_scc_representatives(&constraint_sccs, &definitions);
|
||||
|
||||
let mut result = Self {
|
||||
definitions,
|
||||
liveness_constraints,
|
||||
|
@ -252,6 +226,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
constraint_graph,
|
||||
constraint_sccs,
|
||||
scc_universes,
|
||||
scc_representatives,
|
||||
scc_values,
|
||||
type_tests,
|
||||
universal_regions,
|
||||
|
@ -288,6 +263,27 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
scc_universes
|
||||
}
|
||||
|
||||
/// For each SCC, we compute a unique `RegionVid` (in fact, the
|
||||
/// minimal one that belongs to the SCC). See
|
||||
/// `scc_representatives` field of `RegionInferenceContext` for
|
||||
/// more details.
|
||||
fn compute_scc_representatives(
|
||||
constraints_scc: &Sccs<RegionVid, ConstraintSccIndex>,
|
||||
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>,
|
||||
) -> IndexVec<ConstraintSccIndex, ty::RegionVid> {
|
||||
let num_sccs = constraints_scc.num_sccs();
|
||||
let next_region_vid = definitions.next_index();
|
||||
let mut scc_representatives = IndexVec::from_elem_n(next_region_vid, num_sccs);
|
||||
|
||||
for region_vid in definitions.indices() {
|
||||
let scc = constraints_scc.scc(region_vid);
|
||||
let prev_min = scc_representatives[scc];
|
||||
scc_representatives[scc] = region_vid.min(prev_min);
|
||||
}
|
||||
|
||||
scc_representatives
|
||||
}
|
||||
|
||||
/// Initializes the region variables for each universally
|
||||
/// quantified region (lifetime parameter). The first N variables
|
||||
/// always correspond to the regions appearing in the function
|
||||
|
@ -582,7 +578,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
for type_test in &self.type_tests {
|
||||
debug!("check_type_test: {:?}", type_test);
|
||||
|
||||
if self.eval_region_test(mir, type_test.lower_bound, &type_test.test) {
|
||||
let generic_ty = type_test.generic_kind.to_ty(tcx);
|
||||
if self.eval_verify_bound(
|
||||
tcx,
|
||||
mir,
|
||||
generic_ty,
|
||||
type_test.lower_bound,
|
||||
&type_test.verify_bound,
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -689,7 +692,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
generic_kind,
|
||||
lower_bound,
|
||||
locations,
|
||||
test: _,
|
||||
verify_bound: _,
|
||||
} = type_test;
|
||||
|
||||
let generic_ty = generic_kind.to_ty(tcx);
|
||||
|
@ -716,7 +719,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
// where `ur` is a local bound -- we are sometimes in a
|
||||
// position to prove things that our caller cannot. See
|
||||
// #53570 for an example.
|
||||
if self.eval_region_test(mir, ur, &type_test.test) {
|
||||
if self.eval_verify_bound(tcx, mir, generic_ty, ur, &type_test.verify_bound) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -888,31 +891,99 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
|
||||
/// Test if `test` is true when applied to `lower_bound` at
|
||||
/// `point`, and returns true or false.
|
||||
fn eval_region_test(&self, mir: &Mir<'tcx>, lower_bound: RegionVid, test: &RegionTest) -> bool {
|
||||
fn eval_verify_bound(
|
||||
&self,
|
||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
generic_ty: Ty<'tcx>,
|
||||
lower_bound: RegionVid,
|
||||
verify_bound: &VerifyBound<'tcx>,
|
||||
) -> bool {
|
||||
debug!(
|
||||
"eval_region_test(lower_bound={:?}, test={:?})",
|
||||
lower_bound, test
|
||||
"eval_verify_bound(lower_bound={:?}, verify_bound={:?})",
|
||||
lower_bound, verify_bound
|
||||
);
|
||||
|
||||
match test {
|
||||
RegionTest::IsOutlivedByAllRegionsIn(regions) => regions
|
||||
.iter()
|
||||
.all(|&r| self.eval_outlives(mir, r, lower_bound)),
|
||||
match verify_bound {
|
||||
VerifyBound::IfEq(test_ty, verify_bound1) => {
|
||||
self.eval_if_eq(tcx, mir, generic_ty, lower_bound, test_ty, verify_bound1)
|
||||
}
|
||||
|
||||
RegionTest::IsOutlivedByAnyRegionIn(regions) => regions
|
||||
.iter()
|
||||
.any(|&r| self.eval_outlives(mir, r, lower_bound)),
|
||||
VerifyBound::OutlivedBy(r) => {
|
||||
let r_vid = self.to_region_vid(r);
|
||||
self.eval_outlives(mir, r_vid, lower_bound)
|
||||
}
|
||||
|
||||
RegionTest::Any(tests) => tests
|
||||
.iter()
|
||||
.any(|test| self.eval_region_test(mir, lower_bound, test)),
|
||||
VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| {
|
||||
self.eval_verify_bound(tcx, mir, generic_ty, lower_bound, verify_bound)
|
||||
}),
|
||||
|
||||
RegionTest::All(tests) => tests
|
||||
.iter()
|
||||
.all(|test| self.eval_region_test(mir, lower_bound, test)),
|
||||
VerifyBound::AllBounds(verify_bounds) => verify_bounds.iter().all(|verify_bound| {
|
||||
self.eval_verify_bound(tcx, mir, generic_ty, lower_bound, verify_bound)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_if_eq(
|
||||
&self,
|
||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
generic_ty: Ty<'tcx>,
|
||||
lower_bound: RegionVid,
|
||||
test_ty: Ty<'tcx>,
|
||||
verify_bound: &VerifyBound<'tcx>,
|
||||
) -> bool {
|
||||
let generic_ty_normalized = self.normalize_to_scc_representatives(tcx, generic_ty);
|
||||
let test_ty_normalized = self.normalize_to_scc_representatives(tcx, test_ty);
|
||||
if generic_ty_normalized == test_ty_normalized {
|
||||
self.eval_verify_bound(tcx, mir, generic_ty, lower_bound, verify_bound)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a conservative normalization procedure. It takes every
|
||||
/// free region in `value` and replaces it with the
|
||||
/// "representative" of its SCC (see `scc_representatives` field).
|
||||
/// We are guaranteed that if two values normalize to the same
|
||||
/// thing, then they are equal; this is a conservative check in
|
||||
/// that they could still be equal even if they normalize to
|
||||
/// different results. (For example, there might be two regions
|
||||
/// with the same value that are not in the same SCC).
|
||||
///
|
||||
/// NB. This is not an ideal approach and I would like to revisit
|
||||
/// it. However, it works pretty well in practice. In particular,
|
||||
/// this is needed to deal with projection outlives bounds like
|
||||
///
|
||||
/// <T as Foo<'0>>::Item: '1
|
||||
///
|
||||
/// In particular, this routine winds up being important when
|
||||
/// there are bounds like `where <T as Foo<'a>>::Item: 'b` in the
|
||||
/// environment. In this case, if we can show that `'0 == 'a`,
|
||||
/// and that `'b: '1`, then we know that the clause is
|
||||
/// satisfied. In such cases, particularly due to limitations of
|
||||
/// the trait solver =), we usually wind up with a where-clause like
|
||||
/// `T: Foo<'a>` in scope, which thus forces `'0 == 'a` to be added as
|
||||
/// a constraint, and thus ensures that they are in the same SCC.
|
||||
///
|
||||
/// So why can't we do a more correct routine? Well, we could
|
||||
/// *almost* use the `relate_tys` code, but the way it is
|
||||
/// currently setup it creates inference variables to deal with
|
||||
/// higher-ranked things and so forth, and right now the inference
|
||||
/// context is not permitted to make more inference variables. So
|
||||
/// we use this kind of hacky solution.
|
||||
fn normalize_to_scc_representatives<T>(&self, tcx: TyCtxt<'_, '_, 'tcx>, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
tcx.fold_regions(&value, &mut false, |r, _db| {
|
||||
let vid = self.to_region_vid(r);
|
||||
let scc = self.constraint_sccs.scc(vid);
|
||||
let repr = self.scc_representatives[scc];
|
||||
tcx.mk_region(ty::ReVar(repr))
|
||||
})
|
||||
}
|
||||
|
||||
// Evaluate whether `sup_region: sub_region @ point`.
|
||||
fn eval_outlives(
|
||||
&self,
|
||||
|
|
|
@ -11,10 +11,11 @@
|
|||
use borrow_check::location::LocationTable;
|
||||
use borrow_check::nll::constraints::{ConstraintCategory, ConstraintSet, OutlivesConstraint};
|
||||
use borrow_check::nll::facts::AllFacts;
|
||||
use borrow_check::nll::region_infer::{RegionTest, TypeTest};
|
||||
use borrow_check::nll::region_infer::TypeTest;
|
||||
use borrow_check::nll::type_check::Locations;
|
||||
use borrow_check::nll::universal_regions::UniversalRegions;
|
||||
use rustc::infer::canonical::QueryRegionConstraint;
|
||||
use rustc::infer::outlives::env::RegionBoundPairs;
|
||||
use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
|
||||
use rustc::infer::region_constraints::{GenericKind, VerifyBound};
|
||||
use rustc::infer::{self, SubregionOrigin};
|
||||
|
@ -26,7 +27,7 @@ crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
|||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
location_table: &'a LocationTable,
|
||||
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
locations: Locations,
|
||||
|
@ -41,7 +42,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
|
|||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
location_table: &'a LocationTable,
|
||||
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
locations: Locations,
|
||||
|
@ -139,43 +140,15 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
|
|||
&self,
|
||||
generic_kind: GenericKind<'tcx>,
|
||||
region: ty::Region<'tcx>,
|
||||
bound: VerifyBound<'tcx>,
|
||||
verify_bound: VerifyBound<'tcx>,
|
||||
) -> TypeTest<'tcx> {
|
||||
let lower_bound = self.to_region_vid(region);
|
||||
|
||||
let test = self.verify_bound_to_region_test(&bound);
|
||||
|
||||
TypeTest {
|
||||
generic_kind,
|
||||
lower_bound,
|
||||
locations: self.locations,
|
||||
test,
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_bound_to_region_test(&self, verify_bound: &VerifyBound<'tcx>) -> RegionTest {
|
||||
match verify_bound {
|
||||
VerifyBound::AnyRegion(regions) => RegionTest::IsOutlivedByAnyRegionIn(
|
||||
regions.iter().map(|r| self.to_region_vid(r)).collect(),
|
||||
),
|
||||
|
||||
VerifyBound::AllRegions(regions) => RegionTest::IsOutlivedByAllRegionsIn(
|
||||
regions.iter().map(|r| self.to_region_vid(r)).collect(),
|
||||
),
|
||||
|
||||
VerifyBound::AnyBound(bounds) => RegionTest::Any(
|
||||
bounds
|
||||
.iter()
|
||||
.map(|b| self.verify_bound_to_region_test(b))
|
||||
.collect(),
|
||||
),
|
||||
|
||||
VerifyBound::AllBounds(bounds) => RegionTest::All(
|
||||
bounds
|
||||
.iter()
|
||||
.map(|b| self.verify_bound_to_region_test(b))
|
||||
.collect(),
|
||||
),
|
||||
verify_bound,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,31 +17,31 @@ use borrow_check::nll::constraints::{ConstraintCategory, ConstraintSet, Outlives
|
|||
use borrow_check::nll::facts::AllFacts;
|
||||
use borrow_check::nll::region_infer::values::{LivenessValues, RegionValueElements};
|
||||
use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
|
||||
use borrow_check::nll::renumber;
|
||||
use borrow_check::nll::type_check::free_region_relations::{
|
||||
CreateResult, UniversalRegionRelations,
|
||||
};
|
||||
use borrow_check::nll::universal_regions::UniversalRegions;
|
||||
use borrow_check::nll::ToRegionVid;
|
||||
use borrow_check::nll::renumber;
|
||||
use dataflow::move_paths::MoveData;
|
||||
use dataflow::FlowAtLocation;
|
||||
use dataflow::MaybeInitializedPlaces;
|
||||
use rustc::hir;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::infer::canonical::QueryRegionConstraint;
|
||||
use rustc::infer::region_constraints::GenericKind;
|
||||
use rustc::infer::outlives::env::RegionBoundPairs;
|
||||
use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
||||
use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
|
||||
use rustc::mir::tcx::PlaceTy;
|
||||
use rustc::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc::mir::*;
|
||||
use rustc::traits::{ObligationCause, PredicateObligations};
|
||||
use rustc::traits::query::type_op;
|
||||
use rustc::traits::query::type_op::custom::CustomTypeOp;
|
||||
use rustc::traits::query::{Fallible, NoSolution};
|
||||
use rustc::traits::{ObligationCause, PredicateObligations};
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
@ -161,11 +161,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
|
|||
Some(&mut borrowck_context),
|
||||
Some(&universal_region_relations),
|
||||
|cx| {
|
||||
cx.equate_inputs_and_outputs(
|
||||
mir,
|
||||
universal_regions,
|
||||
&normalized_inputs_and_output,
|
||||
);
|
||||
cx.equate_inputs_and_outputs(mir, universal_regions, &normalized_inputs_and_output);
|
||||
liveness::generate(cx, mir, elements, flow_inits, move_data);
|
||||
},
|
||||
);
|
||||
|
@ -182,7 +178,7 @@ fn type_check_internal<'a, 'gcx, 'tcx, R>(
|
|||
mir_def_id: DefId,
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
mir: &'a Mir<'tcx>,
|
||||
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
|
||||
universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>,
|
||||
|
@ -377,14 +373,12 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
|||
|
||||
debug!("sanitize_constant: expected_ty={:?}", constant.literal.ty);
|
||||
|
||||
if let Err(terr) = self.cx
|
||||
.eq_types(
|
||||
constant.literal.ty,
|
||||
constant.ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
)
|
||||
{
|
||||
if let Err(terr) = self.cx.eq_types(
|
||||
constant.literal.ty,
|
||||
constant.ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
constant,
|
||||
|
@ -429,12 +423,10 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
|||
let sty = self.sanitize_type(place, sty);
|
||||
let ty = self.tcx().type_of(def_id);
|
||||
let ty = self.cx.normalize(ty, location);
|
||||
if let Err(terr) = self.cx.eq_types(
|
||||
ty,
|
||||
sty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
) {
|
||||
if let Err(terr) =
|
||||
self.cx
|
||||
.eq_types(ty, sty, location.to_locations(), ConstraintCategory::Boring)
|
||||
{
|
||||
span_mirbug!(
|
||||
self,
|
||||
place,
|
||||
|
@ -693,7 +685,7 @@ struct TypeChecker<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
|||
last_span: Span,
|
||||
mir: &'a Mir<'tcx>,
|
||||
mir_def_id: DefId,
|
||||
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
|
||||
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
|
||||
|
@ -802,7 +794,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
mir: &'a Mir<'tcx>,
|
||||
mir_def_id: DefId,
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
|
||||
universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>,
|
||||
|
@ -955,66 +947,55 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
let tcx = infcx.tcx;
|
||||
let param_env = self.param_env;
|
||||
let parent_def_id = infcx.tcx.closure_base_def_id(self.mir_def_id);
|
||||
let opaque_type_map =
|
||||
self.fully_perform_op(
|
||||
locations,
|
||||
category,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
let mut obligations = ObligationAccumulator::default();
|
||||
let opaque_type_map = self.fully_perform_op(
|
||||
locations,
|
||||
category,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
let mut obligations = ObligationAccumulator::default();
|
||||
|
||||
let dummy_body_id = ObligationCause::dummy().body_id;
|
||||
let (output_ty, opaque_type_map) =
|
||||
obligations.add(infcx.instantiate_opaque_types(
|
||||
parent_def_id,
|
||||
dummy_body_id,
|
||||
param_env,
|
||||
&anon_ty,
|
||||
));
|
||||
let dummy_body_id = ObligationCause::dummy().body_id;
|
||||
let (output_ty, opaque_type_map) =
|
||||
obligations.add(infcx.instantiate_opaque_types(
|
||||
parent_def_id,
|
||||
dummy_body_id,
|
||||
param_env,
|
||||
&anon_ty,
|
||||
));
|
||||
debug!(
|
||||
"eq_opaque_type_and_type: \
|
||||
instantiated output_ty={:?} \
|
||||
opaque_type_map={:#?} \
|
||||
revealed_ty={:?}",
|
||||
output_ty, opaque_type_map, revealed_ty
|
||||
);
|
||||
obligations.add(infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq(output_ty, revealed_ty)?);
|
||||
|
||||
for (&opaque_def_id, opaque_decl) in &opaque_type_map {
|
||||
let opaque_defn_ty = tcx.type_of(opaque_def_id);
|
||||
let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs);
|
||||
let opaque_defn_ty = renumber::renumber_regions(infcx, &opaque_defn_ty);
|
||||
debug!(
|
||||
"eq_opaque_type_and_type: \
|
||||
instantiated output_ty={:?} \
|
||||
opaque_type_map={:#?} \
|
||||
revealed_ty={:?}",
|
||||
output_ty,
|
||||
opaque_type_map,
|
||||
revealed_ty
|
||||
);
|
||||
obligations.add(
|
||||
infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq(output_ty, revealed_ty)?,
|
||||
"eq_opaque_type_and_type: concrete_ty={:?} opaque_defn_ty={:?}",
|
||||
opaque_decl.concrete_ty, opaque_defn_ty
|
||||
);
|
||||
obligations.add(infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq(opaque_decl.concrete_ty, opaque_defn_ty)?);
|
||||
}
|
||||
|
||||
for (&opaque_def_id, opaque_decl) in &opaque_type_map {
|
||||
let opaque_defn_ty = tcx.type_of(opaque_def_id);
|
||||
let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs);
|
||||
let opaque_defn_ty = renumber::renumber_regions(
|
||||
infcx,
|
||||
&opaque_defn_ty,
|
||||
);
|
||||
debug!(
|
||||
"eq_opaque_type_and_type: concrete_ty={:?} opaque_defn_ty={:?}",
|
||||
opaque_decl.concrete_ty,
|
||||
opaque_defn_ty
|
||||
);
|
||||
obligations.add(
|
||||
infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq(opaque_decl.concrete_ty, opaque_defn_ty)?,
|
||||
);
|
||||
}
|
||||
debug!("eq_opaque_type_and_type: equated");
|
||||
|
||||
debug!("eq_opaque_type_and_type: equated");
|
||||
|
||||
Ok(InferOk {
|
||||
value: Some(opaque_type_map),
|
||||
obligations: obligations.into_vec(),
|
||||
})
|
||||
},
|
||||
|| "input_output".to_string(),
|
||||
),
|
||||
)?;
|
||||
Ok(InferOk {
|
||||
value: Some(opaque_type_map),
|
||||
obligations: obligations.into_vec(),
|
||||
})
|
||||
},
|
||||
|| "input_output".to_string(),
|
||||
),
|
||||
)?;
|
||||
|
||||
let universal_region_relations = match self.universal_region_relations {
|
||||
Some(rel) => rel,
|
||||
|
@ -1035,7 +1016,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
infcx.constrain_opaque_type(
|
||||
opaque_def_id,
|
||||
&opaque_decl,
|
||||
universal_region_relations
|
||||
universal_region_relations,
|
||||
);
|
||||
Ok(InferOk {
|
||||
value: (),
|
||||
|
@ -1073,12 +1054,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
|
||||
let place_ty = place.ty(mir, tcx).to_ty(tcx);
|
||||
let rv_ty = rv.ty(mir, tcx);
|
||||
if let Err(terr) = self.sub_types_or_anon(
|
||||
rv_ty,
|
||||
place_ty,
|
||||
location.to_locations(),
|
||||
category,
|
||||
) {
|
||||
if let Err(terr) =
|
||||
self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category)
|
||||
{
|
||||
span_mirbug!(
|
||||
self,
|
||||
stmt,
|
||||
|
@ -1117,7 +1095,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
self.prove_trait_ref(
|
||||
trait_ref,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::SizedBound,
|
||||
ConstraintCategory::SizedBound,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1148,15 +1126,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
StatementKind::AscribeUserType(ref place, variance, c_ty) => {
|
||||
let place_ty = place.ty(mir, tcx).to_ty(tcx);
|
||||
if let Err(terr) =
|
||||
self.relate_type_and_user_type(
|
||||
place_ty,
|
||||
variance,
|
||||
c_ty,
|
||||
Locations::All(stmt.source_info.span),
|
||||
ConstraintCategory::TypeAnnotation,
|
||||
)
|
||||
{
|
||||
if let Err(terr) = self.relate_type_and_user_type(
|
||||
place_ty,
|
||||
variance,
|
||||
c_ty,
|
||||
Locations::All(stmt.source_info.span),
|
||||
ConstraintCategory::TypeAnnotation,
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
stmt,
|
||||
|
@ -1208,12 +1184,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
let rv_ty = value.ty(mir, tcx);
|
||||
|
||||
let locations = term_location.to_locations();
|
||||
if let Err(terr) = self.sub_types(
|
||||
rv_ty,
|
||||
place_ty,
|
||||
locations,
|
||||
ConstraintCategory::Assignment,
|
||||
) {
|
||||
if let Err(terr) =
|
||||
self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment)
|
||||
{
|
||||
span_mirbug!(
|
||||
self,
|
||||
term,
|
||||
|
@ -1327,8 +1300,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
ty,
|
||||
term_location.to_locations(),
|
||||
ConstraintCategory::Return,
|
||||
)
|
||||
{
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
term,
|
||||
|
@ -1366,12 +1338,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
|
||||
let locations = term_location.to_locations();
|
||||
|
||||
if let Err(terr) = self.sub_types_or_anon(
|
||||
sig.output(),
|
||||
dest_ty,
|
||||
locations,
|
||||
category,
|
||||
) {
|
||||
if let Err(terr) =
|
||||
self.sub_types_or_anon(sig.output(), dest_ty, locations, category)
|
||||
{
|
||||
span_mirbug!(
|
||||
self,
|
||||
term,
|
||||
|
@ -1539,12 +1508,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_local(
|
||||
&mut self,
|
||||
mir: &Mir<'tcx>,
|
||||
local: Local,
|
||||
local_decl: &LocalDecl<'tcx>,
|
||||
) {
|
||||
fn check_local(&mut self, mir: &Mir<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) {
|
||||
match mir.local_kind(local) {
|
||||
LocalKind::ReturnPointer | LocalKind::Arg => {
|
||||
// return values of normal functions are required to be
|
||||
|
@ -1713,13 +1677,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
ConstraintCategory::Cast,
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
"equating {:?} with {:?} yields {:?}",
|
||||
ty_fn_ptr_from,
|
||||
ty,
|
||||
terr
|
||||
);
|
||||
self,
|
||||
rvalue,
|
||||
"equating {:?} with {:?} yields {:?}",
|
||||
ty_fn_ptr_from,
|
||||
ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1739,13 +1703,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
ConstraintCategory::Cast,
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
"equating {:?} with {:?} yields {:?}",
|
||||
ty_fn_ptr_from,
|
||||
ty,
|
||||
terr
|
||||
);
|
||||
self,
|
||||
rvalue,
|
||||
"equating {:?} with {:?} yields {:?}",
|
||||
ty_fn_ptr_from,
|
||||
ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1768,13 +1732,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
ConstraintCategory::Cast,
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
"equating {:?} with {:?} yields {:?}",
|
||||
ty_fn_ptr_from,
|
||||
ty,
|
||||
terr
|
||||
);
|
||||
self,
|
||||
rvalue,
|
||||
"equating {:?} with {:?} yields {:?}",
|
||||
ty_fn_ptr_from,
|
||||
ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2232,7 +2196,7 @@ impl MirPass for TypeckMir {
|
|||
def_id,
|
||||
param_env,
|
||||
mir,
|
||||
&[],
|
||||
&vec![],
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
|
@ -2277,4 +2241,3 @@ impl<'tcx> ObligationAccumulator<'tcx> {
|
|||
self.obligations
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,15 +10,13 @@
|
|||
|
||||
use borrow_check::nll::constraints::{ConstraintCategory, OutlivesConstraint};
|
||||
use borrow_check::nll::type_check::{BorrowCheckContext, Locations};
|
||||
use borrow_check::nll::universal_regions::UniversalRegions;
|
||||
use borrow_check::nll::ToRegionVid;
|
||||
use rustc::infer::canonical::{Canonical, CanonicalVarInfos};
|
||||
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
|
||||
use rustc::traits::query::Fallible;
|
||||
use rustc::ty::fold::{TypeFoldable, TypeVisitor};
|
||||
use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
||||
use rustc::ty::subst::Kind;
|
||||
use rustc::ty::{self, CanonicalTy, CanonicalVar, RegionVid, Ty, TyCtxt};
|
||||
use rustc::ty::{self, CanonicalTy, CanonicalVar, Ty, TyCtxt};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
|
||||
|
@ -33,11 +31,9 @@ pub(super) fn sub_types<'tcx>(
|
|||
) -> Fallible<()> {
|
||||
debug!("sub_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
|
||||
TypeRelating::new(
|
||||
infcx,
|
||||
infcx.tcx,
|
||||
NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
|
||||
ty::Variance::Covariant,
|
||||
locations,
|
||||
category,
|
||||
borrowck_context,
|
||||
ty::List::empty(),
|
||||
).relate(&a, &b)?;
|
||||
Ok(())
|
||||
|
@ -54,11 +50,9 @@ pub(super) fn eq_types<'tcx>(
|
|||
) -> Fallible<()> {
|
||||
debug!("eq_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
|
||||
TypeRelating::new(
|
||||
infcx,
|
||||
infcx.tcx,
|
||||
NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
|
||||
ty::Variance::Invariant,
|
||||
locations,
|
||||
category,
|
||||
borrowck_context,
|
||||
ty::List::empty(),
|
||||
).relate(&a, &b)?;
|
||||
Ok(())
|
||||
|
@ -91,18 +85,22 @@ pub(super) fn relate_type_and_user_type<'tcx>(
|
|||
let v1 = ty::Contravariant.xform(v);
|
||||
|
||||
TypeRelating::new(
|
||||
infcx,
|
||||
infcx.tcx,
|
||||
NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
|
||||
v1,
|
||||
locations,
|
||||
category,
|
||||
borrowck_context,
|
||||
b_variables,
|
||||
).relate(&b_value, &a)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct TypeRelating<'cx, 'bccx: 'cx, 'gcx: 'tcx, 'tcx: 'bccx> {
|
||||
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
struct TypeRelating<'me, 'gcx: 'tcx, 'tcx: 'me, D>
|
||||
where
|
||||
D: TypeRelatingDelegate<'tcx>,
|
||||
{
|
||||
tcx: TyCtxt<'me, 'gcx, 'tcx>,
|
||||
|
||||
/// Callback to use when we deduce an outlives relationship
|
||||
delegate: D,
|
||||
|
||||
/// How are we relating `a` and `b`?
|
||||
///
|
||||
|
@ -122,19 +120,10 @@ struct TypeRelating<'cx, 'bccx: 'cx, 'gcx: 'tcx, 'tcx: 'bccx> {
|
|||
///
|
||||
/// This field stores the instantiations for late-bound regions in
|
||||
/// the `a` type.
|
||||
a_scopes: Vec<BoundRegionScope>,
|
||||
a_scopes: Vec<BoundRegionScope<'tcx>>,
|
||||
|
||||
/// Same as `a_scopes`, but for the `b` type.
|
||||
b_scopes: Vec<BoundRegionScope>,
|
||||
|
||||
/// Where (and why) is this relation taking place?
|
||||
locations: Locations,
|
||||
|
||||
category: ConstraintCategory,
|
||||
|
||||
/// This will be `Some` when we are running the type check as part
|
||||
/// of NLL, and `None` if we are running a "sanity check".
|
||||
borrowck_context: Option<&'cx mut BorrowCheckContext<'bccx, 'tcx>>,
|
||||
b_scopes: Vec<BoundRegionScope<'tcx>>,
|
||||
|
||||
/// As we execute, the type on the LHS *may* come from a canonical
|
||||
/// source. In that case, we will sometimes find a constraint like
|
||||
|
@ -150,37 +139,130 @@ struct TypeRelating<'cx, 'bccx: 'cx, 'gcx: 'tcx, 'tcx: 'bccx> {
|
|||
canonical_var_values: IndexVec<CanonicalVar, Option<Kind<'tcx>>>,
|
||||
}
|
||||
|
||||
trait TypeRelatingDelegate<'tcx> {
|
||||
/// Push a constraint `sup: sub` -- this constraint must be
|
||||
/// satisfied for the two types to be related. `sub` and `sup` may
|
||||
/// be regions from the type or new variables created through the
|
||||
/// delegate.
|
||||
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
|
||||
|
||||
/// Creates a new region variable representing an instantiated
|
||||
/// higher-ranked region; this will be either existential or
|
||||
/// universal depending on the context. So e.g. if you have
|
||||
/// `for<'a> fn(..) <: for<'b> fn(..)`, then we will first
|
||||
/// instantiate `'b` with a universally quantitifed region and
|
||||
/// then `'a` with an existentially quantified region (the order
|
||||
/// is important so that the existential region `'a` can see the
|
||||
/// universal one).
|
||||
fn next_region_var(
|
||||
&mut self,
|
||||
universally_quantified: UniversallyQuantified,
|
||||
) -> ty::Region<'tcx>;
|
||||
|
||||
/// Creates a new existential region in the given universe. This
|
||||
/// is used when handling subtyping and type variables -- if we
|
||||
/// have that `?X <: Foo<'a>`, for example, we would instantiate
|
||||
/// `?X` with a type like `Foo<'?0>` where `'?0` is a fresh
|
||||
/// existential variable created by this function. We would then
|
||||
/// relate `Foo<'?0>` with `Foo<'a>` (and probably add an outlives
|
||||
/// relation stating that `'?0: 'a`).
|
||||
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>;
|
||||
}
|
||||
|
||||
struct NllTypeRelatingDelegate<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> {
|
||||
infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
|
||||
borrowck_context: Option<&'me mut BorrowCheckContext<'bccx, 'tcx>>,
|
||||
|
||||
/// Where (and why) is this relation taking place?
|
||||
locations: Locations,
|
||||
|
||||
/// What category do we assign the resulting `'a: 'b` relationships?
|
||||
category: ConstraintCategory,
|
||||
}
|
||||
|
||||
impl NllTypeRelatingDelegate<'me, 'bccx, 'gcx, 'tcx> {
|
||||
fn new(
|
||||
infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
|
||||
borrowck_context: Option<&'me mut BorrowCheckContext<'bccx, 'tcx>>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
) -> Self {
|
||||
Self {
|
||||
infcx,
|
||||
borrowck_context,
|
||||
locations,
|
||||
category,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, '_, 'tcx> {
|
||||
fn next_region_var(
|
||||
&mut self,
|
||||
universally_quantified: UniversallyQuantified,
|
||||
) -> ty::Region<'tcx> {
|
||||
let origin = if universally_quantified.0 {
|
||||
NLLRegionVariableOrigin::BoundRegion(self.infcx.create_subuniverse())
|
||||
} else {
|
||||
NLLRegionVariableOrigin::Existential
|
||||
};
|
||||
self.infcx.next_nll_region_var(origin)
|
||||
}
|
||||
|
||||
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
|
||||
self.infcx
|
||||
.next_nll_region_var_in_universe(NLLRegionVariableOrigin::Existential, universe)
|
||||
}
|
||||
|
||||
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
|
||||
if let Some(borrowck_context) = &mut self.borrowck_context {
|
||||
let sub = borrowck_context.universal_regions.to_region_vid(sub);
|
||||
let sup = borrowck_context.universal_regions.to_region_vid(sup);
|
||||
borrowck_context
|
||||
.constraints
|
||||
.outlives_constraints
|
||||
.push(OutlivesConstraint {
|
||||
sup,
|
||||
sub,
|
||||
locations: self.locations,
|
||||
category: self.category,
|
||||
});
|
||||
|
||||
// FIXME all facts!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct ScopesAndKind<'tcx> {
|
||||
scopes: Vec<BoundRegionScope>,
|
||||
scopes: Vec<BoundRegionScope<'tcx>>,
|
||||
kind: Kind<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct BoundRegionScope {
|
||||
map: FxHashMap<ty::BoundRegion, RegionVid>,
|
||||
struct BoundRegionScope<'tcx> {
|
||||
map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct UniversallyQuantified(bool);
|
||||
|
||||
impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
|
||||
impl<'me, 'gcx, 'tcx, D> TypeRelating<'me, 'gcx, 'tcx, D>
|
||||
where
|
||||
D: TypeRelatingDelegate<'tcx>,
|
||||
{
|
||||
fn new(
|
||||
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
tcx: TyCtxt<'me, 'gcx, 'tcx>,
|
||||
delegate: D,
|
||||
ambient_variance: ty::Variance,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
borrowck_context: Option<&'cx mut BorrowCheckContext<'bccx, 'tcx>>,
|
||||
canonical_var_infos: CanonicalVarInfos<'tcx>,
|
||||
) -> Self {
|
||||
let canonical_var_values = IndexVec::from_elem_n(None, canonical_var_infos.len());
|
||||
Self {
|
||||
infcx,
|
||||
tcx,
|
||||
delegate,
|
||||
ambient_variance,
|
||||
borrowck_context,
|
||||
locations,
|
||||
canonical_var_values,
|
||||
category,
|
||||
a_scopes: vec![],
|
||||
b_scopes: vec![],
|
||||
}
|
||||
|
@ -204,10 +286,10 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
|
|||
&mut self,
|
||||
value: &ty::Binder<impl TypeFoldable<'tcx>>,
|
||||
universally_quantified: UniversallyQuantified,
|
||||
) -> BoundRegionScope {
|
||||
) -> BoundRegionScope<'tcx> {
|
||||
let mut scope = BoundRegionScope::default();
|
||||
value.skip_binder().visit_with(&mut ScopeInstantiator {
|
||||
infcx: self.infcx,
|
||||
delegate: &mut self.delegate,
|
||||
target_index: ty::INNERMOST,
|
||||
universally_quantified,
|
||||
bound_region_scope: &mut scope,
|
||||
|
@ -227,8 +309,8 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
|
|||
debruijn: ty::DebruijnIndex,
|
||||
br: &ty::BoundRegion,
|
||||
first_free_index: ty::DebruijnIndex,
|
||||
scopes: &[BoundRegionScope],
|
||||
) -> RegionVid {
|
||||
scopes: &[BoundRegionScope<'tcx>],
|
||||
) -> ty::Region<'tcx> {
|
||||
// The debruijn index is a "reverse index" into the
|
||||
// scopes listing. So when we have INNERMOST (0), we
|
||||
// want the *last* scope pushed, and so forth.
|
||||
|
@ -245,40 +327,23 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
|
|||
/// with. Otherwise just return `r`.
|
||||
fn replace_bound_region(
|
||||
&self,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
r: ty::Region<'tcx>,
|
||||
first_free_index: ty::DebruijnIndex,
|
||||
scopes: &[BoundRegionScope],
|
||||
) -> RegionVid {
|
||||
match r {
|
||||
ty::ReLateBound(debruijn, br) => {
|
||||
Self::lookup_bound_region(*debruijn, br, first_free_index, scopes)
|
||||
}
|
||||
|
||||
ty::ReVar(v) => *v,
|
||||
|
||||
_ => universal_regions.to_region_vid(r),
|
||||
scopes: &[BoundRegionScope<'tcx>],
|
||||
) -> ty::Region<'tcx> {
|
||||
if let ty::ReLateBound(debruijn, br) = r {
|
||||
Self::lookup_bound_region(*debruijn, br, first_free_index, scopes)
|
||||
} else {
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
/// Push a new outlives requirement into our output set of
|
||||
/// constraints.
|
||||
fn push_outlives(&mut self, sup: RegionVid, sub: RegionVid) {
|
||||
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
|
||||
debug!("push_outlives({:?}: {:?})", sup, sub);
|
||||
|
||||
if let Some(borrowck_context) = &mut self.borrowck_context {
|
||||
borrowck_context
|
||||
.constraints
|
||||
.outlives_constraints
|
||||
.push(OutlivesConstraint {
|
||||
sup,
|
||||
sub,
|
||||
locations: self.locations,
|
||||
category: self.category,
|
||||
});
|
||||
|
||||
// FIXME all facts!
|
||||
}
|
||||
self.delegate.push_outlives(sup, sub);
|
||||
}
|
||||
|
||||
/// When we encounter a canonical variable `var` in the output,
|
||||
|
@ -316,12 +381,10 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
|
|||
return result;
|
||||
}
|
||||
|
||||
fn generalize_value(
|
||||
&self,
|
||||
kind: Kind<'tcx>,
|
||||
) -> Kind<'tcx> {
|
||||
fn generalize_value(&mut self, kind: Kind<'tcx>) -> Kind<'tcx> {
|
||||
TypeGeneralizer {
|
||||
type_rel: self,
|
||||
tcx: self.tcx,
|
||||
delegate: &mut self.delegate,
|
||||
first_free_index: ty::INNERMOST,
|
||||
ambient_variance: self.ambient_variance,
|
||||
|
||||
|
@ -333,11 +396,12 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
|
||||
for TypeRelating<'cx, 'bccx, 'gcx, 'tcx>
|
||||
impl<D> TypeRelation<'me, 'gcx, 'tcx> for TypeRelating<'me, 'gcx, 'tcx, D>
|
||||
where
|
||||
D: TypeRelatingDelegate<'tcx>,
|
||||
{
|
||||
fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
|
||||
self.infcx.tcx
|
||||
fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn tag(&self) -> &'static str {
|
||||
|
@ -397,37 +461,30 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
|
|||
a: ty::Region<'tcx>,
|
||||
b: ty::Region<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
||||
if let Some(&mut BorrowCheckContext {
|
||||
universal_regions, ..
|
||||
}) = self.borrowck_context
|
||||
{
|
||||
if let ty::ReCanonical(var) = a {
|
||||
self.relate_var(*var, b.into())?;
|
||||
return Ok(a);
|
||||
}
|
||||
if let ty::ReCanonical(var) = a {
|
||||
self.relate_var(*var, b.into())?;
|
||||
return Ok(a);
|
||||
}
|
||||
|
||||
debug!(
|
||||
"regions(a={:?}, b={:?}, variance={:?})",
|
||||
a, b, self.ambient_variance
|
||||
);
|
||||
debug!(
|
||||
"regions(a={:?}, b={:?}, variance={:?})",
|
||||
a, b, self.ambient_variance
|
||||
);
|
||||
|
||||
let v_a =
|
||||
self.replace_bound_region(universal_regions, a, ty::INNERMOST, &self.a_scopes);
|
||||
let v_b =
|
||||
self.replace_bound_region(universal_regions, b, ty::INNERMOST, &self.b_scopes);
|
||||
let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes);
|
||||
let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes);
|
||||
|
||||
debug!("regions: v_a = {:?}", v_a);
|
||||
debug!("regions: v_b = {:?}", v_b);
|
||||
debug!("regions: v_a = {:?}", v_a);
|
||||
debug!("regions: v_b = {:?}", v_b);
|
||||
|
||||
if self.ambient_covariance() {
|
||||
// Covariance: a <= b. Hence, `b: a`.
|
||||
self.push_outlives(v_b, v_a);
|
||||
}
|
||||
if self.ambient_covariance() {
|
||||
// Covariance: a <= b. Hence, `b: a`.
|
||||
self.push_outlives(v_b, v_a);
|
||||
}
|
||||
|
||||
if self.ambient_contravariance() {
|
||||
// Contravariant: b <= a. Hence, `a: b`.
|
||||
self.push_outlives(v_a, v_b);
|
||||
}
|
||||
if self.ambient_contravariance() {
|
||||
// Contravariant: b <= a. Hence, `a: b`.
|
||||
self.push_outlives(v_a, v_b);
|
||||
}
|
||||
|
||||
Ok(a)
|
||||
|
@ -527,10 +584,8 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
|
|||
|
||||
// Reset ambient variance to contravariance. See the
|
||||
// covariant case above for an explanation.
|
||||
let variance = ::std::mem::replace(
|
||||
&mut self.ambient_variance,
|
||||
ty::Variance::Contravariant,
|
||||
);
|
||||
let variance =
|
||||
::std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
|
||||
|
||||
self.relate(a.skip_binder(), b.skip_binder())?;
|
||||
|
||||
|
@ -551,15 +606,21 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
|
|||
/// binder depth, and finds late-bound regions targeting the
|
||||
/// `for<..`>. For each of those, it creates an entry in
|
||||
/// `bound_region_scope`.
|
||||
struct ScopeInstantiator<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
|
||||
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
struct ScopeInstantiator<'me, 'tcx: 'me, D>
|
||||
where
|
||||
D: TypeRelatingDelegate<'tcx> + 'me,
|
||||
{
|
||||
delegate: &'me mut D,
|
||||
// The debruijn index of the scope we are instantiating.
|
||||
target_index: ty::DebruijnIndex,
|
||||
universally_quantified: UniversallyQuantified,
|
||||
bound_region_scope: &'cx mut BoundRegionScope,
|
||||
bound_region_scope: &'me mut BoundRegionScope<'tcx>,
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'cx, 'gcx, 'tcx> {
|
||||
impl<'me, 'tcx, D> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx, D>
|
||||
where
|
||||
D: TypeRelatingDelegate<'tcx>,
|
||||
{
|
||||
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
|
||||
self.target_index.shift_in(1);
|
||||
t.super_visit_with(self);
|
||||
|
@ -570,21 +631,18 @@ impl<'cx, 'gcx, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'cx, 'gcx, 'tcx> {
|
|||
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
|
||||
let ScopeInstantiator {
|
||||
infcx,
|
||||
universally_quantified,
|
||||
bound_region_scope,
|
||||
delegate,
|
||||
..
|
||||
} = *self;
|
||||
} = self;
|
||||
|
||||
match r {
|
||||
ty::ReLateBound(debruijn, br) if *debruijn == self.target_index => {
|
||||
self.bound_region_scope.map.entry(*br).or_insert_with(|| {
|
||||
let origin = if universally_quantified.0 {
|
||||
NLLRegionVariableOrigin::BoundRegion(infcx.create_subuniverse())
|
||||
} else {
|
||||
NLLRegionVariableOrigin::Existential
|
||||
};
|
||||
infcx.next_nll_region_var(origin).to_region_vid()
|
||||
});
|
||||
bound_region_scope
|
||||
.map
|
||||
.entry(*br)
|
||||
.or_insert_with(|| delegate.next_region_var(*universally_quantified));
|
||||
}
|
||||
|
||||
_ => {}
|
||||
|
@ -613,8 +671,13 @@ impl<'cx, 'gcx, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'cx, 'gcx, 'tcx> {
|
|||
/// scopes.
|
||||
///
|
||||
/// [blog post]: https://is.gd/0hKvIr
|
||||
struct TypeGeneralizer<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> {
|
||||
type_rel: &'me TypeRelating<'me, 'bccx, 'gcx, 'tcx>,
|
||||
struct TypeGeneralizer<'me, 'gcx: 'tcx, 'tcx: 'me, D>
|
||||
where
|
||||
D: TypeRelatingDelegate<'tcx> + 'me,
|
||||
{
|
||||
tcx: TyCtxt<'me, 'gcx, 'tcx>,
|
||||
|
||||
delegate: &'me mut D,
|
||||
|
||||
/// After we generalize this type, we are going to relative it to
|
||||
/// some other type. What will be the variance at this point?
|
||||
|
@ -625,9 +688,12 @@ struct TypeGeneralizer<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> {
|
|||
universe: ty::UniverseIndex,
|
||||
}
|
||||
|
||||
impl TypeRelation<'me, 'gcx, 'tcx> for TypeGeneralizer<'me, 'bbcx, 'gcx, 'tcx> {
|
||||
impl<D> TypeRelation<'me, 'gcx, 'tcx> for TypeGeneralizer<'me, 'gcx, 'tcx, D>
|
||||
where
|
||||
D: TypeRelatingDelegate<'tcx>,
|
||||
{
|
||||
fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
|
||||
self.type_rel.infcx.tcx
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn tag(&self) -> &'static str {
|
||||
|
@ -710,9 +776,7 @@ impl TypeRelation<'me, 'gcx, 'tcx> for TypeGeneralizer<'me, 'bbcx, 'gcx, 'tcx> {
|
|||
// though, we may however need to check well-formedness or
|
||||
// risk a problem like #41677 again.
|
||||
|
||||
let replacement_region_vid = self.type_rel
|
||||
.infcx
|
||||
.next_nll_region_var_in_universe(NLLRegionVariableOrigin::Existential, self.universe);
|
||||
let replacement_region_vid = self.delegate.generalize_existential(self.universe);
|
||||
|
||||
Ok(replacement_region_vid)
|
||||
}
|
||||
|
|
|
@ -11,12 +11,12 @@
|
|||
use check::regionck::RegionCtxt;
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use rustc::infer::{self, InferOk};
|
||||
use rustc::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc::infer::{self, InferOk, SuppressRegionErrors};
|
||||
use rustc::middle::region;
|
||||
use rustc::traits::{ObligationCause, TraitEngine, TraitEngineExt};
|
||||
use rustc::ty::subst::{Subst, Substs, UnpackedKind};
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::traits::{ObligationCause, TraitEngine, TraitEngineExt};
|
||||
use util::common::ErrorReported;
|
||||
|
||||
use syntax::ast;
|
||||
|
@ -39,32 +39,41 @@ use syntax_pos::Span;
|
|||
/// struct/enum definition for the nominal type itself (i.e.
|
||||
/// cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
|
||||
///
|
||||
pub fn check_drop_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
drop_impl_did: DefId)
|
||||
-> Result<(), ErrorReported> {
|
||||
pub fn check_drop_impl<'a, 'tcx>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
drop_impl_did: DefId,
|
||||
) -> Result<(), ErrorReported> {
|
||||
let dtor_self_type = tcx.type_of(drop_impl_did);
|
||||
let dtor_predicates = tcx.predicates_of(drop_impl_did);
|
||||
match dtor_self_type.sty {
|
||||
ty::Adt(adt_def, self_to_impl_substs) => {
|
||||
ensure_drop_params_and_item_params_correspond(tcx,
|
||||
drop_impl_did,
|
||||
dtor_self_type,
|
||||
adt_def.did)?;
|
||||
ensure_drop_params_and_item_params_correspond(
|
||||
tcx,
|
||||
drop_impl_did,
|
||||
dtor_self_type,
|
||||
adt_def.did,
|
||||
)?;
|
||||
|
||||
ensure_drop_predicates_are_implied_by_item_defn(tcx,
|
||||
drop_impl_did,
|
||||
&dtor_predicates,
|
||||
adt_def.did,
|
||||
self_to_impl_substs)
|
||||
ensure_drop_predicates_are_implied_by_item_defn(
|
||||
tcx,
|
||||
drop_impl_did,
|
||||
&dtor_predicates,
|
||||
adt_def.did,
|
||||
self_to_impl_substs,
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
// Destructors only work on nominal types. This was
|
||||
// already checked by coherence, but compilation may
|
||||
// not have been terminated.
|
||||
let span = tcx.def_span(drop_impl_did);
|
||||
tcx.sess.delay_span_bug(span,
|
||||
&format!("should have been rejected by coherence check: {}",
|
||||
dtor_self_type));
|
||||
tcx.sess.delay_span_bug(
|
||||
span,
|
||||
&format!(
|
||||
"should have been rejected by coherence check: {}",
|
||||
dtor_self_type
|
||||
),
|
||||
);
|
||||
Err(ErrorReported)
|
||||
}
|
||||
}
|
||||
|
@ -74,9 +83,8 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
|
|||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
drop_impl_did: DefId,
|
||||
drop_impl_ty: Ty<'tcx>,
|
||||
self_type_did: DefId)
|
||||
-> Result<(), ErrorReported>
|
||||
{
|
||||
self_type_did: DefId,
|
||||
) -> Result<(), ErrorReported> {
|
||||
let drop_impl_node_id = tcx.hir.as_local_node_id(drop_impl_did).unwrap();
|
||||
|
||||
// check that the impl type can be made to match the trait type.
|
||||
|
@ -89,22 +97,29 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
|
|||
let named_type = tcx.type_of(self_type_did);
|
||||
|
||||
let drop_impl_span = tcx.def_span(drop_impl_did);
|
||||
let fresh_impl_substs =
|
||||
infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did);
|
||||
let fresh_impl_substs = infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did);
|
||||
let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs);
|
||||
|
||||
let cause = &ObligationCause::misc(drop_impl_span, drop_impl_node_id);
|
||||
match infcx.at(cause, impl_param_env).eq(named_type, fresh_impl_self_ty) {
|
||||
match infcx
|
||||
.at(cause, impl_param_env)
|
||||
.eq(named_type, fresh_impl_self_ty)
|
||||
{
|
||||
Ok(InferOk { obligations, .. }) => {
|
||||
fulfillment_cx.register_predicate_obligations(infcx, obligations);
|
||||
}
|
||||
Err(_) => {
|
||||
let item_span = tcx.def_span(self_type_did);
|
||||
struct_span_err!(tcx.sess, drop_impl_span, E0366,
|
||||
"Implementations of Drop cannot be specialized")
|
||||
.span_note(item_span,
|
||||
"Use same sequence of generic type and region \
|
||||
parameters that is on the struct/enum definition")
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
drop_impl_span,
|
||||
E0366,
|
||||
"Implementations of Drop cannot be specialized"
|
||||
).span_note(
|
||||
item_span,
|
||||
"Use same sequence of generic type and region \
|
||||
parameters that is on the struct/enum definition",
|
||||
)
|
||||
.emit();
|
||||
return Err(ErrorReported);
|
||||
}
|
||||
|
@ -128,7 +143,12 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
|
|||
// conservative. -nmatsakis
|
||||
let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty());
|
||||
|
||||
infcx.resolve_regions_and_report_errors(drop_impl_did, ®ion_scope_tree, &outlives_env);
|
||||
infcx.resolve_regions_and_report_errors(
|
||||
drop_impl_did,
|
||||
®ion_scope_tree,
|
||||
&outlives_env,
|
||||
SuppressRegionErrors::default(),
|
||||
);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
@ -140,9 +160,8 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
|
|||
drop_impl_did: DefId,
|
||||
dtor_predicates: &ty::GenericPredicates<'tcx>,
|
||||
self_type_did: DefId,
|
||||
self_to_impl_substs: &Substs<'tcx>)
|
||||
-> Result<(), ErrorReported>
|
||||
{
|
||||
self_to_impl_substs: &Substs<'tcx>,
|
||||
) -> Result<(), ErrorReported> {
|
||||
let mut result = Ok(());
|
||||
|
||||
// Here is an example, analogous to that from
|
||||
|
@ -213,11 +232,17 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
|
|||
|
||||
if !assumptions_in_impl_context.contains(&predicate) {
|
||||
let item_span = tcx.hir.span(self_type_node_id);
|
||||
struct_span_err!(tcx.sess, drop_impl_span, E0367,
|
||||
"The requirement `{}` is added only by the Drop impl.", predicate)
|
||||
.span_note(item_span,
|
||||
"The same requirement must be part of \
|
||||
the struct/enum definition")
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
drop_impl_span,
|
||||
E0367,
|
||||
"The requirement `{}` is added only by the Drop impl.",
|
||||
predicate
|
||||
).span_note(
|
||||
item_span,
|
||||
"The same requirement must be part of \
|
||||
the struct/enum definition",
|
||||
)
|
||||
.emit();
|
||||
result = Err(ErrorReported);
|
||||
}
|
||||
|
@ -283,18 +308,18 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
|
|||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
body_id: ast::NodeId,
|
||||
scope: region::Scope)
|
||||
-> Result<(), ErrorReported>
|
||||
{
|
||||
debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}",
|
||||
ty, scope);
|
||||
|
||||
scope: region::Scope,
|
||||
) -> Result<(), ErrorReported> {
|
||||
debug!(
|
||||
"check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}",
|
||||
ty, scope
|
||||
);
|
||||
|
||||
let parent_scope = match rcx.region_scope_tree.opt_encl_scope(scope) {
|
||||
Some(parent_scope) => parent_scope,
|
||||
// If no enclosing scope, then it must be the root scope
|
||||
// which cannot be outlived.
|
||||
None => return Ok(())
|
||||
None => return Ok(()),
|
||||
};
|
||||
let parent_scope = rcx.tcx.mk_region(ty::ReScope(parent_scope));
|
||||
let origin = || infer::SubregionOrigin::SafeDestructor(span);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -11,6 +11,7 @@
|
|||
//! Check properties that are required by built-in traits and set
|
||||
//! up data structures required by type-checking/codegen.
|
||||
|
||||
use rustc::infer::SuppressRegionErrors;
|
||||
use rustc::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc::middle::region;
|
||||
use rustc::middle::lang_items::UnsizeTraitLangItem;
|
||||
|
@ -396,6 +397,7 @@ pub fn coerce_unsized_info<'a, 'gcx>(gcx: TyCtxt<'a, 'gcx, 'gcx>,
|
|||
impl_did,
|
||||
®ion_scope_tree,
|
||||
&outlives_env,
|
||||
SuppressRegionErrors::default(),
|
||||
);
|
||||
|
||||
CoerceUnsizedInfo {
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
error[E0621]: explicit lifetime required in the type of `value`
|
||||
--> $DIR/issue-16922.rs:14:5
|
||||
|
|
||||
LL | fn foo<T: Any>(value: &T) -> Box<Any> {
|
||||
| -- help: add explicit lifetime `'static` to the type of `value`: `&'static T`
|
||||
LL | Box::new(value) as Box<Any>
|
||||
| ^^^^^^^^^^^^^^^ lifetime `'static` required
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0621`.
|
|
@ -4,7 +4,7 @@ error[E0621]: explicit lifetime required in the type of `value`
|
|||
LL | fn foo<T: Any>(value: &T) -> Box<Any> {
|
||||
| -- help: add explicit lifetime `'static` to the type of `value`: `&'static T`
|
||||
LL | Box::new(value) as Box<Any>
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required
|
||||
| ^^^^^^^^^^^^^^^ lifetime `'static` required
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
91
src/test/ui/nll/ty-outlives/issue-53789-1.rs
Normal file
91
src/test/ui/nll/ty-outlives/issue-53789-1.rs
Normal file
|
@ -0,0 +1,91 @@
|
|||
// Regression test for #53789.
|
||||
//
|
||||
// compile-pass
|
||||
|
||||
#![feature(nll)]
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
trait ValueTree {
|
||||
type Value;
|
||||
}
|
||||
|
||||
trait Strategy {
|
||||
type Value: ValueTree;
|
||||
}
|
||||
|
||||
type StrategyFor<A> = StrategyType<'static, A>;
|
||||
type StrategyType<'a, A> = <A as Arbitrary<'a>>::Strategy;
|
||||
|
||||
impl<K: ValueTree, V: ValueTree> Strategy for (K, V) {
|
||||
type Value = TupleValueTree<(K, V)>;
|
||||
}
|
||||
|
||||
impl<K: ValueTree, V: ValueTree> ValueTree for TupleValueTree<(K, V)> {
|
||||
type Value = BTreeMapValueTree<K, V>;
|
||||
}
|
||||
|
||||
struct TupleValueTree<T> {
|
||||
tree: T,
|
||||
}
|
||||
|
||||
struct BTreeMapStrategy<K, V>(std::marker::PhantomData<(K, V)>)
|
||||
where
|
||||
K: Strategy,
|
||||
V: Strategy;
|
||||
|
||||
struct BTreeMapValueTree<K, V>(std::marker::PhantomData<(K, V)>)
|
||||
where
|
||||
K: ValueTree,
|
||||
V: ValueTree;
|
||||
|
||||
impl<K, V> Strategy for BTreeMapStrategy<K, V>
|
||||
where
|
||||
K: Strategy,
|
||||
V: Strategy,
|
||||
{
|
||||
type Value = BTreeMapValueTree<K::Value, V::Value>;
|
||||
}
|
||||
|
||||
impl<K, V> ValueTree for BTreeMapValueTree<K, V>
|
||||
where
|
||||
K: ValueTree,
|
||||
V: ValueTree,
|
||||
{
|
||||
type Value = BTreeMap<K::Value, V::Value>;
|
||||
}
|
||||
|
||||
trait Arbitrary<'a>: Sized {
|
||||
fn arbitrary_with(args: Self::Parameters) -> Self::Strategy;
|
||||
type Parameters;
|
||||
type Strategy: Strategy<Value = Self::ValueTree>;
|
||||
type ValueTree: ValueTree<Value = Self>;
|
||||
}
|
||||
|
||||
impl<'a, A, B> Arbitrary<'a> for BTreeMap<A, B>
|
||||
where
|
||||
A: Arbitrary<'static>,
|
||||
B: Arbitrary<'static>,
|
||||
StrategyFor<A>: 'static,
|
||||
StrategyFor<B>: 'static,
|
||||
{
|
||||
type ValueTree = <Self::Strategy as Strategy>::Value;
|
||||
type Parameters = (A::Parameters, B::Parameters);
|
||||
type Strategy = BTreeMapStrategy<A::Strategy, B::Strategy>;
|
||||
fn arbitrary_with(args: Self::Parameters) -> BTreeMapStrategy<A::Strategy, B::Strategy> {
|
||||
let (a, b) = args;
|
||||
btree_map(any_with::<A>(a), any_with::<B>(b))
|
||||
}
|
||||
}
|
||||
|
||||
fn btree_map<K: Strategy + 'static, V: Strategy>(key: K, value: V) -> BTreeMapStrategy<K, V> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn any_with<'a, A: Arbitrary<'a>>(args: A::Parameters) -> StrategyType<'a, A> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
251
src/test/ui/nll/ty-outlives/issue-53789-2.rs
Normal file
251
src/test/ui/nll/ty-outlives/issue-53789-2.rs
Normal file
|
@ -0,0 +1,251 @@
|
|||
// Regression test for #53789.
|
||||
//
|
||||
// compile-pass
|
||||
|
||||
#![feature(nll)]
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::ops::Range;
|
||||
use std::cmp::Ord;
|
||||
|
||||
macro_rules! valuetree {
|
||||
() => {
|
||||
type ValueTree =
|
||||
<Self::Strategy as $crate::Strategy>::Value;
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! product_unpack {
|
||||
($factor: pat) => {
|
||||
($factor,)
|
||||
};
|
||||
($($factor: pat),*) => {
|
||||
( $( $factor ),* )
|
||||
};
|
||||
($($factor: pat),*,) => {
|
||||
( $( $factor ),* )
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! product_type {
|
||||
($factor: ty) => {
|
||||
($factor,)
|
||||
};
|
||||
($($factor: ty),*) => {
|
||||
( $( $factor, )* )
|
||||
};
|
||||
($($factor: ty),*,) => {
|
||||
( $( $factor, )* )
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! default {
|
||||
($type: ty, $val: expr) => {
|
||||
impl Default for $type {
|
||||
fn default() -> Self { $val.into() }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Pervasive internal sugar
|
||||
macro_rules! mapfn {
|
||||
($(#[$meta:meta])* [$($vis:tt)*]
|
||||
fn $name:ident[$($gen:tt)*]($parm:ident: $input:ty) -> $output:ty {
|
||||
$($body:tt)*
|
||||
}) => {
|
||||
$(#[$meta])*
|
||||
#[derive(Clone, Copy)]
|
||||
$($vis)* struct $name;
|
||||
impl $($gen)* statics::MapFn<$input> for $name {
|
||||
type Output = $output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! opaque_strategy_wrapper {
|
||||
($(#[$smeta:meta])* pub struct $stratname:ident
|
||||
[$($sgen:tt)*][$($swhere:tt)*]
|
||||
($innerstrat:ty) -> $stratvtty:ty;
|
||||
|
||||
$(#[$vmeta:meta])* pub struct $vtname:ident
|
||||
[$($vgen:tt)*][$($vwhere:tt)*]
|
||||
($innervt:ty) -> $actualty:ty;
|
||||
) => {
|
||||
$(#[$smeta])* struct $stratname $($sgen)* (std::marker::PhantomData<(K, V)>)
|
||||
$($swhere)*;
|
||||
|
||||
$(#[$vmeta])* struct $vtname $($vgen)* ($innervt) $($vwhere)*;
|
||||
|
||||
impl $($sgen)* Strategy for $stratname $($sgen)* $($swhere)* {
|
||||
type Value = $stratvtty;
|
||||
}
|
||||
|
||||
impl $($vgen)* ValueTree for $vtname $($vgen)* $($vwhere)* {
|
||||
type Value = $actualty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait ValueTree {
|
||||
type Value;
|
||||
}
|
||||
|
||||
trait Strategy {
|
||||
type Value : ValueTree;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct VecStrategy<T : Strategy> {
|
||||
element: T,
|
||||
size: Range<usize>,
|
||||
}
|
||||
|
||||
fn vec<T : Strategy>(element: T, size: Range<usize>)
|
||||
-> VecStrategy<T> {
|
||||
VecStrategy {
|
||||
element: element,
|
||||
size: size,
|
||||
}
|
||||
}
|
||||
|
||||
type ValueFor<S> = <<S as Strategy>::Value as ValueTree>::Value;
|
||||
|
||||
trait Arbitrary<'a>: Sized {
|
||||
fn arbitrary_with(args: Self::Parameters) -> Self::Strategy;
|
||||
|
||||
type Parameters: Default;
|
||||
type Strategy: Strategy<Value = Self::ValueTree>;
|
||||
type ValueTree: ValueTree<Value = Self>;
|
||||
}
|
||||
|
||||
type StrategyFor<A> = StrategyType<'static, A>;
|
||||
type StrategyType<'a, A> = <A as Arbitrary<'a>>::Strategy;
|
||||
|
||||
//#[derive(Clone, PartialEq, Eq, Hash, Debug, From, Into)]
|
||||
struct SizeBounds(Range<usize>);
|
||||
default!(SizeBounds, 0..100);
|
||||
|
||||
|
||||
impl From<Range<usize>> for SizeBounds {
|
||||
fn from(high: Range<usize>) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SizeBounds> for Range<usize> {
|
||||
fn from(high: SizeBounds) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn any_with<'a, A: Arbitrary<'a>>(args: A::Parameters)
|
||||
-> StrategyType<'a, A> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
impl<K: ValueTree, V: ValueTree> Strategy for (K, V) where
|
||||
<K as ValueTree>::Value: Ord {
|
||||
type Value = TupleValueTree<(K, V)>;
|
||||
}
|
||||
|
||||
impl<K: ValueTree, V: ValueTree> ValueTree for TupleValueTree<(K, V)> where
|
||||
<K as ValueTree>::Value: Ord {
|
||||
type Value = BTreeMapValueTree<K, V>;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct VecValueTree<T : ValueTree> {
|
||||
elements: Vec<T>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct TupleValueTree<T> {
|
||||
tree: T,
|
||||
}
|
||||
|
||||
opaque_strategy_wrapper! {
|
||||
#[derive(Clone)]
|
||||
pub struct BTreeMapStrategy[<K, V>]
|
||||
[where K : Strategy, V : Strategy, ValueFor<K> : Ord](
|
||||
statics::Filter<statics::Map<VecStrategy<(K,V)>,
|
||||
VecToBTreeMap>, MinSize>)
|
||||
-> BTreeMapValueTree<K::Value, V::Value>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BTreeMapValueTree[<K, V>]
|
||||
[where K : ValueTree, V : ValueTree, K::Value : Ord](
|
||||
statics::Filter<statics::Map<VecValueTree<TupleValueTree<(K, V)>>,
|
||||
VecToBTreeMap>, MinSize>)
|
||||
-> BTreeMap<K::Value, V::Value>;
|
||||
}
|
||||
|
||||
type RangedParams2<A, B> = product_type![SizeBounds, A, B];
|
||||
|
||||
impl<'a, A, B> Arbitrary<'a> for BTreeMap<A, B>
|
||||
where
|
||||
A: Arbitrary<'static> + Ord,
|
||||
B: Arbitrary<'static>,
|
||||
StrategyFor<A>: 'static,
|
||||
StrategyFor<B>: 'static,
|
||||
{
|
||||
valuetree!();
|
||||
type Parameters = RangedParams2<A::Parameters, B::Parameters>;
|
||||
type Strategy = BTreeMapStrategy<A::Strategy, B::Strategy>;
|
||||
fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
|
||||
let product_unpack![range, a, b] = args;
|
||||
btree_map(any_with::<A>(a), any_with::<B>(b), range.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct MinSize(usize);
|
||||
|
||||
mapfn! {
|
||||
[] fn VecToBTreeMap[<K : Ord, V>]
|
||||
(vec: Vec<(K, V)>) -> BTreeMap<K, V>
|
||||
{
|
||||
vec.into_iter().collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn btree_map<K : Strategy + 'static, V : Strategy + 'static>
|
||||
(key: K, value: V, size: Range<usize>)
|
||||
-> BTreeMapStrategy<K, V>
|
||||
where ValueFor<K> : Ord {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
mod statics {
|
||||
pub(super) trait MapFn<T> {
|
||||
type Output;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Filter<S, F> {
|
||||
source: S,
|
||||
fun: F,
|
||||
}
|
||||
|
||||
impl<S, F> Filter<S, F> {
|
||||
pub fn new(source: S, whence: String, filter: F) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Map<S, F> {
|
||||
source: S,
|
||||
fun: F,
|
||||
}
|
||||
|
||||
impl<S, F> Map<S, F> {
|
||||
pub fn new(source: S, fun: F) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
27
src/test/ui/nll/ty-outlives/projection-body.rs
Normal file
27
src/test/ui/nll/ty-outlives/projection-body.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Test that when we infer the lifetime to a subset of the fn body, it
|
||||
// works out.
|
||||
//
|
||||
// compile-pass
|
||||
|
||||
trait MyTrait<'a> {
|
||||
type Output;
|
||||
}
|
||||
|
||||
fn foo1<T>()
|
||||
where
|
||||
for<'x> T: MyTrait<'x>,
|
||||
{
|
||||
// Here the region `'c` in `<T as MyTrait<'c>>::Output` will be
|
||||
// inferred to a subset of the fn body.
|
||||
let x = bar::<T::Output>();
|
||||
drop(x);
|
||||
}
|
||||
|
||||
fn bar<'a, T>() -> &'a ()
|
||||
where
|
||||
T: 'a,
|
||||
{
|
||||
&()
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -74,19 +74,10 @@ where
|
|||
T: Anything<'b>,
|
||||
T::AssocType: 'a,
|
||||
{
|
||||
// This error is unfortunate. This code ought to type-check: we
|
||||
// are projecting `<T as Anything<'b>>::AssocType`, and we know
|
||||
// that this outlives `'a` because of the where-clause. However,
|
||||
// the way the region checker works, we don't register this
|
||||
// outlives obligation, and hence we get an error: this is because
|
||||
// what we see is a projection like `<T as
|
||||
// Anything<'?0>>::AssocType`, and we don't yet know if `?0` will
|
||||
// equal `'b` or not, so we ignore the where-clause. Obviously we
|
||||
// can do better here with a more involved verification step.
|
||||
// We are projecting `<T as Anything<'b>>::AssocType`, and we know
|
||||
// that this outlives `'a` because of the where-clause.
|
||||
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
//~^ ERROR the parameter type `T` may not live long enough
|
||||
//~| ERROR
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
|
|
|
@ -106,7 +106,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ closure body requires that `'b` must outlive `'a`
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-one-region-closure.rs:87:29
|
||||
--> $DIR/projection-one-region-closure.rs:80:29
|
||||
|
|
||||
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -119,8 +119,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 4
|
||||
= note: where T: '_#3r
|
||||
= note: where '_#2r: '_#3r
|
||||
= note: where <T as Anything<ReClosureBound('_#2r)>>::AssocType: '_#3r
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-closure.rs:72:1
|
||||
|
@ -130,7 +129,7 @@ LL | | where
|
|||
LL | | T: Anything<'b>,
|
||||
LL | | T::AssocType: 'a,
|
||||
... |
|
||||
LL | | //~| ERROR
|
||||
LL | | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
|
@ -140,27 +139,8 @@ LL | | }
|
|||
T
|
||||
]
|
||||
|
||||
error[E0309]: the parameter type `T` may not live long enough
|
||||
--> $DIR/projection-one-region-closure.rs:87:29
|
||||
|
|
||||
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
|
||||
|
||||
error: unsatisfied lifetime constraints
|
||||
--> $DIR/projection-one-region-closure.rs:87:29
|
||||
|
|
||||
LL | fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
| -- -- lifetime `'b` defined here
|
||||
| |
|
||||
| lifetime `'a` defined here
|
||||
...
|
||||
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ closure body requires that `'b` must outlive `'a`
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-one-region-closure.rs:99:29
|
||||
--> $DIR/projection-one-region-closure.rs:90:29
|
||||
|
|
||||
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -177,7 +157,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||
= note: where '_#2r: '_#3r
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-closure.rs:93:1
|
||||
--> $DIR/projection-one-region-closure.rs:84:1
|
||||
|
|
||||
LL | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
LL | | where
|
||||
|
@ -194,6 +174,6 @@ LL | | }
|
|||
T
|
||||
]
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0309`.
|
||||
|
|
|
@ -64,18 +64,10 @@ where
|
|||
T: Anything<'b>,
|
||||
T::AssocType: 'a,
|
||||
{
|
||||
// This error is unfortunate. This code ought to type-check: we
|
||||
// are projecting `<T as Anything<'b>>::AssocType`, and we know
|
||||
// that this outlives `'a` because of the where-clause. However,
|
||||
// the way the region checker works, we don't register this
|
||||
// outlives obligation, and hence we get an error: this is because
|
||||
// what we see is a projection like `<T as
|
||||
// Anything<'?0>>::AssocType`, and we don't yet know if `?0` will
|
||||
// equal `'b` or not, so we ignore the where-clause. Obviously we
|
||||
// can do better here with a more involved verification step.
|
||||
// We are projecting `<T as Anything<'b>>::AssocType`, and we know
|
||||
// that this outlives `'a` because of the where-clause.
|
||||
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
//~^ ERROR
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
|
|
|
@ -88,7 +88,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ closure body requires that `'b` must outlive `'a`
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:77:29
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:70:29
|
||||
|
|
||||
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -101,7 +101,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 4
|
||||
= note: where '_#2r: '_#3r
|
||||
= note: where <T as Anything<ReClosureBound('_#2r)>>::AssocType: '_#3r
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:62:1
|
||||
|
@ -111,7 +111,7 @@ LL | | where
|
|||
LL | | T: Anything<'b>,
|
||||
LL | | T::AssocType: 'a,
|
||||
... |
|
||||
LL | | //~^ ERROR
|
||||
LL | | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
|
@ -121,19 +121,8 @@ LL | | }
|
|||
T
|
||||
]
|
||||
|
||||
error: unsatisfied lifetime constraints
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:77:29
|
||||
|
|
||||
LL | fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
| -- -- lifetime `'b` defined here
|
||||
| |
|
||||
| lifetime `'a` defined here
|
||||
...
|
||||
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ closure body requires that `'b` must outlive `'a`
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:87:29
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:79:29
|
||||
|
|
||||
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -149,7 +138,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||
= note: where '_#2r: '_#3r
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:82:1
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:74:1
|
||||
|
|
||||
LL | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
LL | | where
|
||||
|
@ -167,7 +156,7 @@ LL | | }
|
|||
]
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:99:29
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:91:29
|
||||
|
|
||||
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -182,7 +171,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||
= note: where '_#1r: '_#2r
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:91:1
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:83:1
|
||||
|
|
||||
LL | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
|
||||
LL | | where
|
||||
|
@ -198,5 +187,5 @@ LL | | }
|
|||
T
|
||||
]
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -65,18 +65,10 @@ where
|
|||
T: Anything<'b, 'c>,
|
||||
T::AssocType: 'a,
|
||||
{
|
||||
// This error is unfortunate. This code ought to type-check: we
|
||||
// are projecting `<T as Anything<'b>>::AssocType`, and we know
|
||||
// that this outlives `'a` because of the where-clause. However,
|
||||
// the way the region checker works, we don't register this
|
||||
// outlives obligation, and hence we get an error: this is because
|
||||
// what we see is a projection like `<T as
|
||||
// Anything<'?0>>::AssocType`, and we don't yet know if `?0` will
|
||||
// equal `'b` or not, so we ignore the where-clause. Obviously we
|
||||
// can do better here with a more involved verification step.
|
||||
// We are projecting `<T as Anything<'b>>::AssocType`, and we know
|
||||
// that this outlives `'a` because of the where-clause.
|
||||
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
//~^ ERROR associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
|
|
|
@ -86,7 +86,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||
= help: consider adding an explicit lifetime bound `<T as Anything<'_#6r, '_#7r>>::AssocType: ReEarlyBound(0, 'a)`...
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:78:29
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:71:29
|
||||
|
|
||||
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -110,7 +110,7 @@ LL | | where
|
|||
LL | | T: Anything<'b, 'c>,
|
||||
LL | | T::AssocType: 'a,
|
||||
... |
|
||||
LL | | //~^ ERROR associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough
|
||||
LL | | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
|
@ -121,16 +121,8 @@ LL | | }
|
|||
T
|
||||
]
|
||||
|
||||
error[E0309]: the associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:78:29
|
||||
|
|
||||
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider adding an explicit lifetime bound `<T as Anything<'_#6r, '_#7r>>::AssocType: ReEarlyBound(0, 'a)`...
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:88:29
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:80:29
|
||||
|
|
||||
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -147,7 +139,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:83:1
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:75:1
|
||||
|
|
||||
LL | / fn elements_outlive1<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
|
||||
LL | | where
|
||||
|
@ -166,7 +158,7 @@ LL | | }
|
|||
]
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:97:29
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:89:29
|
||||
|
|
||||
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -183,7 +175,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:92:1
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:84:1
|
||||
|
|
||||
LL | / fn elements_outlive2<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
|
||||
LL | | where
|
||||
|
@ -202,7 +194,7 @@ LL | | }
|
|||
]
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:105:29
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:97:29
|
||||
|
|
||||
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -218,7 +210,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||
= note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:101:1
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:93:1
|
||||
|
|
||||
LL | / fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
LL | | where
|
||||
|
@ -235,7 +227,7 @@ LL | | }
|
|||
]
|
||||
|
||||
error: unsatisfied lifetime constraints
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:105:29
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:97:29
|
||||
|
|
||||
LL | fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
| -- -- lifetime `'b` defined here
|
||||
|
@ -246,7 +238,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ closure body requires that `'b` must outlive `'a`
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:115:29
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:107:29
|
||||
|
|
||||
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -262,7 +254,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#2r)>>::AssocType: '_#3r
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:110:1
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:102:1
|
||||
|
|
||||
LL | / fn two_regions_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
LL | | where
|
||||
|
@ -280,7 +272,7 @@ LL | | }
|
|||
]
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:127:29
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:119:29
|
||||
|
|
||||
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -295,7 +287,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
|||
= note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:119:1
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:111:1
|
||||
|
|
||||
LL | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
|
||||
LL | | where
|
||||
|
@ -311,6 +303,6 @@ LL | | }
|
|||
T
|
||||
]
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0309`.
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
#![feature(nll)]
|
||||
|
||||
// Test that we are able to establish that `<T as
|
||||
// MyTrait<'a>>::Output` outlives `'b` here. We need to prove however
|
||||
// that `<T as MyTrait<'a>>::Output` outlives `'a`, so we also have to
|
||||
// prove that `'b: 'a`.
|
||||
|
||||
trait MyTrait<'a> {
|
||||
type Output;
|
||||
}
|
||||
|
||||
fn foo1<'a, 'b, T>() -> &'a ()
|
||||
where
|
||||
T: MyTrait<'a>,
|
||||
<T as MyTrait<'a>>::Output: 'b,
|
||||
{
|
||||
bar::<T::Output>() //~ ERROR may not live long enough
|
||||
}
|
||||
|
||||
fn foo2<'a, 'b, T>() -> &'a ()
|
||||
where
|
||||
T: MyTrait<'a>,
|
||||
<T as MyTrait<'a>>::Output: 'b,
|
||||
'b: 'a,
|
||||
{
|
||||
bar::<T::Output>() // OK
|
||||
}
|
||||
|
||||
fn bar<'a, T>() -> &'a ()
|
||||
where
|
||||
T: 'a,
|
||||
{
|
||||
&()
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,11 @@
|
|||
error[E0309]: the associated type `<T as MyTrait<'_>>::Output` may not live long enough
|
||||
--> $DIR/projection-where-clause-env-wrong-bound.rs:17:5
|
||||
|
|
||||
LL | bar::<T::Output>() //~ ERROR may not live long enough
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider adding an explicit lifetime bound `<T as MyTrait<'_>>::Output: 'a`...
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0309`.
|
|
@ -0,0 +1,11 @@
|
|||
error[E0309]: the associated type `<T as MyTrait<'_>>::Output` may not live long enough
|
||||
--> $DIR/projection-where-clause-env-wrong-lifetime.rs:14:5
|
||||
|
|
||||
LL | bar::<<T as MyTrait<'a>>::Output>()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider adding an explicit lifetime bound `<T as MyTrait<'_>>::Output: 'a`...
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0309`.
|
|
@ -0,0 +1,25 @@
|
|||
// Test that if we need to prove that `<T as MyTrait<'a>>::Output:
|
||||
// 'a`, but we only know that `<T as MyTrait<'b>>::Output: 'a`, that
|
||||
// doesn't suffice.
|
||||
|
||||
trait MyTrait<'a> {
|
||||
type Output;
|
||||
}
|
||||
|
||||
fn foo1<'a, 'b, T>() -> &'a ()
|
||||
where
|
||||
for<'x> T: MyTrait<'x>,
|
||||
<T as MyTrait<'b>>::Output: 'a,
|
||||
{
|
||||
bar::<<T as MyTrait<'a>>::Output>()
|
||||
//~^ ERROR the associated type `<T as MyTrait<'a>>::Output` may not live long enough
|
||||
}
|
||||
|
||||
fn bar<'a, T>() -> &'a ()
|
||||
where
|
||||
T: 'a,
|
||||
{
|
||||
&()
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,16 @@
|
|||
error[E0309]: the associated type `<T as MyTrait<'a>>::Output` may not live long enough
|
||||
--> $DIR/projection-where-clause-env-wrong-lifetime.rs:14:5
|
||||
|
|
||||
LL | bar::<<T as MyTrait<'a>>::Output>()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider adding an explicit lifetime bound `<T as MyTrait<'a>>::Output: 'a`...
|
||||
note: ...so that the type `<T as MyTrait<'a>>::Output` will meet its required lifetime bounds
|
||||
--> $DIR/projection-where-clause-env-wrong-lifetime.rs:14:5
|
||||
|
|
||||
LL | bar::<<T as MyTrait<'a>>::Output>()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0309`.
|
30
src/test/ui/nll/ty-outlives/projection-where-clause-env.rs
Normal file
30
src/test/ui/nll/ty-outlives/projection-where-clause-env.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
#![feature(nll)]
|
||||
|
||||
// Test that when we have a `<T as MyTrait<'a>>::Output: 'a`
|
||||
// relationship in the environment we take advantage of it. In this
|
||||
// case, that means we **don't** have to prove that `T: 'a`.
|
||||
//
|
||||
// Regression test for #53121.
|
||||
//
|
||||
// compile-pass
|
||||
|
||||
trait MyTrait<'a> {
|
||||
type Output;
|
||||
}
|
||||
|
||||
fn foo<'a, T>() -> &'a ()
|
||||
where
|
||||
T: MyTrait<'a>,
|
||||
<T as MyTrait<'a>>::Output: 'a,
|
||||
{
|
||||
bar::<T::Output>()
|
||||
}
|
||||
|
||||
fn bar<'a, T>() -> &'a ()
|
||||
where
|
||||
T: 'a,
|
||||
{
|
||||
&()
|
||||
}
|
||||
|
||||
fn main() {}
|
26
src/test/ui/nll/ty-outlives/projection-where-clause-none.rs
Normal file
26
src/test/ui/nll/ty-outlives/projection-where-clause-none.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
#![feature(nll)]
|
||||
|
||||
// Test that we are NOT able to establish that `<T as
|
||||
// MyTrait<'a>>::Output: 'a` outlives `'a` here -- we have only one
|
||||
// recourse, which is to prove that `T: 'a` and `'a: 'a`, but we don't
|
||||
// know that `T: 'a`.
|
||||
|
||||
trait MyTrait<'a> {
|
||||
type Output;
|
||||
}
|
||||
|
||||
fn foo<'a, T>() -> &'a ()
|
||||
where
|
||||
T: MyTrait<'a>,
|
||||
{
|
||||
bar::<T::Output>() //~ ERROR the parameter type `T` may not live long enough
|
||||
}
|
||||
|
||||
fn bar<'a, T>() -> &'a ()
|
||||
where
|
||||
T: 'a,
|
||||
{
|
||||
&()
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,11 @@
|
|||
error[E0309]: the parameter type `T` may not live long enough
|
||||
--> $DIR/projection-where-clause-none.rs:16:5
|
||||
|
|
||||
LL | bar::<T::Output>() //~ ERROR the parameter type `T` may not live long enough
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider adding an explicit lifetime bound `T: 'a`...
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0309`.
|
27
src/test/ui/nll/ty-outlives/projection-where-clause-trait.rs
Normal file
27
src/test/ui/nll/ty-outlives/projection-where-clause-trait.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
#![feature(nll)]
|
||||
|
||||
// Test that we are able to establish that `<T as
|
||||
// MyTrait<'a>>::Output: 'a` outlives `'a` (because the trait says
|
||||
// so).
|
||||
//
|
||||
// compile-pass
|
||||
|
||||
trait MyTrait<'a> {
|
||||
type Output: 'a;
|
||||
}
|
||||
|
||||
fn foo<'a, T>() -> &'a ()
|
||||
where
|
||||
T: MyTrait<'a>,
|
||||
{
|
||||
bar::<T::Output>()
|
||||
}
|
||||
|
||||
fn bar<'a, T>() -> &'a ()
|
||||
where
|
||||
T: 'a,
|
||||
{
|
||||
&()
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -9,7 +9,7 @@ note: first, the lifetime cannot outlive the lifetime 'a as defined on the funct
|
|||
|
|
||||
LL | fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait {
|
||||
| ^^
|
||||
note: ...so that the type `(dyn SomeTrait + 'a)` is not borrowed for too long
|
||||
note: ...so that reference does not outlive borrowed content
|
||||
--> $DIR/object-lifetime-default-elision.rs:81:5
|
||||
|
|
||||
LL | ss
|
||||
|
|
|
@ -9,7 +9,7 @@ note: first, the lifetime cannot outlive the lifetime 'a as defined on the funct
|
|||
|
|
||||
LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a Foo) -> &'b () {
|
||||
| ^^
|
||||
note: ...so that the type `(dyn Foo + 'a)` is not borrowed for too long
|
||||
note: ...so that reference does not outlive borrowed content
|
||||
--> $DIR/region-object-lifetime-2.rs:20:5
|
||||
|
|
||||
LL | x.borrowed() //~ ERROR cannot infer
|
||||
|
|
|
@ -26,7 +26,7 @@ note: first, the lifetime cannot outlive the lifetime 'a as defined on the funct
|
|||
|
|
||||
LL | fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy {
|
||||
| ^^
|
||||
note: ...so that the type `(dyn Dummy + 'a)` is not borrowed for too long
|
||||
note: ...so that reference does not outlive borrowed content
|
||||
--> $DIR/regions-trait-object-subtyping.rs:25:5
|
||||
|
|
||||
LL | x //~ ERROR lifetime bound not satisfied
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue