fn check_trait(&mut self, item: &hir::Item) {
let trait_def_id = self.tcx.hir.local_def_id(item.id);
-
self.for_item(item).with_fcx(|fcx, _| {
self.check_where_clauses(fcx, item.span, trait_def_id);
vec![]
});
}
- /// Checks where clauses and inline bounds.
+ /// Checks where clauses and inline bounds that are declared on def_id.
fn check_where_clauses<'fcx, 'tcx>(&mut self,
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
span: Span,
- def_id: DefId)
- {
+ def_id: DefId) {
use ty::subst::Subst;
- use ty::Predicate;
+ use rustc::ty::TypeFoldable;
+
+ let mut predicates = fcx.tcx.predicates_of(def_id);
+ let mut substituted_predicates = Vec::new();
let generics = self.tcx.generics_of(def_id);
- let defaults = generics.types.iter().filter_map(|p| match p.has_default {
- true => Some(p.def_id),
- false => None,
- });
- // Defaults must be well-formed.
- for d in defaults {
- fcx.register_wf_obligation(fcx.tcx.type_of(d), fcx.tcx.def_span(d), self.code.clone());
+ let is_our_default = |def: &ty::TypeParameterDef|
+ def.has_default && def.index >= generics.parent_count() as u32;
+
+ // Check that concrete defaults are well-formed. See test `type-check-defaults.rs`.
+ // For example this forbids the declaration:
+ // struct Foo<T = Vec<[u32]>> { .. }
+ // Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
+ for d in generics.types.iter().cloned().filter(is_our_default).map(|p| p.def_id) {
+ let ty = fcx.tcx.type_of(d);
+ // ignore dependent defaults -- that is, where the default of one type
+ // parameter includes another (e.g., <T, U = T>). In those cases, we can't
+ // be sure if it will error or not as user might always specify the other.
+ if !ty.needs_subst() {
+ fcx.register_wf_obligation(ty, fcx.tcx.def_span(d), self.code.clone());
+ }
}
- // Check that each default fulfills the bounds on it's parameter.
- // We go over each predicate and duplicate it, substituting defaults in the self type.
- let mut predicates = fcx.tcx.predicates_of(def_id);
- let mut default_predicates = Vec::new();
- for pred in &predicates.predicates {
- let mut self_ty = match pred {
- Predicate::Trait(trait_pred) => trait_pred.skip_binder().self_ty(),
- Predicate::TypeOutlives(outlives_pred) => (outlives_pred.0).0,
- Predicate::Projection(proj_pred) => {
- fcx.tcx.mk_ty(ty::TyProjection(proj_pred.skip_binder().projection_ty))
- }
- // Lifetime params can't have defaults.
- Predicate::RegionOutlives(..) => continue,
- _ => bug!("Predicate {:?} not supported in where clauses.", pred)
- };
-
- let mut skip = false;
- let mut no_default = true;
- let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| {
+ // Check that trait predicates are WF when params are substituted by their defaults.
+ // We don't want to overly constrain the predicates that may be written but we want to
+ // catch cases where a default my never be applied such as `struct Foo<T: Copy = String>`.
+ // Therefore we check if a predicate which contains a single type param
+ // with a concrete default is WF with that default substituted.
+ // For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`.
+ //
+ // First we build the defaulted substitution.
+ let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| {
// All regions are identity.
fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
}, |def, _| {
- // No default or generic comes from parent, identity substitution.
- if !def.has_default || (def.index as usize) < generics.parent_count() {
- fcx.tcx.mk_param_from_def(def)
- } else {
- no_default = false;
- // Has a default, use it in the substitution.
+ // If the param has a default,
+ if is_our_default(def) {
let default_ty = fcx.tcx.type_of(def.def_id);
- // Skip `Self : Self` in traits, it's problematic.
- // This means we probably check less than we could.
- let should_skip = match self_ty.sty {
- ty::TyParam(ref p) => {
- // lhs is Self && rhs is Self
- p.is_self() && match pred {
- Predicate::Trait(p) => p.def_id() == def_id,
- Predicate::TypeOutlives(_) => false,
- _ => bug!("Unexpected predicate {:?}", pred)
- }
- }
- ty::TyProjection(ref proj) => {
- let mut projection = proj;
- let mut next_typ = &projection.substs[0].as_type().unwrap().sty;
- // Dig through projections.
- while let ty::TyProjection(ref proj) = next_typ {
- projection = proj;
- next_typ = &projection.substs[0].as_type().unwrap().sty;
- }
- let lhs_is_self = match next_typ {
- ty::TyParam(ref p) => p.is_self(),
- _ => false
- };
- let rhs = fcx.tcx.associated_item(projection.item_def_id)
- .container
- .assert_trait();
- lhs_is_self && rhs == def_id
- }
- _ => false
- };
- skip = skip || should_skip;
-
- match default_ty.sty {
- // Skip `Self: Sized` when `Self` is the default. Needed in traits.
- ty::TyParam(ref p) if p.is_self() => {
- if let Predicate::Trait(p) = pred {
- if Some(p.def_id()) == fcx.tcx.lang_items().sized_trait() {
- skip = true;
- }
- }
- }
- _ => ()
+ // and it's not a dependent default
+ if !default_ty.needs_subst() {
+ // then substitute with the default.
+ return default_ty;
}
- default_ty
}
+ // Mark unwanted params as err.
+ fcx.tcx.types.err
});
-
- if skip || no_default {
+ // Now we build the substituted predicates.
+ for &pred in predicates.predicates.iter() {
+ struct CountParams { params: FxHashSet<u32> }
+ impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams {
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+ match t.sty {
+ ty::TyParam(p) => {
+ self.params.insert(p.idx);
+ t.super_visit_with(self)
+ }
+ _ => t.super_visit_with(self)
+ }
+ }
+ }
+ let mut param_count = CountParams { params: FxHashSet() };
+ pred.visit_with(&mut param_count);
+ let substituted_pred = pred.subst(fcx.tcx, substs);
+ // Don't check non-defaulted params, dependent defaults or preds with multiple params.
+ if substituted_pred.references_error() || param_count.params.len() > 1 {
continue;
}
-
- self_ty = self_ty.subst(fcx.tcx, substs);
- default_predicates.push(match pred {
- Predicate::Trait(trait_pred) => {
- let mut substs = trait_pred.skip_binder().trait_ref.substs.to_vec();
- substs[0] = self_ty.into();
- let substs = fcx.tcx.intern_substs(&substs);
- let trait_ref = ty::Binder(ty::TraitRef::new(trait_pred.def_id(), substs));
- Predicate::Trait(trait_ref.to_poly_trait_predicate())
- }
- Predicate::TypeOutlives(pred) => {
- Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(self_ty, (pred.0).1)))
- }
- Predicate::Projection(proj_pred) => {
- let projection_ty = match self_ty.sty {
- ty::TyProjection(proj_ty) => proj_ty,
- _ => bug!("self_ty not projection for projection predicate.")
- };
- Predicate::Projection(ty::Binder(ty::ProjectionPredicate {
- projection_ty,
- ty: proj_pred.ty().skip_binder()
- }))
- }
- _ => bug!("Predicate {:?} not supported for type params.", pred)
- });
+ // Avoid duplication of predicates that contain no parameters, for example.
+ if !predicates.predicates.contains(&substituted_pred) {
+ substituted_predicates.push(substituted_pred);
+ }
}
- predicates.predicates.extend(default_predicates);
+ predicates.predicates.extend(substituted_predicates);
let predicates = predicates.instantiate_identity(fcx.tcx);
let predicates = fcx.normalize_associated_types_in(span, &predicates);
let is_self_ty = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok();
let self_kind = ExplicitSelf::determine(self_arg_ty, is_self_ty);
- if !fcx.tcx.sess.features.borrow().arbitrary_self_types {
+ if !fcx.tcx.features().arbitrary_self_types {
match self_kind {
ExplicitSelf::ByValue |
ExplicitSelf::ByReference(_, _) |