Skip to content

Commit c3c80aa

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 a03707d commit c3c80aa

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
@@ -657,76 +657,7 @@ fn project_type<'cx,'tcx>(
657657

658658
assert!(candidates.vec.len() <= 1);
659659

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

878809
match vtable {
879-
super::VtableImpl(_) |
880810
super::VtableClosure(_) |
881811
super::VtableFnPointer(_) |
882812
super::VtableObject(_) => {
@@ -885,6 +815,115 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
885815

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

0 commit comments

Comments
 (0)