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;
use rustc::traits;
-use rustc::ty::{self, DefIdTree, Ty, TyCtxt, ToPredicate, TypeFoldable};
+use rustc::ty::{self, DefIdTree, Ty, TyCtxt, Const, ToPredicate, TypeFoldable};
use rustc::ty::{GenericParamDef, GenericParamDefKind};
use rustc::ty::subst::{Kind, Subst, InternalSubsts, SubstsRef};
use rustc::ty::wf::object_region_bounds;
pub struct PathSeg(pub DefId, pub usize);
pub trait AstConv<'gcx, 'tcx> {
- fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>;
+ fn tcx<'a>(&'a self) -> TyCtxt<'gcx, 'tcx>;
/// Returns the set of bounds in scope for the type parameter with
/// the given id.
fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
-> &'tcx ty::GenericPredicates<'tcx>;
- /// What lifetime should we use when a lifetime is omitted (and not elided)?
- fn re_infer(&self, span: Span, _def: Option<&ty::GenericParamDef>)
+ /// Returns the lifetime to use when a lifetime is omitted (and not elided).
+ fn re_infer(
+ &self,
+ param: Option<&ty::GenericParamDef>,
+ span: Span,
+ )
-> Option<ty::Region<'tcx>>;
- /// What type should we use when a type is omitted?
- fn ty_infer(&self, span: Span) -> Ty<'tcx>;
+ /// Returns the type to use when a type is omitted.
+ fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>;
- /// Same as ty_infer, but with a known type parameter definition.
- fn ty_infer_for_def(&self,
- _def: &ty::GenericParamDef,
- span: Span) -> Ty<'tcx> {
- self.ty_infer(span)
- }
+ /// Returns the const to use when a const is omitted.
+ fn ct_infer(
+ &self,
+ ty: Ty<'tcx>,
+ param: Option<&ty::GenericParamDef>,
+ span: Span,
+ ) -> &'tcx Const<'tcx>;
/// Projecting an associated type from a (potentially)
/// higher-ranked trait reference is more complicated, because of
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,
}
None => {
- self.re_infer(lifetime.span, def)
+ self.re_infer(def, lifetime.span)
.unwrap_or_else(|| {
// This indicates an illegal lifetime
// elision. `resolve_lifetime` should have
span,
def_id,
generic_args,
- item_segment.infer_types,
+ item_segment.infer_args,
None,
)
});
/// Report error if there is an explicit type parameter when using `impl Trait`.
fn check_impl_trait(
- tcx: TyCtxt<'_, '_, '_>,
+ tcx: TyCtxt<'_, '_>,
span: Span,
seg: &hir::PathSegment,
generics: &ty::Generics,
) -> bool {
- let explicit = !seg.infer_types;
+ let explicit = !seg.infer_args;
let impl_trait = generics.params.iter().any(|param| match param.kind {
ty::GenericParamDefKind::Type {
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), ..
/// Checks that the correct number of generic arguments have been provided.
/// Used specifically for function calls.
pub fn check_generic_arg_count_for_call(
- tcx: TyCtxt<'_, '_, '_>,
+ tcx: TyCtxt<'_, '_>,
span: Span,
def: &ty::Generics,
seg: &hir::PathSegment,
GenericArgPosition::Value
},
def.parent.is_none() && def.has_self, // `has_self`
- seg.infer_types || suppress_mismatch, // `infer_types`
+ seg.infer_args || suppress_mismatch, // `infer_args`
).0
}
/// Checks that the correct number of generic arguments have been provided.
/// This is used both for datatypes and function calls.
fn check_generic_arg_count(
- tcx: TyCtxt<'_, '_, '_>,
+ tcx: TyCtxt<'_, '_>,
span: Span,
def: &ty::Generics,
args: &hir::GenericArgs,
position: GenericArgPosition,
has_self: bool,
- infer_types: bool,
+ infer_args: bool,
) -> (bool, Option<Vec<Span>>) {
// At this stage we are guaranteed that the generic arguments are in the correct order, e.g.
// that lifetimes will proceed types. So it suffices to check the number of each generic
let param_counts = def.own_counts();
let arg_counts = args.own_counts();
let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0;
- let infer_consts = position != GenericArgPosition::Type && arg_counts.consts == 0;
let mut defaults: ty::GenericParamCount = Default::default();
for param in &def.params {
offset
);
// We enforce the following: `required` <= `provided` <= `permitted`.
- // For kinds without defaults (i.e., lifetimes), `required == permitted`.
+ // For kinds without defaults (e.g.., lifetimes), `required == permitted`.
// For other kinds (i.e., types), `permitted` may be greater than `required`.
if required <= provided && provided <= permitted {
return (reported_late_bound_region_err.unwrap_or(false), None);
}
err.emit();
- (provided > required, // `suppress_error`
- potential_assoc_types)
+ (
+ provided > required, // `suppress_error`
+ potential_assoc_types,
+ )
};
if reported_late_bound_region_err.is_none()
);
}
// FIXME(const_generics:defaults)
- if !infer_consts || arg_counts.consts > param_counts.consts {
+ if !infer_args || arg_counts.consts > param_counts.consts {
check_kind_count(
"const",
param_counts.consts,
);
}
// Note that type errors are currently be emitted *after* const errors.
- if !infer_types
+ if !infer_args
|| arg_counts.types > param_counts.types - defaults.types - has_self as usize {
check_kind_count(
"type",
/// instantiate a `Kind`.
/// - `inferred_kind`: if no parameter was provided, and inference is enabled, then
/// creates a suitable inference variable.
- pub fn create_substs_for_generic_args<'a, 'b>(
- tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ pub fn create_substs_for_generic_args<'b>(
+ tcx: TyCtxt<'gcx, 'tcx>,
def_id: DefId,
parent_substs: &[Kind<'tcx>],
has_self: bool,
}
// Check whether this segment takes generic arguments and the user has provided any.
- let (generic_args, infer_types) = args_for_def_id(def_id);
+ let (generic_args, infer_args) = args_for_def_id(def_id);
let mut args = generic_args.iter().flat_map(|generic_args| generic_args.args.iter())
.peekable();
| (GenericArg::Const(_), GenericParamDefKind::Lifetime) => {
// We expected a lifetime argument, but got a type or const
// argument. That means we're inferring the lifetimes.
- substs.push(inferred_kind(None, param, infer_types));
+ substs.push(inferred_kind(None, param, infer_args));
params.next();
}
(_, _) => {
(None, Some(¶m)) => {
// If there are fewer arguments than parameters, it means
// we're inferring the remaining arguments.
- substs.push(inferred_kind(Some(&substs), param, infer_types));
+ substs.push(inferred_kind(Some(&substs), param, infer_args));
args.next();
params.next();
}
}
/// Given the type/lifetime/const arguments provided to some path (along with
- /// an implicit `Self`, if this is a trait reference) returns the complete
+ /// an implicit `Self`, if this is a trait reference), returns the complete
/// set of substitutions. This may involve applying defaulted type parameters.
+ /// Also returns back constriants on associated types.
+ ///
+ /// Example:
+ ///
+ /// ```
+ /// T: std::ops::Index<usize, Output = u32>
+ /// ^1 ^^^^^^^^^^^^^^2 ^^^^3 ^^^^^^^^^^^4
+ /// ```
+ ///
+ /// 1. The `self_ty` here would refer to the type `T`.
+ /// 2. The path in question is the path to the trait `std::ops::Index`,
+ /// which will have been resolved to a `def_id`
+ /// 3. The `generic_args` contains info on the `<...>` contents. The `usize` type
+ /// parameters are returned in the `SubstsRef`, the associated type bindings like
+ /// `Output = u32` are returned in the `Vec<ConvertedBinding...>` result.
///
/// 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,
- infer_types: bool,
+ generic_args: &'a hir::GenericArgs,
+ infer_args: bool,
self_ty: Option<Ty<'tcx>>)
-> (SubstsRef<'tcx>, Vec<ConvertedBinding<'tcx>>, Option<Vec<Span>>)
{
&generic_args,
GenericArgPosition::Type,
has_self,
- infer_types,
+ infer_args,
);
let is_object = self_ty.map_or(false, |ty| {
self_ty.is_some(),
self_ty,
// Provide the generic args, and whether types should be inferred.
- |_| (Some(generic_args), infer_types),
+ |_| (Some(generic_args), infer_args),
// Provide substitutions for parameters for which (valid) arguments have been provided.
|param, arg| {
match (¶m.kind, arg) {
}
},
// Provide substitutions for parameters for which arguments are inferred.
- |substs, param, infer_types| {
+ |substs, param, infer_args| {
match param.kind {
GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(),
GenericParamDefKind::Type { has_default, .. } => {
- if !infer_types && has_default {
+ if !infer_args && has_default {
// No type parameter provided, but a default exists.
// If we are converting an object type, then the
.subst_spanned(tcx, substs.unwrap(), Some(span))
).into()
}
- } else if infer_types {
+ } else if infer_args {
// No type parameters were provided, we can infer all.
- if !default_needs_object_self(param) {
- self.ty_infer_for_def(param, span).into()
+ let param = if !default_needs_object_self(param) {
+ Some(param)
} else {
- self.ty_infer(span).into()
- }
+ None
+ };
+ self.ty_infer(param, span).into()
} else {
// We've already errored above about the mismatch.
tcx.types.err.into()
}
GenericParamDefKind::Const => {
// FIXME(const_generics:defaults)
- // We've already errored above about the mismatch.
- tcx.consts.err.into()
+ if infer_args {
+ // No const parameters were provided, we can infer all.
+ let ty = tcx.at(span).type_of(param.def_id);
+ self.ct_infer(ty, Some(param), span).into()
+ } else {
+ // We've already errored above about the mismatch.
+ tcx.consts.err.into()
+ }
}
}
},
);
- 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();
+ // Convert associated-type bindings or constraints into a separate vector.
+ // Example: Given this:
+ //
+ // T: Iterator<Item = u32>
+ //
+ // The `T` is passed in as a self-type; the `Item = u32` is
+ // not a "type parameter" of the `Iterator` trait, but rather
+ // a restriction on `<T as Iterator>::Item`, so it is passed
+ // back separately.
+ let assoc_bindings = generic_args.bindings.iter()
+ .map(|binding| {
+ let kind = match binding.kind {
+ hir::TypeBindingKind::Equality { ref ty } =>
+ ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty)),
+ hir::TypeBindingKind::Constraint { ref bounds } =>
+ ConvertedBindingKind::Constraint(bounds.clone()),
+ };
+ 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);
/// are disallowed. Otherwise, they are pushed onto the vector given.
pub fn instantiate_mono_trait_ref(&self,
trait_ref: &hir::TraitRef,
- self_ty: Ty<'tcx>)
- -> ty::TraitRef<'tcx>
+ self_ty: Ty<'tcx>
+ ) -> ty::TraitRef<'tcx>
{
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
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)>,
- speculative: bool)
- -> (ty::PolyTraitRef<'tcx>, Option<Vec<Span>>)
+ bounds: &mut Bounds<'tcx>,
+ speculative: bool,
+ ) -> (ty::PolyTraitRef<'tcx>, Option<Vec<Span>>)
{
let trait_def_id = trait_ref.trait_def_id();
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))
- }));
-
- debug!("instantiate_poly_trait_ref({:?}, projections={:?}) -> {:?}",
- trait_ref, poly_projections, poly_trait_ref);
+ for binding in &assoc_bindings {
+ // Specify type to assert that error was already reported in `Err` case.
+ let _: Result<_, ErrorReported> =
+ 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({:?}, bounds={:?}) -> {:?}",
+ trait_ref, bounds, poly_trait_ref);
(poly_trait_ref, potential_assoc_types)
}
+ /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct
+ /// a full trait reference. The resulting trait reference is returned. This may also generate
+ /// auxiliary bounds, which are added to `bounds`.
+ ///
+ /// Example:
+ ///
+ /// ```
+ /// poly_trait_ref = Iterator<Item = u32>
+ /// self_ty = Foo
+ /// ```
+ ///
+ /// this would return `Foo: Iterator` and add `<Foo as Iterator>::Item = u32` into `bounds`.
+ ///
+ /// **A note on binders:** against our usual convention, there is an implied bounder around
+ /// the `self_ty` and `poly_trait_ref` parameters here. So they may reference bound regions.
+ /// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>`
+ /// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be
+ /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly,
+ /// however.
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,
self.create_substs_for_ast_path(span,
trait_def_id,
generic_args,
- trait_segment.infer_types,
+ trait_segment.infer_args,
Some(self_ty))
})
}
})
}
- 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
+ }
+
+ /// This helper takes a *converted* parameter type (`param_ty`)
+ /// and an *unconverted* list of bounds:
+ ///
+ /// ```
+ /// fn foo<T: Debug>
+ /// ^ ^^^^^ `ast_bounds` parameter, in HIR form
+ /// |
+ /// `param_ty`, in ty form
+ /// ```
+ ///
+ /// It adds these `ast_bounds` into the `bounds` structure.
+ ///
+ /// **A note on binders:** there is an implied binder around
+ /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref`
+ /// for more details.
+ 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))
+ );
+ }
+
+ /// Translates a list of bounds from the HIR into the `Bounds` data structure.
+ /// The self-type for the bounds is given by `param_ty`.
+ ///
+ /// Example:
+ ///
+ /// ```
+ /// fn foo<T: Bar + Baz>() { }
+ /// ^ ^^^^^^^^^ ast_bounds
+ /// param_ty
+ /// ```
+ ///
+ /// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be
+ /// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the
+ /// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`.
+ ///
+ /// `span` should be the declaration size of the parameter.
+ 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.trait_bounds.sort_by_key(|(t, _)| t.def_id());
+
+ bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default {
+ if !self.is_unsized(ast_bounds, span) {
+ Some(span)
+ } else {
+ None
+ }
+ } else {
+ None
+ };
+
+ bounds
+ }
+
+ /// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates
+ /// onto `bounds`.
+ ///
+ /// **A note on binders:** given something like `T: for<'a> Iterator<Item = &'a u32>`, the
+ /// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside*
+ /// the binder (e.g., `&'a u32`) and hence may reference bound regions.
+ 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 {
// trait SubTrait: SuperTrait<int> { }
// trait SuperTrait<A> { type T; }
//
- // ... B : SubTrait<T=foo> ...
+ // ... B: SubTrait<T = foo> ...
// ```
//
// We want to produce `<B as SuperTrait<int>>::T == foo`.
// Find any late-bound regions declared in `ty` that are not
- // declared in the trait-ref. These are not wellformed.
+ // declared in the trait-ref. These are not well-formed.
//
// Example:
//
// 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();
+ }
}
}
.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) => {
+ // "Desugar" a constraint like `T: Iterator<Item = u32>` this to
+ // the "projection predicate" for:
+ //
+ // `<T as Iterator>::Item = u32`
+ 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) => {
+ // "Desugar" a constraint like `T: Iterator<Item: Debug>` to
+ //
+ // `<T as Iterator>::Item: Debug`
+ //
+ // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
+ // parameter to have a skipped binder.
+ let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs);
+ self.add_bounds(
+ param_ty,
+ ast_bounds,
+ bounds,
+ );
}
- }))
+ }
+ Ok(())
}
fn ast_path_to_ty(&self,
{
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
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)
// 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());
}
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 {
if tcx.named_region(lifetime.hir_id).is_some() {
self.ast_region_to_region(lifetime, None)
} else {
- self.re_infer(span, None).unwrap_or_else(|| {
+ self.re_infer(None, span).unwrap_or_else(|| {
span_err!(tcx.sess, span, E0228,
"the lifetime bound for this object type cannot be deduced \
from context; please supply an explicit bound");
has_err
}
- pub fn prohibit_assoc_ty_binding(tcx: TyCtxt<'_, '_, '_>, span: Span) {
+ pub fn prohibit_assoc_ty_binding(tcx: TyCtxt<'_, '_>, span: Span) {
let mut err = struct_span_err!(tcx.sess, span, E0229,
"associated type bindings are not allowed here");
err.span_label(span, "associated type not allowed here").emit();
let span = path.span;
match path.res {
Res::Def(DefKind::Existential, did) => {
- // Check for desugared impl trait.
+ // Check for desugared `impl Trait`.
assert!(ty::is_impl_trait_defn(tcx, did).is_none());
let item_segment = path.segments.split_last().unwrap();
self.prohibit_generics(item_segment.1);
&tcx.hir().local_def_id_from_hir_id(hir_id)];
tcx.mk_ty_param(index, tcx.hir().name_by_hir_id(hir_id).as_interned_str())
}
- Res::SelfTy(_, Some(def_id)) => {
- // `Self` in impl (we know the concrete type).
+ Res::SelfTy(Some(_), None) => {
+ // `Self` in trait or type alias.
assert_eq!(opt_self_ty, None);
self.prohibit_generics(&path.segments);
- // Try to evaluate any array length constants
- self.normalize_ty(span, tcx.at(span).type_of(def_id))
+ tcx.mk_self_type()
}
- Res::SelfTy(Some(_), None) => {
- // `Self` in trait.
+ Res::SelfTy(_, Some(def_id)) => {
+ // `Self` in impl (we know the concrete type).
assert_eq!(opt_self_ty, None);
self.prohibit_generics(&path.segments);
- tcx.mk_self_type()
+ // Try to evaluate any array length constants.
+ self.normalize_ty(span, tcx.at(span).type_of(def_id))
}
Res::Def(DefKind::AssocTy, def_id) => {
debug_assert!(path.segments.len() >= 2);
}
hir::TyKind::Rptr(ref region, ref mt) => {
let r = self.ast_region_to_region(region, None);
- debug!("Ref r={:?}", r);
+ debug!("ast_ty_to_ty: r={:?}", r);
let t = self.ast_ty_to_ty(&mt.ty);
tcx.mk_ref(r, ty::TypeAndMut {ty: t, mutbl: mt.mutbl})
}
hir::TyKind::Def(item_id, ref lifetimes) => {
let did = tcx.hir().local_def_id_from_hir_id(item_id.id);
self.impl_trait_ty_to_ty(did, lifetimes)
- },
+ }
hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment);
let ty = self.ast_ty_to_ty(qself);
// values in a ExprKind::Closure, or as
// the type of local variables. Both of these cases are
// handled specially and will not descend into this routine.
- self.ty_infer(ast_ty.span)
- }
- hir::TyKind::Err => {
- tcx.types.err
+ self.ty_infer(None, ast_ty.span)
}
hir::TyKind::CVarArgs(lt) => {
let va_list_did = match tcx.lang_items().va_list() {
let region = self.ast_region_to_region(<, None);
tcx.type_of(va_list_did).subst(tcx, &[region.into()])
}
+ hir::TyKind::Err => {
+ tcx.types.err
+ }
};
+ debug!("ast_ty_to_ty: result_ty={:?}", result_ty);
+
self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span);
result_ty
}
+ /// Returns the `DefId` of the constant parameter that the provided expression is a path to.
+ pub fn const_param_def_id(&self, expr: &hir::Expr) -> Option<DefId> {
+ match &expr.node {
+ ExprKind::Path(hir::QPath::Resolved(_, path)) => match path.res {
+ Res::Def(DefKind::ConstParam, did) => Some(did),
+ _ => None,
+ },
+ _ => None,
+ }
+ }
+
pub fn ast_const_to_const(
&self,
ast_const: &hir::AnonConst,
}
}
- if let ExprKind::Path(ref qpath) = expr.node {
- if let hir::QPath::Resolved(_, ref path) = qpath {
- if let Res::Def(DefKind::ConstParam, def_id) = path.res {
- let node_id = tcx.hir().as_local_node_id(def_id).unwrap();
- let item_id = tcx.hir().get_parent_node(node_id);
- let item_def_id = tcx.hir().local_def_id(item_id);
- let generics = tcx.generics_of(item_def_id);
- let index = generics.param_def_id_to_index[&tcx.hir().local_def_id(node_id)];
- let name = tcx.hir().name(node_id).as_interned_str();
- const_.val = ConstValue::Param(ty::ParamConst::new(index, name));
- }
- }
- };
+ if let Some(def_id) = self.const_param_def_id(expr) {
+ // Find the name and index of the const parameter by indexing the generics of the
+ // parent item and construct a `ParamConst`.
+ let node_id = tcx.hir().as_local_node_id(def_id).unwrap();
+ let item_id = tcx.hir().get_parent_node(node_id);
+ let item_def_id = tcx.hir().local_def_id(item_id);
+ let generics = tcx.generics_of(item_def_id);
+ let index = generics.param_def_id_to_index[&tcx.hir().local_def_id(node_id)];
+ let name = tcx.hir().name(node_id).as_interned_str();
+ const_.val = ConstValue::Param(ty::ParamConst::new(index, name));
+ }
tcx.mk_const(const_)
}
_ => bug!()
}
} else {
- // Replace all parent lifetimes with 'static.
+ // Replace all parent lifetimes with `'static`.
match param.kind {
GenericParamDefKind::Lifetime => {
tcx.lifetimes.re_static.into()
}
}
});
- debug!("impl_trait_ty_to_ty: final substs = {:?}", substs);
+ debug!("impl_trait_ty_to_ty: substs={:?}", substs);
let ty = tcx.mk_opaque(def_id, substs);
debug!("impl_trait_ty_to_ty: {}", ty);
}
}
-// 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)]
+/// Collects together a list of bounds that are applied to some type,
+/// after they've been converted into `ty` form (from the HIR
+/// representations). These lists of bounds occur in many places in
+/// Rust's syntax:
+///
+/// ```
+/// trait Foo: Bar + Baz { }
+/// ^^^^^^^^^ supertrait list bounding the `Self` type parameter
+///
+/// fn foo<T: Bar + Baz>() { }
+/// ^^^^^^^^^ bounding the type parameter `T`
+///
+/// impl dyn Bar + Baz
+/// ^^^^^^^^^ bounding the forgotten dynamic type
+/// ```
+///
+/// Our representation is a bit mixed here -- in some cases, we
+/// include the self type (e.g., `trait_bounds`) but in others we do
+#[derive(Default, PartialEq, Eq, Clone, Debug)]
pub struct Bounds<'tcx> {
+ /// A list of region bounds on the (implicit) self type. So if you
+ /// had `T: 'a + 'b` this might would be a list `['a, 'b]` (but
+ /// the `T` is not explicitly included).
pub region_bounds: Vec<(ty::Region<'tcx>, Span)>,
- pub implicitly_sized: Option<Span>,
+
+ /// A list of trait bounds. So if you had `T: Debug` this would be
+ /// `T: Debug`. Note that the self-type is explicit here.
pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span)>,
+
+ /// A list of projection equality bounds. So if you had `T:
+ /// Iterator<Item = u32>` this would include `<T as
+ /// Iterator>::Item => u32`. Note that the self-type is explicit
+ /// here.
pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
+
+ /// `Some` if there is *no* `?Sized` predicate. The `span`
+ /// is the location in the source of the `T` declaration which can
+ /// be cited as the source of the `T: Sized` requirement.
+ pub implicitly_sized: Option<Span>,
}
-impl<'a, 'gcx, 'tcx> Bounds<'tcx> {
- pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, param_ty: Ty<'tcx>)
- -> Vec<(ty::Predicate<'tcx>, Span)>
- {
+impl<'gcx, 'tcx> Bounds<'tcx> {
+ /// Converts a bounds list into a flat set of predicates (like
+ /// where-clauses). Because some of our bounds listings (e.g.,
+ /// regions) don't include the self-type, you must supply the
+ /// self-type here (the `param_ty` parameter).
+ pub fn predicates(
+ &self,
+ tcx: TyCtxt<'gcx, 'tcx>,
+ param_ty: Ty<'tcx>,
+ ) -> Vec<(ty::Predicate<'tcx>, Span)> {
// If it could be sized, and is, add the `Sized` predicate.
let sized_predicate = self.implicitly_sized.and_then(|span| {
tcx.lang_items().sized_trait().map(|sized| {