Skip to content

Commit 318121b

Browse files
committed
no candidate for impl with default type
Before we would ignore a candidate if it happened to be an impl with a default type. This change makes us never add the impl in the first place. This seems largely equivalent, though there might be some subtle difference in that -- before -- we would have failed to normalize if there was a "trait-def-candidate" contending with an (opaque) impl candidate. This corresponds I guess to a case like `<<A as Trait>::B as Trait2>::C`, and the definition of `Trait` contains a clause. Pretty obscure, but it seems like it's... ok to favor the trait definition in such a case.
1 parent 170901e commit 318121b

File tree

1 file changed

+110
-71
lines changed

1 file changed

+110
-71
lines changed

src/librustc/traits/project.rs

Lines changed: 110 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -650,76 +650,7 @@ fn project_type<'cx,'tcx>(
650650

651651
assert!(candidates.vec.len() <= 1);
652652

653-
let possible_candidate = candidates.vec.pop().and_then(|candidate| {
654-
// In Any (i.e. trans) mode, all projections succeed;
655-
// otherwise, we need to be sensitive to `default` and
656-
// specialization.
657-
if !selcx.projection_mode().is_any() {
658-
if let ProjectionTyCandidate::Impl(ref impl_data) = candidate {
659-
if let Some(node_item) = assoc_ty_def(selcx,
660-
impl_data.impl_def_id,
661-
obligation.predicate.item_name) {
662-
if node_item.node.is_from_trait() {
663-
if node_item.item.ty.is_some() {
664-
// If the associated type has a default from the
665-
// trait, that should be considered `default` and
666-
// hence not projected.
667-
//
668-
// Note, however, that we allow a projection from
669-
// the trait specifically in the case that the trait
670-
// does *not* give a default. This is purely to
671-
// avoid spurious errors: the situation can only
672-
// arise when *no* impl in the specialization chain
673-
// has provided a definition for the type. When we
674-
// confirm the candidate, we'll turn the projection
675-
// into a TyError, since the actual error will be
676-
// reported in `check_impl_items_against_trait`.
677-
return None;
678-
}
679-
} else if node_item.item.defaultness.is_default() {
680-
return None;
681-
}
682-
} else {
683-
// Normally this situation could only arise througha
684-
// compiler bug, but at coherence-checking time we only look
685-
// at the topmost impl (we don't even consider the trait
686-
// itself) for the definition -- so we can fail to find a
687-
// definition of the type even if it exists.
688-
689-
// For now, we just unconditionally ICE, because otherwise,
690-
// examples like the following will succeed:
691-
//
692-
// ```
693-
// trait Assoc {
694-
// type Output;
695-
// }
696-
//
697-
// impl<T> Assoc for T {
698-
// default type Output = bool;
699-
// }
700-
//
701-
// impl Assoc for u8 {}
702-
// impl Assoc for u16 {}
703-
//
704-
// trait Foo {}
705-
// impl Foo for <u8 as Assoc>::Output {}
706-
// impl Foo for <u16 as Assoc>::Output {}
707-
// return None;
708-
// }
709-
// ```
710-
//
711-
// The essential problem here is that the projection fails,
712-
// leaving two unnormalized types, which appear not to unify
713-
// -- so the overlap check succeeds, when it should fail.
714-
bug!("Tried to project an inherited associated type during \
715-
coherence checking, which is currently not supported.");
716-
}
717-
}
718-
}
719-
Some(candidate)
720-
});
721-
722-
match possible_candidate {
653+
match candidates.vec.pop() {
723654
Some(candidate) => {
724655
let (ty, obligations) = confirm_candidate(selcx,
725656
obligation,
@@ -866,7 +797,6 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
866797
};
867798

868799
match vtable {
869-
super::VtableImpl(_) |
870800
super::VtableClosure(_) |
871801
super::VtableFnPointer(_) |
872802
super::VtableObject(_) => {
@@ -875,6 +805,115 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
875805

876806
candidate_set.vec.push(ProjectionTyCandidate::Select);
877807
}
808+
super::VtableImpl(ref impl_data) if !selcx.projection_mode().is_any() => {
809+
// We have to be careful when projecting out of an
810+
// impl because of specialization. If we are not in
811+
// trans (i.e., projection mode is not "any"), and the
812+
// impl's type is declared as default, then we disable
813+
// projection (even if the trait ref is fully
814+
// monomorphic). In the case where trait ref is not
815+
// fully monomorphic (i.e., includes type parameters),
816+
// this is because those type parameters may
817+
// ultimately be bound to types from other crates that
818+
// may have specialized impls we can't see. In the
819+
// case where the trait ref IS fully monomorphic, this
820+
// is a policy decision that we made in the RFC in
821+
// order to preserve flexibility for the crate that
822+
// defined the specializable impl to specialize later
823+
// for existing types.
824+
//
825+
// In either case, we handle this by not adding a
826+
// candidate for an impl if it contains a `default`
827+
// type.
828+
let opt_node_item = assoc_ty_def(selcx,
829+
impl_data.impl_def_id,
830+
obligation.predicate.item_name);
831+
let new_candidate = if let Some(node_item) = opt_node_item {
832+
if node_item.node.is_from_trait() {
833+
if node_item.item.ty.is_some() {
834+
// The impl inherited a `type Foo =
835+
// Bar` given in the trait, which is
836+
// implicitly default. No candidate.
837+
None
838+
} else {
839+
// The impl did not specify `type` and neither
840+
// did the trait:
841+
//
842+
// ```rust
843+
// trait Foo { type T; }
844+
// impl Foo for Bar { }
845+
// ```
846+
//
847+
// This is an error, but it will be
848+
// reported in `check_impl_items_against_trait`.
849+
// We accept it here but will flag it as
850+
// an error when we confirm the candidate
851+
// (which will ultimately lead to `normalize_to_error`
852+
// being invoked).
853+
Some(ProjectionTyCandidate::Select)
854+
}
855+
} else if node_item.item.defaultness.is_default() {
856+
// The impl specified `default type Foo =
857+
// Bar`. No candidate.
858+
None
859+
} else {
860+
// The impl specified `type Foo = Bar`
861+
// with no default. Add a candidate.
862+
Some(ProjectionTyCandidate::Select)
863+
}
864+
} else {
865+
// This is saying that neither the trait nor
866+
// the impl contain a definition for this
867+
// associated type. Normally this situation
868+
// could only arise through a compiler bug --
869+
// if the user wrote a bad item name, it
870+
// should have failed in astconv. **However**,
871+
// at coherence-checking time, we only look at
872+
// the topmost impl (we don't even consider
873+
// the trait itself) for the definition -- and
874+
// so in that case it may be that the trait
875+
// *DOES* have a declaration, but we don't see
876+
// it, and we end up in this branch.
877+
//
878+
// This is kind of tricky to handle actually.
879+
// For now, we just unconditionally ICE,
880+
// because otherwise, examples like the
881+
// following will succeed:
882+
//
883+
// ```
884+
// trait Assoc {
885+
// type Output;
886+
// }
887+
//
888+
// impl<T> Assoc for T {
889+
// default type Output = bool;
890+
// }
891+
//
892+
// impl Assoc for u8 {}
893+
// impl Assoc for u16 {}
894+
//
895+
// trait Foo {}
896+
// impl Foo for <u8 as Assoc>::Output {}
897+
// impl Foo for <u16 as Assoc>::Output {}
898+
// return None;
899+
// }
900+
// ```
901+
//
902+
// The essential problem here is that the
903+
// projection fails, leaving two unnormalized
904+
// types, which appear not to unify -- so the
905+
// overlap check succeeds, when it should
906+
// fail.
907+
bug!("Tried to project an inherited associated type during \
908+
coherence checking, which is currently not supported.");
909+
};
910+
candidate_set.vec.extend(new_candidate);
911+
}
912+
super::VtableImpl(_) => {
913+
// In trans mode, we can just project out of impls, no prob.
914+
assert!(selcx.projection_mode().is_any());
915+
candidate_set.vec.push(ProjectionTyCandidate::Select);
916+
}
878917
super::VtableParam(..) => {
879918
// This case tell us nothing about the value of an
880919
// associated type. Consider:

0 commit comments

Comments
 (0)