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
|
//! ported to this system, and which relies on string concatenation at the
|
||||||
//! time of error detection.
|
//! 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::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;
|
||||||
use hir::Node;
|
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
|
use hir::Node;
|
||||||
use middle::region;
|
use middle::region;
|
||||||
use traits::{ObligationCause, ObligationCauseCode};
|
use std::{cmp, fmt};
|
||||||
use ty::{self, subst::Subst, Region, Ty, TyCtxt, TypeFoldable, TyKind};
|
|
||||||
use ty::error::TypeError;
|
|
||||||
use session::config::BorrowckMode;
|
|
||||||
use syntax::ast::DUMMY_NODE_ID;
|
use syntax::ast::DUMMY_NODE_ID;
|
||||||
use syntax_pos::{Pos, Span};
|
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;
|
mod note;
|
||||||
|
|
||||||
|
@ -153,8 +152,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We shouldn't encounter an error message with ReClosureBound.
|
// We shouldn't encounter an error message with ReClosureBound.
|
||||||
ty::ReCanonical(..) |
|
ty::ReCanonical(..) | ty::ReClosureBound(..) => {
|
||||||
ty::ReClosureBound(..) => {
|
|
||||||
bug!("encountered unexpected ReClosureBound: {:?}", region,);
|
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>) {
|
fn msg_span_from_free_region(self, region: ty::Region<'tcx>) -> (String, Option<Span>) {
|
||||||
match *region {
|
match *region {
|
||||||
ty::ReEarlyBound(_) | ty::ReFree(_) => {
|
ty::ReEarlyBound(_) | ty::ReFree(_) => {
|
||||||
self.msg_span_from_early_bound_and_free_regions(region)
|
self.msg_span_from_early_bound_and_free_regions(region)
|
||||||
},
|
}
|
||||||
ty::ReStatic => ("the static lifetime".to_owned(), None),
|
ty::ReStatic => ("the static lifetime".to_owned(), None),
|
||||||
_ => bug!("{:?}", region),
|
_ => 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::Item(it)) => Self::item_scope_tag(&it),
|
||||||
Some(Node::TraitItem(it)) => Self::trait_item_scope_tag(&it),
|
Some(Node::TraitItem(it)) => Self::trait_item_scope_tag(&it),
|
||||||
Some(Node::ImplItem(it)) => Self::impl_item_scope_tag(&it),
|
Some(Node::ImplItem(it)) => Self::impl_item_scope_tag(&it),
|
||||||
_ => unreachable!()
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let (prefix, span) = match *region {
|
let (prefix, span) = match *region {
|
||||||
ty::ReEarlyBound(ref br) => {
|
ty::ReEarlyBound(ref br) => {
|
||||||
let mut sp = cm.def_span(self.hir.span(node));
|
let mut sp = cm.def_span(self.hir.span(node));
|
||||||
if let Some(param) = self.hir.get_generics(scope).and_then(|generics| {
|
if let Some(param) = self.hir
|
||||||
generics.get_named(&br.name)
|
.get_generics(scope)
|
||||||
}) {
|
.and_then(|generics| generics.get_named(&br.name))
|
||||||
|
{
|
||||||
sp = param.span;
|
sp = param.span;
|
||||||
}
|
}
|
||||||
(format!("the lifetime {} as defined on", br.name), sp)
|
(format!("the lifetime {} as defined on", br.name), sp)
|
||||||
}
|
}
|
||||||
ty::ReFree(ty::FreeRegion {
|
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));
|
let mut sp = cm.def_span(self.hir.span(node));
|
||||||
if let Some(param) = self.hir.get_generics(scope).and_then(|generics| {
|
if let Some(param) = self.hir
|
||||||
generics.get_named(&name)
|
.get_generics(scope)
|
||||||
}) {
|
.and_then(|generics| generics.get_named(&name))
|
||||||
|
{
|
||||||
sp = param.span;
|
sp = param.span;
|
||||||
}
|
}
|
||||||
(format!("the lifetime {} as defined on", name), sp)
|
(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 {
|
fn impl_item_scope_tag(item: &hir::ImplItem) -> &'static str {
|
||||||
match item.node {
|
match item.node {
|
||||||
hir::ImplItemKind::Method(..) => "method body",
|
hir::ImplItemKind::Method(..) => "method body",
|
||||||
hir::ImplItemKind::Const(..) |
|
hir::ImplItemKind::Const(..)
|
||||||
hir::ImplItemKind::Existential(..) |
|
| hir::ImplItemKind::Existential(..)
|
||||||
hir::ImplItemKind::Type(..) => "associated item",
|
| hir::ImplItemKind::Type(..) => "associated item",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,20 +299,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||||
&self,
|
&self,
|
||||||
region_scope_tree: ®ion::ScopeTree,
|
region_scope_tree: ®ion::ScopeTree,
|
||||||
errors: &Vec<RegionResolutionError<'tcx>>,
|
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
|
if suppress.suppressed() {
|
||||||
// on the borrowck mode
|
return;
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to pre-process the errors, which will group some of them
|
// 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 {
|
} else {
|
||||||
err.span_label(arm_span, msg);
|
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) {
|
if let Ok(try_snippet) = self.tcx.sess.source_map().span_to_snippet(arm_span) {
|
||||||
err.span_suggestion_with_applicability(
|
err.span_suggestion_with_applicability(
|
||||||
arm_span,
|
arm_span,
|
||||||
"try wrapping with a success variant",
|
"try wrapping with a success variant",
|
||||||
format!("Ok({})", try_snippet),
|
format!("Ok({})", try_snippet),
|
||||||
Applicability::MachineApplicable
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let msg = "match arm with an incompatible type";
|
let msg = "match arm with an incompatible type";
|
||||||
if self.tcx.sess.source_map().is_multiline(arm_span) {
|
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(
|
fn strip_generic_default_params(
|
||||||
&self,
|
&self,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
substs: &ty::subst::Substs<'tcx>
|
substs: &ty::subst::Substs<'tcx>,
|
||||||
) -> &'tcx ty::subst::Substs<'tcx> {
|
) -> &'tcx ty::subst::Substs<'tcx> {
|
||||||
let generics = self.tcx.generics_of(def_id);
|
let generics = self.tcx.generics_of(def_id);
|
||||||
let mut num_supplied_defaults = 0;
|
let mut num_supplied_defaults = 0;
|
||||||
let mut type_params = generics.params.iter().rev().filter_map(|param| match param.kind {
|
let mut type_params = generics
|
||||||
ty::GenericParamDefKind::Lifetime => None,
|
.params
|
||||||
ty::GenericParamDefKind::Type { has_default, .. } => {
|
.iter()
|
||||||
Some((param.def_id, has_default))
|
.rev()
|
||||||
}
|
.filter_map(|param| match param.kind {
|
||||||
}).peekable();
|
ty::GenericParamDefKind::Lifetime => None,
|
||||||
|
ty::GenericParamDefKind::Type { has_default, .. } => {
|
||||||
|
Some((param.def_id, has_default))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.peekable();
|
||||||
let has_default = {
|
let has_default = {
|
||||||
let has_default = type_params.peek().map(|(_, has_default)| has_default);
|
let has_default = type_params.peek().map(|(_, has_default)| has_default);
|
||||||
*has_default.unwrap_or(&false)
|
*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::Infer(ty::InferTy::IntVar(_)), &ty::Infer(ty::InferTy::IntVar(_)))
|
||||||
| (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_)))
|
| (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_)))
|
||||||
| (&ty::Infer(ty::InferTy::FloatVar(_)), &ty::Float(_))
|
| (&ty::Infer(ty::InferTy::FloatVar(_)), &ty::Float(_))
|
||||||
| (
|
| (&ty::Infer(ty::InferTy::FloatVar(_)), &ty::Infer(ty::InferTy::FloatVar(_))) => {
|
||||||
&ty::Infer(ty::InferTy::FloatVar(_)),
|
true
|
||||||
&ty::Infer(ty::InferTy::FloatVar(_)),
|
}
|
||||||
) => true,
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -703,11 +705,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||||
"&{}{}{}",
|
"&{}{}{}",
|
||||||
r,
|
r,
|
||||||
if r == "" { "" } else { " " },
|
if r == "" { "" } else { " " },
|
||||||
if mutbl == hir::MutMutable {
|
if mutbl == hir::MutMutable { "mut " } else { "" }
|
||||||
"mut "
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
));
|
));
|
||||||
s.push_normal(ty.to_string());
|
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 common_len = cmp::min(len1, len2);
|
||||||
let remainder1: Vec<_> = sub1.types().skip(common_len).collect();
|
let remainder1: Vec<_> = sub1.types().skip(common_len).collect();
|
||||||
let remainder2: Vec<_> = sub2.types().skip(common_len).collect();
|
let remainder2: Vec<_> = sub2.types().skip(common_len).collect();
|
||||||
let common_default_params =
|
let common_default_params = remainder1
|
||||||
remainder1.iter().rev().zip(remainder2.iter().rev())
|
.iter()
|
||||||
.filter(|(a, b)| a == b).count();
|
.rev()
|
||||||
|
.zip(remainder2.iter().rev())
|
||||||
|
.filter(|(a, b)| a == b)
|
||||||
|
.count();
|
||||||
let len = sub1.len() - common_default_params;
|
let len = sub1.len() - common_default_params;
|
||||||
|
|
||||||
// Only draw `<...>` if there're lifetime/type arguments.
|
// 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
|
// When encountering &T != &mut T, highlight only the borrow
|
||||||
(&ty::Ref(r1, ref_ty1, mutbl1),
|
(&ty::Ref(r1, ref_ty1, mutbl1), &ty::Ref(r2, ref_ty2, mutbl2))
|
||||||
&ty::Ref(r2, ref_ty2, mutbl2)) if equals(&ref_ty1, &ref_ty2) => {
|
if equals(&ref_ty1, &ref_ty2) =>
|
||||||
|
{
|
||||||
let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
|
let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
|
||||||
push_ty_ref(&r1, ref_ty1, mutbl1, &mut values.0);
|
push_ty_ref(&r1, ref_ty1, mutbl1, &mut values.0);
|
||||||
push_ty_ref(&r2, ref_ty2, mutbl2, &mut values.1);
|
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>,
|
bound_kind: GenericKind<'tcx>,
|
||||||
sub: Region<'tcx>,
|
sub: Region<'tcx>,
|
||||||
) {
|
) {
|
||||||
self.construct_generic_bound_failure(region_scope_tree,
|
self.construct_generic_bound_failure(region_scope_tree, span, origin, bound_kind, sub)
|
||||||
span,
|
|
||||||
origin,
|
|
||||||
bound_kind,
|
|
||||||
sub)
|
|
||||||
.emit()
|
.emit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1083,8 +1081,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||||
origin: Option<SubregionOrigin<'tcx>>,
|
origin: Option<SubregionOrigin<'tcx>>,
|
||||||
bound_kind: GenericKind<'tcx>,
|
bound_kind: GenericKind<'tcx>,
|
||||||
sub: Region<'tcx>,
|
sub: Region<'tcx>,
|
||||||
) -> DiagnosticBuilder<'a>
|
) -> DiagnosticBuilder<'a> {
|
||||||
{
|
|
||||||
// Attempt to obtain the span of the parameter so we can
|
// Attempt to obtain the span of the parameter so we can
|
||||||
// suggest adding an explicit lifetime bound to it.
|
// suggest adding an explicit lifetime bound to it.
|
||||||
let type_param_span = match (self.in_progress_tables, bound_kind) {
|
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 tail = if has_lifetimes { " + " } else { "" };
|
||||||
let suggestion = format!("{}: {}{}", bound_kind, sub, tail);
|
let suggestion = format!("{}: {}{}", bound_kind, sub, tail);
|
||||||
err.span_suggestion_short_with_applicability(
|
err.span_suggestion_short_with_applicability(
|
||||||
sp, consider, suggestion,
|
sp,
|
||||||
Applicability::MaybeIncorrect // Issue #41966
|
consider,
|
||||||
|
suggestion,
|
||||||
|
Applicability::MaybeIncorrect, // Issue #41966
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
err.help(consider);
|
err.help(consider);
|
||||||
|
@ -1358,12 +1357,10 @@ impl<'tcx> ObligationCause<'tcx> {
|
||||||
match self.code {
|
match self.code {
|
||||||
CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"),
|
CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"),
|
||||||
MatchExpressionArm { source, .. } => Error0308(match source {
|
MatchExpressionArm { source, .. } => Error0308(match source {
|
||||||
hir::MatchSource::IfLetDesugar { .. } => {
|
hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have incompatible types",
|
||||||
"`if let` arms have incompatible types"
|
|
||||||
},
|
|
||||||
hir::MatchSource::TryDesugar => {
|
hir::MatchSource::TryDesugar => {
|
||||||
"try expression alternatives have incompatible types"
|
"try expression alternatives have incompatible types"
|
||||||
},
|
}
|
||||||
_ => "match arms have incompatible types",
|
_ => "match arms have incompatible types",
|
||||||
}),
|
}),
|
||||||
IfExpression => Error0308("if and else have incompatible types"),
|
IfExpression => Error0308("if and else have incompatible types"),
|
||||||
|
|
|
@ -10,23 +10,26 @@
|
||||||
|
|
||||||
//! The code to do lexical region resolution.
|
//! The code to do lexical region resolution.
|
||||||
|
|
||||||
use infer::SubregionOrigin;
|
|
||||||
use infer::RegionVariableOrigin;
|
|
||||||
use infer::region_constraints::Constraint;
|
use infer::region_constraints::Constraint;
|
||||||
use infer::region_constraints::GenericKind;
|
use infer::region_constraints::GenericKind;
|
||||||
use infer::region_constraints::RegionConstraintData;
|
use infer::region_constraints::RegionConstraintData;
|
||||||
use infer::region_constraints::VarInfos;
|
use infer::region_constraints::VarInfos;
|
||||||
use infer::region_constraints::VerifyBound;
|
use infer::region_constraints::VerifyBound;
|
||||||
|
use infer::RegionVariableOrigin;
|
||||||
|
use infer::SubregionOrigin;
|
||||||
use middle::free_region::RegionRelations;
|
use middle::free_region::RegionRelations;
|
||||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
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::fmt;
|
||||||
use std::u32;
|
use std::u32;
|
||||||
use ty::{self, TyCtxt};
|
use ty::fold::TypeFoldable;
|
||||||
use ty::{Region, RegionVid};
|
use ty::{self, Ty, TyCtxt};
|
||||||
use ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
|
use ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
|
||||||
use ty::{ReLateBound, ReScope, ReSkolemized, ReVar};
|
use ty::{ReLateBound, ReScope, ReSkolemized, ReVar};
|
||||||
|
use ty::{Region, RegionVid};
|
||||||
|
|
||||||
mod graphviz;
|
mod graphviz;
|
||||||
|
|
||||||
|
@ -108,11 +111,15 @@ struct LexicalResolver<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||||
|
fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
|
||||||
|
self.region_rels.tcx
|
||||||
|
}
|
||||||
|
|
||||||
fn infer_variable_values(
|
fn infer_variable_values(
|
||||||
&mut self,
|
&mut self,
|
||||||
errors: &mut Vec<RegionResolutionError<'tcx>>,
|
errors: &mut Vec<RegionResolutionError<'tcx>>,
|
||||||
) -> LexicalRegionResolutions<'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
|
// Dorky hack to cause `dump_constraints` to only get called
|
||||||
// if debug mode is enabled:
|
// if debug mode is enabled:
|
||||||
|
@ -239,9 +246,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"Expanding value of {:?} from {:?} to {:?}",
|
"Expanding value of {:?} from {:?} to {:?}",
|
||||||
b_vid,
|
b_vid, cur_region, lub
|
||||||
cur_region,
|
|
||||||
lub
|
|
||||||
);
|
);
|
||||||
|
|
||||||
*b_data = VarValue::Value(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> {
|
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) {
|
match (a, b) {
|
||||||
(&ty::ReCanonical(..), _) |
|
(&ty::ReCanonical(..), _)
|
||||||
(_, &ty::ReCanonical(..)) |
|
| (_, &ty::ReCanonical(..))
|
||||||
(&ty::ReClosureBound(..), _) |
|
| (&ty::ReClosureBound(..), _)
|
||||||
(_, &ty::ReClosureBound(..)) |
|
| (_, &ty::ReClosureBound(..))
|
||||||
(&ReLateBound(..), _) |
|
| (&ReLateBound(..), _)
|
||||||
(_, &ReLateBound(..)) |
|
| (_, &ReLateBound(..))
|
||||||
(&ReErased, _) |
|
| (&ReErased, _)
|
||||||
(_, &ReErased) => {
|
| (_, &ReErased) => {
|
||||||
bug!("cannot relate region: LUB({:?}, {:?})", a, b);
|
bug!("cannot relate region: LUB({:?}, {:?})", a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,20 +291,20 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
(&ReEarlyBound(_), &ReScope(s_id)) |
|
(&ReEarlyBound(_), &ReScope(s_id))
|
||||||
(&ReScope(s_id), &ReEarlyBound(_)) |
|
| (&ReScope(s_id), &ReEarlyBound(_))
|
||||||
(&ReFree(_), &ReScope(s_id)) |
|
| (&ReFree(_), &ReScope(s_id))
|
||||||
(&ReScope(s_id), &ReFree(_)) => {
|
| (&ReScope(s_id), &ReFree(_)) => {
|
||||||
// A "free" region can be interpreted as "some region
|
// A "free" region can be interpreted as "some region
|
||||||
// at least as big as fr.scope". So, we can
|
// at least as big as fr.scope". So, we can
|
||||||
// reasonably compare free regions and scopes:
|
// reasonably compare free regions and scopes:
|
||||||
let fr_scope = match (a, b) {
|
let fr_scope = match (a, b) {
|
||||||
(&ReEarlyBound(ref br), _) | (_, &ReEarlyBound(ref br)) => self.region_rels
|
(&ReEarlyBound(ref br), _) | (_, &ReEarlyBound(ref br)) => self.region_rels
|
||||||
.region_scope_tree
|
.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
|
(&ReFree(ref fr), _) | (_, &ReFree(ref fr)) => self.region_rels
|
||||||
.region_scope_tree
|
.region_scope_tree
|
||||||
.free_scope(self.region_rels.tcx, fr),
|
.free_scope(self.tcx(), fr),
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
};
|
};
|
||||||
let r_id = self.region_rels
|
let r_id = self.region_rels
|
||||||
|
@ -332,10 +336,10 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||||
tcx.mk_region(ReScope(lub))
|
tcx.mk_region(ReScope(lub))
|
||||||
}
|
}
|
||||||
|
|
||||||
(&ReEarlyBound(_), &ReEarlyBound(_)) |
|
(&ReEarlyBound(_), &ReEarlyBound(_))
|
||||||
(&ReFree(_), &ReEarlyBound(_)) |
|
| (&ReFree(_), &ReEarlyBound(_))
|
||||||
(&ReEarlyBound(_), &ReFree(_)) |
|
| (&ReEarlyBound(_), &ReFree(_))
|
||||||
(&ReFree(_), &ReFree(_)) => self.region_rels.lub_free_regions(a, b),
|
| (&ReFree(_), &ReFree(_)) => self.region_rels.lub_free_regions(a, b),
|
||||||
|
|
||||||
// For these types, we cannot define any additional
|
// For these types, we cannot define any additional
|
||||||
// relationship:
|
// relationship:
|
||||||
|
@ -358,8 +362,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||||
for (constraint, origin) in &self.data.constraints {
|
for (constraint, origin) in &self.data.constraints {
|
||||||
debug!(
|
debug!(
|
||||||
"collect_errors: constraint={:?} origin={:?}",
|
"collect_errors: constraint={:?} origin={:?}",
|
||||||
constraint,
|
constraint, origin
|
||||||
origin
|
|
||||||
);
|
);
|
||||||
match *constraint {
|
match *constraint {
|
||||||
Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
|
Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
|
||||||
|
@ -374,9 +377,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||||
debug!(
|
debug!(
|
||||||
"collect_errors: region error at {:?}: \
|
"collect_errors: region error at {:?}: \
|
||||||
cannot verify that {:?} <= {:?}",
|
cannot verify that {:?} <= {:?}",
|
||||||
origin,
|
origin, sub, sup
|
||||||
sub,
|
|
||||||
sup
|
|
||||||
);
|
);
|
||||||
|
|
||||||
errors.push(RegionResolutionError::ConcreteFailure(
|
errors.push(RegionResolutionError::ConcreteFailure(
|
||||||
|
@ -402,10 +403,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||||
debug!(
|
debug!(
|
||||||
"collect_errors: region error at {:?}: \
|
"collect_errors: region error at {:?}: \
|
||||||
cannot verify that {:?}={:?} <= {:?}",
|
cannot verify that {:?}={:?} <= {:?}",
|
||||||
origin,
|
origin, a_vid, a_region, b_region
|
||||||
a_vid,
|
|
||||||
a_region,
|
|
||||||
b_region
|
|
||||||
);
|
);
|
||||||
*a_data = VarValue::ErrorValue;
|
*a_data = VarValue::ErrorValue;
|
||||||
}
|
}
|
||||||
|
@ -415,7 +413,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||||
|
|
||||||
for verify in &self.data.verifys {
|
for verify in &self.data.verifys {
|
||||||
debug!("collect_errors: verify={:?}", verify);
|
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
|
// This was an inference variable which didn't get
|
||||||
// constrained, therefore it can be assume to hold.
|
// constrained, therefore it can be assume to hold.
|
||||||
|
@ -423,16 +421,15 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||||
continue;
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"collect_errors: region error at {:?}: \
|
"collect_errors: region error at {:?}: \
|
||||||
cannot verify that {:?} <= {:?}",
|
cannot verify that {:?} <= {:?}",
|
||||||
verify.origin,
|
verify.origin, verify.region, verify.bound
|
||||||
verify.region,
|
|
||||||
verify.bound
|
|
||||||
);
|
);
|
||||||
|
|
||||||
errors.push(RegionResolutionError::GenericBoundFailure(
|
errors.push(RegionResolutionError::GenericBoundFailure(
|
||||||
|
@ -580,10 +577,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||||
debug!(
|
debug!(
|
||||||
"region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \
|
"region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \
|
||||||
sup: {:?}",
|
sup: {:?}",
|
||||||
origin,
|
origin, node_idx, lower_bound.region, upper_bound.region
|
||||||
node_idx,
|
|
||||||
lower_bound.region,
|
|
||||||
upper_bound.region
|
|
||||||
);
|
);
|
||||||
errors.push(RegionResolutionError::SubSupConflict(
|
errors.push(RegionResolutionError::SubSupConflict(
|
||||||
origin,
|
origin,
|
||||||
|
@ -645,8 +639,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})",
|
"collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})",
|
||||||
orig_node_idx,
|
orig_node_idx, node_idx
|
||||||
node_idx
|
|
||||||
);
|
);
|
||||||
|
|
||||||
process_edges(&self.data, &mut state, graph, node_idx, dir);
|
process_edges(&self.data, &mut state, graph, node_idx, dir);
|
||||||
|
@ -721,20 +714,26 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||||
&self,
|
&self,
|
||||||
bound: &VerifyBound<'tcx>,
|
bound: &VerifyBound<'tcx>,
|
||||||
var_values: &LexicalRegionResolutions<'tcx>,
|
var_values: &LexicalRegionResolutions<'tcx>,
|
||||||
|
generic_ty: Ty<'tcx>,
|
||||||
min: ty::Region<'tcx>,
|
min: ty::Region<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match bound {
|
match bound {
|
||||||
VerifyBound::AnyRegion(rs) => rs.iter()
|
VerifyBound::IfEq(k, b) => {
|
||||||
.map(|&r| var_values.normalize(r))
|
(var_values.normalize(self.region_rels.tcx, *k) == generic_ty)
|
||||||
.any(|r| self.region_rels.is_subregion_of(min, r)),
|
&& self.bound_is_met(b, var_values, generic_ty, min)
|
||||||
|
}
|
||||||
|
|
||||||
VerifyBound::AllRegions(rs) => rs.iter()
|
VerifyBound::OutlivedBy(r) =>
|
||||||
.map(|&r| var_values.normalize(r))
|
self.region_rels.is_subregion_of(
|
||||||
.all(|r| self.region_rels.is_subregion_of(min, r)),
|
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> {
|
impl<'tcx> LexicalRegionResolutions<'tcx> {
|
||||||
fn normalize(&self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
fn normalize<T>(&self, tcx: TyCtxt<'_, '_, 'tcx>, value: T) -> T
|
||||||
match *r {
|
where
|
||||||
ty::ReVar(rid) => self.resolve_var(rid),
|
T: TypeFoldable<'tcx>,
|
||||||
|
{
|
||||||
|
tcx.fold_regions(&value, &mut false, |r, _db| match r {
|
||||||
|
ty::ReVar(rid) => self.resolve_var(*rid),
|
||||||
_ => r,
|
_ => r,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn value(&self, rid: RegionVid) -> &VarValue<'tcx> {
|
fn value(&self, rid: RegionVid) -> &VarValue<'tcx> {
|
||||||
|
|
|
@ -24,6 +24,7 @@ use middle::free_region::RegionRelations;
|
||||||
use middle::lang_items;
|
use middle::lang_items;
|
||||||
use middle::region;
|
use middle::region;
|
||||||
use rustc_data_structures::unify as ut;
|
use rustc_data_structures::unify as ut;
|
||||||
|
use session::config::BorrowckMode;
|
||||||
use std::cell::{Cell, Ref, RefCell, RefMut};
|
use std::cell::{Cell, Ref, RefCell, RefMut};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -80,6 +81,38 @@ pub type Bound<T> = Option<T>;
|
||||||
pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
|
pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
|
||||||
pub type FixupResult<T> = Result<T, FixupError>; // "fixup 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 struct InferCtxt<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||||
pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
|
|
||||||
|
@ -408,7 +441,7 @@ pub enum FixupError {
|
||||||
pub struct RegionObligation<'tcx> {
|
pub struct RegionObligation<'tcx> {
|
||||||
pub sub_region: ty::Region<'tcx>,
|
pub sub_region: ty::Region<'tcx>,
|
||||||
pub sup_type: Ty<'tcx>,
|
pub sup_type: Ty<'tcx>,
|
||||||
pub cause: ObligationCause<'tcx>,
|
pub origin: SubregionOrigin<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for FixupError {
|
impl fmt::Display for FixupError {
|
||||||
|
@ -1039,34 +1072,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||||
region_context: DefId,
|
region_context: DefId,
|
||||||
region_map: ®ion::ScopeTree,
|
region_map: ®ion::ScopeTree,
|
||||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||||
) {
|
suppress: SuppressRegionErrors,
|
||||||
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,
|
|
||||||
) {
|
) {
|
||||||
assert!(
|
assert!(
|
||||||
self.is_tainted_by_errors() || self.region_obligations.borrow().is_empty(),
|
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
|
// this infcx was in use. This is totally hokey but
|
||||||
// otherwise we have a hard time separating legit region
|
// otherwise we have a hard time separating legit region
|
||||||
// errors from silly ones.
|
// 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
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use infer::{GenericKind, InferCtxt};
|
|
||||||
use infer::outlives::free_region_map::FreeRegionMap;
|
use infer::outlives::free_region_map::FreeRegionMap;
|
||||||
use traits::query::outlives_bounds::{self, OutlivesBound};
|
use infer::{GenericKind, InferCtxt};
|
||||||
use ty::{self, Ty};
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
use traits::query::outlives_bounds::{self, OutlivesBound};
|
||||||
|
use ty::{self, Ty};
|
||||||
|
|
||||||
/// The `OutlivesEnvironment` collects information about what outlives
|
/// The `OutlivesEnvironment` collects information about what outlives
|
||||||
/// what in a given type-checking setting. For example, if we have a
|
/// 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> {
|
pub struct OutlivesEnvironment<'tcx> {
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
free_region_map: FreeRegionMap<'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> {
|
impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
|
||||||
pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
|
pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
|
||||||
let mut env = OutlivesEnvironment {
|
let mut env = OutlivesEnvironment {
|
||||||
param_env,
|
param_env,
|
||||||
free_region_map: FreeRegionMap::new(),
|
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));
|
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`.
|
/// Borrows current value of the `region_bound_pairs`.
|
||||||
pub fn region_bound_pairs(&self) -> &[(ty::Region<'tcx>, GenericKind<'tcx>)] {
|
pub fn region_bound_pairs_map(&self) -> &FxHashMap<ast::NodeId, RegionBoundPairs<'tcx>> {
|
||||||
&self.region_bound_pairs
|
&self.region_bound_pairs_map
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns ownership of the `free_region_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
|
/// similar leaks around givens that seem equally suspicious, to
|
||||||
/// be honest. --nmatsakis
|
/// be honest. --nmatsakis
|
||||||
pub fn push_snapshot_pre_closure(&self) -> usize {
|
pub fn push_snapshot_pre_closure(&self) -> usize {
|
||||||
self.region_bound_pairs.len()
|
self.region_bound_pairs_accum.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See `push_snapshot_pre_closure`.
|
/// See `push_snapshot_pre_closure`.
|
||||||
pub fn pop_snapshot_post_closure(&mut self, len: usize) {
|
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.
|
/// 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.
|
/// Processes outlives bounds that are known to hold, whether from implied or other sources.
|
||||||
///
|
///
|
||||||
/// The `infcx` parameter is optional; if the implied bounds may
|
/// 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 {
|
for outlives_bound in outlives_bounds {
|
||||||
debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
|
debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
|
||||||
match outlives_bound {
|
match outlives_bound {
|
||||||
OutlivesBound::RegionSubRegion(r_a @ &ty::ReEarlyBound(_), &ty::ReVar(vid_b)) |
|
OutlivesBound::RegionSubRegion(r_a @ &ty::ReEarlyBound(_), &ty::ReVar(vid_b))
|
||||||
OutlivesBound::RegionSubRegion(r_a @ &ty::ReFree(_), &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);
|
infcx
|
||||||
|
.expect("no infcx provided but region vars found")
|
||||||
|
.add_given(r_a, vid_b);
|
||||||
}
|
}
|
||||||
OutlivesBound::RegionSubParam(r_a, param_b) => {
|
OutlivesBound::RegionSubParam(r_a, param_b) => {
|
||||||
self.region_bound_pairs
|
self.region_bound_pairs_accum
|
||||||
.push((r_a, GenericKind::Param(param_b)));
|
.push((r_a, GenericKind::Param(param_b)));
|
||||||
}
|
}
|
||||||
OutlivesBound::RegionSubProjection(r_a, projection_b) => {
|
OutlivesBound::RegionSubProjection(r_a, projection_b) => {
|
||||||
self.region_bound_pairs
|
self.region_bound_pairs_accum
|
||||||
.push((r_a, GenericKind::Projection(projection_b)));
|
.push((r_a, GenericKind::Projection(projection_b)));
|
||||||
}
|
}
|
||||||
OutlivesBound::RegionSubRegion(r_a, r_b) => {
|
OutlivesBound::RegionSubRegion(r_a, r_b) => {
|
||||||
|
|
|
@ -13,3 +13,4 @@
|
||||||
pub mod env;
|
pub mod env;
|
||||||
pub mod free_region_map;
|
pub mod free_region_map;
|
||||||
pub mod obligations;
|
pub mod obligations;
|
||||||
|
pub mod verify;
|
||||||
|
|
|
@ -69,13 +69,14 @@
|
||||||
//! might later infer `?U` to something like `&'b u32`, which would
|
//! might later infer `?U` to something like `&'b u32`, which would
|
||||||
//! imply that `'b: 'a`.
|
//! 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 infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound};
|
||||||
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use traits;
|
use traits::ObligationCause;
|
||||||
use ty::outlives::Component;
|
use ty::outlives::Component;
|
||||||
use ty::subst::{Subst, Substs};
|
use ty::{self, Region, Ty, TyCtxt, TypeFoldable};
|
||||||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
|
||||||
|
|
||||||
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
||||||
/// Registers that the given region obligation must be resolved
|
/// 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));
|
.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"
|
/// Trait queries just want to pass back type obligations "as is"
|
||||||
pub fn take_registered_region_obligations(&self) -> Vec<(ast::NodeId, RegionObligation<'tcx>)> {
|
pub fn take_registered_region_obligations(&self) -> Vec<(ast::NodeId, RegionObligation<'tcx>)> {
|
||||||
::std::mem::replace(&mut *self.region_obligations.borrow_mut(), vec![])
|
::std::mem::replace(&mut *self.region_obligations.borrow_mut(), vec![])
|
||||||
|
@ -138,10 +159,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
||||||
/// processed.
|
/// processed.
|
||||||
pub fn process_registered_region_obligations(
|
pub fn process_registered_region_obligations(
|
||||||
&self,
|
&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>>,
|
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
body_id: ast::NodeId,
|
|
||||||
) {
|
) {
|
||||||
assert!(
|
assert!(
|
||||||
!self.in_snapshot.get(),
|
!self.in_snapshot.get(),
|
||||||
|
@ -150,41 +170,39 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
||||||
|
|
||||||
debug!("process_registered_region_obligations()");
|
debug!("process_registered_region_obligations()");
|
||||||
|
|
||||||
// pull out the region obligations with the given `body_id` (leaving the rest)
|
let my_region_obligations = self.take_registered_region_obligations();
|
||||||
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 outlives = &mut TypeOutlives::new(
|
for (
|
||||||
self,
|
body_id,
|
||||||
self.tcx,
|
RegionObligation {
|
||||||
region_bound_pairs,
|
sup_type,
|
||||||
implicit_region_bound,
|
sub_region,
|
||||||
param_env,
|
origin,
|
||||||
);
|
},
|
||||||
|
) in my_region_obligations
|
||||||
for RegionObligation {
|
|
||||||
sup_type,
|
|
||||||
sub_region,
|
|
||||||
cause,
|
|
||||||
} in my_region_obligations
|
|
||||||
{
|
{
|
||||||
debug!(
|
debug!(
|
||||||
"process_registered_region_obligations: sup_type={:?} sub_region={:?} cause={:?}",
|
"process_registered_region_obligations: sup_type={:?} sub_region={:?} origin={:?}",
|
||||||
sup_type, sub_region, cause
|
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);
|
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.
|
/// registered in advance.
|
||||||
pub fn type_must_outlive(
|
pub fn type_must_outlive(
|
||||||
&self,
|
&self,
|
||||||
region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)],
|
region_bound_pairs: &RegionBoundPairs<'tcx>,
|
||||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
origin: infer::SubregionOrigin<'tcx>,
|
origin: infer::SubregionOrigin<'tcx>,
|
||||||
|
@ -225,9 +243,7 @@ where
|
||||||
// of these fields.
|
// of these fields.
|
||||||
delegate: D,
|
delegate: D,
|
||||||
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
||||||
region_bound_pairs: &'cx [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
verify_bound: VerifyBoundCx<'cx, 'gcx, 'tcx>,
|
||||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TypeOutlivesDelegate<'tcx> {
|
pub trait TypeOutlivesDelegate<'tcx> {
|
||||||
|
@ -254,16 +270,19 @@ where
|
||||||
pub fn new(
|
pub fn new(
|
||||||
delegate: D,
|
delegate: D,
|
||||||
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
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>>,
|
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
delegate,
|
delegate,
|
||||||
tcx,
|
tcx,
|
||||||
region_bound_pairs,
|
verify_bound: VerifyBoundCx::new(
|
||||||
implicit_region_bound,
|
tcx,
|
||||||
param_env,
|
region_bound_pairs,
|
||||||
|
implicit_region_bound,
|
||||||
|
param_env,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,7 +321,8 @@ where
|
||||||
let origin = origin.clone();
|
let origin = origin.clone();
|
||||||
match component {
|
match component {
|
||||||
Component::Region(region1) => {
|
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) => {
|
Component::Param(param_ty) => {
|
||||||
self.param_ty_must_outlive(origin, region, param_ty);
|
self.param_ty_must_outlive(origin, region, param_ty);
|
||||||
|
@ -337,8 +357,8 @@ where
|
||||||
region, param_ty, origin
|
region, param_ty, origin
|
||||||
);
|
);
|
||||||
|
|
||||||
let verify_bound = self.param_bound(param_ty);
|
|
||||||
let generic = GenericKind::Param(param_ty);
|
let generic = GenericKind::Param(param_ty);
|
||||||
|
let verify_bound = self.verify_bound.generic_bound(generic);
|
||||||
self.delegate
|
self.delegate
|
||||||
.push_verify(origin, generic, region, verify_bound);
|
.push_verify(origin, generic, region, verify_bound);
|
||||||
}
|
}
|
||||||
|
@ -368,19 +388,22 @@ where
|
||||||
// rule might not apply (but another rule might). For now, we err
|
// rule might not apply (but another rule might). For now, we err
|
||||||
// on the side of adding too few edges into the graph.
|
// on the side of adding too few edges into the graph.
|
||||||
|
|
||||||
// Compute the bounds we can derive from the environment or trait
|
// Compute the bounds we can derive from the environment. This
|
||||||
// definition. We know that the projection outlives all the
|
// is an "approximate" match -- in some cases, these bounds
|
||||||
// regions in this list.
|
// may not apply.
|
||||||
let env_bounds = self.projection_declared_bounds(projection_ty);
|
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);
|
// Compute the bounds we can derive from the trait definition.
|
||||||
|
// These are guaranteed to apply, no matter the inference
|
||||||
// If we know that the projection outlives 'static, then we're
|
// results.
|
||||||
// done here.
|
let trait_bounds: Vec<_> = self.verify_bound
|
||||||
if env_bounds.contains(&&ty::ReStatic) {
|
.projection_declared_bounds_from_trait(projection_ty)
|
||||||
debug!("projection_must_outlive: 'static as declared bound");
|
.collect();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If declared bounds list is empty, the only applicable rule is
|
// If declared bounds list is empty, the only applicable rule is
|
||||||
// OutlivesProjectionComponent. If there are inference variables,
|
// OutlivesProjectionComponent. If there are inference variables,
|
||||||
|
@ -397,7 +420,7 @@ where
|
||||||
// inference variables, we use a verify constraint instead of adding
|
// inference variables, we use a verify constraint instead of adding
|
||||||
// edges, which winds up enforcing the same condition.
|
// edges, which winds up enforcing the same condition.
|
||||||
let needs_infer = projection_ty.needs_infer();
|
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");
|
debug!("projection_must_outlive: no declared bounds");
|
||||||
|
|
||||||
for component_ty in projection_ty.substs.types() {
|
for component_ty in projection_ty.substs.types() {
|
||||||
|
@ -405,36 +428,38 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
for r in projection_ty.substs.regions() {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we find that there is a unique declared bound `'b`, and this bound
|
// If we found a unique bound `'b` from the trait, and we
|
||||||
// appears in the trait reference, then the best action is to require that `'b:'r`,
|
// found nothing else from the environment, then the best
|
||||||
// so do that. This is best no matter what rule we use:
|
// action is to require that `'b: 'r`, so do that.
|
||||||
//
|
//
|
||||||
// - OutlivesProjectionEnv or OutlivesProjectionTraitDef: these would translate to
|
// This is best no matter what rule we use:
|
||||||
// the requirement that `'b:'r`
|
//
|
||||||
// - OutlivesProjectionComponent: this would require `'b:'r` in addition to
|
// - OutlivesProjectionEnv: these would translate to the requirement that `'b:'r`
|
||||||
// other conditions
|
// - OutlivesProjectionTraitDef: these would translate to the requirement that `'b:'r`
|
||||||
if !env_bounds.is_empty() && env_bounds[1..].iter().all(|b| *b == env_bounds[0]) {
|
// - OutlivesProjectionComponent: this would require `'b:'r`
|
||||||
let unique_bound = env_bounds[0];
|
// 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!(
|
debug!(
|
||||||
"projection_must_outlive: unique declared bound = {:?}",
|
"projection_must_outlive: unique trait bound = {:?}",
|
||||||
unique_bound
|
unique_bound
|
||||||
);
|
);
|
||||||
if projection_ty
|
debug!("projection_must_outlive: unique declared bound appears in trait ref");
|
||||||
.substs
|
self.delegate
|
||||||
.regions()
|
.push_sub_region_constraint(origin.clone(), region, unique_bound);
|
||||||
.any(|r| env_bounds.contains(&r))
|
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
|
// Fallback to verifying after the fact that there exists a
|
||||||
|
@ -442,216 +467,11 @@ where
|
||||||
// projection outlive; in some cases, this may add insufficient
|
// projection outlive; in some cases, this may add insufficient
|
||||||
// edges into the inference graph, leading to inference failures
|
// edges into the inference graph, leading to inference failures
|
||||||
// even though a satisfactory solution exists.
|
// even though a satisfactory solution exists.
|
||||||
let verify_bound = self.projection_bound(env_bounds, projection_ty);
|
|
||||||
let generic = GenericKind::Projection(projection_ty);
|
let generic = GenericKind::Projection(projection_ty);
|
||||||
|
let verify_bound = self.verify_bound.generic_bound(generic);
|
||||||
self.delegate
|
self.delegate
|
||||||
.push_verify(origin, generic.clone(), region, verify_bound);
|
.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> {
|
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)
|
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>),
|
Projection(ty::ProjectionTy<'tcx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When we introduce a verification step, we wish to test that a
|
EnumTypeFoldableImpl! {
|
||||||
/// particular region (let's call it `'min`) meets some bound.
|
impl<'tcx> TypeFoldable<'tcx> for GenericKind<'tcx> {
|
||||||
/// The bound is described the by the following grammar:
|
(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)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum VerifyBound<'tcx> {
|
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
|
/// fn(min) -> bool {
|
||||||
/// regions in {R}, so if any of those outlives 'min, then the
|
/// if G == K {
|
||||||
/// bound is met.
|
/// B(min)
|
||||||
AnyRegion(Vec<Region<'tcx>>),
|
/// } else {
|
||||||
|
/// false
|
||||||
/// B = forall {R} --> all 'r in {R} must outlive 'min
|
/// }
|
||||||
|
/// }
|
||||||
///
|
///
|
||||||
/// Put another way, the subject value is known to outlive some
|
/// In other words, if the generic `G` that we are checking is
|
||||||
/// region in {R}, so if all of those outlives 'min, then the bound
|
/// equal to `K`, then check the associated verify bound
|
||||||
/// is met.
|
/// (otherwise, false).
|
||||||
AllRegions(Vec<Region<'tcx>>),
|
///
|
||||||
|
/// 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>>),
|
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>>),
|
AllBounds(Vec<VerifyBound<'tcx>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -882,33 +947,23 @@ impl<'a, 'gcx, 'tcx> GenericKind<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> VerifyBound<'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 {
|
pub fn must_hold(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
&VerifyBound::AnyRegion(ref bs) => bs.contains(&&ty::ReStatic),
|
VerifyBound::IfEq(..) => false,
|
||||||
&VerifyBound::AllRegions(ref bs) => bs.is_empty(),
|
VerifyBound::OutlivedBy(ty::ReStatic) => true,
|
||||||
&VerifyBound::AnyBound(ref bs) => bs.iter().any(|b| b.must_hold()),
|
VerifyBound::OutlivedBy(_) => false,
|
||||||
&VerifyBound::AllBounds(ref bs) => bs.iter().all(|b| b.must_hold()),
|
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 {
|
pub fn cannot_hold(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
&VerifyBound::AnyRegion(ref bs) => bs.is_empty(),
|
VerifyBound::IfEq(_, b) => b.cannot_hold(),
|
||||||
&VerifyBound::AllRegions(ref bs) => bs.contains(&&ty::ReEmpty),
|
VerifyBound::OutlivedBy(ty::ReEmpty) => true,
|
||||||
&VerifyBound::AnyBound(ref bs) => bs.iter().all(|b| b.cannot_hold()),
|
VerifyBound::OutlivedBy(_) => false,
|
||||||
&VerifyBound::AllBounds(ref bs) => bs.iter().any(|b| b.cannot_hold()),
|
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)]
|
#[derive(Debug)]
|
||||||
pub(super) struct TaintSet<'tcx> {
|
pub(super) struct TaintSet<'tcx> {
|
||||||
directions: TaintDirections,
|
directions: TaintDirections,
|
||||||
regions: FxHashSet<ty::Region<'tcx>>
|
regions: FxHashSet<ty::Region<'tcx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TaintSet<'tcx> {
|
impl<'tcx> TaintSet<'tcx> {
|
||||||
pub(super) fn new(directions: TaintDirections,
|
pub(super) fn new(directions: TaintDirections, initial_region: ty::Region<'tcx>) -> Self {
|
||||||
initial_region: ty::Region<'tcx>)
|
|
||||||
-> Self {
|
|
||||||
let mut regions = FxHashSet();
|
let mut regions = FxHashSet();
|
||||||
regions.insert(initial_region);
|
regions.insert(initial_region);
|
||||||
TaintSet { directions: directions, regions: regions }
|
TaintSet {
|
||||||
|
directions: directions,
|
||||||
|
regions: regions,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn fixed_point(&mut self,
|
pub(super) fn fixed_point(
|
||||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
&mut self,
|
||||||
undo_log: &[UndoLogEntry<'tcx>],
|
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||||
verifys: &[Verify<'tcx>]) {
|
undo_log: &[UndoLogEntry<'tcx>],
|
||||||
|
verifys: &[Verify<'tcx>],
|
||||||
|
) {
|
||||||
let mut prev_len = 0;
|
let mut prev_len = 0;
|
||||||
while prev_len < self.len() {
|
while prev_len < self.len() {
|
||||||
debug!("tainted: prev_len = {:?} new_len = {:?}",
|
debug!(
|
||||||
prev_len, self.len());
|
"tainted: prev_len = {:?} new_len = {:?}",
|
||||||
|
prev_len,
|
||||||
|
self.len()
|
||||||
|
);
|
||||||
|
|
||||||
prev_len = self.len();
|
prev_len = self.len();
|
||||||
|
|
||||||
for undo_entry in undo_log {
|
for undo_entry in undo_log {
|
||||||
match undo_entry {
|
match undo_entry {
|
||||||
&AddConstraint(Constraint::VarSubVar(a, b)) => {
|
&AddConstraint(Constraint::VarSubVar(a, b)) => {
|
||||||
self.add_edge(tcx.mk_region(ReVar(a)),
|
self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
|
||||||
tcx.mk_region(ReVar(b)));
|
|
||||||
}
|
}
|
||||||
&AddConstraint(Constraint::RegSubVar(a, b)) => {
|
&AddConstraint(Constraint::RegSubVar(a, b)) => {
|
||||||
self.add_edge(a, tcx.mk_region(ReVar(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)));
|
self.add_edge(a, tcx.mk_region(ReVar(b)));
|
||||||
}
|
}
|
||||||
&AddVerify(i) => {
|
&AddVerify(i) => {
|
||||||
verifys[i].bound.for_each_region(&mut |b| {
|
span_bug!(
|
||||||
self.add_edge(verifys[i].region, b);
|
verifys[i].origin.span(),
|
||||||
});
|
"we never add verifications while doing higher-ranked things",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
&Purged |
|
&Purged | &AddCombination(..) | &AddVar(..) | &OpenSnapshot
|
||||||
&AddCombination(..) |
|
| &CommitedSnapshot => {}
|
||||||
&AddVar(..) |
|
|
||||||
&OpenSnapshot |
|
|
||||||
&CommitedSnapshot => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,9 +80,7 @@ impl<'tcx> TaintSet<'tcx> {
|
||||||
self.regions.len()
|
self.regions.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_edge(&mut self,
|
fn add_edge(&mut self, source: ty::Region<'tcx>, target: ty::Region<'tcx>) {
|
||||||
source: ty::Region<'tcx>,
|
|
||||||
target: ty::Region<'tcx>) {
|
|
||||||
if self.directions.incoming {
|
if self.directions.incoming {
|
||||||
if self.regions.contains(&target) {
|
if self.regions.contains(&target) {
|
||||||
self.regions.insert(source);
|
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::hash_map::Entry;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
|
||||||
|
|
||||||
use infer::region_constraints::{Constraint, RegionConstraintData};
|
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::fold::TypeFolder;
|
||||||
use ty::{Region, RegionVid};
|
use ty::{Region, RegionVid};
|
||||||
|
@ -227,20 +226,18 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|param| match param.kind {
|
.filter_map(|param| match param.kind {
|
||||||
ty::GenericParamDefKind::Lifetime => Some(param.name.to_string()),
|
ty::GenericParamDefKind::Lifetime => Some(param.name.to_string()),
|
||||||
_ => None
|
_ => None,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let body_ids: FxHashSet<_> = infcx
|
let body_id_map: FxHashMap<_, _> = infcx
|
||||||
.region_obligations
|
.region_obligations
|
||||||
.borrow()
|
.borrow()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&(id, _)| id)
|
.map(|&(id, _)| (id, vec![]))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
for id in body_ids {
|
infcx.process_registered_region_obligations(&body_id_map, None, full_env.clone());
|
||||||
infcx.process_registered_region_obligations(&[], None, full_env.clone(), id);
|
|
||||||
}
|
|
||||||
|
|
||||||
let region_data = infcx
|
let region_data = infcx
|
||||||
.borrow_region_constraints()
|
.borrow_region_constraints()
|
||||||
|
@ -359,8 +356,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
||||||
&Err(SelectionError::Unimplemented) => {
|
&Err(SelectionError::Unimplemented) => {
|
||||||
if self.is_of_param(pred.skip_binder().trait_ref.substs) {
|
if self.is_of_param(pred.skip_binder().trait_ref.substs) {
|
||||||
already_visited.remove(&pred);
|
already_visited.remove(&pred);
|
||||||
self.add_user_pred(&mut user_computed_preds,
|
self.add_user_pred(
|
||||||
ty::Predicate::Trait(pred.clone()));
|
&mut user_computed_preds,
|
||||||
|
ty::Predicate::Trait(pred.clone()),
|
||||||
|
);
|
||||||
predicates.push_back(pred);
|
predicates.push_back(pred);
|
||||||
} else {
|
} else {
|
||||||
debug!(
|
debug!(
|
||||||
|
@ -418,8 +417,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
||||||
// under which a type implements an auto trait. A trait predicate involving
|
// 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,
|
// a HRTB means that the type needs to work with any choice of lifetime,
|
||||||
// not just one specific lifetime (e.g. 'static).
|
// not just one specific lifetime (e.g. 'static).
|
||||||
fn add_user_pred<'c>(&self, user_computed_preds: &mut FxHashSet<ty::Predicate<'c>>,
|
fn add_user_pred<'c>(
|
||||||
new_pred: ty::Predicate<'c>) {
|
&self,
|
||||||
|
user_computed_preds: &mut FxHashSet<ty::Predicate<'c>>,
|
||||||
|
new_pred: ty::Predicate<'c>,
|
||||||
|
) {
|
||||||
let mut should_add_new = true;
|
let mut should_add_new = true;
|
||||||
user_computed_preds.retain(|&old_pred| {
|
user_computed_preds.retain(|&old_pred| {
|
||||||
match (&new_pred, 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()) {
|
if !new_substs.types().eq(old_substs.types()) {
|
||||||
// We can't compare lifetimes if the types are different,
|
// We can't compare lifetimes if the types are different,
|
||||||
// so skip checking old_pred
|
// so skip checking old_pred
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (new_region, old_region) in new_substs
|
for (new_region, old_region) in
|
||||||
.regions()
|
new_substs.regions().zip(old_substs.regions())
|
||||||
.zip(old_substs.regions()) {
|
{
|
||||||
|
|
||||||
match (new_region, old_region) {
|
match (new_region, old_region) {
|
||||||
// If both predicates have an 'ReLateBound' (a HRTB) in the
|
// If both predicates have an 'ReLateBound' (a HRTB) in the
|
||||||
// same spot, we do nothing
|
// same spot, we do nothing
|
||||||
(
|
(
|
||||||
ty::RegionKind::ReLateBound(_, _),
|
ty::RegionKind::ReLateBound(_, _),
|
||||||
ty::RegionKind::ReLateBound(_, _)
|
ty::RegionKind::ReLateBound(_, _),
|
||||||
) => {},
|
) => {}
|
||||||
|
|
||||||
(ty::RegionKind::ReLateBound(_, _), _) => {
|
(ty::RegionKind::ReLateBound(_, _), _) => {
|
||||||
// The new predicate has a HRTB in a spot where the old
|
// 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
|
// so we return 'false' to remove the old predicate from
|
||||||
// user_computed_preds
|
// user_computed_preds
|
||||||
return false;
|
return false;
|
||||||
},
|
}
|
||||||
(_, ty::RegionKind::ReLateBound(_, _)) => {
|
(_, ty::RegionKind::ReLateBound(_, _)) => {
|
||||||
// This is the opposite situation as the previous arm - the
|
// This is the opposite situation as the previous arm - the
|
||||||
// old predicate has a HRTB lifetime in a place where 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 {
|
if should_add_new {
|
||||||
|
@ -513,28 +514,20 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
||||||
match constraint {
|
match constraint {
|
||||||
&Constraint::VarSubVar(r1, r2) => {
|
&Constraint::VarSubVar(r1, r2) => {
|
||||||
{
|
{
|
||||||
let deps1 = vid_map
|
let deps1 = vid_map.entry(RegionTarget::RegionVid(r1)).or_default();
|
||||||
.entry(RegionTarget::RegionVid(r1))
|
|
||||||
.or_default();
|
|
||||||
deps1.larger.insert(RegionTarget::RegionVid(r2));
|
deps1.larger.insert(RegionTarget::RegionVid(r2));
|
||||||
}
|
}
|
||||||
|
|
||||||
let deps2 = vid_map
|
let deps2 = vid_map.entry(RegionTarget::RegionVid(r2)).or_default();
|
||||||
.entry(RegionTarget::RegionVid(r2))
|
|
||||||
.or_default();
|
|
||||||
deps2.smaller.insert(RegionTarget::RegionVid(r1));
|
deps2.smaller.insert(RegionTarget::RegionVid(r1));
|
||||||
}
|
}
|
||||||
&Constraint::RegSubVar(region, vid) => {
|
&Constraint::RegSubVar(region, vid) => {
|
||||||
{
|
{
|
||||||
let deps1 = vid_map
|
let deps1 = vid_map.entry(RegionTarget::Region(region)).or_default();
|
||||||
.entry(RegionTarget::Region(region))
|
|
||||||
.or_default();
|
|
||||||
deps1.larger.insert(RegionTarget::RegionVid(vid));
|
deps1.larger.insert(RegionTarget::RegionVid(vid));
|
||||||
}
|
}
|
||||||
|
|
||||||
let deps2 = vid_map
|
let deps2 = vid_map.entry(RegionTarget::RegionVid(vid)).or_default();
|
||||||
.entry(RegionTarget::RegionVid(vid))
|
|
||||||
.or_default();
|
|
||||||
deps2.smaller.insert(RegionTarget::Region(region));
|
deps2.smaller.insert(RegionTarget::Region(region));
|
||||||
}
|
}
|
||||||
&Constraint::VarSubReg(vid, region) => {
|
&Constraint::VarSubReg(vid, region) => {
|
||||||
|
@ -542,15 +535,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
&Constraint::RegSubReg(r1, r2) => {
|
&Constraint::RegSubReg(r1, r2) => {
|
||||||
{
|
{
|
||||||
let deps1 = vid_map
|
let deps1 = vid_map.entry(RegionTarget::Region(r1)).or_default();
|
||||||
.entry(RegionTarget::Region(r1))
|
|
||||||
.or_default();
|
|
||||||
deps1.larger.insert(RegionTarget::Region(r2));
|
deps1.larger.insert(RegionTarget::Region(r2));
|
||||||
}
|
}
|
||||||
|
|
||||||
let deps2 = vid_map
|
let deps2 = vid_map.entry(RegionTarget::Region(r2)).or_default();
|
||||||
.entry(RegionTarget::Region(r2))
|
|
||||||
.or_default();
|
|
||||||
deps2.smaller.insert(RegionTarget::Region(r1));
|
deps2.smaller.insert(RegionTarget::Region(r1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -683,7 +672,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&ty::Predicate::RegionOutlives(ref binder) => {
|
&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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -693,23 +686,17 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
||||||
binder.map_bound_ref(|pred| pred.0).no_late_bound_regions(),
|
binder.map_bound_ref(|pred| pred.0).no_late_bound_regions(),
|
||||||
) {
|
) {
|
||||||
(None, Some(t_a)) => {
|
(None, Some(t_a)) => {
|
||||||
select.infcx().register_region_obligation(
|
select.infcx().register_region_obligation_with_cause(
|
||||||
ast::DUMMY_NODE_ID,
|
t_a,
|
||||||
RegionObligation {
|
select.infcx().tcx.types.re_static,
|
||||||
sup_type: t_a,
|
&dummy_cause,
|
||||||
sub_region: select.infcx().tcx.types.re_static,
|
|
||||||
cause: dummy_cause.clone(),
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
(Some(ty::OutlivesPredicate(t_a, r_b)), _) => {
|
(Some(ty::OutlivesPredicate(t_a, r_b)), _) => {
|
||||||
select.infcx().register_region_obligation(
|
select.infcx().register_region_obligation_with_cause(
|
||||||
ast::DUMMY_NODE_ID,
|
t_a,
|
||||||
RegionObligation {
|
r_b,
|
||||||
sup_type: t_a,
|
&dummy_cause,
|
||||||
sub_region: r_b,
|
|
||||||
cause: dummy_cause.clone(),
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use infer::{RegionObligation, InferCtxt};
|
use infer::InferCtxt;
|
||||||
use mir::interpret::GlobalId;
|
use mir::interpret::GlobalId;
|
||||||
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate};
|
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate};
|
||||||
use ty::error::ExpectedFound;
|
use ty::error::ExpectedFound;
|
||||||
|
@ -372,13 +372,11 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
|
||||||
Some(t_a) => {
|
Some(t_a) => {
|
||||||
let r_static = self.selcx.tcx().types.re_static;
|
let r_static = self.selcx.tcx().types.re_static;
|
||||||
if self.register_region_obligations {
|
if self.register_region_obligations {
|
||||||
self.selcx.infcx().register_region_obligation(
|
self.selcx.infcx().register_region_obligation_with_cause(
|
||||||
obligation.cause.body_id,
|
t_a,
|
||||||
RegionObligation {
|
r_static,
|
||||||
sup_type: t_a,
|
&obligation.cause,
|
||||||
sub_region: r_static,
|
);
|
||||||
cause: obligation.cause.clone(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
ProcessResult::Changed(vec![])
|
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.
|
// If there aren't, register the obligation.
|
||||||
Some(ty::OutlivesPredicate(t_a, r_b)) => {
|
Some(ty::OutlivesPredicate(t_a, r_b)) => {
|
||||||
if self.register_region_obligations {
|
if self.register_region_obligations {
|
||||||
self.selcx.infcx().register_region_obligation(
|
self.selcx.infcx().register_region_obligation_with_cause(
|
||||||
obligation.cause.body_id,
|
t_a,
|
||||||
RegionObligation {
|
r_b,
|
||||||
sup_type: t_a,
|
&obligation.cause,
|
||||||
sub_region: r_b,
|
);
|
||||||
cause: obligation.cause.clone()
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
ProcessResult::Changed(vec![])
|
ProcessResult::Changed(vec![])
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ pub use self::ObligationCauseCode::*;
|
||||||
use chalk_engine;
|
use chalk_engine;
|
||||||
use hir;
|
use hir;
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
|
use infer::SuppressRegionErrors;
|
||||||
use infer::outlives::env::OutlivesEnvironment;
|
use infer::outlives::env::OutlivesEnvironment;
|
||||||
use middle::region;
|
use middle::region;
|
||||||
use mir::interpret::ConstEvalErr;
|
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`.
|
// cares about declarations like `'a: 'b`.
|
||||||
let outlives_env = OutlivesEnvironment::new(elaborated_env);
|
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) {
|
let predicates = match infcx.fully_resolve(&predicates) {
|
||||||
Ok(predicates) => predicates,
|
Ok(predicates) => predicates,
|
||||||
|
|
|
@ -535,6 +535,13 @@ impl<I: Idx, T> IndexVec<I, T> {
|
||||||
self.raw.len()
|
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]
|
#[inline]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.raw.is_empty()
|
self.raw.is_empty()
|
||||||
|
|
|
@ -14,29 +14,29 @@ use std::path::PathBuf;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
|
|
||||||
use driver;
|
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;
|
||||||
use errors::emitter::Emitter;
|
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::feature_gate::UnstableFeatures;
|
||||||
|
use syntax::source_map::{FileName, FilePathMapping, SourceMap};
|
||||||
use syntax::symbol::Symbol;
|
use syntax::symbol::Symbol;
|
||||||
use syntax_pos::DUMMY_SP;
|
use syntax_pos::DUMMY_SP;
|
||||||
|
|
||||||
|
@ -90,13 +90,15 @@ impl Emitter for ExpectErrorEmitter {
|
||||||
|
|
||||||
fn errors(msgs: &[&str]) -> (Box<dyn Emitter + sync::Send>, usize) {
|
fn errors(msgs: &[&str]) -> (Box<dyn Emitter + sync::Send>, usize) {
|
||||||
let v = msgs.iter().map(|m| m.to_string()).collect();
|
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,
|
fn test_env<F>(source_string: &str, args: (Box<dyn Emitter + sync::Send>, usize), body: F)
|
||||||
args: (Box<dyn Emitter + sync::Send>, usize),
|
where
|
||||||
body: F)
|
F: FnOnce(Env),
|
||||||
where F: FnOnce(Env)
|
|
||||||
{
|
{
|
||||||
syntax::with_globals(|| {
|
syntax::with_globals(|| {
|
||||||
let mut options = config::Options::default();
|
let mut options = config::Options::default();
|
||||||
|
@ -113,34 +115,41 @@ fn test_env_with_pool<F>(
|
||||||
options: config::Options,
|
options: config::Options,
|
||||||
source_string: &str,
|
source_string: &str,
|
||||||
(emitter, expected_err_count): (Box<dyn Emitter + sync::Send>, usize),
|
(emitter, expected_err_count): (Box<dyn Emitter + sync::Send>, usize),
|
||||||
body: F
|
body: F,
|
||||||
)
|
) where
|
||||||
where F: FnOnce(Env)
|
F: FnOnce(Env),
|
||||||
{
|
{
|
||||||
let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);
|
let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);
|
||||||
let sess = session::build_session_(options,
|
let sess = session::build_session_(
|
||||||
None,
|
options,
|
||||||
diagnostic_handler,
|
None,
|
||||||
Lrc::new(SourceMap::new(FilePathMapping::empty())));
|
diagnostic_handler,
|
||||||
|
Lrc::new(SourceMap::new(FilePathMapping::empty())),
|
||||||
|
);
|
||||||
let cstore = CStore::new(::get_codegen_backend(&sess).metadata_loader());
|
let cstore = CStore::new(::get_codegen_backend(&sess).metadata_loader());
|
||||||
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
|
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
|
||||||
let input = config::Input::Str {
|
let input = config::Input::Str {
|
||||||
name: FileName::Anon,
|
name: FileName::Anon,
|
||||||
input: source_string.to_string(),
|
input: source_string.to_string(),
|
||||||
};
|
};
|
||||||
let krate = driver::phase_1_parse_input(&driver::CompileController::basic(),
|
let krate =
|
||||||
&sess,
|
driver::phase_1_parse_input(&driver::CompileController::basic(), &sess, &input).unwrap();
|
||||||
&input).unwrap();
|
let driver::ExpansionResult {
|
||||||
let driver::ExpansionResult { defs, resolutions, mut hir_forest, .. } = {
|
defs,
|
||||||
driver::phase_2_configure_and_expand(&sess,
|
resolutions,
|
||||||
&cstore,
|
mut hir_forest,
|
||||||
krate,
|
..
|
||||||
None,
|
} = {
|
||||||
"test",
|
driver::phase_2_configure_and_expand(
|
||||||
None,
|
&sess,
|
||||||
MakeGlobMap::No,
|
&cstore,
|
||||||
|_| Ok(()))
|
krate,
|
||||||
.expect("phase 2 aborted")
|
None,
|
||||||
|
"test",
|
||||||
|
None,
|
||||||
|
MakeGlobMap::No,
|
||||||
|
|_| Ok(()),
|
||||||
|
).expect("phase 2 aborted")
|
||||||
};
|
};
|
||||||
|
|
||||||
let arenas = ty::AllArenas::new();
|
let arenas = ty::AllArenas::new();
|
||||||
|
@ -155,32 +164,39 @@ fn test_env_with_pool<F>(
|
||||||
extra: String::new(),
|
extra: String::new(),
|
||||||
outputs: OutputTypes::new(&[]),
|
outputs: OutputTypes::new(&[]),
|
||||||
};
|
};
|
||||||
TyCtxt::create_and_enter(&sess,
|
TyCtxt::create_and_enter(
|
||||||
&cstore,
|
&sess,
|
||||||
ty::query::Providers::default(),
|
&cstore,
|
||||||
ty::query::Providers::default(),
|
ty::query::Providers::default(),
|
||||||
&arenas,
|
ty::query::Providers::default(),
|
||||||
resolutions,
|
&arenas,
|
||||||
hir_map,
|
resolutions,
|
||||||
OnDiskCache::new_empty(sess.source_map()),
|
hir_map,
|
||||||
"test_crate",
|
OnDiskCache::new_empty(sess.source_map()),
|
||||||
tx,
|
"test_crate",
|
||||||
&outputs,
|
tx,
|
||||||
|tcx| {
|
&outputs,
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
|tcx| {
|
||||||
let mut region_scope_tree = region::ScopeTree::default();
|
tcx.infer_ctxt().enter(|infcx| {
|
||||||
let param_env = ty::ParamEnv::empty();
|
let mut region_scope_tree = region::ScopeTree::default();
|
||||||
body(Env {
|
let param_env = ty::ParamEnv::empty();
|
||||||
infcx: &infcx,
|
body(Env {
|
||||||
region_scope_tree: &mut region_scope_tree,
|
infcx: &infcx,
|
||||||
param_env: param_env,
|
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 {
|
fn d1() -> ty::DebruijnIndex {
|
||||||
|
@ -196,9 +212,15 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
||||||
self.infcx.tcx
|
self.infcx.tcx
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_region_hierarchy(&mut self, rh: &RH,
|
pub fn create_region_hierarchy(
|
||||||
parent: (region::Scope, region::ScopeDepth)) {
|
&mut self,
|
||||||
let me = region::Scope { id: rh.id, data: region::ScopeData::Node };
|
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));
|
self.region_scope_tree.record_scope_parent(me, Some(parent));
|
||||||
for child_rh in rh.sub {
|
for child_rh in rh.sub {
|
||||||
self.create_region_hierarchy(child_rh, (me, parent.1 + 1));
|
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 {
|
let dscope = region::Scope {
|
||||||
id: hir::ItemLocalId(1),
|
id: hir::ItemLocalId(1),
|
||||||
data: region::ScopeData::Destruction
|
data: region::ScopeData::Destruction,
|
||||||
};
|
};
|
||||||
self.region_scope_tree.record_scope_parent(dscope, None);
|
self.region_scope_tree.record_scope_parent(dscope, None);
|
||||||
self.create_region_hierarchy(&RH {
|
self.create_region_hierarchy(
|
||||||
id: hir::ItemLocalId(1),
|
&RH {
|
||||||
sub: &[RH {
|
id: hir::ItemLocalId(1),
|
||||||
id: hir::ItemLocalId(10),
|
sub: &[
|
||||||
sub: &[],
|
RH {
|
||||||
|
id: hir::ItemLocalId(10),
|
||||||
|
sub: &[],
|
||||||
|
},
|
||||||
|
RH {
|
||||||
|
id: hir::ItemLocalId(11),
|
||||||
|
sub: &[],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
RH {
|
(dscope, 1),
|
||||||
id: hir::ItemLocalId(11),
|
);
|
||||||
sub: &[],
|
|
||||||
}],
|
|
||||||
}, (dscope, 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)] // this seems like it could be useful, even if we don't use it now
|
#[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,
|
fn search_mod(
|
||||||
m: &hir::Mod,
|
this: &Env,
|
||||||
idx: usize,
|
m: &hir::Mod,
|
||||||
names: &[String])
|
idx: usize,
|
||||||
-> Option<ast::NodeId> {
|
names: &[String],
|
||||||
|
) -> Option<ast::NodeId> {
|
||||||
assert!(idx < names.len());
|
assert!(idx < names.len());
|
||||||
for item in &m.item_ids {
|
for item in &m.item_ids {
|
||||||
let item = this.infcx.tcx.hir.expect_item(item.id);
|
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 {
|
return match it.node {
|
||||||
hir::ItemKind::Use(..) |
|
hir::ItemKind::Use(..)
|
||||||
hir::ItemKind::ExternCrate(..) |
|
| hir::ItemKind::ExternCrate(..)
|
||||||
hir::ItemKind::Const(..) |
|
| hir::ItemKind::Const(..)
|
||||||
hir::ItemKind::Static(..) |
|
| hir::ItemKind::Static(..)
|
||||||
hir::ItemKind::Fn(..) |
|
| hir::ItemKind::Fn(..)
|
||||||
hir::ItemKind::ForeignMod(..) |
|
| hir::ItemKind::ForeignMod(..)
|
||||||
hir::ItemKind::GlobalAsm(..) |
|
| hir::ItemKind::GlobalAsm(..)
|
||||||
hir::ItemKind::Existential(..) |
|
| hir::ItemKind::Existential(..)
|
||||||
hir::ItemKind::Ty(..) => None,
|
| hir::ItemKind::Ty(..) => None,
|
||||||
|
|
||||||
hir::ItemKind::Enum(..) |
|
hir::ItemKind::Enum(..)
|
||||||
hir::ItemKind::Struct(..) |
|
| hir::ItemKind::Struct(..)
|
||||||
hir::ItemKind::Union(..) |
|
| hir::ItemKind::Union(..)
|
||||||
hir::ItemKind::Trait(..) |
|
| hir::ItemKind::Trait(..)
|
||||||
hir::ItemKind::TraitAlias(..) |
|
| hir::ItemKind::TraitAlias(..)
|
||||||
hir::ItemKind::Impl(..) => None,
|
| hir::ItemKind::Impl(..) => None,
|
||||||
|
|
||||||
hir::ItemKind::Mod(ref m) => search_mod(this, m, idx, names),
|
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 {
|
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,
|
Ok(_) => true,
|
||||||
Err(ref e) => panic!("Encountered error: {}", e),
|
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> {
|
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(
|
self.infcx
|
||||||
input_tys.iter().cloned(),
|
.tcx
|
||||||
output_ty,
|
.mk_fn_ptr(ty::Binder::bind(self.infcx.tcx.mk_fn_sig(
|
||||||
false,
|
input_tys.iter().cloned(),
|
||||||
hir::Unsafety::Normal,
|
output_ty,
|
||||||
Abi::Rust
|
false,
|
||||||
)))
|
hir::Unsafety::Normal,
|
||||||
|
Abi::Rust,
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn t_nil(&self) -> Ty<'tcx> {
|
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> {
|
pub fn t_param(&self, index: u32) -> Ty<'tcx> {
|
||||||
let name = format!("T{}", index);
|
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> {
|
pub fn re_early_bound(&self, index: u32, name: &'static str) -> ty::Region<'tcx> {
|
||||||
let name = Symbol::intern(name).as_interned_str();
|
let name = Symbol::intern(name).as_interned_str();
|
||||||
self.infcx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
|
self.infcx
|
||||||
def_id: self.infcx.tcx.hir.local_def_id(ast::CRATE_NODE_ID),
|
.tcx
|
||||||
index,
|
.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
|
||||||
name,
|
def_id: self.infcx.tcx.hir.local_def_id(ast::CRATE_NODE_ID),
|
||||||
}))
|
index,
|
||||||
|
name,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn re_late_bound_with_debruijn(&self,
|
pub fn re_late_bound_with_debruijn(
|
||||||
id: u32,
|
&self,
|
||||||
debruijn: ty::DebruijnIndex)
|
id: u32,
|
||||||
-> ty::Region<'tcx> {
|
debruijn: ty::DebruijnIndex,
|
||||||
self.infcx.tcx.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(id)))
|
) -> 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> {
|
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)
|
self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn t_rptr_late_bound_with_debruijn(&self,
|
pub fn t_rptr_late_bound_with_debruijn(
|
||||||
id: u32,
|
&self,
|
||||||
debruijn: ty::DebruijnIndex)
|
id: u32,
|
||||||
-> Ty<'tcx> {
|
debruijn: ty::DebruijnIndex,
|
||||||
|
) -> Ty<'tcx> {
|
||||||
let r = self.re_late_bound_with_debruijn(id, debruijn);
|
let r = self.re_late_bound_with_debruijn(id, debruijn);
|
||||||
self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
|
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> {
|
pub fn t_rptr_scope(&self, id: u32) -> Ty<'tcx> {
|
||||||
let r = ty::ReScope(region::Scope {
|
let r = ty::ReScope(region::Scope {
|
||||||
id: hir::ItemLocalId(id),
|
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> {
|
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, ()> {
|
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
|
/// Checks that `t1 <: t2` is true (this may register additional
|
||||||
/// region checks).
|
/// region checks).
|
||||||
pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
|
pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
|
||||||
match self.sub(t1, t2) {
|
match self.sub(t1, t2) {
|
||||||
Ok(InferOk { obligations, value: () }) => {
|
Ok(InferOk {
|
||||||
|
obligations,
|
||||||
|
value: (),
|
||||||
|
}) => {
|
||||||
// None of these tests should require nested obligations:
|
// None of these tests should require nested obligations:
|
||||||
assert!(obligations.is_empty());
|
assert!(obligations.is_empty());
|
||||||
}
|
}
|
||||||
|
@ -445,8 +493,10 @@ fn sub_free_bound_false() {
|
||||||
env.create_simple_region_hierarchy();
|
env.create_simple_region_hierarchy();
|
||||||
let t_rptr_free1 = env.t_rptr_free(1);
|
let t_rptr_free1 = env.t_rptr_free(1);
|
||||||
let t_rptr_bound1 = env.t_rptr_late_bound(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.check_not_sub(
|
||||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
|
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();
|
env.create_simple_region_hierarchy();
|
||||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||||
let t_rptr_free1 = env.t_rptr_free(1);
|
let t_rptr_free1 = env.t_rptr_free(1);
|
||||||
env.check_sub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
|
env.check_sub(
|
||||||
env.t_fn(&[t_rptr_free1], env.tcx().types.isize));
|
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`.
|
//! does NOT hold for any instantiation of `_#1`.
|
||||||
|
|
||||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
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);
|
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||||
env.check_not_sub(env.t_fn(&[t_infer1], env.tcx().types.isize),
|
env.check_not_sub(
|
||||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
|
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.
|
/// This requires adjusting the Debruijn index.
|
||||||
#[test]
|
#[test]
|
||||||
fn subst_ty_renumber_bound() {
|
fn subst_ty_renumber_bound() {
|
||||||
|
|
||||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||||
// Situation:
|
// Situation:
|
||||||
// Theta = [A -> &'a foo]
|
// Theta = [A -> &'a foo]
|
||||||
|
@ -509,11 +563,10 @@ fn subst_ty_renumber_bound() {
|
||||||
env.t_fn(&[t_ptr_bound2], env.t_nil())
|
env.t_fn(&[t_ptr_bound2], env.t_nil())
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
|
debug!(
|
||||||
t_source,
|
"subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
|
||||||
substs,
|
t_source, substs, t_substituted, t_expected
|
||||||
t_substituted,
|
);
|
||||||
t_expected);
|
|
||||||
|
|
||||||
assert_eq!(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()))
|
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={:?}",
|
debug!(
|
||||||
t_source,
|
"subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
|
||||||
substs,
|
t_source, substs, t_substituted, t_expected
|
||||||
t_substituted,
|
);
|
||||||
t_expected);
|
|
||||||
|
|
||||||
assert_eq!(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 that we correctly compute whether a type has escaping regions or not.
|
||||||
#[test]
|
#[test]
|
||||||
fn escaping() {
|
fn escaping() {
|
||||||
|
|
||||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
|
test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
|
||||||
// Situation:
|
// Situation:
|
||||||
// Theta = [A -> &'a foo]
|
// Theta = [A -> &'a foo]
|
||||||
|
@ -608,11 +659,10 @@ fn subst_region_renumber_region() {
|
||||||
env.t_fn(&[t_rptr_bound2], env.t_nil())
|
env.t_fn(&[t_rptr_bound2], env.t_nil())
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
|
debug!(
|
||||||
t_source,
|
"subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
|
||||||
substs,
|
t_source, substs, t_substituted, t_expected
|
||||||
t_substituted,
|
);
|
||||||
t_expected);
|
|
||||||
|
|
||||||
assert_eq!(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 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 tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, usize_ty]);
|
||||||
let walked: Vec<_> = tup2_ty.walk().collect();
|
let walked: Vec<_> = tup2_ty.walk().collect();
|
||||||
assert_eq!(walked,
|
assert_eq!(
|
||||||
[tup2_ty, tup1_ty, int_ty, usize_ty, int_ty, usize_ty, tup1_ty, int_ty,
|
walked,
|
||||||
usize_ty, int_ty, usize_ty, usize_ty]);
|
[
|
||||||
|
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
|
// types we expect to see (in order), plus a boolean saying
|
||||||
// whether to skip the subtree.
|
// whether to skip the subtree.
|
||||||
let mut expected = vec![(tup2_ty, false),
|
let mut expected = vec![
|
||||||
(tup1_ty, false),
|
(tup2_ty, false),
|
||||||
(int_ty, false),
|
(tup1_ty, false),
|
||||||
(usize_ty, false),
|
(int_ty, false),
|
||||||
(int_ty, false),
|
(usize_ty, false),
|
||||||
(usize_ty, false),
|
(int_ty, false),
|
||||||
(tup1_ty, true), // skip the isize/usize/isize/usize
|
(usize_ty, false),
|
||||||
(usize_ty, false)];
|
(tup1_ty, true), // skip the isize/usize/isize/usize
|
||||||
|
(usize_ty, false),
|
||||||
|
];
|
||||||
expected.reverse();
|
expected.reverse();
|
||||||
|
|
||||||
let mut walker = tup2_ty.walk();
|
let mut walker = tup2_ty.walk();
|
||||||
|
|
|
@ -10,15 +10,13 @@
|
||||||
|
|
||||||
use super::universal_regions::UniversalRegions;
|
use super::universal_regions::UniversalRegions;
|
||||||
use borrow_check::nll::constraints::graph::NormalConstraintGraph;
|
use borrow_check::nll::constraints::graph::NormalConstraintGraph;
|
||||||
use borrow_check::nll::constraints::{
|
use borrow_check::nll::constraints::{ConstraintSccIndex, ConstraintSet, OutlivesConstraint};
|
||||||
ConstraintSccIndex, ConstraintSet, OutlivesConstraint,
|
|
||||||
};
|
|
||||||
use borrow_check::nll::region_infer::values::{RegionElement, ToElementIndex};
|
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::free_region_relations::UniversalRegionRelations;
|
||||||
use borrow_check::nll::type_check::Locations;
|
use borrow_check::nll::type_check::Locations;
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::infer::canonical::QueryRegionConstraint;
|
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::infer::{InferCtxt, NLLRegionVariableOrigin, RegionVariableOrigin};
|
||||||
use rustc::mir::{
|
use rustc::mir::{
|
||||||
ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, Local, Location,
|
ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, Local, Location,
|
||||||
|
@ -29,7 +27,7 @@ use rustc::util::common;
|
||||||
use rustc_data_structures::bit_set::BitSet;
|
use rustc_data_structures::bit_set::BitSet;
|
||||||
use rustc_data_structures::graph::scc::Sccs;
|
use rustc_data_structures::graph::scc::Sccs;
|
||||||
use rustc_data_structures::indexed_vec::IndexVec;
|
use rustc_data_structures::indexed_vec::IndexVec;
|
||||||
use rustc_errors::{DiagnosticBuilder, Diagnostic};
|
use rustc_errors::{Diagnostic, DiagnosticBuilder};
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
@ -71,6 +69,15 @@ pub struct RegionInferenceContext<'tcx> {
|
||||||
/// visible from this index.
|
/// visible from this index.
|
||||||
scc_universes: IndexVec<ConstraintSccIndex, ty::UniverseIndex>,
|
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
|
/// The final inferred values of the region variables; we compute
|
||||||
/// one value per SCC. To get the value for any given *region*,
|
/// one value per SCC. To get the value for any given *region*,
|
||||||
/// you first find which scc it is a part of.
|
/// 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
|
/// A test which, if met by the region `'x`, proves that this type
|
||||||
/// constraint is satisfied.
|
/// constraint is satisfied.
|
||||||
pub test: RegionTest,
|
pub verify_bound: VerifyBound<'tcx>,
|
||||||
}
|
|
||||||
|
|
||||||
/// 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>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> RegionInferenceContext<'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_universes = Self::compute_scc_universes(&constraint_sccs, &definitions);
|
||||||
|
|
||||||
|
let scc_representatives = Self::compute_scc_representatives(&constraint_sccs, &definitions);
|
||||||
|
|
||||||
let mut result = Self {
|
let mut result = Self {
|
||||||
definitions,
|
definitions,
|
||||||
liveness_constraints,
|
liveness_constraints,
|
||||||
|
@ -252,6 +226,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
constraint_graph,
|
constraint_graph,
|
||||||
constraint_sccs,
|
constraint_sccs,
|
||||||
scc_universes,
|
scc_universes,
|
||||||
|
scc_representatives,
|
||||||
scc_values,
|
scc_values,
|
||||||
type_tests,
|
type_tests,
|
||||||
universal_regions,
|
universal_regions,
|
||||||
|
@ -288,6 +263,27 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
scc_universes
|
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
|
/// Initializes the region variables for each universally
|
||||||
/// quantified region (lifetime parameter). The first N variables
|
/// quantified region (lifetime parameter). The first N variables
|
||||||
/// always correspond to the regions appearing in the function
|
/// always correspond to the regions appearing in the function
|
||||||
|
@ -582,7 +578,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
for type_test in &self.type_tests {
|
for type_test in &self.type_tests {
|
||||||
debug!("check_type_test: {:?}", type_test);
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -689,7 +692,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
generic_kind,
|
generic_kind,
|
||||||
lower_bound,
|
lower_bound,
|
||||||
locations,
|
locations,
|
||||||
test: _,
|
verify_bound: _,
|
||||||
} = type_test;
|
} = type_test;
|
||||||
|
|
||||||
let generic_ty = generic_kind.to_ty(tcx);
|
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
|
// where `ur` is a local bound -- we are sometimes in a
|
||||||
// position to prove things that our caller cannot. See
|
// position to prove things that our caller cannot. See
|
||||||
// #53570 for an example.
|
// #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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -888,31 +891,99 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
|
|
||||||
/// Test if `test` is true when applied to `lower_bound` at
|
/// Test if `test` is true when applied to `lower_bound` at
|
||||||
/// `point`, and returns true or false.
|
/// `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!(
|
debug!(
|
||||||
"eval_region_test(lower_bound={:?}, test={:?})",
|
"eval_verify_bound(lower_bound={:?}, verify_bound={:?})",
|
||||||
lower_bound, test
|
lower_bound, verify_bound
|
||||||
);
|
);
|
||||||
|
|
||||||
match test {
|
match verify_bound {
|
||||||
RegionTest::IsOutlivedByAllRegionsIn(regions) => regions
|
VerifyBound::IfEq(test_ty, verify_bound1) => {
|
||||||
.iter()
|
self.eval_if_eq(tcx, mir, generic_ty, lower_bound, test_ty, verify_bound1)
|
||||||
.all(|&r| self.eval_outlives(mir, r, lower_bound)),
|
}
|
||||||
|
|
||||||
RegionTest::IsOutlivedByAnyRegionIn(regions) => regions
|
VerifyBound::OutlivedBy(r) => {
|
||||||
.iter()
|
let r_vid = self.to_region_vid(r);
|
||||||
.any(|&r| self.eval_outlives(mir, r, lower_bound)),
|
self.eval_outlives(mir, r_vid, lower_bound)
|
||||||
|
}
|
||||||
|
|
||||||
RegionTest::Any(tests) => tests
|
VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| {
|
||||||
.iter()
|
self.eval_verify_bound(tcx, mir, generic_ty, lower_bound, verify_bound)
|
||||||
.any(|test| self.eval_region_test(mir, lower_bound, test)),
|
}),
|
||||||
|
|
||||||
RegionTest::All(tests) => tests
|
VerifyBound::AllBounds(verify_bounds) => verify_bounds.iter().all(|verify_bound| {
|
||||||
.iter()
|
self.eval_verify_bound(tcx, mir, generic_ty, lower_bound, verify_bound)
|
||||||
.all(|test| self.eval_region_test(mir, lower_bound, test)),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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`.
|
// Evaluate whether `sup_region: sub_region @ point`.
|
||||||
fn eval_outlives(
|
fn eval_outlives(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -11,10 +11,11 @@
|
||||||
use borrow_check::location::LocationTable;
|
use borrow_check::location::LocationTable;
|
||||||
use borrow_check::nll::constraints::{ConstraintCategory, ConstraintSet, OutlivesConstraint};
|
use borrow_check::nll::constraints::{ConstraintCategory, ConstraintSet, OutlivesConstraint};
|
||||||
use borrow_check::nll::facts::AllFacts;
|
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::type_check::Locations;
|
||||||
use borrow_check::nll::universal_regions::UniversalRegions;
|
use borrow_check::nll::universal_regions::UniversalRegions;
|
||||||
use rustc::infer::canonical::QueryRegionConstraint;
|
use rustc::infer::canonical::QueryRegionConstraint;
|
||||||
|
use rustc::infer::outlives::env::RegionBoundPairs;
|
||||||
use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
|
use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
|
||||||
use rustc::infer::region_constraints::{GenericKind, VerifyBound};
|
use rustc::infer::region_constraints::{GenericKind, VerifyBound};
|
||||||
use rustc::infer::{self, SubregionOrigin};
|
use rustc::infer::{self, SubregionOrigin};
|
||||||
|
@ -26,7 +27,7 @@ crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
universal_regions: &'a UniversalRegions<'tcx>,
|
universal_regions: &'a UniversalRegions<'tcx>,
|
||||||
location_table: &'a LocationTable,
|
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>>,
|
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
locations: Locations,
|
locations: Locations,
|
||||||
|
@ -41,7 +42,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
|
||||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
universal_regions: &'a UniversalRegions<'tcx>,
|
universal_regions: &'a UniversalRegions<'tcx>,
|
||||||
location_table: &'a LocationTable,
|
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>>,
|
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
locations: Locations,
|
locations: Locations,
|
||||||
|
@ -139,43 +140,15 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
|
||||||
&self,
|
&self,
|
||||||
generic_kind: GenericKind<'tcx>,
|
generic_kind: GenericKind<'tcx>,
|
||||||
region: ty::Region<'tcx>,
|
region: ty::Region<'tcx>,
|
||||||
bound: VerifyBound<'tcx>,
|
verify_bound: VerifyBound<'tcx>,
|
||||||
) -> TypeTest<'tcx> {
|
) -> TypeTest<'tcx> {
|
||||||
let lower_bound = self.to_region_vid(region);
|
let lower_bound = self.to_region_vid(region);
|
||||||
|
|
||||||
let test = self.verify_bound_to_region_test(&bound);
|
|
||||||
|
|
||||||
TypeTest {
|
TypeTest {
|
||||||
generic_kind,
|
generic_kind,
|
||||||
lower_bound,
|
lower_bound,
|
||||||
locations: self.locations,
|
locations: self.locations,
|
||||||
test,
|
verify_bound,
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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(),
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,31 +17,31 @@ use borrow_check::nll::constraints::{ConstraintCategory, ConstraintSet, Outlives
|
||||||
use borrow_check::nll::facts::AllFacts;
|
use borrow_check::nll::facts::AllFacts;
|
||||||
use borrow_check::nll::region_infer::values::{LivenessValues, RegionValueElements};
|
use borrow_check::nll::region_infer::values::{LivenessValues, RegionValueElements};
|
||||||
use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
|
use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
|
||||||
|
use borrow_check::nll::renumber;
|
||||||
use borrow_check::nll::type_check::free_region_relations::{
|
use borrow_check::nll::type_check::free_region_relations::{
|
||||||
CreateResult, UniversalRegionRelations,
|
CreateResult, UniversalRegionRelations,
|
||||||
};
|
};
|
||||||
use borrow_check::nll::universal_regions::UniversalRegions;
|
use borrow_check::nll::universal_regions::UniversalRegions;
|
||||||
use borrow_check::nll::ToRegionVid;
|
use borrow_check::nll::ToRegionVid;
|
||||||
use borrow_check::nll::renumber;
|
|
||||||
use dataflow::move_paths::MoveData;
|
use dataflow::move_paths::MoveData;
|
||||||
use dataflow::FlowAtLocation;
|
use dataflow::FlowAtLocation;
|
||||||
use dataflow::MaybeInitializedPlaces;
|
use dataflow::MaybeInitializedPlaces;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::infer::canonical::QueryRegionConstraint;
|
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::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
||||||
use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
|
use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
|
||||||
use rustc::mir::tcx::PlaceTy;
|
use rustc::mir::tcx::PlaceTy;
|
||||||
use rustc::mir::visit::{PlaceContext, Visitor};
|
use rustc::mir::visit::{PlaceContext, Visitor};
|
||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
use rustc::traits::{ObligationCause, PredicateObligations};
|
|
||||||
use rustc::traits::query::type_op;
|
use rustc::traits::query::type_op;
|
||||||
use rustc::traits::query::type_op::custom::CustomTypeOp;
|
use rustc::traits::query::type_op::custom::CustomTypeOp;
|
||||||
use rustc::traits::query::{Fallible, NoSolution};
|
use rustc::traits::query::{Fallible, NoSolution};
|
||||||
|
use rustc::traits::{ObligationCause, PredicateObligations};
|
||||||
use rustc::ty::fold::TypeFoldable;
|
use rustc::ty::fold::TypeFoldable;
|
||||||
use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
|
|
||||||
use rustc::ty::subst::Subst;
|
use rustc::ty::subst::Subst;
|
||||||
|
use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use syntax_pos::{Span, DUMMY_SP};
|
use syntax_pos::{Span, DUMMY_SP};
|
||||||
|
@ -161,11 +161,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
|
||||||
Some(&mut borrowck_context),
|
Some(&mut borrowck_context),
|
||||||
Some(&universal_region_relations),
|
Some(&universal_region_relations),
|
||||||
|cx| {
|
|cx| {
|
||||||
cx.equate_inputs_and_outputs(
|
cx.equate_inputs_and_outputs(mir, universal_regions, &normalized_inputs_and_output);
|
||||||
mir,
|
|
||||||
universal_regions,
|
|
||||||
&normalized_inputs_and_output,
|
|
||||||
);
|
|
||||||
liveness::generate(cx, mir, elements, flow_inits, move_data);
|
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,
|
mir_def_id: DefId,
|
||||||
param_env: ty::ParamEnv<'gcx>,
|
param_env: ty::ParamEnv<'gcx>,
|
||||||
mir: &'a Mir<'tcx>,
|
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>>,
|
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||||
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
|
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
|
||||||
universal_region_relations: Option<&'a UniversalRegionRelations<'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);
|
debug!("sanitize_constant: expected_ty={:?}", constant.literal.ty);
|
||||||
|
|
||||||
if let Err(terr) = self.cx
|
if let Err(terr) = self.cx.eq_types(
|
||||||
.eq_types(
|
constant.literal.ty,
|
||||||
constant.literal.ty,
|
constant.ty,
|
||||||
constant.ty,
|
location.to_locations(),
|
||||||
location.to_locations(),
|
ConstraintCategory::Boring,
|
||||||
ConstraintCategory::Boring,
|
) {
|
||||||
)
|
|
||||||
{
|
|
||||||
span_mirbug!(
|
span_mirbug!(
|
||||||
self,
|
self,
|
||||||
constant,
|
constant,
|
||||||
|
@ -429,12 +423,10 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
||||||
let sty = self.sanitize_type(place, sty);
|
let sty = self.sanitize_type(place, sty);
|
||||||
let ty = self.tcx().type_of(def_id);
|
let ty = self.tcx().type_of(def_id);
|
||||||
let ty = self.cx.normalize(ty, location);
|
let ty = self.cx.normalize(ty, location);
|
||||||
if let Err(terr) = self.cx.eq_types(
|
if let Err(terr) =
|
||||||
ty,
|
self.cx
|
||||||
sty,
|
.eq_types(ty, sty, location.to_locations(), ConstraintCategory::Boring)
|
||||||
location.to_locations(),
|
{
|
||||||
ConstraintCategory::Boring,
|
|
||||||
) {
|
|
||||||
span_mirbug!(
|
span_mirbug!(
|
||||||
self,
|
self,
|
||||||
place,
|
place,
|
||||||
|
@ -693,7 +685,7 @@ struct TypeChecker<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||||
last_span: Span,
|
last_span: Span,
|
||||||
mir: &'a Mir<'tcx>,
|
mir: &'a Mir<'tcx>,
|
||||||
mir_def_id: DefId,
|
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>>,
|
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||||
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
|
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
|
||||||
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
|
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: &'a Mir<'tcx>,
|
||||||
mir_def_id: DefId,
|
mir_def_id: DefId,
|
||||||
param_env: ty::ParamEnv<'gcx>,
|
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>>,
|
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||||
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
|
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
|
||||||
universal_region_relations: Option<&'a UniversalRegionRelations<'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 tcx = infcx.tcx;
|
||||||
let param_env = self.param_env;
|
let param_env = self.param_env;
|
||||||
let parent_def_id = infcx.tcx.closure_base_def_id(self.mir_def_id);
|
let parent_def_id = infcx.tcx.closure_base_def_id(self.mir_def_id);
|
||||||
let opaque_type_map =
|
let opaque_type_map = self.fully_perform_op(
|
||||||
self.fully_perform_op(
|
locations,
|
||||||
locations,
|
category,
|
||||||
category,
|
CustomTypeOp::new(
|
||||||
CustomTypeOp::new(
|
|infcx| {
|
||||||
|infcx| {
|
let mut obligations = ObligationAccumulator::default();
|
||||||
let mut obligations = ObligationAccumulator::default();
|
|
||||||
|
|
||||||
let dummy_body_id = ObligationCause::dummy().body_id;
|
let dummy_body_id = ObligationCause::dummy().body_id;
|
||||||
let (output_ty, opaque_type_map) =
|
let (output_ty, opaque_type_map) =
|
||||||
obligations.add(infcx.instantiate_opaque_types(
|
obligations.add(infcx.instantiate_opaque_types(
|
||||||
parent_def_id,
|
parent_def_id,
|
||||||
dummy_body_id,
|
dummy_body_id,
|
||||||
param_env,
|
param_env,
|
||||||
&anon_ty,
|
&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!(
|
debug!(
|
||||||
"eq_opaque_type_and_type: \
|
"eq_opaque_type_and_type: concrete_ty={:?} opaque_defn_ty={:?}",
|
||||||
instantiated output_ty={:?} \
|
opaque_decl.concrete_ty, opaque_defn_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)?,
|
|
||||||
);
|
);
|
||||||
|
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 {
|
debug!("eq_opaque_type_and_type: equated");
|
||||||
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");
|
Ok(InferOk {
|
||||||
|
value: Some(opaque_type_map),
|
||||||
Ok(InferOk {
|
obligations: obligations.into_vec(),
|
||||||
value: Some(opaque_type_map),
|
})
|
||||||
obligations: obligations.into_vec(),
|
},
|
||||||
})
|
|| "input_output".to_string(),
|
||||||
},
|
),
|
||||||
|| "input_output".to_string(),
|
)?;
|
||||||
),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let universal_region_relations = match self.universal_region_relations {
|
let universal_region_relations = match self.universal_region_relations {
|
||||||
Some(rel) => rel,
|
Some(rel) => rel,
|
||||||
|
@ -1035,7 +1016,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
infcx.constrain_opaque_type(
|
infcx.constrain_opaque_type(
|
||||||
opaque_def_id,
|
opaque_def_id,
|
||||||
&opaque_decl,
|
&opaque_decl,
|
||||||
universal_region_relations
|
universal_region_relations,
|
||||||
);
|
);
|
||||||
Ok(InferOk {
|
Ok(InferOk {
|
||||||
value: (),
|
value: (),
|
||||||
|
@ -1073,12 +1054,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
let place_ty = place.ty(mir, tcx).to_ty(tcx);
|
let place_ty = place.ty(mir, tcx).to_ty(tcx);
|
||||||
let rv_ty = rv.ty(mir, tcx);
|
let rv_ty = rv.ty(mir, tcx);
|
||||||
if let Err(terr) = self.sub_types_or_anon(
|
if let Err(terr) =
|
||||||
rv_ty,
|
self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category)
|
||||||
place_ty,
|
{
|
||||||
location.to_locations(),
|
|
||||||
category,
|
|
||||||
) {
|
|
||||||
span_mirbug!(
|
span_mirbug!(
|
||||||
self,
|
self,
|
||||||
stmt,
|
stmt,
|
||||||
|
@ -1117,7 +1095,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
self.prove_trait_ref(
|
self.prove_trait_ref(
|
||||||
trait_ref,
|
trait_ref,
|
||||||
location.to_locations(),
|
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) => {
|
StatementKind::AscribeUserType(ref place, variance, c_ty) => {
|
||||||
let place_ty = place.ty(mir, tcx).to_ty(tcx);
|
let place_ty = place.ty(mir, tcx).to_ty(tcx);
|
||||||
if let Err(terr) =
|
if let Err(terr) = self.relate_type_and_user_type(
|
||||||
self.relate_type_and_user_type(
|
place_ty,
|
||||||
place_ty,
|
variance,
|
||||||
variance,
|
c_ty,
|
||||||
c_ty,
|
Locations::All(stmt.source_info.span),
|
||||||
Locations::All(stmt.source_info.span),
|
ConstraintCategory::TypeAnnotation,
|
||||||
ConstraintCategory::TypeAnnotation,
|
) {
|
||||||
)
|
|
||||||
{
|
|
||||||
span_mirbug!(
|
span_mirbug!(
|
||||||
self,
|
self,
|
||||||
stmt,
|
stmt,
|
||||||
|
@ -1208,12 +1184,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
let rv_ty = value.ty(mir, tcx);
|
let rv_ty = value.ty(mir, tcx);
|
||||||
|
|
||||||
let locations = term_location.to_locations();
|
let locations = term_location.to_locations();
|
||||||
if let Err(terr) = self.sub_types(
|
if let Err(terr) =
|
||||||
rv_ty,
|
self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment)
|
||||||
place_ty,
|
{
|
||||||
locations,
|
|
||||||
ConstraintCategory::Assignment,
|
|
||||||
) {
|
|
||||||
span_mirbug!(
|
span_mirbug!(
|
||||||
self,
|
self,
|
||||||
term,
|
term,
|
||||||
|
@ -1327,8 +1300,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
ty,
|
ty,
|
||||||
term_location.to_locations(),
|
term_location.to_locations(),
|
||||||
ConstraintCategory::Return,
|
ConstraintCategory::Return,
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
span_mirbug!(
|
span_mirbug!(
|
||||||
self,
|
self,
|
||||||
term,
|
term,
|
||||||
|
@ -1366,12 +1338,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
let locations = term_location.to_locations();
|
let locations = term_location.to_locations();
|
||||||
|
|
||||||
if let Err(terr) = self.sub_types_or_anon(
|
if let Err(terr) =
|
||||||
sig.output(),
|
self.sub_types_or_anon(sig.output(), dest_ty, locations, category)
|
||||||
dest_ty,
|
{
|
||||||
locations,
|
|
||||||
category,
|
|
||||||
) {
|
|
||||||
span_mirbug!(
|
span_mirbug!(
|
||||||
self,
|
self,
|
||||||
term,
|
term,
|
||||||
|
@ -1539,12 +1508,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_local(
|
fn check_local(&mut self, mir: &Mir<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) {
|
||||||
&mut self,
|
|
||||||
mir: &Mir<'tcx>,
|
|
||||||
local: Local,
|
|
||||||
local_decl: &LocalDecl<'tcx>,
|
|
||||||
) {
|
|
||||||
match mir.local_kind(local) {
|
match mir.local_kind(local) {
|
||||||
LocalKind::ReturnPointer | LocalKind::Arg => {
|
LocalKind::ReturnPointer | LocalKind::Arg => {
|
||||||
// return values of normal functions are required to be
|
// return values of normal functions are required to be
|
||||||
|
@ -1713,13 +1677,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
ConstraintCategory::Cast,
|
ConstraintCategory::Cast,
|
||||||
) {
|
) {
|
||||||
span_mirbug!(
|
span_mirbug!(
|
||||||
self,
|
self,
|
||||||
rvalue,
|
rvalue,
|
||||||
"equating {:?} with {:?} yields {:?}",
|
"equating {:?} with {:?} yields {:?}",
|
||||||
ty_fn_ptr_from,
|
ty_fn_ptr_from,
|
||||||
ty,
|
ty,
|
||||||
terr
|
terr
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1739,13 +1703,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
ConstraintCategory::Cast,
|
ConstraintCategory::Cast,
|
||||||
) {
|
) {
|
||||||
span_mirbug!(
|
span_mirbug!(
|
||||||
self,
|
self,
|
||||||
rvalue,
|
rvalue,
|
||||||
"equating {:?} with {:?} yields {:?}",
|
"equating {:?} with {:?} yields {:?}",
|
||||||
ty_fn_ptr_from,
|
ty_fn_ptr_from,
|
||||||
ty,
|
ty,
|
||||||
terr
|
terr
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1768,13 +1732,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
ConstraintCategory::Cast,
|
ConstraintCategory::Cast,
|
||||||
) {
|
) {
|
||||||
span_mirbug!(
|
span_mirbug!(
|
||||||
self,
|
self,
|
||||||
rvalue,
|
rvalue,
|
||||||
"equating {:?} with {:?} yields {:?}",
|
"equating {:?} with {:?} yields {:?}",
|
||||||
ty_fn_ptr_from,
|
ty_fn_ptr_from,
|
||||||
ty,
|
ty,
|
||||||
terr
|
terr
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2232,7 +2196,7 @@ impl MirPass for TypeckMir {
|
||||||
def_id,
|
def_id,
|
||||||
param_env,
|
param_env,
|
||||||
mir,
|
mir,
|
||||||
&[],
|
&vec![],
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
@ -2277,4 +2241,3 @@ impl<'tcx> ObligationAccumulator<'tcx> {
|
||||||
self.obligations
|
self.obligations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,15 +10,13 @@
|
||||||
|
|
||||||
use borrow_check::nll::constraints::{ConstraintCategory, OutlivesConstraint};
|
use borrow_check::nll::constraints::{ConstraintCategory, OutlivesConstraint};
|
||||||
use borrow_check::nll::type_check::{BorrowCheckContext, Locations};
|
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::canonical::{Canonical, CanonicalVarInfos};
|
||||||
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
|
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
|
||||||
use rustc::traits::query::Fallible;
|
use rustc::traits::query::Fallible;
|
||||||
use rustc::ty::fold::{TypeFoldable, TypeVisitor};
|
use rustc::ty::fold::{TypeFoldable, TypeVisitor};
|
||||||
use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
||||||
use rustc::ty::subst::Kind;
|
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::fx::FxHashMap;
|
||||||
use rustc_data_structures::indexed_vec::IndexVec;
|
use rustc_data_structures::indexed_vec::IndexVec;
|
||||||
|
|
||||||
|
@ -33,11 +31,9 @@ pub(super) fn sub_types<'tcx>(
|
||||||
) -> Fallible<()> {
|
) -> Fallible<()> {
|
||||||
debug!("sub_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
|
debug!("sub_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
|
||||||
TypeRelating::new(
|
TypeRelating::new(
|
||||||
infcx,
|
infcx.tcx,
|
||||||
|
NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
|
||||||
ty::Variance::Covariant,
|
ty::Variance::Covariant,
|
||||||
locations,
|
|
||||||
category,
|
|
||||||
borrowck_context,
|
|
||||||
ty::List::empty(),
|
ty::List::empty(),
|
||||||
).relate(&a, &b)?;
|
).relate(&a, &b)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -54,11 +50,9 @@ pub(super) fn eq_types<'tcx>(
|
||||||
) -> Fallible<()> {
|
) -> Fallible<()> {
|
||||||
debug!("eq_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
|
debug!("eq_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
|
||||||
TypeRelating::new(
|
TypeRelating::new(
|
||||||
infcx,
|
infcx.tcx,
|
||||||
|
NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
|
||||||
ty::Variance::Invariant,
|
ty::Variance::Invariant,
|
||||||
locations,
|
|
||||||
category,
|
|
||||||
borrowck_context,
|
|
||||||
ty::List::empty(),
|
ty::List::empty(),
|
||||||
).relate(&a, &b)?;
|
).relate(&a, &b)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -91,18 +85,22 @@ pub(super) fn relate_type_and_user_type<'tcx>(
|
||||||
let v1 = ty::Contravariant.xform(v);
|
let v1 = ty::Contravariant.xform(v);
|
||||||
|
|
||||||
TypeRelating::new(
|
TypeRelating::new(
|
||||||
infcx,
|
infcx.tcx,
|
||||||
|
NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
|
||||||
v1,
|
v1,
|
||||||
locations,
|
|
||||||
category,
|
|
||||||
borrowck_context,
|
|
||||||
b_variables,
|
b_variables,
|
||||||
).relate(&b_value, &a)?;
|
).relate(&b_value, &a)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TypeRelating<'cx, 'bccx: 'cx, 'gcx: 'tcx, 'tcx: 'bccx> {
|
struct TypeRelating<'me, 'gcx: 'tcx, 'tcx: 'me, D>
|
||||||
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
|
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`?
|
/// 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
|
/// This field stores the instantiations for late-bound regions in
|
||||||
/// the `a` type.
|
/// the `a` type.
|
||||||
a_scopes: Vec<BoundRegionScope>,
|
a_scopes: Vec<BoundRegionScope<'tcx>>,
|
||||||
|
|
||||||
/// Same as `a_scopes`, but for the `b` type.
|
/// Same as `a_scopes`, but for the `b` type.
|
||||||
b_scopes: Vec<BoundRegionScope>,
|
b_scopes: Vec<BoundRegionScope<'tcx>>,
|
||||||
|
|
||||||
/// 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>>,
|
|
||||||
|
|
||||||
/// As we execute, the type on the LHS *may* come from a canonical
|
/// As we execute, the type on the LHS *may* come from a canonical
|
||||||
/// source. In that case, we will sometimes find a constraint like
|
/// 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>>>,
|
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)]
|
#[derive(Clone, Debug)]
|
||||||
struct ScopesAndKind<'tcx> {
|
struct ScopesAndKind<'tcx> {
|
||||||
scopes: Vec<BoundRegionScope>,
|
scopes: Vec<BoundRegionScope<'tcx>>,
|
||||||
kind: Kind<'tcx>,
|
kind: Kind<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
struct BoundRegionScope {
|
struct BoundRegionScope<'tcx> {
|
||||||
map: FxHashMap<ty::BoundRegion, RegionVid>,
|
map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
struct UniversallyQuantified(bool);
|
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(
|
fn new(
|
||||||
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
|
tcx: TyCtxt<'me, 'gcx, 'tcx>,
|
||||||
|
delegate: D,
|
||||||
ambient_variance: ty::Variance,
|
ambient_variance: ty::Variance,
|
||||||
locations: Locations,
|
|
||||||
category: ConstraintCategory,
|
|
||||||
borrowck_context: Option<&'cx mut BorrowCheckContext<'bccx, 'tcx>>,
|
|
||||||
canonical_var_infos: CanonicalVarInfos<'tcx>,
|
canonical_var_infos: CanonicalVarInfos<'tcx>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let canonical_var_values = IndexVec::from_elem_n(None, canonical_var_infos.len());
|
let canonical_var_values = IndexVec::from_elem_n(None, canonical_var_infos.len());
|
||||||
Self {
|
Self {
|
||||||
infcx,
|
tcx,
|
||||||
|
delegate,
|
||||||
ambient_variance,
|
ambient_variance,
|
||||||
borrowck_context,
|
|
||||||
locations,
|
|
||||||
canonical_var_values,
|
canonical_var_values,
|
||||||
category,
|
|
||||||
a_scopes: vec![],
|
a_scopes: vec![],
|
||||||
b_scopes: vec![],
|
b_scopes: vec![],
|
||||||
}
|
}
|
||||||
|
@ -204,10 +286,10 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
value: &ty::Binder<impl TypeFoldable<'tcx>>,
|
value: &ty::Binder<impl TypeFoldable<'tcx>>,
|
||||||
universally_quantified: UniversallyQuantified,
|
universally_quantified: UniversallyQuantified,
|
||||||
) -> BoundRegionScope {
|
) -> BoundRegionScope<'tcx> {
|
||||||
let mut scope = BoundRegionScope::default();
|
let mut scope = BoundRegionScope::default();
|
||||||
value.skip_binder().visit_with(&mut ScopeInstantiator {
|
value.skip_binder().visit_with(&mut ScopeInstantiator {
|
||||||
infcx: self.infcx,
|
delegate: &mut self.delegate,
|
||||||
target_index: ty::INNERMOST,
|
target_index: ty::INNERMOST,
|
||||||
universally_quantified,
|
universally_quantified,
|
||||||
bound_region_scope: &mut scope,
|
bound_region_scope: &mut scope,
|
||||||
|
@ -227,8 +309,8 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelating<'cx, 'bccx, 'gcx, 'tcx> {
|
||||||
debruijn: ty::DebruijnIndex,
|
debruijn: ty::DebruijnIndex,
|
||||||
br: &ty::BoundRegion,
|
br: &ty::BoundRegion,
|
||||||
first_free_index: ty::DebruijnIndex,
|
first_free_index: ty::DebruijnIndex,
|
||||||
scopes: &[BoundRegionScope],
|
scopes: &[BoundRegionScope<'tcx>],
|
||||||
) -> RegionVid {
|
) -> ty::Region<'tcx> {
|
||||||
// The debruijn index is a "reverse index" into the
|
// The debruijn index is a "reverse index" into the
|
||||||
// scopes listing. So when we have INNERMOST (0), we
|
// scopes listing. So when we have INNERMOST (0), we
|
||||||
// want the *last* scope pushed, and so forth.
|
// 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`.
|
/// with. Otherwise just return `r`.
|
||||||
fn replace_bound_region(
|
fn replace_bound_region(
|
||||||
&self,
|
&self,
|
||||||
universal_regions: &UniversalRegions<'tcx>,
|
|
||||||
r: ty::Region<'tcx>,
|
r: ty::Region<'tcx>,
|
||||||
first_free_index: ty::DebruijnIndex,
|
first_free_index: ty::DebruijnIndex,
|
||||||
scopes: &[BoundRegionScope],
|
scopes: &[BoundRegionScope<'tcx>],
|
||||||
) -> RegionVid {
|
) -> ty::Region<'tcx> {
|
||||||
match r {
|
if let ty::ReLateBound(debruijn, br) = r {
|
||||||
ty::ReLateBound(debruijn, br) => {
|
Self::lookup_bound_region(*debruijn, br, first_free_index, scopes)
|
||||||
Self::lookup_bound_region(*debruijn, br, first_free_index, scopes)
|
} else {
|
||||||
}
|
r
|
||||||
|
|
||||||
ty::ReVar(v) => *v,
|
|
||||||
|
|
||||||
_ => universal_regions.to_region_vid(r),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push a new outlives requirement into our output set of
|
/// Push a new outlives requirement into our output set of
|
||||||
/// constraints.
|
/// 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);
|
debug!("push_outlives({:?}: {:?})", sup, sub);
|
||||||
|
|
||||||
if let Some(borrowck_context) = &mut self.borrowck_context {
|
self.delegate.push_outlives(sup, sub);
|
||||||
borrowck_context
|
|
||||||
.constraints
|
|
||||||
.outlives_constraints
|
|
||||||
.push(OutlivesConstraint {
|
|
||||||
sup,
|
|
||||||
sub,
|
|
||||||
locations: self.locations,
|
|
||||||
category: self.category,
|
|
||||||
});
|
|
||||||
|
|
||||||
// FIXME all facts!
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When we encounter a canonical variable `var` in the output,
|
/// 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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generalize_value(
|
fn generalize_value(&mut self, kind: Kind<'tcx>) -> Kind<'tcx> {
|
||||||
&self,
|
|
||||||
kind: Kind<'tcx>,
|
|
||||||
) -> Kind<'tcx> {
|
|
||||||
TypeGeneralizer {
|
TypeGeneralizer {
|
||||||
type_rel: self,
|
tcx: self.tcx,
|
||||||
|
delegate: &mut self.delegate,
|
||||||
first_free_index: ty::INNERMOST,
|
first_free_index: ty::INNERMOST,
|
||||||
ambient_variance: self.ambient_variance,
|
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>
|
impl<D> TypeRelation<'me, 'gcx, 'tcx> for TypeRelating<'me, 'gcx, 'tcx, D>
|
||||||
for TypeRelating<'cx, 'bccx, 'gcx, 'tcx>
|
where
|
||||||
|
D: TypeRelatingDelegate<'tcx>,
|
||||||
{
|
{
|
||||||
fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
|
fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
|
||||||
self.infcx.tcx
|
self.tcx
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tag(&self) -> &'static str {
|
fn tag(&self) -> &'static str {
|
||||||
|
@ -397,37 +461,30 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
|
||||||
a: ty::Region<'tcx>,
|
a: ty::Region<'tcx>,
|
||||||
b: ty::Region<'tcx>,
|
b: ty::Region<'tcx>,
|
||||||
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
||||||
if let Some(&mut BorrowCheckContext {
|
if let ty::ReCanonical(var) = a {
|
||||||
universal_regions, ..
|
self.relate_var(*var, b.into())?;
|
||||||
}) = self.borrowck_context
|
return Ok(a);
|
||||||
{
|
}
|
||||||
if let ty::ReCanonical(var) = a {
|
|
||||||
self.relate_var(*var, b.into())?;
|
|
||||||
return Ok(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"regions(a={:?}, b={:?}, variance={:?})",
|
"regions(a={:?}, b={:?}, variance={:?})",
|
||||||
a, b, self.ambient_variance
|
a, b, self.ambient_variance
|
||||||
);
|
);
|
||||||
|
|
||||||
let v_a =
|
let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes);
|
||||||
self.replace_bound_region(universal_regions, a, ty::INNERMOST, &self.a_scopes);
|
let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes);
|
||||||
let v_b =
|
|
||||||
self.replace_bound_region(universal_regions, b, ty::INNERMOST, &self.b_scopes);
|
|
||||||
|
|
||||||
debug!("regions: v_a = {:?}", v_a);
|
debug!("regions: v_a = {:?}", v_a);
|
||||||
debug!("regions: v_b = {:?}", v_b);
|
debug!("regions: v_b = {:?}", v_b);
|
||||||
|
|
||||||
if self.ambient_covariance() {
|
if self.ambient_covariance() {
|
||||||
// Covariance: a <= b. Hence, `b: a`.
|
// Covariance: a <= b. Hence, `b: a`.
|
||||||
self.push_outlives(v_b, v_a);
|
self.push_outlives(v_b, v_a);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.ambient_contravariance() {
|
if self.ambient_contravariance() {
|
||||||
// Contravariant: b <= a. Hence, `a: b`.
|
// Contravariant: b <= a. Hence, `a: b`.
|
||||||
self.push_outlives(v_a, v_b);
|
self.push_outlives(v_a, v_b);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(a)
|
Ok(a)
|
||||||
|
@ -527,10 +584,8 @@ impl<'cx, 'bccx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx>
|
||||||
|
|
||||||
// Reset ambient variance to contravariance. See the
|
// Reset ambient variance to contravariance. See the
|
||||||
// covariant case above for an explanation.
|
// covariant case above for an explanation.
|
||||||
let variance = ::std::mem::replace(
|
let variance =
|
||||||
&mut self.ambient_variance,
|
::std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
|
||||||
ty::Variance::Contravariant,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.relate(a.skip_binder(), b.skip_binder())?;
|
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
|
/// binder depth, and finds late-bound regions targeting the
|
||||||
/// `for<..`>. For each of those, it creates an entry in
|
/// `for<..`>. For each of those, it creates an entry in
|
||||||
/// `bound_region_scope`.
|
/// `bound_region_scope`.
|
||||||
struct ScopeInstantiator<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
|
struct ScopeInstantiator<'me, 'tcx: 'me, D>
|
||||||
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
|
where
|
||||||
|
D: TypeRelatingDelegate<'tcx> + 'me,
|
||||||
|
{
|
||||||
|
delegate: &'me mut D,
|
||||||
// The debruijn index of the scope we are instantiating.
|
// The debruijn index of the scope we are instantiating.
|
||||||
target_index: ty::DebruijnIndex,
|
target_index: ty::DebruijnIndex,
|
||||||
universally_quantified: UniversallyQuantified,
|
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 {
|
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
|
||||||
self.target_index.shift_in(1);
|
self.target_index.shift_in(1);
|
||||||
t.super_visit_with(self);
|
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 {
|
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
|
||||||
let ScopeInstantiator {
|
let ScopeInstantiator {
|
||||||
infcx,
|
|
||||||
universally_quantified,
|
universally_quantified,
|
||||||
|
bound_region_scope,
|
||||||
|
delegate,
|
||||||
..
|
..
|
||||||
} = *self;
|
} = self;
|
||||||
|
|
||||||
match r {
|
match r {
|
||||||
ty::ReLateBound(debruijn, br) if *debruijn == self.target_index => {
|
ty::ReLateBound(debruijn, br) if *debruijn == self.target_index => {
|
||||||
self.bound_region_scope.map.entry(*br).or_insert_with(|| {
|
bound_region_scope
|
||||||
let origin = if universally_quantified.0 {
|
.map
|
||||||
NLLRegionVariableOrigin::BoundRegion(infcx.create_subuniverse())
|
.entry(*br)
|
||||||
} else {
|
.or_insert_with(|| delegate.next_region_var(*universally_quantified));
|
||||||
NLLRegionVariableOrigin::Existential
|
|
||||||
};
|
|
||||||
infcx.next_nll_region_var(origin).to_region_vid()
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -613,8 +671,13 @@ impl<'cx, 'gcx, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'cx, 'gcx, 'tcx> {
|
||||||
/// scopes.
|
/// scopes.
|
||||||
///
|
///
|
||||||
/// [blog post]: https://is.gd/0hKvIr
|
/// [blog post]: https://is.gd/0hKvIr
|
||||||
struct TypeGeneralizer<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> {
|
struct TypeGeneralizer<'me, 'gcx: 'tcx, 'tcx: 'me, D>
|
||||||
type_rel: &'me TypeRelating<'me, 'bccx, 'gcx, 'tcx>,
|
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
|
/// After we generalize this type, we are going to relative it to
|
||||||
/// some other type. What will be the variance at this point?
|
/// 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,
|
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> {
|
fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
|
||||||
self.type_rel.infcx.tcx
|
self.tcx
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tag(&self) -> &'static str {
|
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
|
// though, we may however need to check well-formedness or
|
||||||
// risk a problem like #41677 again.
|
// risk a problem like #41677 again.
|
||||||
|
|
||||||
let replacement_region_vid = self.type_rel
|
let replacement_region_vid = self.delegate.generalize_existential(self.universe);
|
||||||
.infcx
|
|
||||||
.next_nll_region_var_in_universe(NLLRegionVariableOrigin::Existential, self.universe);
|
|
||||||
|
|
||||||
Ok(replacement_region_vid)
|
Ok(replacement_region_vid)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,12 @@
|
||||||
use check::regionck::RegionCtxt;
|
use check::regionck::RegionCtxt;
|
||||||
|
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use rustc::infer::{self, InferOk};
|
|
||||||
use rustc::infer::outlives::env::OutlivesEnvironment;
|
use rustc::infer::outlives::env::OutlivesEnvironment;
|
||||||
|
use rustc::infer::{self, InferOk, SuppressRegionErrors};
|
||||||
use rustc::middle::region;
|
use rustc::middle::region;
|
||||||
|
use rustc::traits::{ObligationCause, TraitEngine, TraitEngineExt};
|
||||||
use rustc::ty::subst::{Subst, Substs, UnpackedKind};
|
use rustc::ty::subst::{Subst, Substs, UnpackedKind};
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
use rustc::traits::{ObligationCause, TraitEngine, TraitEngineExt};
|
|
||||||
use util::common::ErrorReported;
|
use util::common::ErrorReported;
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
@ -39,32 +39,41 @@ use syntax_pos::Span;
|
||||||
/// struct/enum definition for the nominal type itself (i.e.
|
/// struct/enum definition for the nominal type itself (i.e.
|
||||||
/// cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
|
/// cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
|
||||||
///
|
///
|
||||||
pub fn check_drop_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
pub fn check_drop_impl<'a, 'tcx>(
|
||||||
drop_impl_did: DefId)
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
-> Result<(), ErrorReported> {
|
drop_impl_did: DefId,
|
||||||
|
) -> Result<(), ErrorReported> {
|
||||||
let dtor_self_type = tcx.type_of(drop_impl_did);
|
let dtor_self_type = tcx.type_of(drop_impl_did);
|
||||||
let dtor_predicates = tcx.predicates_of(drop_impl_did);
|
let dtor_predicates = tcx.predicates_of(drop_impl_did);
|
||||||
match dtor_self_type.sty {
|
match dtor_self_type.sty {
|
||||||
ty::Adt(adt_def, self_to_impl_substs) => {
|
ty::Adt(adt_def, self_to_impl_substs) => {
|
||||||
ensure_drop_params_and_item_params_correspond(tcx,
|
ensure_drop_params_and_item_params_correspond(
|
||||||
drop_impl_did,
|
tcx,
|
||||||
dtor_self_type,
|
drop_impl_did,
|
||||||
adt_def.did)?;
|
dtor_self_type,
|
||||||
|
adt_def.did,
|
||||||
|
)?;
|
||||||
|
|
||||||
ensure_drop_predicates_are_implied_by_item_defn(tcx,
|
ensure_drop_predicates_are_implied_by_item_defn(
|
||||||
drop_impl_did,
|
tcx,
|
||||||
&dtor_predicates,
|
drop_impl_did,
|
||||||
adt_def.did,
|
&dtor_predicates,
|
||||||
self_to_impl_substs)
|
adt_def.did,
|
||||||
|
self_to_impl_substs,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// Destructors only work on nominal types. This was
|
// Destructors only work on nominal types. This was
|
||||||
// already checked by coherence, but compilation may
|
// already checked by coherence, but compilation may
|
||||||
// not have been terminated.
|
// not have been terminated.
|
||||||
let span = tcx.def_span(drop_impl_did);
|
let span = tcx.def_span(drop_impl_did);
|
||||||
tcx.sess.delay_span_bug(span,
|
tcx.sess.delay_span_bug(
|
||||||
&format!("should have been rejected by coherence check: {}",
|
span,
|
||||||
dtor_self_type));
|
&format!(
|
||||||
|
"should have been rejected by coherence check: {}",
|
||||||
|
dtor_self_type
|
||||||
|
),
|
||||||
|
);
|
||||||
Err(ErrorReported)
|
Err(ErrorReported)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,9 +83,8 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
drop_impl_did: DefId,
|
drop_impl_did: DefId,
|
||||||
drop_impl_ty: Ty<'tcx>,
|
drop_impl_ty: Ty<'tcx>,
|
||||||
self_type_did: DefId)
|
self_type_did: DefId,
|
||||||
-> Result<(), ErrorReported>
|
) -> Result<(), ErrorReported> {
|
||||||
{
|
|
||||||
let drop_impl_node_id = tcx.hir.as_local_node_id(drop_impl_did).unwrap();
|
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.
|
// 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 named_type = tcx.type_of(self_type_did);
|
||||||
|
|
||||||
let drop_impl_span = tcx.def_span(drop_impl_did);
|
let drop_impl_span = tcx.def_span(drop_impl_did);
|
||||||
let fresh_impl_substs =
|
let fresh_impl_substs = infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did);
|
||||||
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 fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs);
|
||||||
|
|
||||||
let cause = &ObligationCause::misc(drop_impl_span, drop_impl_node_id);
|
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, .. }) => {
|
Ok(InferOk { obligations, .. }) => {
|
||||||
fulfillment_cx.register_predicate_obligations(infcx, obligations);
|
fulfillment_cx.register_predicate_obligations(infcx, obligations);
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let item_span = tcx.def_span(self_type_did);
|
let item_span = tcx.def_span(self_type_did);
|
||||||
struct_span_err!(tcx.sess, drop_impl_span, E0366,
|
struct_span_err!(
|
||||||
"Implementations of Drop cannot be specialized")
|
tcx.sess,
|
||||||
.span_note(item_span,
|
drop_impl_span,
|
||||||
"Use same sequence of generic type and region \
|
E0366,
|
||||||
parameters that is on the struct/enum definition")
|
"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();
|
.emit();
|
||||||
return Err(ErrorReported);
|
return Err(ErrorReported);
|
||||||
}
|
}
|
||||||
|
@ -128,7 +143,12 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
|
||||||
// conservative. -nmatsakis
|
// conservative. -nmatsakis
|
||||||
let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty());
|
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(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -140,9 +160,8 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
|
||||||
drop_impl_did: DefId,
|
drop_impl_did: DefId,
|
||||||
dtor_predicates: &ty::GenericPredicates<'tcx>,
|
dtor_predicates: &ty::GenericPredicates<'tcx>,
|
||||||
self_type_did: DefId,
|
self_type_did: DefId,
|
||||||
self_to_impl_substs: &Substs<'tcx>)
|
self_to_impl_substs: &Substs<'tcx>,
|
||||||
-> Result<(), ErrorReported>
|
) -> Result<(), ErrorReported> {
|
||||||
{
|
|
||||||
let mut result = Ok(());
|
let mut result = Ok(());
|
||||||
|
|
||||||
// Here is an example, analogous to that from
|
// 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) {
|
if !assumptions_in_impl_context.contains(&predicate) {
|
||||||
let item_span = tcx.hir.span(self_type_node_id);
|
let item_span = tcx.hir.span(self_type_node_id);
|
||||||
struct_span_err!(tcx.sess, drop_impl_span, E0367,
|
struct_span_err!(
|
||||||
"The requirement `{}` is added only by the Drop impl.", predicate)
|
tcx.sess,
|
||||||
.span_note(item_span,
|
drop_impl_span,
|
||||||
"The same requirement must be part of \
|
E0367,
|
||||||
the struct/enum definition")
|
"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();
|
.emit();
|
||||||
result = Err(ErrorReported);
|
result = Err(ErrorReported);
|
||||||
}
|
}
|
||||||
|
@ -283,18 +308,18 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
body_id: ast::NodeId,
|
body_id: ast::NodeId,
|
||||||
scope: region::Scope)
|
scope: region::Scope,
|
||||||
-> Result<(), ErrorReported>
|
) -> Result<(), ErrorReported> {
|
||||||
{
|
debug!(
|
||||||
debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}",
|
"check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}",
|
||||||
ty, scope);
|
ty, scope
|
||||||
|
);
|
||||||
|
|
||||||
let parent_scope = match rcx.region_scope_tree.opt_encl_scope(scope) {
|
let parent_scope = match rcx.region_scope_tree.opt_encl_scope(scope) {
|
||||||
Some(parent_scope) => parent_scope,
|
Some(parent_scope) => parent_scope,
|
||||||
// If no enclosing scope, then it must be the root scope
|
// If no enclosing scope, then it must be the root scope
|
||||||
// which cannot be outlived.
|
// which cannot be outlived.
|
||||||
None => return Ok(())
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
let parent_scope = rcx.tcx.mk_region(ty::ReScope(parent_scope));
|
let parent_scope = rcx.tcx.mk_region(ty::ReScope(parent_scope));
|
||||||
let origin = || infer::SubregionOrigin::SafeDestructor(span);
|
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
|
//! Check properties that are required by built-in traits and set
|
||||||
//! up data structures required by type-checking/codegen.
|
//! up data structures required by type-checking/codegen.
|
||||||
|
|
||||||
|
use rustc::infer::SuppressRegionErrors;
|
||||||
use rustc::infer::outlives::env::OutlivesEnvironment;
|
use rustc::infer::outlives::env::OutlivesEnvironment;
|
||||||
use rustc::middle::region;
|
use rustc::middle::region;
|
||||||
use rustc::middle::lang_items::UnsizeTraitLangItem;
|
use rustc::middle::lang_items::UnsizeTraitLangItem;
|
||||||
|
@ -396,6 +397,7 @@ pub fn coerce_unsized_info<'a, 'gcx>(gcx: TyCtxt<'a, 'gcx, 'gcx>,
|
||||||
impl_did,
|
impl_did,
|
||||||
®ion_scope_tree,
|
®ion_scope_tree,
|
||||||
&outlives_env,
|
&outlives_env,
|
||||||
|
SuppressRegionErrors::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
CoerceUnsizedInfo {
|
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> {
|
LL | fn foo<T: Any>(value: &T) -> Box<Any> {
|
||||||
| -- help: add explicit lifetime `'static` to the type of `value`: `&'static T`
|
| -- help: add explicit lifetime `'static` to the type of `value`: `&'static T`
|
||||||
LL | Box::new(value) as Box<Any>
|
LL | Box::new(value) as Box<Any>
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required
|
| ^^^^^^^^^^^^^^^ lifetime `'static` required
|
||||||
|
|
||||||
error: aborting due to previous error
|
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: Anything<'b>,
|
||||||
T::AssocType: 'a,
|
T::AssocType: 'a,
|
||||||
{
|
{
|
||||||
// This error is unfortunate. This code ought to type-check: we
|
// We are projecting `<T as Anything<'b>>::AssocType`, and we know
|
||||||
// are projecting `<T as Anything<'b>>::AssocType`, and we know
|
// that this outlives `'a` because of the where-clause.
|
||||||
// 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.
|
|
||||||
|
|
||||||
with_signature(cell, t, |cell, t| require(cell, t));
|
with_signature(cell, t, |cell, t| require(cell, t));
|
||||||
//~^ ERROR the parameter type `T` may not live long enough
|
|
||||||
//~| ERROR
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_regions]
|
#[rustc_regions]
|
||||||
|
|
|
@ -106,7 +106,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ closure body requires that `'b` must outlive `'a`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ closure body requires that `'b` must outlive `'a`
|
||||||
|
|
||||||
note: External requirements
|
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));
|
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))
|
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
|
||||||
]
|
]
|
||||||
= note: number of external vids: 4
|
= note: number of external vids: 4
|
||||||
= note: where T: '_#3r
|
= note: where <T as Anything<ReClosureBound('_#2r)>>::AssocType: '_#3r
|
||||||
= note: where '_#2r: '_#3r
|
|
||||||
|
|
||||||
note: No external requirements
|
note: No external requirements
|
||||||
--> $DIR/projection-one-region-closure.rs:72:1
|
--> $DIR/projection-one-region-closure.rs:72:1
|
||||||
|
@ -130,7 +129,7 @@ LL | | where
|
||||||
LL | | T: Anything<'b>,
|
LL | | T: Anything<'b>,
|
||||||
LL | | T::AssocType: 'a,
|
LL | | T::AssocType: 'a,
|
||||||
... |
|
... |
|
||||||
LL | | //~| ERROR
|
LL | | with_signature(cell, t, |cell, t| require(cell, t));
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
|
|
||||||
|
@ -140,27 +139,8 @@ LL | | }
|
||||||
T
|
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
|
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));
|
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: where '_#2r: '_#3r
|
||||||
|
|
||||||
note: No external requirements
|
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 | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||||
LL | | where
|
LL | | where
|
||||||
|
@ -194,6 +174,6 @@ LL | | }
|
||||||
T
|
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`.
|
For more information about this error, try `rustc --explain E0309`.
|
||||||
|
|
|
@ -64,18 +64,10 @@ where
|
||||||
T: Anything<'b>,
|
T: Anything<'b>,
|
||||||
T::AssocType: 'a,
|
T::AssocType: 'a,
|
||||||
{
|
{
|
||||||
// This error is unfortunate. This code ought to type-check: we
|
// We are projecting `<T as Anything<'b>>::AssocType`, and we know
|
||||||
// are projecting `<T as Anything<'b>>::AssocType`, and we know
|
// that this outlives `'a` because of the where-clause.
|
||||||
// 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.
|
|
||||||
|
|
||||||
with_signature(cell, t, |cell, t| require(cell, t));
|
with_signature(cell, t, |cell, t| require(cell, t));
|
||||||
//~^ ERROR
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_regions]
|
#[rustc_regions]
|
||||||
|
|
|
@ -88,7 +88,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ closure body requires that `'b` must outlive `'a`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ closure body requires that `'b` must outlive `'a`
|
||||||
|
|
||||||
note: External requirements
|
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));
|
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))
|
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
|
||||||
]
|
]
|
||||||
= note: number of external vids: 4
|
= note: number of external vids: 4
|
||||||
= note: where '_#2r: '_#3r
|
= note: where <T as Anything<ReClosureBound('_#2r)>>::AssocType: '_#3r
|
||||||
|
|
||||||
note: No external requirements
|
note: No external requirements
|
||||||
--> $DIR/projection-one-region-trait-bound-closure.rs:62:1
|
--> $DIR/projection-one-region-trait-bound-closure.rs:62:1
|
||||||
|
@ -111,7 +111,7 @@ LL | | where
|
||||||
LL | | T: Anything<'b>,
|
LL | | T: Anything<'b>,
|
||||||
LL | | T::AssocType: 'a,
|
LL | | T::AssocType: 'a,
|
||||||
... |
|
... |
|
||||||
LL | | //~^ ERROR
|
LL | | with_signature(cell, t, |cell, t| require(cell, t));
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
|
|
||||||
|
@ -121,19 +121,8 @@ LL | | }
|
||||||
T
|
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
|
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));
|
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: where '_#2r: '_#3r
|
||||||
|
|
||||||
note: No external requirements
|
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 | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||||
LL | | where
|
LL | | where
|
||||||
|
@ -167,7 +156,7 @@ LL | | }
|
||||||
]
|
]
|
||||||
|
|
||||||
note: External requirements
|
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));
|
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: where '_#1r: '_#2r
|
||||||
|
|
||||||
note: No external requirements
|
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 | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
|
||||||
LL | | where
|
LL | | where
|
||||||
|
@ -198,5 +187,5 @@ LL | | }
|
||||||
T
|
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: Anything<'b, 'c>,
|
||||||
T::AssocType: 'a,
|
T::AssocType: 'a,
|
||||||
{
|
{
|
||||||
// This error is unfortunate. This code ought to type-check: we
|
// We are projecting `<T as Anything<'b>>::AssocType`, and we know
|
||||||
// are projecting `<T as Anything<'b>>::AssocType`, and we know
|
// that this outlives `'a` because of the where-clause.
|
||||||
// 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.
|
|
||||||
|
|
||||||
with_signature(cell, t, |cell, t| require(cell, t));
|
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]
|
#[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)`...
|
= help: consider adding an explicit lifetime bound `<T as Anything<'_#6r, '_#7r>>::AssocType: ReEarlyBound(0, 'a)`...
|
||||||
|
|
||||||
note: External requirements
|
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));
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -110,7 +110,7 @@ LL | | where
|
||||||
LL | | T: Anything<'b, 'c>,
|
LL | | T: Anything<'b, 'c>,
|
||||||
LL | | T::AssocType: 'a,
|
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 | | }
|
LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
|
|
||||||
|
@ -121,16 +121,8 @@ LL | | }
|
||||||
T
|
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
|
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));
|
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: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
|
||||||
|
|
||||||
note: No external requirements
|
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 | / fn elements_outlive1<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
|
||||||
LL | | where
|
LL | | where
|
||||||
|
@ -166,7 +158,7 @@ LL | | }
|
||||||
]
|
]
|
||||||
|
|
||||||
note: External requirements
|
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));
|
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: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
|
||||||
|
|
||||||
note: No external requirements
|
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 | / fn elements_outlive2<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
|
||||||
LL | | where
|
LL | | where
|
||||||
|
@ -202,7 +194,7 @@ LL | | }
|
||||||
]
|
]
|
||||||
|
|
||||||
note: External requirements
|
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));
|
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: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
|
||||||
|
|
||||||
note: No external requirements
|
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 | / fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||||
LL | | where
|
LL | | where
|
||||||
|
@ -235,7 +227,7 @@ LL | | }
|
||||||
]
|
]
|
||||||
|
|
||||||
error: unsatisfied lifetime constraints
|
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)
|
LL | fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||||
| -- -- lifetime `'b` defined here
|
| -- -- 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`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ closure body requires that `'b` must outlive `'a`
|
||||||
|
|
||||||
note: External requirements
|
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));
|
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: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#2r)>>::AssocType: '_#3r
|
||||||
|
|
||||||
note: No external requirements
|
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 | / fn two_regions_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||||
LL | | where
|
LL | | where
|
||||||
|
@ -280,7 +272,7 @@ LL | | }
|
||||||
]
|
]
|
||||||
|
|
||||||
note: External requirements
|
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));
|
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: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
|
||||||
|
|
||||||
note: No external requirements
|
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 | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
|
||||||
LL | | where
|
LL | | where
|
||||||
|
@ -311,6 +303,6 @@ LL | | }
|
||||||
T
|
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`.
|
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 {
|
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
|
--> $DIR/object-lifetime-default-elision.rs:81:5
|
||||||
|
|
|
|
||||||
LL | ss
|
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 () {
|
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
|
--> $DIR/region-object-lifetime-2.rs:20:5
|
||||||
|
|
|
|
||||||
LL | x.borrowed() //~ ERROR cannot infer
|
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 {
|
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
|
--> $DIR/regions-trait-object-subtyping.rs:25:5
|
||||||
|
|
|
|
||||||
LL | x //~ ERROR lifetime bound not satisfied
|
LL | x //~ ERROR lifetime bound not satisfied
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue