@@ -23,9 +23,10 @@ use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable};
2323use rustc:: infer:: type_variable:: TypeVariableOrigin ;
2424use rustc:: util:: nodemap:: FxHashSet ;
2525use rustc:: infer:: { self , InferOk } ;
26+ use rustc:: middle:: stability;
2627use syntax:: ast;
2728use syntax:: util:: lev_distance:: { lev_distance, find_best_match_for_name} ;
28- use syntax_pos:: Span ;
29+ use syntax_pos:: { Span , symbol :: Symbol } ;
2930use rustc:: hir;
3031use rustc:: lint;
3132use std:: mem;
@@ -937,30 +938,59 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
937938 debug ! ( "pick_method(self_ty={})" , self . ty_to_string( self_ty) ) ;
938939
939940 let mut possibly_unsatisfied_predicates = Vec :: new ( ) ;
940-
941- debug ! ( "searching inherent candidates" ) ;
942- if let Some ( pick) = self . consider_candidates ( self_ty,
943- & self . inherent_candidates ,
944- & mut possibly_unsatisfied_predicates) {
945- return Some ( pick) ;
941+ let mut unstable_candidates = Vec :: new ( ) ;
942+
943+ for ( kind, candidates) in & [
944+ ( "inherent" , & self . inherent_candidates ) ,
945+ ( "extension" , & self . extension_candidates ) ,
946+ ] {
947+ debug ! ( "searching {} candidates" , kind) ;
948+ let res = self . consider_candidates (
949+ self_ty,
950+ candidates. iter ( ) ,
951+ & mut possibly_unsatisfied_predicates,
952+ Some ( & mut unstable_candidates) ,
953+ ) ;
954+ if let Some ( pick) = res {
955+ if !unstable_candidates. is_empty ( ) && !self_ty. is_ty_var ( ) {
956+ if let Ok ( p) = & pick {
957+ // Emit a lint if there are unstable candidates alongside the stable ones.
958+ //
959+ // Note, we suppress warning if `self_ty` is TyVar (`_`), since every
960+ // possible candidates of every type will be considered, which leads to
961+ // bogus ambiguity like `str::rsplit` vs `[_]::rsplit`. This condition is
962+ // seen in `src/test/compile-fail/occurs-check-2.rs`.
963+ self . emit_unstable_name_collision_hint ( p, & unstable_candidates) ;
964+ }
965+ }
966+ return Some ( pick) ;
967+ }
946968 }
947969
948- debug ! ( "searching extension candidates" ) ;
949- let res = self . consider_candidates ( self_ty,
950- & self . extension_candidates ,
951- & mut possibly_unsatisfied_predicates) ;
952- if let None = res {
970+ debug ! ( "searching unstable candidates" ) ;
971+ let res = self . consider_candidates (
972+ self_ty,
973+ unstable_candidates. into_iter ( ) . map ( |( c, _) | c) ,
974+ & mut possibly_unsatisfied_predicates,
975+ None ,
976+ ) ;
977+ if res. is_none ( ) {
953978 self . unsatisfied_predicates . extend ( possibly_unsatisfied_predicates) ;
954979 }
955980 res
956981 }
957982
958- fn consider_candidates ( & self ,
959- self_ty : Ty < ' tcx > ,
960- probes : & [ Candidate < ' tcx > ] ,
961- possibly_unsatisfied_predicates : & mut Vec < TraitRef < ' tcx > > )
962- -> Option < PickResult < ' tcx > > {
963- let mut applicable_candidates: Vec < _ > = probes. iter ( )
983+ fn consider_candidates < ' b , ProbesIter > (
984+ & self ,
985+ self_ty : Ty < ' tcx > ,
986+ probes : ProbesIter ,
987+ possibly_unsatisfied_predicates : & mut Vec < TraitRef < ' tcx > > ,
988+ unstable_candidates : Option < & mut Vec < ( & ' b Candidate < ' tcx > , Symbol ) > > ,
989+ ) -> Option < PickResult < ' tcx > >
990+ where
991+ ProbesIter : Iterator < Item = & ' b Candidate < ' tcx > > + Clone ,
992+ {
993+ let mut applicable_candidates: Vec < _ > = probes. clone ( )
964994 . map ( |probe| {
965995 ( probe, self . consider_probe ( self_ty, probe, possibly_unsatisfied_predicates) )
966996 } )
@@ -975,8 +1005,20 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
9751005 }
9761006 }
9771007
1008+ if let Some ( uc) = unstable_candidates {
1009+ applicable_candidates. retain ( |& ( p, _) | {
1010+ if let stability:: EvalResult :: Deny { feature, .. } =
1011+ self . tcx . eval_stability ( p. item . def_id , ast:: DUMMY_NODE_ID , self . span )
1012+ {
1013+ uc. push ( ( p, feature) ) ;
1014+ return false ;
1015+ }
1016+ true
1017+ } ) ;
1018+ }
1019+
9781020 if applicable_candidates. len ( ) > 1 {
979- let sources = probes. iter ( )
1021+ let sources = probes
9801022 . map ( |p| self . candidate_source ( p, self_ty) )
9811023 . collect ( ) ;
9821024 return Some ( Err ( MethodError :: Ambiguity ( sources) ) ) ;
@@ -991,6 +1033,39 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
9911033 } )
9921034 }
9931035
1036+ fn emit_unstable_name_collision_hint (
1037+ & self ,
1038+ stable_pick : & Pick ,
1039+ unstable_candidates : & [ ( & Candidate < ' tcx > , Symbol ) ] ,
1040+ ) {
1041+ let mut diag = self . tcx . struct_span_lint_node (
1042+ lint:: builtin:: UNSTABLE_NAME_COLLISION ,
1043+ self . fcx . body_id ,
1044+ self . span ,
1045+ "a method with this name will be added to the standard library in the future" ,
1046+ ) ;
1047+
1048+ // FIXME: This should be a `span_suggestion` instead of `help`. However `self.span` only
1049+ // highlights the method name, so we can't use it. Also consider reusing the code from
1050+ // `report_method_error()`.
1051+ diag. help ( & format ! (
1052+ "call with fully qualified syntax `{}(...)` to keep using the current method" ,
1053+ self . tcx. item_path_str( stable_pick. item. def_id) ,
1054+ ) ) ;
1055+
1056+ if :: rustc:: session:: config:: nightly_options:: is_nightly_build ( ) {
1057+ for ( candidate, feature) in unstable_candidates {
1058+ diag. note ( & format ! (
1059+ "add #![feature({})] to the crate attributes to enable `{}`" ,
1060+ feature,
1061+ self . tcx. item_path_str( candidate. item. def_id) ,
1062+ ) ) ;
1063+ }
1064+ }
1065+
1066+ diag. emit ( ) ;
1067+ }
1068+
9941069 fn select_trait_candidate ( & self , trait_ref : ty:: TraitRef < ' tcx > )
9951070 -> traits:: SelectionResult < ' tcx , traits:: Selection < ' tcx > >
9961071 {
0 commit comments