Various simplifications and renamings based on the fact that old-school closures are gone and type parameters can now have multiple region bounds (and hence use a different path). Should have no effect on the external behavior of the compiler.
This commit is contained in:
parent
931a3c4f9d
commit
f5c6a23c9e
@ -5896,42 +5896,13 @@ pub fn each_bound_trait_and_supertraits<'tcx, F>(tcx: &ctxt<'tcx>,
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn object_region_bounds<'tcx>(
|
||||
tcx: &ctxt<'tcx>,
|
||||
opt_principal: Option<&PolyTraitRef<'tcx>>, // None for closures
|
||||
others: BuiltinBounds)
|
||||
-> Vec<ty::Region>
|
||||
{
|
||||
// Since we don't actually *know* the self type for an object,
|
||||
// this "open(err)" serves as a kind of dummy standin -- basically
|
||||
// a skolemized type.
|
||||
let open_ty = ty::mk_infer(tcx, FreshTy(0));
|
||||
|
||||
let opt_trait_ref = opt_principal.map_or(Vec::new(), |principal| {
|
||||
// Note that we preserve the overall binding levels here.
|
||||
assert!(!open_ty.has_escaping_regions());
|
||||
let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
|
||||
vec!(ty::Binder(Rc::new(ty::TraitRef::new(principal.0.def_id, substs))))
|
||||
});
|
||||
|
||||
let param_bounds = ty::ParamBounds {
|
||||
region_bounds: Vec::new(),
|
||||
builtin_bounds: others,
|
||||
trait_bounds: opt_trait_ref,
|
||||
projection_bounds: Vec::new(), // not relevant to computing region bounds
|
||||
};
|
||||
|
||||
let predicates = ty::predicates(tcx, open_ty, ¶m_bounds);
|
||||
ty::required_region_bounds(tcx, open_ty, predicates)
|
||||
}
|
||||
|
||||
/// Given a set of predicates that apply to an object type, returns
|
||||
/// the region bounds that the (erased) `Self` type must
|
||||
/// outlive. Precisely *because* the `Self` type is erased, the
|
||||
/// parameter `erased_self_ty` must be supplied to indicate what type
|
||||
/// has been used to represent `Self` in the predicates
|
||||
/// themselves. This should really be a unique type; `FreshTy(0)` is a
|
||||
/// popular choice (see `object_region_bounds` above).
|
||||
/// popular choice.
|
||||
///
|
||||
/// Requires that trait definitions have been processed so that we can
|
||||
/// elaborate predicates and walk supertraits.
|
||||
|
@ -55,7 +55,7 @@ use middle::resolve_lifetime as rl;
|
||||
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
|
||||
use middle::traits;
|
||||
use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
|
||||
use rscope::{self, UnelidableRscope, RegionScope, SpecificRscope,
|
||||
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
|
||||
ShiftedRscope, BindingRscope};
|
||||
use TypeAndSubsts;
|
||||
use util::common::{ErrorReported, FN_OUTPUT_NAME};
|
||||
@ -465,7 +465,7 @@ fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>,
|
||||
{
|
||||
match implied_output_region {
|
||||
Some(implied_output_region) => {
|
||||
let rb = SpecificRscope::new(implied_output_region);
|
||||
let rb = ElidableRscope::new(implied_output_region);
|
||||
ast_ty_to_ty(this, &rb, ty)
|
||||
}
|
||||
None => {
|
||||
@ -932,7 +932,7 @@ fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>,
|
||||
let existential_bounds = conv_existential_bounds(this,
|
||||
rscope,
|
||||
span,
|
||||
Some(trait_ref.clone()),
|
||||
trait_ref.clone(),
|
||||
projection_bounds,
|
||||
bounds);
|
||||
|
||||
@ -1518,11 +1518,11 @@ pub fn ty_of_closure<'tcx>(
|
||||
/// `ExistentialBounds` struct. The `main_trait_refs` argument specifies the `Foo` -- it is absent
|
||||
/// for closures. Eventually this should all be normalized, I think, so that there is no "main
|
||||
/// trait ref" and instead we just have a flat list of bounds as the existential type.
|
||||
pub fn conv_existential_bounds<'tcx>(
|
||||
fn conv_existential_bounds<'tcx>(
|
||||
this: &AstConv<'tcx>,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for boxed closures
|
||||
principal_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
|
||||
ast_bounds: &[ast::TyParamBound])
|
||||
-> ty::ExistentialBounds<'tcx>
|
||||
@ -1546,15 +1546,15 @@ fn conv_ty_poly_trait_ref<'tcx>(
|
||||
let mut projection_bounds = Vec::new();
|
||||
let main_trait_bound = if !partitioned_bounds.trait_bounds.is_empty() {
|
||||
let trait_bound = partitioned_bounds.trait_bounds.remove(0);
|
||||
Some(instantiate_poly_trait_ref(this,
|
||||
rscope,
|
||||
trait_bound,
|
||||
None,
|
||||
&mut projection_bounds))
|
||||
instantiate_poly_trait_ref(this,
|
||||
rscope,
|
||||
trait_bound,
|
||||
None,
|
||||
&mut projection_bounds)
|
||||
} else {
|
||||
span_err!(this.tcx().sess, span, E0224,
|
||||
"at least one non-builtin trait is required for an object type");
|
||||
None
|
||||
"at least one non-builtin trait is required for an object type");
|
||||
return this.tcx().types.err;
|
||||
};
|
||||
|
||||
let bounds =
|
||||
@ -1565,17 +1565,14 @@ fn conv_ty_poly_trait_ref<'tcx>(
|
||||
projection_bounds,
|
||||
partitioned_bounds);
|
||||
|
||||
match main_trait_bound {
|
||||
None => this.tcx().types.err,
|
||||
Some(principal) => ty::mk_trait(this.tcx(), principal, bounds)
|
||||
}
|
||||
ty::mk_trait(this.tcx(), main_trait_bound, bounds)
|
||||
}
|
||||
|
||||
pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>(
|
||||
this: &AstConv<'tcx>,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for boxed closures
|
||||
principal_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
mut projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>, // Empty for boxed closures
|
||||
partitioned_bounds: PartitionedBounds)
|
||||
-> ty::ExistentialBounds<'tcx>
|
||||
@ -1588,16 +1585,15 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>(
|
||||
if !trait_bounds.is_empty() {
|
||||
let b = &trait_bounds[0];
|
||||
span_err!(this.tcx().sess, b.trait_ref.path.span, E0225,
|
||||
"only the builtin traits can be used \
|
||||
as closure or object bounds");
|
||||
"only the builtin traits can be used as closure or object bounds");
|
||||
}
|
||||
|
||||
let region_bound = compute_region_bound(this,
|
||||
rscope,
|
||||
span,
|
||||
®ion_bounds,
|
||||
principal_trait_ref,
|
||||
builtin_bounds);
|
||||
let region_bound = compute_object_lifetime_bound(this,
|
||||
rscope,
|
||||
span,
|
||||
®ion_bounds,
|
||||
principal_trait_ref,
|
||||
builtin_bounds);
|
||||
|
||||
ty::sort_bounds_list(&mut projection_bounds);
|
||||
|
||||
@ -1608,17 +1604,21 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Given the bounds on a type parameter / existential type, determines what single region bound
|
||||
/// Given the bounds on an object, determines what single region bound
|
||||
/// (if any) we can use to summarize this type. The basic idea is that we will use the bound the
|
||||
/// user provided, if they provided one, and otherwise search the supertypes of trait bounds for
|
||||
/// region bounds. It may be that we can derive no bound at all, in which case we return `None`.
|
||||
fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
span: Span,
|
||||
explicit_region_bounds: &[&ast::Lifetime],
|
||||
principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
|
||||
builtin_bounds: ty::BuiltinBounds)
|
||||
-> Option<ty::Region>
|
||||
fn compute_object_lifetime_bound<'tcx>(
|
||||
this: &AstConv<'tcx>,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
explicit_region_bounds: &[&ast::Lifetime],
|
||||
principal_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
builtin_bounds: ty::BuiltinBounds)
|
||||
-> ty::Region
|
||||
{
|
||||
let tcx = this.tcx();
|
||||
|
||||
debug!("compute_opt_region_bound(explicit_region_bounds={:?}, \
|
||||
principal_trait_ref={}, builtin_bounds={})",
|
||||
explicit_region_bounds,
|
||||
@ -1633,24 +1633,32 @@ fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
if explicit_region_bounds.len() != 0 {
|
||||
// Explicitly specified region bound. Use that.
|
||||
let r = explicit_region_bounds[0];
|
||||
return Some(ast_region_to_region(tcx, r));
|
||||
return ast_region_to_region(tcx, r);
|
||||
}
|
||||
|
||||
// No explicit region bound specified. Therefore, examine trait
|
||||
// bounds and see if we can derive region bounds from those.
|
||||
let derived_region_bounds =
|
||||
ty::object_region_bounds(tcx, principal_trait_ref.as_ref(), builtin_bounds);
|
||||
object_region_bounds(tcx, &principal_trait_ref, builtin_bounds);
|
||||
|
||||
// If there are no derived region bounds, then report back that we
|
||||
// can find no region bound.
|
||||
if derived_region_bounds.len() == 0 {
|
||||
return None;
|
||||
match rscope.object_lifetime_default(span) {
|
||||
Some(r) => { return r; }
|
||||
None => {
|
||||
span_err!(this.tcx().sess, span, E0228,
|
||||
"the lifetime bound for this object type cannot be deduced \
|
||||
from context; please supply an explicit bound");
|
||||
return ty::ReStatic;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If any of the derived region bounds are 'static, that is always
|
||||
// the best choice.
|
||||
if derived_region_bounds.iter().any(|r| ty::ReStatic == *r) {
|
||||
return Some(ty::ReStatic);
|
||||
return ty::ReStatic;
|
||||
}
|
||||
|
||||
// Determine whether there is exactly one unique region in the set
|
||||
@ -1659,38 +1667,36 @@ fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
let r = derived_region_bounds[0];
|
||||
if derived_region_bounds[1..].iter().any(|r1| r != *r1) {
|
||||
span_err!(tcx.sess, span, E0227,
|
||||
"ambiguous lifetime bound, \
|
||||
explicit lifetime bound required");
|
||||
"ambiguous lifetime bound, explicit lifetime bound required");
|
||||
}
|
||||
return Some(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/// A version of `compute_opt_region_bound` for use where some region bound is required
|
||||
/// (existential types, basically). Reports an error if no region bound can be derived and we are
|
||||
/// in an `rscope` that does not provide a default.
|
||||
fn compute_region_bound<'tcx>(
|
||||
this: &AstConv<'tcx>,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
region_bounds: &[&ast::Lifetime],
|
||||
principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for closures
|
||||
builtin_bounds: ty::BuiltinBounds)
|
||||
-> ty::Region
|
||||
pub fn object_region_bounds<'tcx>(
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
principal: &ty::PolyTraitRef<'tcx>,
|
||||
others: ty::BuiltinBounds)
|
||||
-> Vec<ty::Region>
|
||||
{
|
||||
match compute_opt_region_bound(this.tcx(), span, region_bounds,
|
||||
principal_trait_ref, builtin_bounds) {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
match rscope.default_region_bound(span) {
|
||||
Some(r) => { r }
|
||||
None => {
|
||||
span_err!(this.tcx().sess, span, E0228,
|
||||
"explicit lifetime bound required");
|
||||
ty::ReStatic
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Since we don't actually *know* the self type for an object,
|
||||
// this "open(err)" serves as a kind of dummy standin -- basically
|
||||
// a skolemized type.
|
||||
let open_ty = ty::mk_infer(tcx, ty::FreshTy(0));
|
||||
|
||||
// Note that we preserve the overall binding levels here.
|
||||
assert!(!open_ty.has_escaping_regions());
|
||||
let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
|
||||
let trait_refs = vec!(ty::Binder(Rc::new(ty::TraitRef::new(principal.0.def_id, substs))));
|
||||
|
||||
let param_bounds = ty::ParamBounds {
|
||||
region_bounds: Vec::new(),
|
||||
builtin_bounds: others,
|
||||
trait_bounds: trait_refs,
|
||||
projection_bounds: Vec::new(), // not relevant to computing region bounds
|
||||
};
|
||||
|
||||
let predicates = ty::predicates(tcx, open_ty, ¶m_bounds);
|
||||
ty::required_region_bounds(tcx, open_ty, predicates)
|
||||
}
|
||||
|
||||
pub struct PartitionedBounds<'a> {
|
||||
|
@ -1890,7 +1890,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> {
|
||||
fn default_region_bound(&self, span: Span) -> Option<ty::Region> {
|
||||
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
|
||||
Some(self.infcx().next_region_var(infer::MiscVariable(span)))
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
pub use self::WfConstraint::*;
|
||||
|
||||
use astconv::object_region_bounds;
|
||||
use middle::infer::GenericKind;
|
||||
use middle::subst::{ParamSpace, Subst, Substs};
|
||||
use middle::ty::{self, Ty};
|
||||
@ -95,7 +96,7 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {
|
||||
|
||||
ty::ty_trait(ref t) => {
|
||||
let required_region_bounds =
|
||||
ty::object_region_bounds(self.tcx, Some(&t.principal), t.bounds.builtin_bounds);
|
||||
object_region_bounds(self.tcx, &t.principal, t.bounds.builtin_bounds);
|
||||
self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds)
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,10 @@ pub trait RegionScope {
|
||||
count: uint)
|
||||
-> Result<Vec<ty::Region>, Option<Vec<(String, uint)>>>;
|
||||
|
||||
fn default_region_bound(&self, span: Span) -> Option<ty::Region>;
|
||||
/// If an object omits any explicit lifetime bound, and none can
|
||||
/// be derived from the object traits, what should we use? If
|
||||
/// `None` is returned, an explicit annotation is required.
|
||||
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region>;
|
||||
}
|
||||
|
||||
// A scope in which all regions must be explicitly named. This is used
|
||||
@ -41,7 +44,7 @@ pub trait RegionScope {
|
||||
pub struct ExplicitRscope;
|
||||
|
||||
impl RegionScope for ExplicitRscope {
|
||||
fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
|
||||
fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
|
||||
None
|
||||
}
|
||||
|
||||
@ -63,7 +66,7 @@ impl UnelidableRscope {
|
||||
}
|
||||
|
||||
impl RegionScope for UnelidableRscope {
|
||||
fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
|
||||
fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
|
||||
None
|
||||
}
|
||||
|
||||
@ -76,21 +79,22 @@ impl RegionScope for UnelidableRscope {
|
||||
}
|
||||
}
|
||||
|
||||
// A scope in which any omitted region defaults to `default`. This is
|
||||
// used after the `->` in function signatures, but also for backwards
|
||||
// compatibility with object types. The latter use may go away.
|
||||
pub struct SpecificRscope {
|
||||
default: ty::Region
|
||||
// A scope in which omitted anonymous region defaults to
|
||||
// `default`. This is used after the `->` in function signatures. The
|
||||
// latter use may go away. Note that object-lifetime defaults work a
|
||||
// bit differently, as specified in RFC #599.
|
||||
pub struct ElidableRscope {
|
||||
default: ty::Region,
|
||||
}
|
||||
|
||||
impl SpecificRscope {
|
||||
pub fn new(r: ty::Region) -> SpecificRscope {
|
||||
SpecificRscope { default: r }
|
||||
impl ElidableRscope {
|
||||
pub fn new(r: ty::Region) -> ElidableRscope {
|
||||
ElidableRscope { default: r }
|
||||
}
|
||||
}
|
||||
|
||||
impl RegionScope for SpecificRscope {
|
||||
fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
|
||||
impl RegionScope for ElidableRscope {
|
||||
fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
|
||||
Some(self.default)
|
||||
}
|
||||
|
||||
@ -124,7 +128,7 @@ impl BindingRscope {
|
||||
}
|
||||
|
||||
impl RegionScope for BindingRscope {
|
||||
fn default_region_bound(&self, _span: Span) -> Option<ty::Region>
|
||||
fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region>
|
||||
{
|
||||
Some(self.next_region())
|
||||
}
|
||||
@ -151,9 +155,8 @@ impl<'r> ShiftedRscope<'r> {
|
||||
}
|
||||
|
||||
impl<'r> RegionScope for ShiftedRscope<'r> {
|
||||
fn default_region_bound(&self, span: Span) -> Option<ty::Region>
|
||||
{
|
||||
self.base_scope.default_region_bound(span)
|
||||
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
|
||||
self.base_scope.object_lifetime_default(span)
|
||||
.map(|r| ty_fold::shift_region(r, 1))
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user