mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-31 12:04:43 +00:00 
			
		
		
		
	fix: Apply adjusts to pats and exprs when doing pat analysis
This commit is contained in:
		
							parent
							
								
									8b45a73551
								
							
						
					
					
						commit
						e587367b4d
					
				
					 4 changed files with 95 additions and 49 deletions
				
			
		|  | @ -175,8 +175,9 @@ impl ExprValidator { | |||
|                 }); | ||||
|             } | ||||
| 
 | ||||
|             let receiver_ty = self.infer[*receiver].clone(); | ||||
|             checker.prev_receiver_ty = Some(receiver_ty); | ||||
|             if let Some(receiver_ty) = self.infer.type_of_expr_with_adjust(*receiver) { | ||||
|                 checker.prev_receiver_ty = Some(receiver_ty.clone()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -187,7 +188,9 @@ impl ExprValidator { | |||
|         arms: &[MatchArm], | ||||
|         db: &dyn HirDatabase, | ||||
|     ) { | ||||
|         let scrut_ty = &self.infer[scrutinee_expr]; | ||||
|         let Some(scrut_ty) = self.infer.type_of_expr_with_adjust(scrutinee_expr) else { | ||||
|             return; | ||||
|         }; | ||||
|         if scrut_ty.contains_unknown() { | ||||
|             return; | ||||
|         } | ||||
|  | @ -200,7 +203,7 @@ impl ExprValidator { | |||
|         // Note: Skipping the entire diagnostic rather than just not including a faulty match arm is
 | ||||
|         // preferred to avoid the chance of false positives.
 | ||||
|         for arm in arms { | ||||
|             let Some(pat_ty) = self.infer.type_of_pat.get(arm.pat) else { | ||||
|             let Some(pat_ty) = self.infer.type_of_pat_with_adjust(arm.pat) else { | ||||
|                 return; | ||||
|             }; | ||||
|             if pat_ty.contains_unknown() { | ||||
|  | @ -328,7 +331,7 @@ impl ExprValidator { | |||
|                 continue; | ||||
|             } | ||||
|             let Some(initializer) = initializer else { continue }; | ||||
|             let ty = &self.infer[initializer]; | ||||
|             let Some(ty) = self.infer.type_of_expr_with_adjust(initializer) else { continue }; | ||||
|             if ty.contains_unknown() { | ||||
|                 continue; | ||||
|             } | ||||
|  | @ -433,17 +436,18 @@ impl ExprValidator { | |||
|                     Statement::Expr { expr, .. } => Some(*expr), | ||||
|                     _ => None, | ||||
|                 }); | ||||
|                 if let Some(last_then_expr) = last_then_expr { | ||||
|                     let last_then_expr_ty = &self.infer[last_then_expr]; | ||||
|                     if last_then_expr_ty.is_never() { | ||||
|                 if let Some(last_then_expr) = last_then_expr | ||||
|                     && let Some(last_then_expr_ty) = | ||||
|                         self.infer.type_of_expr_with_adjust(last_then_expr) | ||||
|                     && last_then_expr_ty.is_never() | ||||
|                 { | ||||
|                     // Only look at sources if the then branch diverges and we have an else branch.
 | ||||
|                     let source_map = db.body_with_source_map(self.owner).1; | ||||
|                     let Ok(source_ptr) = source_map.expr_syntax(id) else { | ||||
|                         return; | ||||
|                     }; | ||||
|                     let root = source_ptr.file_syntax(db); | ||||
|                         let either::Left(ast::Expr::IfExpr(if_expr)) = | ||||
|                             source_ptr.value.to_node(&root) | ||||
|                     let either::Left(ast::Expr::IfExpr(if_expr)) = source_ptr.value.to_node(&root) | ||||
|                     else { | ||||
|                         return; | ||||
|                     }; | ||||
|  | @ -475,7 +479,6 @@ impl ExprValidator { | |||
|         } | ||||
|     } | ||||
| } | ||||
| } | ||||
| 
 | ||||
| struct FilterMapNextChecker { | ||||
|     filter_map_function_id: Option<hir_def::FunctionId>, | ||||
|  |  | |||
|  | @ -561,6 +561,32 @@ impl InferenceResult { | |||
|             ExprOrPatId::PatId(id) => self.type_of_pat.get(id), | ||||
|         } | ||||
|     } | ||||
|     pub fn type_of_expr_with_adjust(&self, id: ExprId) -> Option<&Ty> { | ||||
|         match self.expr_adjustments.get(&id).and_then(|adjustments| { | ||||
|             adjustments | ||||
|                 .iter() | ||||
|                 .filter(|adj| { | ||||
|                     // https://github.com/rust-lang/rust/blob/67819923ac8ea353aaa775303f4c3aacbf41d010/compiler/rustc_mir_build/src/thir/cx/expr.rs#L140
 | ||||
|                     !matches!( | ||||
|                         adj, | ||||
|                         Adjustment { | ||||
|                             kind: Adjust::NeverToAny, | ||||
|                             target, | ||||
|                         } if target.is_never() | ||||
|                     ) | ||||
|                 }) | ||||
|                 .next_back() | ||||
|         }) { | ||||
|             Some(adjustment) => Some(&adjustment.target), | ||||
|             None => self.type_of_expr.get(id), | ||||
|         } | ||||
|     } | ||||
|     pub fn type_of_pat_with_adjust(&self, id: PatId) -> Option<&Ty> { | ||||
|         match self.pat_adjustments.get(&id).and_then(|adjustments| adjustments.last()) { | ||||
|             adjusted @ Some(_) => adjusted, | ||||
|             None => self.type_of_pat.get(id), | ||||
|         } | ||||
|     } | ||||
|     pub fn is_erroneous(&self) -> bool { | ||||
|         self.has_errors && self.type_of_expr.iter().count() == 0 | ||||
|     } | ||||
|  |  | |||
|  | @ -441,7 +441,7 @@ impl<'db> SourceAnalyzer<'db> { | |||
|     ) -> Option<GenericSubstitution<'db>> { | ||||
|         let body = self.store()?; | ||||
|         if let Expr::Field { expr: object_expr, name: _ } = body[field_expr] { | ||||
|             let (adt, subst) = type_of_expr_including_adjust(infer, object_expr)?.as_adt()?; | ||||
|             let (adt, subst) = infer.type_of_expr_with_adjust(object_expr)?.as_adt()?; | ||||
|             return Some(GenericSubstitution::new( | ||||
|                 adt.into(), | ||||
|                 subst.clone(), | ||||
|  | @ -1780,10 +1780,3 @@ pub(crate) fn name_hygiene(db: &dyn HirDatabase, name: InFile<&SyntaxNode>) -> H | |||
|     let ctx = span_map.span_at(name.value.text_range().start()).ctx; | ||||
|     HygieneId::new(ctx.opaque_and_semitransparent(db)) | ||||
| } | ||||
| 
 | ||||
| fn type_of_expr_including_adjust(infer: &InferenceResult, id: ExprId) -> Option<&Ty> { | ||||
|     match infer.expr_adjustment(id).and_then(|adjustments| adjustments.last()) { | ||||
|         Some(adjustment) => Some(&adjustment.target), | ||||
|         None => Some(&infer[id]), | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -127,6 +127,30 @@ impl Foo for () { | |||
| 
 | ||||
| fn foo(v: Enum<()>) { | ||||
|     let Enum::A = v; | ||||
| } | ||||
|         "#,
 | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn regression_20259() { | ||||
|         check_diagnostics( | ||||
|             r#" | ||||
| //- minicore: deref
 | ||||
| use core::ops::Deref; | ||||
| 
 | ||||
| struct Foo<T>(T); | ||||
| 
 | ||||
| impl<T> Deref for Foo<T> { | ||||
|     type Target = T; | ||||
| 
 | ||||
|     fn deref(&self) -> &Self::Target { | ||||
|         &self.0 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn test(x: Foo<(i32, bool)>) { | ||||
|     let (_a, _b): &(i32, bool) = &x; | ||||
| } | ||||
| "#,
 | ||||
|         ); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Shoyu Vanilla
						Shoyu Vanilla