提交 c5befdc6 编写于 作者: E Eduard-Mihai Burtescu

rustc: always keep an explicit lifetime in trait objects.

上级 41553d6f
......@@ -301,7 +301,7 @@ fn visit_trait_ref(&mut self, t: &'v TraitRef) {
fn visit_ty_param_bound(&mut self, bounds: &'v TyParamBound) {
walk_ty_param_bound(self, bounds)
}
fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) {
fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: TraitBoundModifier) {
walk_poly_trait_ref(self, t, m)
}
fn visit_variant_data(&mut self,
......@@ -421,7 +421,7 @@ pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v
pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V,
trait_ref: &'v PolyTraitRef,
_modifier: &'v TraitBoundModifier)
_modifier: TraitBoundModifier)
where V: Visitor<'v>
{
walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes);
......@@ -566,8 +566,11 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
visitor.visit_ty(ty);
visitor.visit_nested_body(length)
}
TyTraitObject(ref bounds) => {
walk_list!(visitor, visit_ty_param_bound, bounds);
TyTraitObject(ref bounds, ref lifetime) => {
for bound in bounds {
visitor.visit_poly_trait_ref(bound, TraitBoundModifier::None);
}
visitor.visit_lifetime(lifetime);
}
TyImplTrait(ref bounds) => {
walk_list!(visitor, visit_ty_param_bound, bounds);
......@@ -695,7 +698,7 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v
pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyParamBound) {
match *bound {
TraitTyParamBound(ref typ, ref modifier) => {
TraitTyParamBound(ref typ, modifier) => {
visitor.visit_poly_trait_ref(typ, modifier);
}
RegionTyParamBound(ref lifetime) => {
......
......@@ -360,7 +360,23 @@ fn lower_ty(&mut self, t: &Ty) -> P<hir::Ty> {
hir::TyTypeof(self.record_body(expr, None))
}
TyKind::TraitObject(ref bounds) => {
hir::TyTraitObject(self.lower_bounds(bounds))
let mut lifetime_bound = None;
let bounds = bounds.iter().filter_map(|bound| {
match *bound {
TraitTyParamBound(ref ty, TraitBoundModifier::None) => {
Some(self.lower_poly_trait_ref(ty))
}
TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
RegionTyParamBound(ref lifetime) => {
lifetime_bound = Some(self.lower_lifetime(lifetime));
None
}
}
}).collect();
let lifetime_bound = lifetime_bound.unwrap_or_else(|| {
self.elided_lifetime(t.span)
});
hir::TyTraitObject(bounds, lifetime_bound)
}
TyKind::ImplTrait(ref bounds) => {
hir::TyImplTrait(self.lower_bounds(bounds))
......@@ -2361,20 +2377,20 @@ fn ty_path(&mut self, id: NodeId, span: Span, qpath: hir::QPath) -> P<hir::Ty> {
hir::QPath::Resolved(None, path) => {
// Turn trait object paths into `TyTraitObject` instead.
if let Def::Trait(_) = path.def {
let principal = hir::TraitTyParamBound(hir::PolyTraitRef {
let principal = hir::PolyTraitRef {
bound_lifetimes: hir_vec![],
trait_ref: hir::TraitRef {
path: path.and_then(|path| path),
ref_id: id,
},
span,
}, hir::TraitBoundModifier::None);
};
// The original ID is taken by the `PolyTraitRef`,
// so the `Ty` itself needs a different one.
id = self.next_id();
hir::TyTraitObject(hir_vec![principal])
hir::TyTraitObject(hir_vec![principal], self.elided_lifetime(span))
} else {
hir::TyPath(hir::QPath::Resolved(None, path))
}
......
......@@ -1205,7 +1205,7 @@ pub enum Ty_ {
TyPath(QPath),
/// A trait object type `Bound1 + Bound2 + Bound3`
/// where `Bound` is a trait or a lifetime.
TyTraitObject(TyParamBounds),
TyTraitObject(HirVec<PolyTraitRef>, Lifetime),
/// An `impl Bound1 + Bound2 + Bound3` type
/// where `Bound` is a trait or a lifetime.
TyImplTrait(TyParamBounds),
......
......@@ -416,8 +416,21 @@ pub fn print_type(&mut self, ty: &hir::Ty) -> io::Result<()> {
hir::TyPath(ref qpath) => {
self.print_qpath(qpath, false)?
}
hir::TyTraitObject(ref bounds) => {
self.print_bounds("", &bounds[..])?;
hir::TyTraitObject(ref bounds, ref lifetime) => {
let mut first = true;
for bound in bounds {
self.nbsp()?;
if first {
first = false;
} else {
self.word_space("+")?;
}
self.print_poly_trait_ref(bound)?;
}
if !lifetime.is_elided() {
self.word_space("+")?;
self.print_lifetime(lifetime)?;
}
}
hir::TyImplTrait(ref bounds) => {
self.print_bounds("impl ", &bounds[..])?;
......
......@@ -322,6 +322,14 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
intravisit::walk_ty(this, ty);
});
}
hir::TyTraitObject(ref bounds, ref lifetime) => {
for bound in bounds {
self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
}
if !lifetime.is_elided() {
self.visit_lifetime(lifetime);
}
}
_ => {
intravisit::walk_ty(self, ty)
}
......@@ -441,7 +449,7 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
fn visit_poly_trait_ref(&mut self,
trait_ref: &'tcx hir::PolyTraitRef,
_modifier: &'tcx hir::TraitBoundModifier) {
_modifier: hir::TraitBoundModifier) {
debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
if !self.trait_ref_hack || !trait_ref.bound_lifetimes.is_empty() {
......@@ -962,7 +970,7 @@ fn visit_ty(&mut self, ty: &hir::Ty) {
fn visit_poly_trait_ref(&mut self,
trait_ref: &hir::PolyTraitRef,
modifier: &hir::TraitBoundModifier) {
modifier: hir::TraitBoundModifier) {
self.binder_depth += 1;
intravisit::walk_poly_trait_ref(self, trait_ref, modifier);
self.binder_depth -= 1;
......
......@@ -828,7 +828,7 @@ fn visit_ty_param_bound(&mut self, bounds: &'tcx TyParamBound) {
visit::walk_ty_param_bound(self, bounds)
}
fn visit_poly_trait_ref(&mut self, t: &'tcx PolyTraitRef, m: &'tcx TraitBoundModifier) {
fn visit_poly_trait_ref(&mut self, t: &'tcx PolyTraitRef, m: TraitBoundModifier) {
debug!("visit_poly_trait_ref: st={:?}", self.st);
SawPolyTraitRef.hash(self.st);
m.hash(self.st);
......
......@@ -144,6 +144,17 @@ fn visit_ty(&mut self, ty: &'a Ty) {
});
}
TyKind::TraitObject(ref bounds) => {
let mut any_lifetime_bounds = false;
for bound in bounds {
if let RegionTyParamBound(ref lifetime) = *bound {
if any_lifetime_bounds {
span_err!(self.session, lifetime.span, E0226,
"only a single explicit lifetime bound is permitted");
break;
}
any_lifetime_bounds = true;
}
}
self.no_questions_in_bounds(bounds, "trait object types", false);
}
TyKind::ImplTrait(ref bounds) => {
......
......@@ -244,6 +244,7 @@ pub fn foo() {}
}
register_diagnostics! {
E0226, // only a single explicit lifetime bound is permitted
E0472, // asm! is unsupported on this target
E0561, // patterns aren't allowed in function pointer types
E0571, // `break` with a value in a non-`loop`-loop
......
......@@ -453,24 +453,6 @@ fn convert_parenthesized_parameters(&self,
(self.tcx().mk_ty(ty::TyTuple(inputs)), output_binding)
}
pub fn instantiate_poly_trait_ref(&self,
rscope: &RegionScope,
ast_trait_ref: &hir::PolyTraitRef,
self_ty: Ty<'tcx>,
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
-> ty::PolyTraitRef<'tcx>
{
let trait_ref = &ast_trait_ref.trait_ref;
let trait_def_id = self.trait_def_id(trait_ref);
self.ast_path_to_poly_trait_ref(rscope,
trait_ref.path.span,
trait_def_id,
self_ty,
trait_ref.ref_id,
trait_ref.path.segments.last().unwrap(),
poly_projections)
}
/// Instantiates the path for the given trait reference, assuming that it's
/// bound to a valid trait type. Returns the def_id for the defining trait.
/// Fails if the type is a type other than a trait type.
......@@ -505,17 +487,17 @@ fn trait_def_id(&self, trait_ref: &hir::TraitRef) -> DefId {
}
}
fn ast_path_to_poly_trait_ref(&self,
pub fn instantiate_poly_trait_ref(&self,
rscope: &RegionScope,
span: Span,
trait_def_id: DefId,
ast_trait_ref: &hir::PolyTraitRef,
self_ty: Ty<'tcx>,
path_id: ast::NodeId,
trait_segment: &hir::PathSegment,
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
-> ty::PolyTraitRef<'tcx>
{
debug!("ast_path_to_poly_trait_ref(trait_segment={:?})", trait_segment);
let trait_ref = &ast_trait_ref.trait_ref;
let trait_def_id = self.trait_def_id(trait_ref);
debug!("ast_path_to_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id);
// The trait reference introduces a binding level here, so
// we need to shift the `rscope`. It'd be nice if we could
// do away with this rscope stuff and work this knowledge
......@@ -525,23 +507,23 @@ fn ast_path_to_poly_trait_ref(&self,
let (substs, assoc_bindings) =
self.create_substs_for_ast_trait_ref(shifted_rscope,
span,
trait_ref.path.span,
trait_def_id,
self_ty,
trait_segment);
trait_ref.path.segments.last().unwrap());
let poly_trait_ref = ty::Binder(ty::TraitRef::new(trait_def_id, substs));
poly_projections.extend(assoc_bindings.iter().filter_map(|binding| {
// specify type to assert that error was already reported in Err case:
let predicate: Result<_, ErrorReported> =
self.ast_type_binding_to_poly_projection_predicate(path_id,
self.ast_type_binding_to_poly_projection_predicate(trait_ref.ref_id,
poly_trait_ref,
binding);
predicate.ok() // ok to ignore Err() because ErrorReported (see above)
}));
debug!("ast_path_to_poly_trait_ref(trait_segment={:?}, projections={:?}) -> {:?}",
trait_segment, poly_projections, poly_trait_ref);
debug!("ast_path_to_poly_trait_ref({:?}, projections={:?}) -> {:?}",
trait_ref, poly_projections, poly_trait_ref);
poly_trait_ref
}
......@@ -754,32 +736,29 @@ fn trait_ref_to_existential(&self, trait_ref: ty::TraitRef<'tcx>)
ty::ExistentialTraitRef::erase_self_ty(self.tcx(), trait_ref)
}
fn trait_path_to_object_type(&self,
rscope: &RegionScope,
path_span: Span,
trait_def_id: DefId,
trait_path_ref_id: ast::NodeId,
trait_segment: &hir::PathSegment,
span: Span,
partitioned_bounds: PartitionedBounds)
-> Ty<'tcx> {
fn conv_object_ty_poly_trait_ref(&self,
rscope: &RegionScope,
span: Span,
trait_bounds: &[hir::PolyTraitRef],
lifetime: &hir::Lifetime)
-> Ty<'tcx>
{
let tcx = self.tcx();
if trait_bounds.is_empty() {
span_err!(tcx.sess, span, E0224,
"at least one non-builtin trait is required for an object type");
return tcx.types.err;
}
let mut projection_bounds = vec![];
let dummy_self = tcx.mk_ty(TRAIT_OBJECT_DUMMY_SELF);
let principal = self.ast_path_to_poly_trait_ref(rscope,
path_span,
trait_def_id,
let principal = self.instantiate_poly_trait_ref(rscope,
&trait_bounds[0],
dummy_self,
trait_path_ref_id,
trait_segment,
&mut projection_bounds);
let PartitionedBounds { trait_bounds,
region_bounds } =
partitioned_bounds;
let (auto_traits, trait_bounds) = split_auto_traits(tcx, trait_bounds);
let (auto_traits, trait_bounds) = split_auto_traits(tcx, &trait_bounds[1..]);
if !trait_bounds.is_empty() {
let b = &trait_bounds[0];
......@@ -854,13 +833,12 @@ fn trait_path_to_object_type(&self,
v.sort_by(|a, b| a.cmp(tcx, b));
let existential_predicates = ty::Binder(tcx.mk_existential_predicates(v.into_iter()));
let region_bound = self.compute_object_lifetime_bound(span,
&region_bounds,
existential_predicates);
let region_bound = match region_bound {
Some(r) => r,
None => {
// Explicitly specified region bound. Use that.
let region_bound = if !lifetime.is_elided() {
self.ast_region_to_region(lifetime, None)
} else {
self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| {
tcx.mk_region(match rscope.object_lifetime_default(span) {
Some(r) => r,
None => {
......@@ -870,7 +848,7 @@ fn trait_path_to_object_type(&self,
ty::ReStatic
}
})
}
})
};
debug!("region_bound: {:?}", region_bound);
......@@ -1330,8 +1308,8 @@ pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> {
}
tcx.mk_fn_ptr(bare_fn_ty)
}
hir::TyTraitObject(ref bounds) => {
self.conv_object_ty_poly_trait_ref(rscope, ast_ty.span, bounds)
hir::TyTraitObject(ref bounds, ref lifetime) => {
self.conv_object_ty_poly_trait_ref(rscope, ast_ty.span, bounds, lifetime)
}
hir::TyImplTrait(ref bounds) => {
use collect::{compute_bounds, SizedByDefault};
......@@ -1537,33 +1515,6 @@ pub fn ty_of_closure(&self,
}
}
fn conv_object_ty_poly_trait_ref(&self,
rscope: &RegionScope,
span: Span,
ast_bounds: &[hir::TyParamBound])
-> Ty<'tcx>
{
let mut partitioned_bounds = partition_bounds(ast_bounds);
let trait_bound = if !partitioned_bounds.trait_bounds.is_empty() {
partitioned_bounds.trait_bounds.remove(0)
} else {
span_err!(self.tcx().sess, span, E0224,
"at least one non-builtin trait is required for an object type");
return self.tcx().types.err;
};
let trait_ref = &trait_bound.trait_ref;
let trait_def_id = self.trait_def_id(trait_ref);
self.trait_path_to_object_type(rscope,
trait_ref.path.span,
trait_def_id,
trait_ref.ref_id,
trait_ref.path.segments.last().unwrap(),
span,
partitioned_bounds)
}
/// 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
......@@ -1571,27 +1522,14 @@ fn conv_object_ty_poly_trait_ref(&self,
/// we return `None`.
fn compute_object_lifetime_bound(&self,
span: Span,
explicit_region_bounds: &[&hir::Lifetime],
existential_predicates: ty::Binder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>)
-> Option<&'tcx ty::Region> // if None, use the default
{
let tcx = self.tcx();
debug!("compute_opt_region_bound(explicit_region_bounds={:?}, \
existential_predicates={:?})",
explicit_region_bounds,
debug!("compute_opt_region_bound(existential_predicates={:?})",
existential_predicates);
if explicit_region_bounds.len() > 1 {
span_err!(tcx.sess, explicit_region_bounds[1].span, E0226,
"only a single explicit lifetime bound is permitted");
}
if let Some(&r) = explicit_region_bounds.get(0) {
// Explicitly specified region bound. Use that.
return Some(self.ast_region_to_region(r, None));
}
if let Some(principal) = existential_predicates.principal() {
if let Err(ErrorReported) = self.ensure_super_predicates(span, principal.def_id()) {
return Some(tcx.mk_region(ty::ReStatic));
......@@ -1627,18 +1565,13 @@ fn compute_object_lifetime_bound(&self,
}
}
pub struct PartitionedBounds<'a> {
pub trait_bounds: Vec<&'a hir::PolyTraitRef>,
pub region_bounds: Vec<&'a hir::Lifetime>,
}
/// Divides a list of general trait bounds into two groups: builtin bounds (Sync/Send) and the
/// remaining general trait bounds.
fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
trait_bounds: Vec<&'b hir::PolyTraitRef>)
trait_bounds: &'b [hir::PolyTraitRef])
-> (Vec<DefId>, Vec<&'b hir::PolyTraitRef>)
{
let (auto_traits, trait_bounds): (Vec<_>, _) = trait_bounds.into_iter().partition(|bound| {
let (auto_traits, trait_bounds): (Vec<_>, _) = trait_bounds.iter().partition(|bound| {
match bound.trait_ref.path.def {
Def::Trait(trait_did) => {
// Checks whether `trait_did` refers to one of the builtin
......@@ -1675,30 +1608,6 @@ fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
(auto_traits, trait_bounds)
}
/// Divides a list of bounds from the AST into two groups: general trait bounds and region bounds
pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(ast_bounds: &'b [hir::TyParamBound])
-> PartitionedBounds<'b>
{
let mut region_bounds = Vec::new();
let mut trait_bounds = Vec::new();
for ast_bound in ast_bounds {
match *ast_bound {
hir::TraitTyParamBound(ref b, hir::TraitBoundModifier::None) => {
trait_bounds.push(b);
}
hir::TraitTyParamBound(_, hir::TraitBoundModifier::Maybe) => {}
hir::RegionTyParamBound(ref l) => {
region_bounds.push(l);
}
}
}
PartitionedBounds {
trait_bounds: trait_bounds,
region_bounds: region_bounds,
}
}
fn check_type_argument_count(tcx: TyCtxt, span: Span, supplied: usize,
ty_param_defs: &[ty::TypeParameterDef]) {
let accepted = ty_param_defs.len();
......
......@@ -57,7 +57,7 @@
*/
use astconv::{AstConv, Bounds, PartitionedBounds, partition_bounds};
use astconv::{AstConv, Bounds};
use lint;
use constrained_type_params as ctp;
use middle::lang_items::SizedTraitLangItem;
......@@ -1961,10 +1961,19 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
span: Span)
-> Bounds<'tcx>
{
let PartitionedBounds {
trait_bounds,
region_bounds
} = partition_bounds(&ast_bounds);
let mut region_bounds = vec![];
let mut trait_bounds = vec![];
for ast_bound in ast_bounds {
match *ast_bound {
hir::TraitTyParamBound(ref b, hir::TraitBoundModifier::None) => {
trait_bounds.push(b);
}
hir::TraitTyParamBound(_, hir::TraitBoundModifier::Maybe) => {}
hir::RegionTyParamBound(ref l) => {
region_bounds.push(l);
}
}
}
let mut projection_bounds = vec![];
......
......@@ -4096,7 +4096,6 @@ fn main() {
// E0222, // Error code E0045 (variadic function must have C calling
// convention) duplicate
E0224, // at least one non-builtin train is required for an object type
E0226, // only a single explicit lifetime bound is permitted
E0227, // ambiguous lifetime bound, explicit lifetime bound required
E0228, // explicit lifetime bound required
E0231, // only named substitution parameters are allowed
......
......@@ -1776,20 +1776,20 @@ fn clean(&self, cx: &DocContext) -> Type {
trait_: box resolve_type(cx, trait_path.clean(cx), self.id)
}
}
TyTraitObject(ref bounds) => {
let lhs_ty = bounds[0].clean(cx);
match lhs_ty {
TraitBound(poly_trait, ..) => {
match poly_trait.trait_ {
ResolvedPath { path, typarams: None, did, is_generic } => {
ResolvedPath {
path: path,
typarams: Some(bounds[1..].clean(cx)),
did: did,
is_generic: is_generic,
}
}
_ => Infer // shouldn't happen
TyTraitObject(ref bounds, ref lifetime) => {
match bounds[0].clean(cx).trait_ {
ResolvedPath { path, typarams: None, did, is_generic } => {
let mut bounds: Vec<_> = bounds[1..].iter().map(|bound| {
TraitBound(bound.clean(cx), hir::TraitBoundModifier::None)
}).collect();
if !lifetime.is_elided() {
bounds.push(RegionBound(lifetime.clean(cx)));
}
ResolvedPath {
path: path,
typarams: Some(bounds),
did: did,
is_generic: is_generic,
}
}
_ => Infer // shouldn't happen
......
......@@ -18,7 +18,7 @@ trait SomeTrait { }
// Bounds on object types:
struct Foo<'a,'b,'c> {
struct Foo<'a,'b,'c> { //~ ERROR parameter `'b` is never used
// All of these are ok, because we can derive exactly one bound:
a: Box<IsStatic>,
b: Box<Is<'static>>,
......@@ -28,7 +28,9 @@ struct Foo<'a,'b,'c> {
f: Box<SomeTrait>, // OK, defaults to 'static due to RFC 599.
g: Box<SomeTrait+'a>,
z: Box<Is<'a>+'b+'c>, //~ ERROR only a single explicit lifetime bound is permitted
z: Box<Is<'a>+'b+'c>,
//~^ ERROR only a single explicit lifetime bound is permitted
//~| ERROR lifetime bound not satisfied
}
fn test<
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册