mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-31 12:04:43 +00:00 
			
		
		
		
	Merge pull request #19167 from ChayimFriedman2/fix-ref-pat
fix: Fix detection of ref patterns for path patterns
This commit is contained in:
		
						commit
						656daef4da
					
				
					 4 changed files with 64 additions and 17 deletions
				
			
		|  | @ -7,6 +7,7 @@ use std::ops::{Deref, DerefMut}; | ||||||
| 
 | 
 | ||||||
| use either::Either; | use either::Either; | ||||||
| use hir_def::{hir::ExprOrPatId, path::Path, resolver::Resolver, type_ref::TypesMap, TypeOwnerId}; | use hir_def::{hir::ExprOrPatId, path::Path, resolver::Resolver, type_ref::TypesMap, TypeOwnerId}; | ||||||
|  | use la_arena::{Idx, RawIdx}; | ||||||
| 
 | 
 | ||||||
| use crate::{ | use crate::{ | ||||||
|     db::HirDatabase, |     db::HirDatabase, | ||||||
|  | @ -81,6 +82,26 @@ impl<'a> InferenceTyLoweringContext<'a> { | ||||||
|         }; |         }; | ||||||
|         PathLoweringContext::new(&mut self.ctx, on_diagnostic, path) |         PathLoweringContext::new(&mut self.ctx, on_diagnostic, path) | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub(super) fn at_path_forget_diagnostics<'b>( | ||||||
|  |         &'b mut self, | ||||||
|  |         path: &'b Path, | ||||||
|  |     ) -> PathLoweringContext<'b, 'a> { | ||||||
|  |         let on_diagnostic = PathDiagnosticCallback { | ||||||
|  |             data: Either::Right(PathDiagnosticCallbackData { | ||||||
|  |                 diagnostics: self.diagnostics, | ||||||
|  |                 node: ExprOrPatId::ExprId(Idx::from_raw(RawIdx::from_u32(0))), | ||||||
|  |             }), | ||||||
|  |             callback: |_data, _, _diag| {}, | ||||||
|  |         }; | ||||||
|  |         PathLoweringContext::new(&mut self.ctx, on_diagnostic, path) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub(super) fn forget_diagnostics(&mut self) { | ||||||
|  |         self.ctx.diagnostics.clear(); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'a> Deref for InferenceTyLoweringContext<'a> { | impl<'a> Deref for InferenceTyLoweringContext<'a> { | ||||||
|  |  | ||||||
|  | @ -565,16 +565,9 @@ impl InferenceContext<'_> { | ||||||
|             | Pat::Slice { .. } => true, |             | Pat::Slice { .. } => true, | ||||||
|             Pat::Or(pats) => pats.iter().all(|p| self.is_non_ref_pat(body, *p)), |             Pat::Or(pats) => pats.iter().all(|p| self.is_non_ref_pat(body, *p)), | ||||||
|             Pat::Path(path) => { |             Pat::Path(path) => { | ||||||
|                 // A const is a reference pattern, but other value ns things aren't (see #16131). We don't need more than
 |                 // A const is a reference pattern, but other value ns things aren't (see #16131).
 | ||||||
|                 // the hir-def resolver for this, because if there are segments left, this can only be an (associated) const.
 |                 let resolved = self.resolve_value_path_inner(path, pat.into(), true); | ||||||
|                 //
 |                 resolved.is_some_and(|it| !matches!(it.0, hir_def::resolver::ValueNs::ConstId(_))) | ||||||
|                 // Do not use `TyLoweringContext`'s resolution, we want to ignore errors here (they'll be reported elsewhere).
 |  | ||||||
|                 let resolution = self.resolver.resolve_path_in_value_ns_fully( |  | ||||||
|                     self.db.upcast(), |  | ||||||
|                     path, |  | ||||||
|                     body.pat_path_hygiene(pat), |  | ||||||
|                 ); |  | ||||||
|                 resolution.is_some_and(|it| !matches!(it, hir_def::resolver::ValueNs::ConstId(_))) |  | ||||||
|             } |             } | ||||||
|             Pat::ConstBlock(..) => false, |             Pat::ConstBlock(..) => false, | ||||||
|             Pat::Lit(expr) => !matches!( |             Pat::Lit(expr) => !matches!( | ||||||
|  |  | ||||||
|  | @ -40,7 +40,7 @@ impl InferenceContext<'_> { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<ValuePathResolution> { |     fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<ValuePathResolution> { | ||||||
|         let (value, self_subst) = self.resolve_value_path_inner(path, id)?; |         let (value, self_subst) = self.resolve_value_path_inner(path, id, false)?; | ||||||
| 
 | 
 | ||||||
|         let value_def: ValueTyDefId = match value { |         let value_def: ValueTyDefId = match value { | ||||||
|             ValueNs::FunctionId(it) => it.into(), |             ValueNs::FunctionId(it) => it.into(), | ||||||
|  | @ -152,6 +152,7 @@ impl InferenceContext<'_> { | ||||||
|         &mut self, |         &mut self, | ||||||
|         path: &Path, |         path: &Path, | ||||||
|         id: ExprOrPatId, |         id: ExprOrPatId, | ||||||
|  |         no_diagnostics: bool, | ||||||
|     ) -> Option<(ValueNs, Option<chalk_ir::Substitution<Interner>>)> { |     ) -> Option<(ValueNs, Option<chalk_ir::Substitution<Interner>>)> { | ||||||
|         // Don't use `self.make_ty()` here as we need `orig_ns`.
 |         // Don't use `self.make_ty()` here as we need `orig_ns`.
 | ||||||
|         let mut ctx = TyLoweringContext::new( |         let mut ctx = TyLoweringContext::new( | ||||||
|  | @ -162,7 +163,11 @@ impl InferenceContext<'_> { | ||||||
|             &self.diagnostics, |             &self.diagnostics, | ||||||
|             InferenceTyDiagnosticSource::Body, |             InferenceTyDiagnosticSource::Body, | ||||||
|         ); |         ); | ||||||
|         let mut path_ctx = ctx.at_path(path, id); |         let mut path_ctx = if no_diagnostics { | ||||||
|  |             ctx.at_path_forget_diagnostics(path) | ||||||
|  |         } else { | ||||||
|  |             ctx.at_path(path, id) | ||||||
|  |         }; | ||||||
|         let (value, self_subst) = if let Some(type_ref) = path.type_anchor() { |         let (value, self_subst) = if let Some(type_ref) = path.type_anchor() { | ||||||
|             let last = path.segments().last()?; |             let last = path.segments().last()?; | ||||||
| 
 | 
 | ||||||
|  | @ -172,7 +177,7 @@ impl InferenceContext<'_> { | ||||||
| 
 | 
 | ||||||
|             path_ctx.ignore_last_segment(); |             path_ctx.ignore_last_segment(); | ||||||
|             let (ty, _) = path_ctx.lower_ty_relative_path(ty, orig_ns); |             let (ty, _) = path_ctx.lower_ty_relative_path(ty, orig_ns); | ||||||
|             drop(ctx); |             drop_ctx(ctx, no_diagnostics); | ||||||
|             let ty = self.table.insert_type_vars(ty); |             let ty = self.table.insert_type_vars(ty); | ||||||
|             let ty = self.table.normalize_associated_types_in(ty); |             let ty = self.table.normalize_associated_types_in(ty); | ||||||
|             self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))? |             self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))? | ||||||
|  | @ -183,7 +188,7 @@ impl InferenceContext<'_> { | ||||||
| 
 | 
 | ||||||
|             match value_or_partial { |             match value_or_partial { | ||||||
|                 ResolveValueResult::ValueNs(it, _) => { |                 ResolveValueResult::ValueNs(it, _) => { | ||||||
|                     drop(ctx); |                     drop_ctx(ctx, no_diagnostics); | ||||||
|                     (it, None) |                     (it, None) | ||||||
|                 } |                 } | ||||||
|                 ResolveValueResult::Partial(def, remaining_index, _) => { |                 ResolveValueResult::Partial(def, remaining_index, _) => { | ||||||
|  | @ -202,7 +207,7 @@ impl InferenceContext<'_> { | ||||||
|                             let self_ty = self.table.new_type_var(); |                             let self_ty = self.table.new_type_var(); | ||||||
|                             let trait_ref = |                             let trait_ref = | ||||||
|                                 path_ctx.lower_trait_ref_from_resolved_path(trait_, self_ty); |                                 path_ctx.lower_trait_ref_from_resolved_path(trait_, self_ty); | ||||||
|                             drop(ctx); |                             drop_ctx(ctx, no_diagnostics); | ||||||
|                             self.resolve_trait_assoc_item(trait_ref, last_segment, id) |                             self.resolve_trait_assoc_item(trait_ref, last_segment, id) | ||||||
|                         } |                         } | ||||||
|                         (def, _) => { |                         (def, _) => { | ||||||
|  | @ -212,7 +217,7 @@ impl InferenceContext<'_> { | ||||||
|                             // as Iterator>::Item::default`)
 |                             // as Iterator>::Item::default`)
 | ||||||
|                             path_ctx.ignore_last_segment(); |                             path_ctx.ignore_last_segment(); | ||||||
|                             let (ty, _) = path_ctx.lower_partly_resolved_path(def, true); |                             let (ty, _) = path_ctx.lower_partly_resolved_path(def, true); | ||||||
|                             drop(ctx); |                             drop_ctx(ctx, no_diagnostics); | ||||||
|                             if ty.is_unknown() { |                             if ty.is_unknown() { | ||||||
|                                 return None; |                                 return None; | ||||||
|                             } |                             } | ||||||
|  | @ -227,7 +232,14 @@ impl InferenceContext<'_> { | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|         Some((value, self_subst)) |         return Some((value, self_subst)); | ||||||
|  | 
 | ||||||
|  |         #[inline] | ||||||
|  |         fn drop_ctx(mut ctx: TyLoweringContext<'_>, no_diagnostics: bool) { | ||||||
|  |             if no_diagnostics { | ||||||
|  |                 ctx.forget_diagnostics(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn add_required_obligations_for_value_path(&mut self, def: GenericDefId, subst: &Substitution) { |     fn add_required_obligations_for_value_path(&mut self, def: GenericDefId, subst: &Substitution) { | ||||||
|  |  | ||||||
|  | @ -1235,4 +1235,25 @@ fn f() { | ||||||
| "#,
 | "#,
 | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn complex_enum_variant_non_ref_pat() { | ||||||
|  |         check_diagnostics( | ||||||
|  |             r#" | ||||||
|  | enum Enum { Variant } | ||||||
|  | 
 | ||||||
|  | trait Trait { | ||||||
|  |     type Assoc; | ||||||
|  | } | ||||||
|  | impl Trait for () { | ||||||
|  |     type Assoc = Enum; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn foo(v: &Enum) { | ||||||
|  |     let <Enum>::Variant = v; | ||||||
|  |     let <() as Trait>::Assoc::Variant = v; | ||||||
|  | } | ||||||
|  |     "#,
 | ||||||
|  |         ); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lukas Wirth
						Lukas Wirth