11
11
//! Code for projecting associated types out of trait references.
12
12
13
13
use super :: elaborate_predicates;
14
- use super :: get_impl_item_or_default;
15
14
use super :: report_overflow_error;
15
+ use super :: specialization_graph;
16
+ use super :: translate_substs;
16
17
use super :: Obligation ;
17
18
use super :: ObligationCause ;
18
19
use super :: PredicateObligation ;
@@ -22,14 +23,18 @@ use super::VtableClosureData;
22
23
use super :: VtableImplData ;
23
24
use super :: util;
24
25
26
+ use middle:: def_id:: DefId ;
25
27
use middle:: infer:: { self , TypeOrigin } ;
26
28
use middle:: subst:: Subst ;
27
29
use middle:: ty:: { self , ToPredicate , RegionEscape , HasTypeFlags , ToPolyTraitRef , Ty , TyCtxt } ;
28
30
use middle:: ty:: fold:: { TypeFoldable , TypeFolder } ;
29
31
use rustc_front:: hir;
30
32
use syntax:: parse:: token;
33
+ use syntax:: ast;
31
34
use util:: common:: FN_OUTPUT_NAME ;
32
35
36
+ use std:: rc:: Rc ;
37
+
33
38
pub type PolyProjectionObligation < ' tcx > =
34
39
Obligation < ' tcx , ty:: PolyProjectionPredicate < ' tcx > > ;
35
40
@@ -568,7 +573,49 @@ fn project_type<'cx,'tcx>(
568
573
569
574
assert ! ( candidates. vec. len( ) <= 1 ) ;
570
575
571
- match candidates. vec . pop ( ) {
576
+ let possible_candidate = candidates. vec . pop ( ) . and_then ( |candidate| {
577
+ // In Any (i.e. trans) mode, all projections succeed;
578
+ // otherwise, we need to be sensitive to `default` and
579
+ // specialization.
580
+ if !selcx. projection_mode ( ) . any ( ) {
581
+ if let ProjectionTyCandidate :: Impl ( ref impl_data) = candidate {
582
+ if let Some ( node_item) = assoc_ty_def ( selcx,
583
+ impl_data. impl_def_id ,
584
+ obligation. predicate . item_name ) {
585
+ if node_item. node . is_from_trait ( ) {
586
+ if node_item. item . ty . is_some ( ) {
587
+ // If the associated type has a default from the
588
+ // trait, that should be considered `default` and
589
+ // hence not projected.
590
+ //
591
+ // Note, however, that we allow a projection from
592
+ // the trait specifically in the case that the trait
593
+ // does *not* give a default. This is purely to
594
+ // avoid spurious errors: the situation can only
595
+ // arise when *no* impl in the specialization chain
596
+ // has provided a definition for the type. When we
597
+ // confirm the candidate, we'll turn the projection
598
+ // into a TyError, since the actual error will be
599
+ // reported in `check_impl_items_against_trait`.
600
+ return None ;
601
+ }
602
+ } else if node_item. item . defaultness . is_default ( ) {
603
+ return None ;
604
+ }
605
+ } else {
606
+ // Normally this situation could only arise througha
607
+ // compiler bug, but at coherence-checking time we only look
608
+ // at the topmost impl (we don't even consider the trait
609
+ // itself) for the definition -- so we can fail to find a
610
+ // definition of the type even if it exists.
611
+ return None ;
612
+ }
613
+ }
614
+ }
615
+ Some ( candidate)
616
+ } ) ;
617
+
618
+ match possible_candidate {
572
619
Some ( candidate) => {
573
620
let ( ty, obligations) = confirm_candidate ( selcx, obligation, candidate) ;
574
621
Ok ( ProjectedTy :: Progress ( ty, obligations) )
@@ -744,28 +791,6 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
744
791
745
792
match vtable {
746
793
super :: VtableImpl ( data) => {
747
- if data. substs . types . needs_infer ( ) {
748
- let assoc_ty_opt = get_impl_item_or_default ( selcx. tcx ( ) , data. impl_def_id , |cand| {
749
- if let & ty:: TypeTraitItem ( ref assoc_ty) = cand {
750
- if assoc_ty. name == obligation. predicate . item_name {
751
- return Some ( assoc_ty. defaultness ) ;
752
- }
753
- }
754
- None
755
- } ) ;
756
-
757
- if let Some ( ( defaultness, source) ) = assoc_ty_opt {
758
- if !source. is_from_trait ( ) && defaultness == hir:: Defaultness :: Default {
759
- // FIXME: is it OK to not mark as ambiguous?
760
- return Ok ( ( ) ) ;
761
- }
762
- } else {
763
- selcx. tcx ( ) . sess . span_bug ( obligation. cause . span ,
764
- & format ! ( "No associated type for {:?}" ,
765
- obligation_trait_ref) ) ;
766
- }
767
- }
768
-
769
794
debug ! ( "assemble_candidates_from_impls: impl candidate {:?}" ,
770
795
data) ;
771
796
@@ -967,29 +992,59 @@ fn confirm_impl_candidate<'cx,'tcx>(
967
992
{
968
993
let VtableImplData { substs, nested, impl_def_id } = impl_vtable;
969
994
970
- get_impl_item_or_default ( selcx. tcx ( ) , impl_def_id, |cand| {
971
- if let & ty:: TypeTraitItem ( ref assoc_ty) = cand {
972
- if assoc_ty. name == obligation. predicate . item_name {
973
- if let Some ( ty) = assoc_ty. ty {
974
- return Some ( ty)
975
- } else {
976
- // This means that the impl is missing a definition for the
977
- // associated type. This error will be reported by the type
978
- // checker method `check_impl_items_against_trait`, so here
979
- // we just return TyError.
980
- debug ! ( "confirm_impl_candidate: no associated type {:?} for {:?}" ,
981
- assoc_ty. name,
982
- obligation. predicate. trait_ref) ;
983
- return Some ( selcx. tcx ( ) . types . err ) ;
995
+ let tcx = selcx. tcx ( ) ;
996
+ let trait_ref = obligation. predicate . trait_ref ;
997
+ let assoc_ty = assoc_ty_def ( selcx, impl_def_id, obligation. predicate . item_name ) ;
998
+
999
+ match assoc_ty {
1000
+ Some ( node_item) => {
1001
+ let ty = node_item. item . ty . unwrap_or_else ( || {
1002
+ // This means that the impl is missing a definition for the
1003
+ // associated type. This error will be reported by the type
1004
+ // checker method `check_impl_items_against_trait`, so here we
1005
+ // just return TyError.
1006
+ debug ! ( "confirm_impl_candidate: no associated type {:?} for {:?}" ,
1007
+ node_item. item. name,
1008
+ obligation. predicate. trait_ref) ;
1009
+ tcx. types . err
1010
+ } ) ;
1011
+ let substs = translate_substs ( tcx, impl_def_id, substs, node_item. node ) ;
1012
+ ( ty. subst ( tcx, & substs) , nested)
1013
+ }
1014
+ None => {
1015
+ tcx. sess . span_bug ( obligation. cause . span ,
1016
+ & format ! ( "No associated type for {:?}" , trait_ref) ) ;
1017
+ }
1018
+ }
1019
+ }
1020
+
1021
+ /// Locate the definition of an associated type in the specialization hierarchy,
1022
+ /// starting from the given impl.
1023
+ ///
1024
+ /// Based on the "projection mode", this lookup may in fact only examine the
1025
+ /// topmost impl. See the comments for `ProjectionMode` for more details.
1026
+ fn assoc_ty_def < ' cx , ' tcx > ( selcx : & SelectionContext < ' cx , ' tcx > , impl_def_id : DefId , assoc_ty_name : ast:: Name )
1027
+ -> Option < specialization_graph:: NodeItem < Rc < ty:: AssociatedType < ' tcx > > > >
1028
+ {
1029
+ let trait_def_id = selcx. tcx ( ) . impl_trait_ref ( impl_def_id) . unwrap ( ) . def_id ;
1030
+
1031
+ if selcx. projection_mode ( ) . topmost ( ) {
1032
+ let impl_node = specialization_graph:: Node :: Impl ( impl_def_id) ;
1033
+ for item in impl_node. items ( selcx. tcx ( ) ) {
1034
+ if let ty:: TypeTraitItem ( assoc_ty) = item {
1035
+ if assoc_ty. name == assoc_ty_name {
1036
+ return Some ( specialization_graph:: NodeItem {
1037
+ node : specialization_graph:: Node :: Impl ( impl_def_id) ,
1038
+ item : assoc_ty,
1039
+ } ) ;
984
1040
}
985
1041
}
986
1042
}
987
1043
None
988
- } ) . map ( |( ty, source) | {
989
- ( ty. subst ( selcx. tcx ( ) , & source. translate_substs ( selcx. tcx ( ) , substs) ) , nested)
990
- } ) . unwrap_or_else ( || {
991
- selcx. tcx ( ) . sess . span_bug ( obligation. cause . span ,
992
- & format ! ( "No associated type for {:?}" ,
993
- obligation. predicate. trait_ref) ) ;
994
- } )
1044
+ } else {
1045
+ selcx. tcx ( ) . lookup_trait_def ( trait_def_id)
1046
+ . ancestors ( impl_def_id)
1047
+ . type_defs ( selcx. tcx ( ) , assoc_ty_name)
1048
+ . next ( )
1049
+ }
995
1050
}
0 commit comments