mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-30 19:49:36 +00:00 
			
		
		
		
	Merge pull request #19111 from ShoyuVanilla/issue-19021
fix: Apply adjustments to proper expr when invoking `CoerceMany`
This commit is contained in:
		
						commit
						c9838ec62d
					
				
					 4 changed files with 89 additions and 9 deletions
				
			
		|  | @ -1239,7 +1239,29 @@ impl<'a> InferenceContext<'a> { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn write_expr_adj(&mut self, expr: ExprId, adjustments: Vec<Adjustment>) { |     fn write_expr_adj(&mut self, expr: ExprId, adjustments: Vec<Adjustment>) { | ||||||
|         self.result.expr_adjustments.insert(expr, adjustments); |         if adjustments.is_empty() { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         match self.result.expr_adjustments.entry(expr) { | ||||||
|  |             std::collections::hash_map::Entry::Occupied(mut entry) => { | ||||||
|  |                 match (&mut entry.get_mut()[..], &adjustments[..]) { | ||||||
|  |                     ( | ||||||
|  |                         [Adjustment { kind: Adjust::NeverToAny, target }], | ||||||
|  |                         [.., Adjustment { target: new_target, .. }], | ||||||
|  |                     ) => { | ||||||
|  |                         // NeverToAny coercion can target any type, so instead of adding a new
 | ||||||
|  |                         // adjustment on top we can change the target.
 | ||||||
|  |                         *target = new_target.clone(); | ||||||
|  |                     } | ||||||
|  |                     _ => { | ||||||
|  |                         *entry.get_mut() = adjustments; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             std::collections::hash_map::Entry::Vacant(entry) => { | ||||||
|  |                 entry.insert(adjustments); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) { |     fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) { | ||||||
|  |  | ||||||
|  | @ -163,10 +163,27 @@ impl CoerceMany { | ||||||
|         // type is a type variable and the new one is `!`, trying it the other
 |         // type is a type variable and the new one is `!`, trying it the other
 | ||||||
|         // way around first would mean we make the type variable `!`, instead of
 |         // way around first would mean we make the type variable `!`, instead of
 | ||||||
|         // just marking it as possibly diverging.
 |         // just marking it as possibly diverging.
 | ||||||
|  |         //
 | ||||||
|  |         // - [Comment from rustc](https://github.com/rust-lang/rust/blob/5ff18d0eaefd1bd9ab8ec33dab2404a44e7631ed/compiler/rustc_hir_typeck/src/coercion.rs#L1334-L1335)
 | ||||||
|  |         // First try to coerce the new expression to the type of the previous ones,
 | ||||||
|  |         // but only if the new expression has no coercion already applied to it.
 | ||||||
|  |         if expr.is_none_or(|expr| !ctx.result.expr_adjustments.contains_key(&expr)) { | ||||||
|             if let Ok(res) = ctx.coerce(expr, &expr_ty, &self.merged_ty(), CoerceNever::Yes) { |             if let Ok(res) = ctx.coerce(expr, &expr_ty, &self.merged_ty(), CoerceNever::Yes) { | ||||||
|                 self.final_ty = Some(res); |                 self.final_ty = Some(res); | ||||||
|         } else if let Ok(res) = ctx.coerce(expr, &self.merged_ty(), &expr_ty, CoerceNever::Yes) { |                 if let Some(expr) = expr { | ||||||
|  |                     self.expressions.push(expr); | ||||||
|  |                 } | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if let Ok((adjustments, res)) = | ||||||
|  |             ctx.coerce_inner(&self.merged_ty(), &expr_ty, CoerceNever::Yes) | ||||||
|  |         { | ||||||
|             self.final_ty = Some(res); |             self.final_ty = Some(res); | ||||||
|  |             for &e in &self.expressions { | ||||||
|  |                 ctx.write_expr_adj(e, adjustments.clone()); | ||||||
|  |             } | ||||||
|         } else { |         } else { | ||||||
|             match cause { |             match cause { | ||||||
|                 CoercionCause::Expr(id) => { |                 CoercionCause::Expr(id) => { | ||||||
|  | @ -244,14 +261,23 @@ impl InferenceContext<'_> { | ||||||
|         // between places and values.
 |         // between places and values.
 | ||||||
|         coerce_never: CoerceNever, |         coerce_never: CoerceNever, | ||||||
|     ) -> Result<Ty, TypeError> { |     ) -> Result<Ty, TypeError> { | ||||||
|         let from_ty = self.resolve_ty_shallow(from_ty); |         let (adjustments, ty) = self.coerce_inner(from_ty, to_ty, coerce_never)?; | ||||||
|         let to_ty = self.resolve_ty_shallow(to_ty); |  | ||||||
|         let (adjustments, ty) = self.table.coerce(&from_ty, &to_ty, coerce_never)?; |  | ||||||
|         if let Some(expr) = expr { |         if let Some(expr) = expr { | ||||||
|             self.write_expr_adj(expr, adjustments); |             self.write_expr_adj(expr, adjustments); | ||||||
|         } |         } | ||||||
|         Ok(ty) |         Ok(ty) | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     fn coerce_inner( | ||||||
|  |         &mut self, | ||||||
|  |         from_ty: &Ty, | ||||||
|  |         to_ty: &Ty, | ||||||
|  |         coerce_never: CoerceNever, | ||||||
|  |     ) -> Result<(Vec<Adjustment>, Ty), TypeError> { | ||||||
|  |         let from_ty = self.resolve_ty_shallow(from_ty); | ||||||
|  |         let to_ty = self.resolve_ty_shallow(to_ty); | ||||||
|  |         self.table.coerce(&from_ty, &to_ty, coerce_never) | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl InferenceTable<'_> { | impl InferenceTable<'_> { | ||||||
|  |  | ||||||
|  | @ -912,3 +912,36 @@ fn main() { | ||||||
|         "", |         "", | ||||||
|     ); |     ); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | #[test] | ||||||
|  | fn regression_19021() { | ||||||
|  |     check_pass( | ||||||
|  |         r#" | ||||||
|  | //- minicore: deref
 | ||||||
|  | use core::ops::Deref; | ||||||
|  | 
 | ||||||
|  | #[lang = "owned_box"] | ||||||
|  | struct Box<T>(T); | ||||||
|  | 
 | ||||||
|  | impl<T> Deref for Box<T> { | ||||||
|  |     type Target = T; | ||||||
|  | 
 | ||||||
|  |     fn deref(&self) -> &Self::Target { | ||||||
|  |         &self.0 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct Foo; | ||||||
|  | 
 | ||||||
|  | fn main() { | ||||||
|  |     let x = Box(Foo); | ||||||
|  |     let y = &Foo; | ||||||
|  | 
 | ||||||
|  |     || match x { | ||||||
|  |         ref x => x, | ||||||
|  |         _ => y, | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | "#,
 | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -185,11 +185,10 @@ fn test() { | ||||||
|     let t = &mut 1; |     let t = &mut 1; | ||||||
|     let x = match 1 { |     let x = match 1 { | ||||||
|         1 => t as *mut i32, |         1 => t as *mut i32, | ||||||
|  |            //^^^^^^^^^^^^^ adjustments: Pointer(MutToConstPointer)
 | ||||||
|         2 => t as &i32, |         2 => t as &i32, | ||||||
|            //^^^^^^^^^ expected *mut i32, got &'? i32
 |            //^^^^^^^^^ expected *mut i32, got &'? i32
 | ||||||
|         _ => t as *const i32, |         _ => t as *const i32, | ||||||
|           // ^^^^^^^^^^^^^^^ adjustments: Pointer(MutToConstPointer)
 |  | ||||||
| 
 |  | ||||||
|     }; |     }; | ||||||
|     x; |     x; | ||||||
|   //^ type: *const i32
 |   //^ type: *const i32
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lukas Wirth
						Lukas Wirth