Implemented for traits (associated type definitions).

This commit is contained in:
Alexander Regueiro 2019-03-16 00:04:02 +00:00
parent 3816958f18
commit aaa53ec853
12 changed files with 312 additions and 249 deletions

View file

@ -626,6 +626,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
TyKind::CVarArgs(ref lt) => {
visitor.visit_lifetime(lt)
}
TyKind::AssocTyExistential(ref bounds) => {
walk_list!(visitor, visit_param_bound, bounds);
}
TyKind::Infer | TyKind::Err => {}
}
}

View file

@ -195,6 +195,12 @@ enum ImplTraitContext<'a> {
/// (e.g., for consts and statics).
Existential(Option<DefId> /* fn def-ID */),
/// Treat `impl Trait` as a bound on the associated type applied to the trait.
/// Example: `trait Foo { type Bar: Iterator<Item = impl Debug>; }` is conceptually
/// equivalent to `trait Foo where <Self::Bar as Iterator>::Item: Debug
/// { type Bar: Iterator; }`.
AssociatedTy,
/// `impl Trait` is not accepted in this position.
Disallowed(ImplTraitPosition),
}
@ -217,6 +223,7 @@ impl<'a> ImplTraitContext<'a> {
match self {
Universal(params) => Universal(params),
Existential(fn_def_id) => Existential(*fn_def_id),
AssociatedTy => AssociatedTy,
Disallowed(pos) => Disallowed(*pos),
}
}
@ -1537,6 +1544,16 @@ impl<'a> LoweringContext<'a> {
}),
))
}
ImplTraitContext::AssociatedTy => {
let hir_bounds = self.lower_param_bounds(
bounds,
ImplTraitContext::AssociatedTy,
);
hir::TyKind::AssocTyExistential(
hir_bounds,
)
}
ImplTraitContext::Disallowed(pos) => {
let allowed_in = if self.sess.features_untracked()
.impl_trait_in_bindings {
@ -1640,8 +1657,8 @@ impl<'a> LoweringContext<'a> {
})
}
/// Registers a new existential type with the proper `NodeId`ss and
/// returns the lowered node ID for the existential type.
/// Registers a new existential type with the proper `NodeId`s and
/// returns the lowered node-ID for the existential type.
fn generate_existential_type(
&mut self,
exist_ty_node_id: NodeId,
@ -2226,8 +2243,9 @@ impl<'a> LoweringContext<'a> {
(
hir::GenericArgs {
args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(),
bindings: constraints.iter().map(
|b| self.lower_assoc_ty_constraint(b, itctx.reborrow())).collect(),
bindings: constraints.iter()
.map(|b| self.lower_assoc_ty_constraint(b, itctx.reborrow()))
.collect(),
parenthesized: false,
},
!has_types && param_mode == ParamMode::Optional
@ -3257,13 +3275,13 @@ impl<'a> LoweringContext<'a> {
ItemKind::ForeignMod(ref nm) => hir::ItemKind::ForeignMod(self.lower_foreign_mod(nm)),
ItemKind::GlobalAsm(ref ga) => hir::ItemKind::GlobalAsm(self.lower_global_asm(ga)),
ItemKind::Ty(ref t, ref generics) => hir::ItemKind::Ty(
self.lower_ty(t, ImplTraitContext::disallowed()),
self.lower_generics(generics, ImplTraitContext::disallowed()),
self.lower_ty(t, ImplTraitContext::AssociatedTy),
self.lower_generics(generics, ImplTraitContext::AssociatedTy),
),
ItemKind::Existential(ref b, ref generics) => hir::ItemKind::Existential(
hir::ExistTy {
generics: self.lower_generics(generics, ImplTraitContext::disallowed()),
bounds: self.lower_param_bounds(b, ImplTraitContext::Existential(None)),
generics: self.lower_generics(generics, ImplTraitContext::AssociatedTy),
bounds: self.lower_param_bounds(b, ImplTraitContext::AssociatedTy),
impl_trait_fn: None,
origin: hir::ExistTyOrigin::ExistentialType,
},
@ -3276,20 +3294,20 @@ impl<'a> LoweringContext<'a> {
.map(|x| self.lower_variant(x))
.collect(),
},
self.lower_generics(generics, ImplTraitContext::disallowed()),
self.lower_generics(generics, ImplTraitContext::AssociatedTy),
),
ItemKind::Struct(ref struct_def, ref generics) => {
let struct_def = self.lower_variant_data(struct_def);
hir::ItemKind::Struct(
struct_def,
self.lower_generics(generics, ImplTraitContext::disallowed()),
self.lower_generics(generics, ImplTraitContext::AssociatedTy),
)
}
ItemKind::Union(ref vdata, ref generics) => {
let vdata = self.lower_variant_data(vdata);
hir::ItemKind::Union(
vdata,
self.lower_generics(generics, ImplTraitContext::disallowed()),
self.lower_generics(generics, ImplTraitContext::AssociatedTy),
)
}
ItemKind::Impl(
@ -3656,15 +3674,17 @@ impl<'a> LoweringContext<'a> {
);
(generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id)))
}
TraitItemKind::Type(ref bounds, ref default) => (
self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
hir::TraitItemKind::Type(
self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
TraitItemKind::Type(ref bounds, ref default) => {
let generics = self.lower_generics(&i.generics, ImplTraitContext::AssociatedTy);
let node = hir::TraitItemKind::Type(
self.lower_param_bounds(bounds, ImplTraitContext::AssociatedTy),
default
.as_ref()
.map(|x| self.lower_ty(x, ImplTraitContext::disallowed())),
),
),
);
(generics, node)
},
TraitItemKind::Macro(..) => bug!("macro item shouldn't exist at this point"),
};

View file

@ -1898,6 +1898,8 @@ pub enum TyKind {
/// Placeholder for C-variadic arguments. We "spoof" the `VaList` created
/// from the variadic arguments. This type is only valid up to typeck.
CVarArgs(Lifetime),
/// The existential type (i.e., `impl Trait`) that constrains an associated type.
AssocTyExistential(HirVec<GenericBound>),
}
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]

View file

@ -409,6 +409,9 @@ impl<'a> State<'a> {
hir::TyKind::CVarArgs(_) => {
self.s.word("...")?;
}
hir::TyKind::AssocTyExistential(ref bounds) => {
self.print_bounds(":", bounds)?;
}
}
self.end()
}

View file

@ -948,15 +948,17 @@ pub fn may_define_existential_type(
let mut hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
trace!(
"may_define_existential_type(def={:?}, opaque_node={:?})",
tcx.hir().get(hir_id),
tcx.hir().get(opaque_hir_id)
tcx.hir().get_by_hir_id(hir_id),
tcx.hir().get_by_hir_id(opaque_hir_id)
);
// Named existential types can be defined by any siblings or children of siblings.
let scope_id = tcx.hir().get_defining_scope(opaque_hir_id)
.expect("could not get defining scope");
let scope_node_id = tcx.hir()
.get_defining_scope(tcx.hir().hir_to_node_id(opaque_hir_id))
.expect("could not get defining scope");
let scope_id = tcx.hir().node_to_hir_id(scope_node_id);
// We walk up the node tree until we hit the root or the scope of the opaque type.
while hir_id != scope_id && hir_id != ast::CRATE_hir_ID {
while hir_id != scope_id && hir_id != hir::CRATE_HIR_ID {
hir_id = tcx.hir().get_parent_item(hir_id);
}
// Syntactically, we are allowed to define the concrete type if:

View file

@ -726,7 +726,8 @@ impl<'a> ReplaceBodyWithLoop<'a> {
any_assoc_ty_bounds ||
any_involves_impl_trait(types.into_iter()) ||
any_involves_impl_trait(data.constraints.iter().filter_map(|c| {
if let ast::AssocTyConstraintKind::Equality { ref ty } = c.kind {
if let ast::AssocTyConstraintKind::Equality { ref ty }
= c.kind {
Some(ty)
} else {
None

View file

@ -1040,12 +1040,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
if !self.in_body {
// Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
// The traits' privacy in bodies is already checked as a part of trait object types.
let (principal, projections) =
rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);
let (principal, bounds) = rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);
if self.visit_trait(*principal.skip_binder()) {
return;
}
for (poly_predicate, _) in projections {
for (poly_predicate, _) in bounds.projection_bounds {
let tcx = self.tcx;
if self.visit(poly_predicate.skip_binder().ty) ||
self.visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx)) {

View file

@ -8,6 +8,7 @@ use crate::hir::def::{CtorOf, Res, DefKind};
use crate::hir::def_id::DefId;
use crate::hir::HirVec;
use crate::lint;
use crate::middle::lang_items::SizedTraitLangItem;
use crate::middle::resolve_lifetime as rl;
use crate::namespace::Namespace;
use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
@ -86,12 +87,22 @@ pub trait AstConv<'gcx, 'tcx> {
fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span);
}
pub enum SizedByDefault {
Yes,
No,
}
struct ConvertedBinding<'tcx> {
item_name: ast::Ident,
ty: Ty<'tcx>,
kind: ConvertedBindingKind<'tcx>,
span: Span,
}
enum ConvertedBindingKind<'tcx> {
Equality(Ty<'tcx>),
Constraint(P<[hir::GenericBound]>),
}
#[derive(PartialEq)]
enum GenericArgPosition {
Type,
@ -562,10 +573,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
/// set of substitutions. This may involve applying defaulted type parameters.
///
/// Note that the type listing given here is *exactly* what the user provided.
fn create_substs_for_ast_path(&self,
fn create_substs_for_ast_path<'a>(&self,
span: Span,
def_id: DefId,
generic_args: &hir::GenericArgs,
generic_args: &'a hir::GenericArgs,
infer_types: bool,
self_ty: Option<Ty<'tcx>>)
-> (SubstsRef<'tcx>, Vec<ConvertedBinding<'tcx>>, Option<Vec<Span>>)
@ -688,13 +699,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
},
);
let assoc_bindings = generic_args.bindings.iter().map(|binding| {
ConvertedBinding {
item_name: binding.ident,
ty: self.ast_ty_to_ty(&binding.ty),
span: binding.span,
}
}).collect();
let assoc_bindings = generic_args.bindings.iter()
.map(|binding| {
let kind = if let hir::TyKind::AssocTyExistential(ref bounds) = binding.ty.node {
ConvertedBindingKind::Constraint(bounds.clone())
} else {
ConvertedBindingKind::Equality(self.ast_ty_to_ty(&binding.ty))
};
ConvertedBinding {
item_name: binding.ident,
kind,
span: binding.span,
}
})
.collect();
debug!("create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}",
generic_params, self_ty, substs);
@ -725,7 +743,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
pub(super) fn instantiate_poly_trait_ref_inner(&self,
trait_ref: &hir::TraitRef,
self_ty: Ty<'tcx>,
poly_projections: &mut Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
bounds: &mut Bounds<'tcx>,
speculative: bool,
) -> (ty::PolyTraitRef<'tcx>, Option<Vec<Span>>)
{
@ -744,36 +762,40 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs));
let mut dup_bindings = FxHashMap::default();
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(
trait_ref.hir_ref_id, poly_trait_ref, binding, speculative, &mut dup_bindings);
// okay to ignore Err because of ErrorReported (see above)
Some((predicate.ok()?, binding.span))
}));
for binding in &assoc_bindings {
// Specify type to assert that error was already reported in `Err` case.
let _ =
self.add_predicates_for_ast_type_binding(
trait_ref.hir_ref_id,
poly_trait_ref,
binding,
bounds,
speculative,
&mut dup_bindings
);
// Okay to ignore `Err` because of `ErrorReported` (see above).
}
debug!("instantiate_poly_trait_ref({:?}, projections={:?}) -> {:?}",
trait_ref, poly_projections, poly_trait_ref);
debug!("instantiate_poly_trait_ref({:?}, bounds={:?}) -> {:?}",
trait_ref, bounds, poly_trait_ref);
(poly_trait_ref, potential_assoc_types)
}
pub fn instantiate_poly_trait_ref(&self,
poly_trait_ref: &hir::PolyTraitRef,
self_ty: Ty<'tcx>,
poly_projections: &mut Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>)
-> (ty::PolyTraitRef<'tcx>, Option<Vec<Span>>)
bounds: &mut Bounds<'tcx>
) -> (ty::PolyTraitRef<'tcx>, Option<Vec<Span>>)
{
self.instantiate_poly_trait_ref_inner(&poly_trait_ref.trait_ref, self_ty,
poly_projections, false)
self.instantiate_poly_trait_ref_inner(&poly_trait_ref.trait_ref, self_ty, bounds, false)
}
fn ast_path_to_mono_trait_ref(&self,
span: Span,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
trait_segment: &hir::PathSegment)
-> ty::TraitRef<'tcx>
span: Span,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
trait_segment: &hir::PathSegment
) -> ty::TraitRef<'tcx>
{
let (substs, assoc_bindings, _) =
self.create_substs_for_ast_trait_ref(span,
@ -830,15 +852,120 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
})
}
fn ast_type_binding_to_poly_projection_predicate(
// Returns `true` if a bounds list includes `?Sized`.
pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound], span: Span) -> bool {
let tcx = self.tcx();
// Try to find an unbound in bounds.
let mut unbound = None;
for ab in ast_bounds {
if let &hir::GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = ab {
if unbound.is_none() {
unbound = Some(ptr.trait_ref.clone());
} else {
span_err!(
tcx.sess,
span,
E0203,
"type parameter has more than one relaxed default \
bound, only one is supported"
);
}
}
}
let kind_id = tcx.lang_items().require(SizedTraitLangItem);
match unbound {
Some(ref tpb) => {
// FIXME(#8559) currently requires the unbound to be built-in.
if let Ok(kind_id) = kind_id {
if tpb.path.res != Res::Def(DefKind::Trait, kind_id) {
tcx.sess.span_warn(
span,
"default bound relaxed for a type parameter, but \
this does nothing because the given bound is not \
a default. Only `?Sized` is supported",
);
}
}
}
_ if kind_id.is_ok() => {
return false;
}
// No lang item for `Sized`, so we can't add it as a bound.
None => {}
}
true
}
pub fn add_bounds(&self,
param_ty: Ty<'tcx>,
ast_bounds: &[hir::GenericBound],
bounds: &mut Bounds<'tcx>,
) {
let mut trait_bounds = Vec::new();
let mut region_bounds = Vec::new();
for ast_bound in ast_bounds {
match *ast_bound {
hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) =>
trait_bounds.push(b),
hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
hir::GenericBound::Outlives(ref l) =>
region_bounds.push(l),
}
}
for bound in trait_bounds {
let (poly_trait_ref, _) = self.instantiate_poly_trait_ref(
bound,
param_ty,
bounds,
);
bounds.trait_bounds.push((poly_trait_ref, bound.span))
}
bounds.region_bounds.extend(region_bounds
.into_iter()
.map(|r| (self.ast_region_to_region(r, None), r.span))
);
bounds.trait_bounds.sort_by_key(|(t, _)| t.def_id());
}
/// Translates the AST's notion of ty param bounds (which are an enum consisting of a newtyped `Ty`
/// or a region) to ty's notion of ty param bounds, which can either be user-defined traits or the
/// built-in trait `Send`.
pub fn compute_bounds(&self,
param_ty: Ty<'tcx>,
ast_bounds: &[hir::GenericBound],
sized_by_default: SizedByDefault,
span: Span,
) -> Bounds<'tcx> {
let mut bounds = Bounds::default();
self.add_bounds(param_ty, ast_bounds, &mut bounds);
bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default {
if !self.is_unsized(ast_bounds, span) {
Some(span)
} else {
None
}
} else {
None
};
bounds
}
fn add_predicates_for_ast_type_binding(
&self,
hir_ref_id: hir::HirId,
trait_ref: ty::PolyTraitRef<'tcx>,
binding: &ConvertedBinding<'tcx>,
bounds: &mut Bounds<'tcx>,
speculative: bool,
dup_bindings: &mut FxHashMap<DefId, Span>)
-> Result<ty::PolyProjectionPredicate<'tcx>, ErrorReported>
{
dup_bindings: &mut FxHashMap<DefId, Span>,
) -> Result<(), ErrorReported> {
let tcx = self.tcx();
if !speculative {
@ -865,28 +992,30 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
//
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref);
let late_bound_in_ty =
tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(binding.ty));
debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
let br_name = match *br {
ty::BrNamed(_, name) => name,
_ => {
span_bug!(
binding.span,
"anonymous bound region {:?} in binding but not trait ref",
br);
}
};
struct_span_err!(tcx.sess,
if let ConvertedBindingKind::Equality(ty) = binding.kind {
let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref);
let late_bound_in_ty =
tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty));
debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
let br_name = match *br {
ty::BrNamed(_, name) => name,
_ => {
span_bug!(
binding.span,
E0582,
"binding for associated type `{}` references lifetime `{}`, \
which does not appear in the trait input types",
binding.item_name, br_name)
.emit();
"anonymous bound region {:?} in binding but not trait ref",
br);
}
};
struct_span_err!(tcx.sess,
binding.span,
E0582,
"binding for associated type `{}` references lifetime `{}`, \
which does not appear in the trait input types",
binding.item_name, br_name)
.emit();
}
}
}
@ -931,16 +1060,28 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
.or_insert(binding.span);
}
Ok(candidate.map_bound(|trait_ref| {
ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy::from_ref_and_name(
tcx,
trait_ref,
binding.item_name,
),
ty: binding.ty,
match binding.kind {
ConvertedBindingKind::Equality(ref ty) => {
bounds.projection_bounds.push((candidate.map_bound(|trait_ref| {
ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy::from_ref_and_name(
tcx,
trait_ref,
binding.item_name,
),
ty,
}
}), binding.span));
}
}))
ConvertedBindingKind::Constraint(ref ast_bounds) => {
self.add_bounds(
trait_ref.self_ty(),
ast_bounds,
bounds,
);
}
}
Ok(())
}
fn ast_path_to_ty(&self,
@ -974,7 +1115,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
{
let tcx = self.tcx();
let mut projection_bounds = Vec::new();
let mut bounds = Bounds::default();
let mut potential_assoc_types = Vec::new();
let dummy_self = self.tcx().types.trait_object_dummy_self;
// FIXME: we want to avoid collecting into a `Vec` here, but simply cloning the iterator is
@ -986,7 +1127,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
let (trait_ref, cur_potential_assoc_types) = self.instantiate_poly_trait_ref(
trait_bound,
dummy_self,
&mut projection_bounds
&mut bounds,
);
potential_assoc_types.extend(cur_potential_assoc_types.into_iter().flatten());
(trait_ref, trait_bound.span)
@ -1074,14 +1215,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
// which is uglier but works. See the discussion in #56288 for alternatives.
if !references_self {
// Include projections defined on supertraits.
projection_bounds.push((pred, DUMMY_SP))
bounds.projection_bounds.push((pred, DUMMY_SP))
}
}
_ => ()
}
}
for (projection_bound, _) in &projection_bounds {
for (projection_bound, _) in &bounds.projection_bounds {
associated_types.remove(&projection_bound.projection_def_id());
}
@ -1161,7 +1302,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
let existential_trait_refs = regular_traits.iter().map(|i| {
i.trait_ref().map_bound(|trait_ref| self.trait_ref_to_existential(trait_ref))
});
let existential_projections = projection_bounds.iter().map(|(bound, _)| {
let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
bound.map_bound(|b| {
let trait_ref = self.trait_ref_to_existential(b.projection_ty.trait_ref(tcx));
ty::ExistentialProjection {
@ -1900,6 +2041,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
let region = self.ast_region_to_region(&lt, None);
tcx.type_of(va_list_did).subst(tcx, &[region.into()])
}
hir::TyKind::AssocTyExistential(..) => {
// Type is never actually used.
tcx.types.err
}
hir::TyKind::Err => {
tcx.types.err
}
@ -2121,12 +2266,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
// A helper struct for conveniently grouping a set of bounds which we pass to
// and return from functions in multiple places.
#[derive(PartialEq, Eq, Clone, Debug)]
#[derive(Default, PartialEq, Eq, Clone, Debug)]
pub struct Bounds<'tcx> {
pub region_bounds: Vec<(ty::Region<'tcx>, Span)>,
pub implicitly_sized: Option<Span>,
pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span)>,
pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
pub implicitly_sized: Option<Span>,
}
impl<'a, 'gcx, 'tcx> Bounds<'tcx> {

View file

@ -991,8 +991,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
}
}
/// Guarantees that any lifetimes which appear in the type of the node `id` (after applying
/// adjustments) are valid for at least `minimum_lifetime`
/// Guarantees that any lifetimes that appear in the type of the node `id` (after applying
/// adjustments) are valid for at least `minimum_lifetime`.
fn type_of_node_must_outlive(
&mut self,
origin: infer::SubregionOrigin<'tcx>,

View file

@ -14,11 +14,10 @@
//! At present, however, we do run collection across all items in the
//! crate as a kind of pass. This should eventually be factored away.
use crate::astconv::{AstConv, Bounds};
use crate::astconv::{AstConv, Bounds, SizedByDefault};
use crate::constrained_generic_params as cgp;
use crate::check::intrinsic::intrisic_operation_unsafety;
use crate::lint;
use crate::middle::lang_items::SizedTraitLangItem;
use crate::middle::resolve_lifetime as rl;
use crate::middle::weak_lang_items;
use rustc::mir::mono::Linkage;
@ -704,7 +703,7 @@ fn super_predicates_of<'a, 'tcx>(
// Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
let self_param_ty = tcx.mk_self_type();
let superbounds1 = compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span);
let superbounds1 = AstConv::compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span);
let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
@ -1650,9 +1649,11 @@ fn find_existential_constraints<'a, 'tcx>(
}
}
let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
let scope_id = tcx.hir().get_defining_scope(hir_id)
.expect("could not get defining scope");
let node_id = tcx.hir().as_local_node_id(def_id).unwrap();
let scope_node_id = tcx.hir()
.get_defining_scope(node_id)
.expect("could not get defining scope");
let scope_id = tcx.hir().node_to_hir_id(scope_node_id);
let mut locator = ConstraintLocator {
def_id,
tcx,
@ -1661,7 +1662,7 @@ fn find_existential_constraints<'a, 'tcx>(
debug!("find_existential_constraints: scope_id={:?}", scope_id);
if scope_id == ast::CRATE_HIR_ID {
if scope_id == hir::CRATE_HIR_ID {
intravisit::walk_crate(&mut locator, tcx.hir().krate());
} else {
debug!("find_existential_constraints: scope={:?}", tcx.hir().get_by_hir_id(scope_id));
@ -1788,57 +1789,6 @@ fn impl_polarity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> hir::I
}
}
// Is it marked with ?Sized
fn is_unsized<'gcx: 'tcx, 'tcx>(
astconv: &dyn AstConv<'gcx, 'tcx>,
ast_bounds: &[hir::GenericBound],
span: Span,
) -> bool {
let tcx = astconv.tcx();
// Try to find an unbound in bounds.
let mut unbound = None;
for ab in ast_bounds {
if let &hir::GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = ab {
if unbound.is_none() {
unbound = Some(ptr.trait_ref.clone());
} else {
span_err!(
tcx.sess,
span,
E0203,
"type parameter has more than one relaxed default \
bound, only one is supported"
);
}
}
}
let kind_id = tcx.lang_items().require(SizedTraitLangItem);
match unbound {
Some(ref tpb) => {
// FIXME(#8559) currently requires the unbound to be built-in.
if let Ok(kind_id) = kind_id {
if tpb.path.res != Res::Def(DefKind::Trait, kind_id) {
tcx.sess.span_warn(
span,
"default bound relaxed for a type parameter, but \
this does nothing because the given bound is not \
a default. Only `?Sized` is supported",
);
}
}
}
_ if kind_id.is_ok() => {
return false;
}
// No lang item for Sized, so we can't add it as a bound.
None => {}
}
true
}
/// Returns the early-bound lifetimes declared in this generics
/// listing. For anything other than fns/methods, this is just all
/// the lifetimes that are declared. For fns or methods, we have to
@ -1984,7 +1934,7 @@ fn explicit_predicates_of<'a, 'tcx>(
let opaque_ty = tcx.mk_opaque(def_id, substs);
// Collect the bounds, i.e., the `A + B + 'c` in `impl A + B + 'c`.
let bounds = compute_bounds(
let bounds = AstConv::compute_bounds(
&icx,
opaque_ty,
bounds,
@ -2030,7 +1980,7 @@ fn explicit_predicates_of<'a, 'tcx>(
let opaque_ty = tcx.mk_opaque(def_id, substs);
// Collect the bounds, i.e., the `A + B + 'c` in `impl A + B + 'c`.
let bounds = compute_bounds(
let bounds = AstConv::compute_bounds(
&icx,
opaque_ty,
bounds,
@ -2124,7 +2074,7 @@ fn explicit_predicates_of<'a, 'tcx>(
index += 1;
let sized = SizedByDefault::Yes;
let bounds = compute_bounds(&icx, param_ty, &param.bounds, sized, param.span);
let bounds = AstConv::compute_bounds(&icx, param_ty, &param.bounds, sized, param.span);
predicates.extend(bounds.predicates(tcx, param_ty));
}
}
@ -2159,19 +2109,17 @@ fn explicit_predicates_of<'a, 'tcx>(
for bound in bound_pred.bounds.iter() {
match bound {
&hir::GenericBound::Trait(ref poly_trait_ref, _) => {
let mut projections = Vec::new();
let mut bounds = Bounds::default();
let (trait_ref, _) = AstConv::instantiate_poly_trait_ref(
&icx,
poly_trait_ref,
ty,
&mut projections,
&mut bounds,
);
predicates.extend(
iter::once((trait_ref.to_predicate(), poly_trait_ref.span)).chain(
projections.iter().map(|&(p, span)| (p.to_predicate(), span)
)));
predicates.push((trait_ref.to_predicate(), poly_trait_ref.span));
predicates.extend(bounds.predicates(tcx, ty));
}
&hir::GenericBound::Outlives(ref lifetime) => {
@ -2210,14 +2158,14 @@ fn explicit_predicates_of<'a, 'tcx>(
let trait_item = tcx.hir().trait_item(trait_item_ref.id);
let bounds = match trait_item.node {
hir::TraitItemKind::Type(ref bounds, _) => bounds,
_ => return vec![].into_iter()
_ => return Vec::new().into_iter()
};
let assoc_ty =
tcx.mk_projection(tcx.hir().local_def_id_from_hir_id(trait_item.hir_id),
self_trait_ref.substs);
let bounds = compute_bounds(
let bounds = AstConv::compute_bounds(
&ItemCtxt::new(tcx, def_id),
assoc_ty,
bounds,
@ -2259,68 +2207,6 @@ fn explicit_predicates_of<'a, 'tcx>(
result
}
pub enum SizedByDefault {
Yes,
No,
}
/// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped `Ty`
/// or a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the
/// built-in trait `Send`.
pub fn compute_bounds<'gcx: 'tcx, 'tcx>(
astconv: &dyn AstConv<'gcx, 'tcx>,
param_ty: Ty<'tcx>,
ast_bounds: &[hir::GenericBound],
sized_by_default: SizedByDefault,
span: Span,
) -> Bounds<'tcx> {
let mut region_bounds = Vec::new();
let mut trait_bounds = Vec::new();
for ast_bound in ast_bounds {
match *ast_bound {
hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => trait_bounds.push(b),
hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
hir::GenericBound::Outlives(ref l) => region_bounds.push(l),
}
}
let mut projection_bounds = Vec::new();
let mut trait_bounds: Vec<_> = trait_bounds.iter().map(|&bound| {
let (poly_trait_ref, _) = astconv.instantiate_poly_trait_ref(
bound,
param_ty,
&mut projection_bounds,
);
(poly_trait_ref, bound.span)
}).collect();
let region_bounds = region_bounds
.into_iter()
.map(|r| (astconv.ast_region_to_region(r, None), r.span))
.collect();
trait_bounds.sort_by_key(|(t, _)| t.def_id());
let implicitly_sized = if let SizedByDefault::Yes = sized_by_default {
if !is_unsized(astconv, ast_bounds, span) {
Some(span)
} else {
None
}
} else {
None
};
Bounds {
region_bounds,
implicitly_sized,
trait_bounds,
projection_bounds,
}
}
/// Converts a specific `GenericBound` from the AST into a set of
/// predicates that apply to the self type. A vector is returned
/// because this can be anywhere from zero predicates (`T: ?Sized` adds no
@ -2333,13 +2219,11 @@ fn predicates_from_bound<'tcx>(
) -> Vec<(ty::Predicate<'tcx>, Span)> {
match *bound {
hir::GenericBound::Trait(ref tr, hir::TraitBoundModifier::None) => {
let mut projections = Vec::new();
let (pred, _) = astconv.instantiate_poly_trait_ref(tr, param_ty, &mut projections);
iter::once((pred.to_predicate(), tr.span)).chain(
projections
.into_iter()
.map(|(p, span)| (p.to_predicate(), span))
).collect()
let mut bounds = Bounds::default();
let (pred, _) = astconv.instantiate_poly_trait_ref(tr, param_ty, &mut bounds);
iter::once((pred.to_predicate(), tr.span))
.chain(bounds.predicates(astconv.tcx(), param_ty))
.collect()
}
hir::GenericBound::Outlives(ref lifetime) => {
let region = astconv.ast_region_to_region(lifetime, None);
@ -2363,8 +2247,8 @@ fn compute_sig_of_foreign_fn_decl<'a, 'tcx>(
};
let fty = AstConv::ty_of_fn(&ItemCtxt::new(tcx, def_id), unsafety, abi, decl);
// feature gate SIMD types in FFI, since I (huonw) am not sure the
// ABIs are handled at all correctly.
// Feature gate SIMD types in FFI, since I am not sure that the
// ABIs are handled at all correctly. -huonw
if abi != abi::Abi::RustIntrinsic
&& abi != abi::Abi::PlatformIntrinsic
&& !tcx.features().simd_ffi
@ -2439,7 +2323,7 @@ fn from_target_feature(
};
let rust_features = tcx.features();
for item in list {
// Only `enable = ...` is accepted in the meta item list
// Only `enable = ...` is accepted in the meta-item list.
if !item.check_name(sym::enable) {
bad_item(item.span());
continue;
@ -2454,9 +2338,9 @@ fn from_target_feature(
}
};
// We allow comma separation to enable multiple features
// We allow comma separation to enable multiple features.
target_features.extend(value.as_str().split(',').filter_map(|feature| {
// Only allow whitelisted features per platform
// Only allow whitelisted features per platform.
let feature_gate = match whitelist.get(feature) {
Some(g) => g,
None => {
@ -2480,7 +2364,7 @@ fn from_target_feature(
}
};
// Only allow features whose feature gates have been enabled
// Only allow features whose feature gates have been enabled.
let allowed = match feature_gate.as_ref().map(|s| *s) {
Some(sym::arm_target_feature) => rust_features.arm_target_feature,
Some(sym::aarch64_target_feature) => rust_features.aarch64_target_feature,

View file

@ -114,6 +114,7 @@ use util::common::time;
use std::iter;
use astconv::{AstConv, Bounds};
pub use collect::checked_type_of;
pub struct TypeAndSubsts<'tcx> {
@ -390,19 +391,19 @@ pub fn hir_ty_to_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_ty: &hir::Ty) ->
}
pub fn hir_trait_to_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_trait: &hir::TraitRef)
-> (ty::PolyTraitRef<'tcx>, Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>) {
-> (ty::PolyTraitRef<'tcx>, Bounds<'tcx>) {
// In case there are any projections, etc., find the "environment"
// def-ID that will be used to determine the traits/predicates in
// scope. This is derived from the enclosing item-like thing.
let env_hir_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
let env_def_id = tcx.hir().local_def_id_from_hir_id(env_hir_id);
let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id);
let mut projections = Vec::new();
let (principal, _) = astconv::AstConv::instantiate_poly_trait_ref_inner(
&item_cx, hir_trait, tcx.types.err, &mut projections, true
let mut bounds = Bounds::default();
let (principal, _) = AstConv::instantiate_poly_trait_ref_inner(
&item_cx, hir_trait, tcx.types.err, &mut bounds, true
);
(principal, projections)
(principal, bounds)
}
__build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }

View file

@ -2445,7 +2445,7 @@ pub struct PolyTrait {
/// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original
/// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most
/// importantly, it does not preserve mutability or boxes.
/// importanntly, it does not preserve mutability or boxes.
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
pub enum Type {
/// Structs/enums/traits (most that would be an `hir::TyKind::Path`).
@ -2939,6 +2939,9 @@ impl Clean<Type> for hir::Ty {
TyKind::Infer | TyKind::Err => Infer,
TyKind::Typeof(..) => panic!("Unimplemented type {:?}", self.node),
TyKind::CVarArgs(_) => CVarArgs,
TyKind::AssocTyExistential(ref bounds) => {
ImplTrait(bounds.into_iter().map(|b| b.clean(cx)).collect())
}
}
}
}