@@ -56,6 +56,64 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
5656 }
5757 }
5858
59+ fn variant_field (
60+ & self ,
61+ path_str : & str ,
62+ current_item : & Option < String > ,
63+ module_id : syntax:: ast:: NodeId ,
64+ ) -> Result < ( Res , Option < String > ) , ErrorKind > {
65+ let cx = self . cx ;
66+
67+ let mut split = path_str. rsplitn ( 3 , "::" ) ;
68+ let variant_field_name = split
69+ . next ( )
70+ . map ( |f| Symbol :: intern ( f) )
71+ . ok_or ( ErrorKind :: ResolutionFailure ) ?;
72+ let variant_name = split
73+ . next ( )
74+ . map ( |f| Symbol :: intern ( f) )
75+ . ok_or ( ErrorKind :: ResolutionFailure ) ?;
76+ let path = split. next ( ) . map ( |f| {
77+ if f == "self" || f == "Self" {
78+ if let Some ( name) = current_item. as_ref ( ) {
79+ return name. clone ( ) ;
80+ }
81+ }
82+ f. to_owned ( )
83+ } ) . ok_or ( ErrorKind :: ResolutionFailure ) ?;
84+ let ( _, ty_res) = cx. enter_resolver ( |resolver| {
85+ resolver. resolve_str_path_error ( DUMMY_SP , & path, TypeNS , module_id)
86+ } ) . map_err ( |_| ErrorKind :: ResolutionFailure ) ?;
87+ if let Res :: Err = ty_res {
88+ return Err ( ErrorKind :: ResolutionFailure ) ;
89+ }
90+ let ty_res = ty_res. map_id ( |_| panic ! ( "unexpected node_id" ) ) ;
91+ match ty_res {
92+ Res :: Def ( DefKind :: Enum , did) => {
93+ if cx. tcx . inherent_impls ( did)
94+ . iter ( )
95+ . flat_map ( |imp| cx. tcx . associated_items ( * imp) )
96+ . any ( |item| item. ident . name == variant_name) {
97+ return Err ( ErrorKind :: ResolutionFailure ) ;
98+ }
99+ match cx. tcx . type_of ( did) . kind {
100+ ty:: Adt ( def, _) if def. is_enum ( ) => {
101+ if def. all_fields ( )
102+ . any ( |item| item. ident . name == variant_field_name) {
103+ Ok ( ( ty_res,
104+ Some ( format ! ( "variant.{}.field.{}" ,
105+ variant_name, variant_field_name) ) ) )
106+ } else {
107+ Err ( ErrorKind :: ResolutionFailure )
108+ }
109+ }
110+ _ => Err ( ErrorKind :: ResolutionFailure ) ,
111+ }
112+ }
113+ _ => Err ( ErrorKind :: ResolutionFailure )
114+ }
115+ }
116+
59117 /// Resolves a string as a path within a particular namespace. Also returns an optional
60118 /// URL fragment in the case of variants and methods.
61119 fn resolve (
@@ -121,23 +179,18 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
121179
122180 // Try looking for methods and associated items.
123181 let mut split = path_str. rsplitn ( 2 , "::" ) ;
124- let item_name = if let Some ( first) = split. next ( ) {
125- Symbol :: intern ( first)
126- } else {
127- return Err ( ErrorKind :: ResolutionFailure )
128- } ;
129-
130- let mut path = if let Some ( second) = split. next ( ) {
131- second. to_owned ( )
132- } else {
133- return Err ( ErrorKind :: ResolutionFailure )
134- } ;
135-
136- if path == "self" || path == "Self" {
137- if let Some ( name) = current_item. as_ref ( ) {
138- path = name. clone ( ) ;
182+ let item_name = split. next ( )
183+ . map ( |f| Symbol :: intern ( f) )
184+ . ok_or ( ErrorKind :: ResolutionFailure ) ?;
185+ let path = split. next ( ) . map ( |f| {
186+ if f == "self" || f == "Self" {
187+ if let Some ( name) = current_item. as_ref ( ) {
188+ return name. clone ( ) ;
189+ }
139190 }
140- }
191+ f. to_owned ( )
192+ } ) . ok_or ( ErrorKind :: ResolutionFailure ) ?;
193+
141194 if let Some ( prim) = is_primitive ( & path, TypeNS ) {
142195 let did = primitive_impl ( cx, & path) . ok_or ( ErrorKind :: ResolutionFailure ) ?;
143196 return cx. tcx . associated_items ( did)
@@ -154,7 +207,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
154207 resolver. resolve_str_path_error ( DUMMY_SP , & path, TypeNS , module_id)
155208 } ) . map_err ( |_| ErrorKind :: ResolutionFailure ) ?;
156209 if let Res :: Err = ty_res {
157- return Err ( ErrorKind :: ResolutionFailure ) ;
210+ return self . variant_field ( path_str , current_item , module_id ) ;
158211 }
159212 let ty_res = ty_res. map_id ( |_| panic ! ( "unexpected node_id" ) ) ;
160213 match ty_res {
@@ -170,7 +223,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
170223 let out = match item. kind {
171224 ty:: AssocKind :: Method if ns == ValueNS => "method" ,
172225 ty:: AssocKind :: Const if ns == ValueNS => "associatedconstant" ,
173- _ => return Err ( ErrorKind :: ResolutionFailure )
226+ _ => return self . variant_field ( path_str , current_item , module_id ) ,
174227 } ;
175228 if extra_fragment. is_some ( ) {
176229 Err ( ErrorKind :: AnchorFailure (
@@ -211,10 +264,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
211264 item. ident) ) ) )
212265 }
213266 } else {
214- Err ( ErrorKind :: ResolutionFailure )
267+ self . variant_field ( path_str , current_item , module_id )
215268 }
216269 }
217- _ => Err ( ErrorKind :: ResolutionFailure ) ,
270+ _ => self . variant_field ( path_str , current_item , module_id ) ,
218271 }
219272 }
220273 }
@@ -233,7 +286,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
233286 "tymethod"
234287 }
235288 }
236- _ => return Err ( ErrorKind :: ResolutionFailure )
289+ _ => return self . variant_field ( path_str , current_item , module_id ) ,
237290 } ;
238291
239292 if extra_fragment. is_some ( ) {
@@ -249,10 +302,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
249302 Ok ( ( ty_res, Some ( format ! ( "{}.{}" , kind, item_name) ) ) )
250303 }
251304 } else {
252- Err ( ErrorKind :: ResolutionFailure )
305+ self . variant_field ( path_str , current_item , module_id )
253306 }
254307 }
255- _ => Err ( ErrorKind :: ResolutionFailure )
308+ _ => self . variant_field ( path_str , current_item , module_id ) ,
256309 }
257310 } else {
258311 debug ! ( "attempting to resolve item without parent module: {}" , path_str) ;
0 commit comments