impl_id: DefId,
impl_item: &hir::ImplItem,
) {
- let ancestors = trait_def.ancestors(tcx, impl_id);
-
let kind = match impl_item.kind {
hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
hir::ImplItemKind::Method(..) => ty::AssocKind::Method,
hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type,
};
- let parent = ancestors.defs(tcx, trait_item.ident, kind, trait_def.def_id).nth(1)
- .map(|node_item| node_item.map(|parent| parent.defaultness));
+ let mut ancestor_impls = trait_def.ancestors(tcx, impl_id)
+ .skip(1)
+ .filter_map(|parent| {
+ if parent.is_from_trait() {
+ None
+ } else {
+ Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id)))
+ }
+ })
+ .peekable();
- if let Some(parent) = parent {
- if tcx.impl_item_is_final(&parent) {
- report_forbidden_specialization(tcx, impl_item, parent.node.def_id());
- }
+ if ancestor_impls.peek().is_none() {
+ // No parent, nothing to specialize.
+ return;
}
+ let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| {
+ match parent_item {
+ // Parent impl exists, and contains the parent item we're trying to specialize, but
+ // doesn't mark it `default`.
+ Some(parent_item) if tcx.impl_item_is_final(&parent_item) => {
+ Some(Err(parent_impl.def_id()))
+ }
+
+ // Parent impl contains item and makes it specializable.
+ Some(_) => {
+ Some(Ok(()))
+ }
+
+ // Parent impl doesn't mention the item. This means it's inherited from the
+ // grandparent. In that case, if parent is a `default impl`, inherited items use the
+ // "defaultness" from the grandparent, else they are final.
+ None => if tcx.impl_is_default(parent_impl.def_id()) {
+ None
+ } else {
+ Some(Err(parent_impl.def_id()))
+ }
+ }
+ });
+
+ // If `opt_result` is `None`, we have only encoutered `default impl`s that don't contain the
+ // item. This is allowed, the item isn't actually getting specialized here.
+ let result = opt_result.unwrap_or(Ok(()));
+
+ if let Err(parent_impl) = result {
+ report_forbidden_specialization(tcx, impl_item, parent_impl);
+ }
}
fn check_impl_items_against_trait<'tcx>(
let associated_type_overridden = overridden_associated_type.is_some();
for trait_item in tcx.associated_items(impl_trait_ref.def_id) {
let is_implemented = trait_def.ancestors(tcx, impl_id)
- .defs(tcx, trait_item.ident, trait_item.kind, impl_trait_ref.def_id)
- .next()
+ .leaf_def(tcx, trait_item.ident, trait_item.kind)
.map(|node_item| !node_item.node.is_from_trait())
.unwrap_or(false);
self.tcx
}
- fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
- -> &'tcx ty::GenericPredicates<'tcx>
- {
+ fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
let tcx = self.tcx;
let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
let item_id = tcx.hir().ty_param_owner(hir_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[&def_id];
- tcx.arena.alloc(ty::GenericPredicates {
+ ty::GenericPredicates {
parent: None,
- predicates: self.param_env.caller_bounds.iter().filter_map(|&predicate| {
- match predicate {
+ predicates: tcx.arena.alloc_from_iter(
+ self.param_env.caller_bounds.iter().filter_map(|&predicate| match predicate {
ty::Predicate::Trait(ref data)
if data.skip_binder().self_ty().is_param(index) => {
// HACK(eddyb) should get the original `Span`.
Some((predicate, span))
}
_ => None
- }
- }).collect()
- })
+ }),
+ ),
+ }
}
fn re_infer(
pub fn suggest_mismatched_types_on_tail(
&self,
err: &mut DiagnosticBuilder<'tcx>,
- expression: &'tcx hir::Expr,
+ expr: &'tcx hir::Expr,
expected: Ty<'tcx>,
found: Ty<'tcx>,
cause_span: Span,
blk_id: hir::HirId,
) -> bool {
- self.suggest_missing_semicolon(err, expression, expected, cause_span);
+ let expr = expr.peel_drop_temps();
+ self.suggest_missing_semicolon(err, expr, expected, cause_span);
let mut pointing_at_return_type = false;
if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
pointing_at_return_type = self.suggest_missing_return_type(
err, &fn_decl, expected, found, can_suggest);
}
- self.suggest_ref_or_into(err, expression, expected, found);
- self.suggest_boxing_when_appropriate(err, expression, expected, found);
+ self.suggest_ref_or_into(err, expr, expected, found);
+ self.suggest_boxing_when_appropriate(err, expr, expected, found);
pointing_at_return_type
}
ty::Closure(def_id, substs) => {
// We don't use `closure_sig` to account for malformed closures like
// `|_: [_; continue]| {}` and instead we don't suggest anything.
- let closure_sig_ty = substs.closure_sig_ty(def_id, self.tcx);
+ let closure_sig_ty = substs.as_closure().sig_ty(def_id, self.tcx);
(def_id, match closure_sig_ty.kind {
ty::FnPtr(sig) => sig,
_ => return false,