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_trait_where_clauses(fcx, item.span, trait_def_id);
+ self.check_where_clauses(fcx, item.span, trait_def_id);
vec![]
});
}
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
span: Span,
def_id: DefId) {
- self.inner_check_where_clauses(fcx, span, def_id, false)
- }
-
- fn check_trait_where_clauses<'fcx, 'tcx>(&mut self,
- fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
- span: Span,
- def_id: DefId) {
- self.inner_check_where_clauses(fcx, span, def_id, true)
- }
-
- /// Checks where clauses and inline bounds that are declared on def_id.
- fn inner_check_where_clauses<'fcx, 'tcx>(&mut self,
- fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
- span: Span,
- def_id: DefId,
- is_trait: bool)
- {
use ty::subst::Subst;
use rustc::ty::TypeFoldable;
let generics = self.tcx.generics_of(def_id);
let is_our_default = |def: &ty::TypeParameterDef|
def.has_default && def.index >= generics.parent_count() as u32;
- let defaulted_params = generics.types.iter().cloned().filter(&is_our_default);
- // Check that defaults are well-formed. See test `type-check-defaults.rs`.
+
+ // 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 defaulted_params.map(|p| p.def_id) {
- fcx.register_wf_obligation(fcx.tcx.type_of(d), fcx.tcx.def_span(d), self.code.clone());
+ 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 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 obviously wrong cases such as `struct Foo<T: Copy = String>`
- // or cases that may cause backwards incompatibility such as a library going from
- // `pub struct Foo<T>` to `pub struct Foo<T, U = i32>` where U: Trait<T>`
- // which may break existing uses of Foo<T>.
- // Therefore the check we do is: If if all params appearing in the LHS of the predicate
- // have defaults then we verify that it is WF with all defaults substituted simultaneously.
+ // 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 mut defaulted_params = Vec::new();
+ // 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, _| {
- if !is_our_default(def) {
- // Identity substitution.
- fcx.tcx.mk_param_from_def(def)
- } else {
- // Substitute with default.
- defaulted_params.push(def.index);
- fcx.tcx.type_of(def.def_id)
+ // If the param has a default,
+ if is_our_default(def) {
+ let default_ty = fcx.tcx.type_of(def.def_id);
+ // and it's not a dependent default
+ if !default_ty.needs_subst() {
+ // then substitute with the default.
+ return default_ty;
+ }
}
+ // Mark unwanted params as err.
+ fcx.tcx.types.err
});
- // In `trait Trait: Super`, checking `Self: Trait` or `Self: Super` is problematic.
- // We avoid those by skipping any predicates in trait declarations that contain `Self`,
- // which is excessive so we end up checking less than we could.
- for pred in predicates.predicates.iter()
- .filter_map(ty::Predicate::as_poly_trait_predicate)
- .filter(|p| !(is_trait && p.has_self_ty())) {
- let is_defaulted_param = |ty: ty::Ty| match ty.sty {
- ty::TyParam(p) => defaulted_params.contains(&p.idx),
- _ => false
- };
- // If there is a non-defaulted param in the LHS, don't check the substituted predicate.
- // `skip_binder()` is ok, we're only inspecting the type params.
- if !pred.skip_binder().self_ty().walk().all(is_defaulted_param) {
- continue;
+ // 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);
- // `skip_binder()` is ok, we're only inspecting for `has_self_ty()`.
- let substituted_lhs = substituted_pred.skip_binder().self_ty();
- // In trait defs, don't check `Self: Sized` when `Self` is the default.
- let pred_is_sized = Some(pred.def_id()) == fcx.tcx.lang_items().sized_trait();
- if is_trait && substituted_lhs.has_self_ty() && pred_is_sized {
+ // Don't check non-defaulted params, dependent defaults or preds with multiple params.
+ if substituted_pred.references_error() || param_count.params.len() > 1 {
continue;
}
- let pred = ty::Predicate::Trait(pred.subst(fcx.tcx, substs));
- // Avoid duplicates.
- if !predicates.predicates.contains(&pred) {
- substituted_predicates.push(pred);
+ // Avoid duplication of predicates that contain no parameters, for example.
+ if !predicates.predicates.contains(&substituted_pred) {
+ substituted_predicates.push(substituted_pred);
}
}
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(_, _) |