From 08660afe90d6c2257c59408116c718929af58963 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 16 May 2017 17:31:18 +0200 Subject: [PATCH] Remove unreachable branches in traits::project --- src/librustc/traits/project.rs | 188 +++++++++++++-------------------- 1 file changed, 72 insertions(+), 116 deletions(-) diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 0b12531f60abf..d7911870f391a 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -900,96 +900,50 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // In either case, we handle this by not adding a // candidate for an impl if it contains a `default` // type. - let opt_node_item = assoc_ty_def(selcx, - impl_data.impl_def_id, - obligation.predicate.item_name); - let new_candidate = if let Some(node_item) = opt_node_item { - let is_default = if node_item.node.is_from_trait() { - // If true, the impl inherited a `type Foo = Bar` - // given in the trait, which is implicitly default. - // Otherwise, the impl did not specify `type` and - // neither did the trait: - // - // ```rust - // trait Foo { type T; } - // impl Foo for Bar { } - // ``` - // - // This is an error, but it will be - // reported in `check_impl_items_against_trait`. - // We accept it here but will flag it as - // an error when we confirm the candidate - // (which will ultimately lead to `normalize_to_error` - // being invoked). - node_item.item.defaultness.has_value() - } else { - node_item.item.defaultness.is_default() || - selcx.tcx().impl_is_default(node_item.node.def_id()) - }; - - // Only reveal a specializable default if we're past type-checking - // and the obligations is monomorphic, otherwise passes such as - // transmute checking and polymorphic MIR optimizations could - // get a result which isn't correct for all monomorphizations. - if !is_default { + let node_item = assoc_ty_def(selcx, + impl_data.impl_def_id, + obligation.predicate.item_name); + + let is_default = if node_item.node.is_from_trait() { + // If true, the impl inherited a `type Foo = Bar` + // given in the trait, which is implicitly default. + // Otherwise, the impl did not specify `type` and + // neither did the trait: + // + // ```rust + // trait Foo { type T; } + // impl Foo for Bar { } + // ``` + // + // This is an error, but it will be + // reported in `check_impl_items_against_trait`. + // We accept it here but will flag it as + // an error when we confirm the candidate + // (which will ultimately lead to `normalize_to_error` + // being invoked). + node_item.item.defaultness.has_value() + } else { + node_item.item.defaultness.is_default() || + selcx.tcx().impl_is_default(node_item.node.def_id()) + }; + + // Only reveal a specializable default if we're past type-checking + // and the obligations is monomorphic, otherwise passes such as + // transmute checking and polymorphic MIR optimizations could + // get a result which isn't correct for all monomorphizations. + let new_candidate = if !is_default { + Some(ProjectionTyCandidate::Select) + } else if selcx.projection_mode() == Reveal::All { + assert!(!poly_trait_ref.needs_infer()); + if !poly_trait_ref.needs_subst() { Some(ProjectionTyCandidate::Select) - } else if selcx.projection_mode() == Reveal::All { - assert!(!poly_trait_ref.needs_infer()); - if !poly_trait_ref.needs_subst() { - Some(ProjectionTyCandidate::Select) - } else { - None - } } else { None } } else { - // This is saying that neither the trait nor - // the impl contain a definition for this - // associated type. Normally this situation - // could only arise through a compiler bug -- - // if the user wrote a bad item name, it - // should have failed in astconv. **However**, - // at coherence-checking time, we only look at - // the topmost impl (we don't even consider - // the trait itself) for the definition -- and - // so in that case it may be that the trait - // *DOES* have a declaration, but we don't see - // it, and we end up in this branch. - // - // This is kind of tricky to handle actually. - // For now, we just unconditionally ICE, - // because otherwise, examples like the - // following will succeed: - // - // ``` - // trait Assoc { - // type Output; - // } - // - // impl Assoc for T { - // default type Output = bool; - // } - // - // impl Assoc for u8 {} - // impl Assoc for u16 {} - // - // trait Foo {} - // impl Foo for ::Output {} - // impl Foo for ::Output {} - // return None; - // } - // ``` - // - // The essential problem here is that the - // projection fails, leaving two unnormalized - // types, which appear not to unify -- so the - // overlap check succeeds, when it should - // fail. - span_bug!(obligation.cause.span, - "Tried to project an inherited associated type during \ - coherence checking, which is currently not supported."); + None }; + candidate_set.vec.extend(new_candidate); } super::VtableParam(..) => { @@ -1274,35 +1228,25 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( let VtableImplData { substs, nested, impl_def_id } = impl_vtable; let tcx = selcx.tcx(); - let trait_ref = obligation.predicate.trait_ref; let assoc_ty = assoc_ty_def(selcx, impl_def_id, obligation.predicate.item_name); - match assoc_ty { - Some(node_item) => { - let ty = if !node_item.item.defaultness.has_value() { - // This means that the impl is missing a definition for the - // associated type. This error will be reported by the type - // checker method `check_impl_items_against_trait`, so here we - // just return TyError. - debug!("confirm_impl_candidate: no associated type {:?} for {:?}", - node_item.item.name, - obligation.predicate.trait_ref); - tcx.types.err - } else { - tcx.type_of(node_item.item.def_id) - }; - let substs = translate_substs(selcx.infcx(), impl_def_id, substs, node_item.node); - Progress { - ty: ty.subst(tcx, substs), - obligations: nested, - cacheable: true - } - } - None => { - span_bug!(obligation.cause.span, - "No associated type for {:?}", - trait_ref); - } + let ty = if !assoc_ty.item.defaultness.has_value() { + // This means that the impl is missing a definition for the + // associated type. This error will be reported by the type + // checker method `check_impl_items_against_trait`, so here we + // just return TyError. + debug!("confirm_impl_candidate: no associated type {:?} for {:?}", + assoc_ty.item.name, + obligation.predicate.trait_ref); + tcx.types.err + } else { + tcx.type_of(assoc_ty.item.def_id) + }; + let substs = translate_substs(selcx.infcx(), impl_def_id, substs, assoc_ty.node); + Progress { + ty: ty.subst(tcx, substs), + obligations: nested, + cacheable: true } } @@ -1315,7 +1259,7 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>( selcx: &SelectionContext<'cx, 'gcx, 'tcx>, impl_def_id: DefId, assoc_ty_name: ast::Name) - -> Option> + -> specialization_graph::NodeItem { let tcx = selcx.tcx(); let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id; @@ -1330,17 +1274,29 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>( let impl_node = specialization_graph::Node::Impl(impl_def_id); for item in impl_node.items(tcx) { if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name { - return Some(specialization_graph::NodeItem { + return specialization_graph::NodeItem { node: specialization_graph::Node::Impl(impl_def_id), item: item, - }); + }; } } - trait_def + if let Some(assoc_item) = trait_def .ancestors(tcx, impl_def_id) .defs(tcx, assoc_ty_name, ty::AssociatedKind::Type) - .next() + .next() { + assoc_item + } else { + // This is saying that neither the trait nor + // the impl contain a definition for this + // associated type. Normally this situation + // could only arise through a compiler bug -- + // if the user wrote a bad item name, it + // should have failed in astconv. + bug!("No associated type `{}` for {}", + assoc_ty_name, + tcx.item_path_str(impl_def_id)) + } } // # Cache