mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-31 03:54:42 +00:00 
			
		
		
		
	Fix a bug where enum variants were not considered properly in type ns resolution
They should be considered just as well as in value ns, for example for struct literals.
This commit is contained in:
		
							parent
							
								
									248bd511ae
								
							
						
					
					
						commit
						044c831f7f
					
				
					 3 changed files with 81 additions and 29 deletions
				
			
		|  | @ -166,6 +166,17 @@ impl Resolver { | ||||||
|         db: &dyn DefDatabase, |         db: &dyn DefDatabase, | ||||||
|         path: &Path, |         path: &Path, | ||||||
|     ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> { |     ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> { | ||||||
|  |         self.resolve_path_in_type_ns_with_prefix_info(db, path).map( | ||||||
|  |             |(resolution, remaining_segments, import, _)| (resolution, remaining_segments, import), | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn resolve_path_in_type_ns_with_prefix_info( | ||||||
|  |         &self, | ||||||
|  |         db: &dyn DefDatabase, | ||||||
|  |         path: &Path, | ||||||
|  |     ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>, ResolvePathResultPrefixInfo)> | ||||||
|  |     { | ||||||
|         let path = match path { |         let path = match path { | ||||||
|             Path::BarePath(mod_path) => mod_path, |             Path::BarePath(mod_path) => mod_path, | ||||||
|             Path::Normal(it) => it.mod_path(), |             Path::Normal(it) => it.mod_path(), | ||||||
|  | @ -181,7 +192,12 @@ impl Resolver { | ||||||
|                     | LangItemTarget::ImplDef(_) |                     | LangItemTarget::ImplDef(_) | ||||||
|                     | LangItemTarget::Static(_) => return None, |                     | LangItemTarget::Static(_) => return None, | ||||||
|                 }; |                 }; | ||||||
|                 return Some((type_ns, seg.as_ref().map(|_| 1), None)); |                 return Some(( | ||||||
|  |                     type_ns, | ||||||
|  |                     seg.as_ref().map(|_| 1), | ||||||
|  |                     None, | ||||||
|  |                     ResolvePathResultPrefixInfo::default(), | ||||||
|  |                 )); | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|         let first_name = path.segments().first()?; |         let first_name = path.segments().first()?; | ||||||
|  | @ -197,17 +213,32 @@ impl Resolver { | ||||||
|                 Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue, |                 Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue, | ||||||
|                 Scope::GenericParams { params, def } => { |                 Scope::GenericParams { params, def } => { | ||||||
|                     if let Some(id) = params.find_type_by_name(first_name, *def) { |                     if let Some(id) = params.find_type_by_name(first_name, *def) { | ||||||
|                         return Some((TypeNs::GenericParam(id), remaining_idx(), None)); |                         return Some(( | ||||||
|  |                             TypeNs::GenericParam(id), | ||||||
|  |                             remaining_idx(), | ||||||
|  |                             None, | ||||||
|  |                             ResolvePathResultPrefixInfo::default(), | ||||||
|  |                         )); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 &Scope::ImplDefScope(impl_) => { |                 &Scope::ImplDefScope(impl_) => { | ||||||
|                     if *first_name == sym::Self_.clone() { |                     if *first_name == sym::Self_.clone() { | ||||||
|                         return Some((TypeNs::SelfType(impl_), remaining_idx(), None)); |                         return Some(( | ||||||
|  |                             TypeNs::SelfType(impl_), | ||||||
|  |                             remaining_idx(), | ||||||
|  |                             None, | ||||||
|  |                             ResolvePathResultPrefixInfo::default(), | ||||||
|  |                         )); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 &Scope::AdtScope(adt) => { |                 &Scope::AdtScope(adt) => { | ||||||
|                     if *first_name == sym::Self_.clone() { |                     if *first_name == sym::Self_.clone() { | ||||||
|                         return Some((TypeNs::AdtSelfType(adt), remaining_idx(), None)); |                         return Some(( | ||||||
|  |                             TypeNs::AdtSelfType(adt), | ||||||
|  |                             remaining_idx(), | ||||||
|  |                             None, | ||||||
|  |                             ResolvePathResultPrefixInfo::default(), | ||||||
|  |                         )); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 Scope::BlockScope(m) => { |                 Scope::BlockScope(m) => { | ||||||
|  | @ -220,18 +251,6 @@ impl Resolver { | ||||||
|         self.module_scope.resolve_path_in_type_ns(db, path) |         self.module_scope.resolve_path_in_type_ns(db, path) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn resolve_path_in_type_ns_fully_with_imports( |  | ||||||
|         &self, |  | ||||||
|         db: &dyn DefDatabase, |  | ||||||
|         path: &Path, |  | ||||||
|     ) -> Option<(TypeNs, Option<ImportOrExternCrate>)> { |  | ||||||
|         let (res, unresolved, imp) = self.resolve_path_in_type_ns(db, path)?; |  | ||||||
|         if unresolved.is_some() { |  | ||||||
|             return None; |  | ||||||
|         } |  | ||||||
|         Some((res, imp)) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn resolve_path_in_type_ns_fully( |     pub fn resolve_path_in_type_ns_fully( | ||||||
|         &self, |         &self, | ||||||
|         db: &dyn DefDatabase, |         db: &dyn DefDatabase, | ||||||
|  | @ -986,11 +1005,12 @@ impl ModuleItemMap { | ||||||
|         &self, |         &self, | ||||||
|         db: &dyn DefDatabase, |         db: &dyn DefDatabase, | ||||||
|         path: &ModPath, |         path: &ModPath, | ||||||
|     ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> { |     ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>, ResolvePathResultPrefixInfo)> | ||||||
|         let (module_def, idx, _) = |     { | ||||||
|  |         let (module_def, idx, prefix_info) = | ||||||
|             self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other); |             self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other); | ||||||
|         let (res, import) = to_type_ns(module_def)?; |         let (res, import) = to_type_ns(module_def)?; | ||||||
|         Some((res, idx, import)) |         Some((res, idx, import, prefix_info)) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -761,8 +761,8 @@ impl<'a> TyLoweringContext<'a> { | ||||||
|         path: &Path, |         path: &Path, | ||||||
|         on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic), |         on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic), | ||||||
|     ) -> Option<(TypeNs, Option<usize>)> { |     ) -> Option<(TypeNs, Option<usize>)> { | ||||||
|         let (resolution, remaining_index, _) = |         let (resolution, remaining_index, _, prefix_info) = | ||||||
|             self.resolver.resolve_path_in_type_ns(self.db.upcast(), path)?; |             self.resolver.resolve_path_in_type_ns_with_prefix_info(self.db.upcast(), path)?; | ||||||
|         let segments = path.segments(); |         let segments = path.segments(); | ||||||
| 
 | 
 | ||||||
|         match path { |         match path { | ||||||
|  | @ -771,13 +771,12 @@ impl<'a> TyLoweringContext<'a> { | ||||||
|             _ => return Some((resolution, remaining_index)), |             _ => return Some((resolution, remaining_index)), | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         let (module_segments, resolved_segment_idx, resolved_segment) = match remaining_index { |         let (module_segments, resolved_segment_idx, enum_segment) = match remaining_index { | ||||||
|             None => ( |             None if prefix_info.enum_variant => { | ||||||
|                 segments.strip_last(), |                 (segments.strip_last_two(), segments.len() - 1, Some(segments.len() - 2)) | ||||||
|                 segments.len() - 1, |             } | ||||||
|                 segments.last().expect("resolved path has at least one element"), |             None => (segments.strip_last(), segments.len() - 1, None), | ||||||
|             ), |             Some(i) => (segments.take(i - 1), i - 1, None), | ||||||
|             Some(i) => (segments.take(i - 1), i - 1, segments.get(i - 1).unwrap()), |  | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         for (i, mod_segment) in module_segments.iter().enumerate() { |         for (i, mod_segment) in module_segments.iter().enumerate() { | ||||||
|  | @ -792,9 +791,23 @@ impl<'a> TyLoweringContext<'a> { | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         if let Some(enum_segment) = enum_segment { | ||||||
|  |             if segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some()) | ||||||
|  |                 && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some()) | ||||||
|  |             { | ||||||
|  |                 on_diagnostic( | ||||||
|  |                     self, | ||||||
|  |                     PathLoweringDiagnostic::GenericArgsProhibited { | ||||||
|  |                         segment: (enum_segment + 1) as u32, | ||||||
|  |                         reason: GenericArgsProhibitedReason::EnumVariant, | ||||||
|  |                     }, | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         self.handle_type_ns_resolution( |         self.handle_type_ns_resolution( | ||||||
|             &resolution, |             &resolution, | ||||||
|             resolved_segment, |             segments.get(resolved_segment_idx).expect("should have resolved segment"), | ||||||
|             resolved_segment_idx, |             resolved_segment_idx, | ||||||
|             on_diagnostic, |             on_diagnostic, | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
|  | @ -600,6 +600,25 @@ pub mod __private { | ||||||
| //- /bar.rs crate:bar deps:foo edition:2018
 | //- /bar.rs crate:bar deps:foo edition:2018
 | ||||||
| fn bar() { | fn bar() { | ||||||
|     _ = foo::__private::Result::<(), ()>::Ok; |     _ = foo::__private::Result::<(), ()>::Ok; | ||||||
|  | } | ||||||
|  |         "#,
 | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn enum_variant_type_ns() { | ||||||
|  |         check_diagnostics( | ||||||
|  |             r#" | ||||||
|  | enum KvnDeserializerErr<I> { | ||||||
|  |     UnexpectedKeyword { found: I, expected: I }, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn foo() { | ||||||
|  |     let _x: KvnDeserializerErr<()> = | ||||||
|  |         KvnDeserializerErr::<()>::UnexpectedKeyword { found: (), expected: () }; | ||||||
|  |     let _x: KvnDeserializerErr<()> = | ||||||
|  |         KvnDeserializerErr::<()>::UnexpectedKeyword::<()> { found: (), expected: () }; | ||||||
|  |                                                 // ^^^^^^ 💡 error: you can specify generic arguments on either the enum or the variant, but not both
 | ||||||
| } | } | ||||||
|         "#,
 |         "#,
 | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Chayim Refael Friedman
						Chayim Refael Friedman