mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-30 19:49:36 +00:00 
			
		
		
		
	Merge record lit's ellipsis into pre-existing spread's variant
This commit is contained in:
		
							parent
							
								
									e6a103ae50
								
							
						
					
					
						commit
						c134b20c9c
					
				
					 10 changed files with 55 additions and 34 deletions
				
			
		|  | @ -25,7 +25,7 @@ use crate::{ | ||||||
|     db::DefDatabase, |     db::DefDatabase, | ||||||
|     hir::{ |     hir::{ | ||||||
|         Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label, LabelId, Pat, |         Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label, LabelId, Pat, | ||||||
|         PatId, RecordFieldPat, Statement, |         PatId, RecordFieldPat, Spread, Statement, | ||||||
|     }, |     }, | ||||||
|     nameres::DefMap, |     nameres::DefMap, | ||||||
|     path::{ModPath, Path}, |     path::{ModPath, Path}, | ||||||
|  | @ -362,7 +362,7 @@ impl ExpressionStore { | ||||||
|                 for field in fields.iter() { |                 for field in fields.iter() { | ||||||
|                     f(field.expr); |                     f(field.expr); | ||||||
|                 } |                 } | ||||||
|                 if let &Some(expr) = spread { |                 if let &Spread::Base(expr) = spread { | ||||||
|                     f(expr); |                     f(expr); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | @ -490,7 +490,7 @@ impl ExpressionStore { | ||||||
|                 for field in fields.iter() { |                 for field in fields.iter() { | ||||||
|                     f(field.expr); |                     f(field.expr); | ||||||
|                 } |                 } | ||||||
|                 if let &Some(expr) = spread { |                 if let &Spread::Base(expr) = spread { | ||||||
|                     f(expr); |                     f(expr); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  | @ -45,7 +45,7 @@ use crate::{ | ||||||
|         }, |         }, | ||||||
|         Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind, |         Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind, | ||||||
|         Expr, ExprId, Item, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability, |         Expr, ExprId, Item, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability, | ||||||
|         OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, Statement, |         OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, Spread, Statement, | ||||||
|     }, |     }, | ||||||
|     item_scope::BuiltinShadowMode, |     item_scope::BuiltinShadowMode, | ||||||
|     lang_item::LangItem, |     lang_item::LangItem, | ||||||
|  | @ -602,11 +602,13 @@ impl ExprCollector<'_> { | ||||||
|                             Some(RecordLitField { name, expr }) |                             Some(RecordLitField { name, expr }) | ||||||
|                         }) |                         }) | ||||||
|                         .collect(); |                         .collect(); | ||||||
|                     let spread = nfl.spread().map(|s| self.collect_expr(s)); |                     let spread = nfl.spread().map(|s| self.collect_expr(s)).map_or_else( | ||||||
|                     let ellipsis = nfl.dotdot_token().is_some(); |                         || if nfl.dotdot_token().is_some() { Spread::Yes } else { Spread::No }, | ||||||
|                     Expr::RecordLit { path, fields, spread, ellipsis } |                         Spread::Base, | ||||||
|  |                     ); | ||||||
|  |                     Expr::RecordLit { path, fields, spread } | ||||||
|                 } else { |                 } else { | ||||||
|                     Expr::RecordLit { path, fields: Box::default(), spread: None, ellipsis: false } |                     Expr::RecordLit { path, fields: Box::default(), spread: Spread::No } | ||||||
|                 }; |                 }; | ||||||
| 
 | 
 | ||||||
|                 self.alloc_expr(record_lit, syntax_ptr) |                 self.alloc_expr(record_lit, syntax_ptr) | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ use span::Edition; | ||||||
| use crate::{ | use crate::{ | ||||||
|     hir::{ |     hir::{ | ||||||
|         Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, LiteralOrConst, Movability, |         Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, LiteralOrConst, Movability, | ||||||
|         Statement, |         Spread, Statement, | ||||||
|     }, |     }, | ||||||
|     pretty::{print_generic_args, print_path, print_type_ref}, |     pretty::{print_generic_args, print_path, print_type_ref}, | ||||||
|     VariantId, |     VariantId, | ||||||
|  | @ -398,7 +398,7 @@ impl Printer<'_> { | ||||||
|                     self.print_expr(*expr); |                     self.print_expr(*expr); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             Expr::RecordLit { path, fields, spread, ellipsis: _ } => { |             Expr::RecordLit { path, fields, spread } => { | ||||||
|                 match path { |                 match path { | ||||||
|                     Some(path) => self.print_path(path), |                     Some(path) => self.print_path(path), | ||||||
|                     None => w!(self, "<EFBFBD>"), |                     None => w!(self, "<EFBFBD>"), | ||||||
|  | @ -412,11 +412,17 @@ impl Printer<'_> { | ||||||
|                         p.print_expr(field.expr); |                         p.print_expr(field.expr); | ||||||
|                         wln!(p, ","); |                         wln!(p, ","); | ||||||
|                     } |                     } | ||||||
|                     if let Some(spread) = spread { |                     match spread { | ||||||
|  |                         Spread::No => {} | ||||||
|  |                         Spread::Yes => { | ||||||
|                             w!(p, ".."); |                             w!(p, ".."); | ||||||
|                         p.print_expr(*spread); |                         } | ||||||
|  |                         Spread::Base(expr) => { | ||||||
|  |                             w!(p, ".."); | ||||||
|  |                             p.print_expr(*expr); | ||||||
|                             wln!(p); |                             wln!(p); | ||||||
|                         } |                         } | ||||||
|  |                     } | ||||||
|                 }); |                 }); | ||||||
|                 w!(self, "}}"); |                 w!(self, "}}"); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  | @ -251,8 +251,7 @@ pub enum Expr { | ||||||
|     RecordLit { |     RecordLit { | ||||||
|         path: Option<Box<Path>>, |         path: Option<Box<Path>>, | ||||||
|         fields: Box<[RecordLitField]>, |         fields: Box<[RecordLitField]>, | ||||||
|         spread: Option<ExprId>, |         spread: Spread, | ||||||
|         ellipsis: bool, |  | ||||||
|     }, |     }, | ||||||
|     Field { |     Field { | ||||||
|         expr: ExprId, |         expr: ExprId, | ||||||
|  | @ -479,6 +478,13 @@ pub struct RecordLitField { | ||||||
|     pub expr: ExprId, |     pub expr: ExprId, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[derive(Debug, Clone, Eq, PartialEq)] | ||||||
|  | pub enum Spread { | ||||||
|  |     No, | ||||||
|  |     Yes, | ||||||
|  |     Base(ExprId), | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[derive(Debug, Clone, Eq, PartialEq)] | #[derive(Debug, Clone, Eq, PartialEq)] | ||||||
| pub enum Statement { | pub enum Statement { | ||||||
|     Let { |     Let { | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ use base_db::CrateId; | ||||||
| use chalk_solve::rust_ir::AdtKind; | use chalk_solve::rust_ir::AdtKind; | ||||||
| use either::Either; | use either::Either; | ||||||
| use hir_def::{ | use hir_def::{ | ||||||
|  |     hir::Spread, | ||||||
|     lang_item::LangItem, |     lang_item::LangItem, | ||||||
|     resolver::{HasResolver, ValueNs}, |     resolver::{HasResolver, ValueNs}, | ||||||
|     AdtId, AssocItemId, DefWithBodyId, HasModule, ItemContainerId, Lookup, |     AdtId, AssocItemId, DefWithBodyId, HasModule, ItemContainerId, Lookup, | ||||||
|  | @ -546,9 +547,11 @@ pub fn record_literal_missing_fields( | ||||||
|     infer: &InferenceResult, |     infer: &InferenceResult, | ||||||
|     id: ExprId, |     id: ExprId, | ||||||
|     expr: &Expr, |     expr: &Expr, | ||||||
| ) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> { | ) -> Option<(VariantId, Vec<LocalFieldId>, /*has spread expr*/ bool)> { | ||||||
|     let (fields, exhaustive, ellipsis) = match expr { |     let (fields, has_spread_expr, has_ellipsis) = match expr { | ||||||
|         Expr::RecordLit { fields, spread, ellipsis, .. } => (fields, spread.is_none(), *ellipsis), |         Expr::RecordLit { fields, spread, .. } => { | ||||||
|  |             (fields, matches!(spread, Spread::Base(_)), matches!(spread, Spread::Yes)) | ||||||
|  |         } | ||||||
|         _ => return None, |         _ => return None, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  | @ -564,7 +567,7 @@ pub fn record_literal_missing_fields( | ||||||
|         .fields() |         .fields() | ||||||
|         .iter() |         .iter() | ||||||
|         .filter_map(|(f, d)| { |         .filter_map(|(f, d)| { | ||||||
|             if (ellipsis && d.has_default) || specified_fields.contains(&d.name) { |             if (has_ellipsis && d.has_default) || specified_fields.contains(&d.name) { | ||||||
|                 None |                 None | ||||||
|             } else { |             } else { | ||||||
|                 Some(f) |                 Some(f) | ||||||
|  | @ -574,7 +577,7 @@ pub fn record_literal_missing_fields( | ||||||
|     if missed_fields.is_empty() { |     if missed_fields.is_empty() { | ||||||
|         return None; |         return None; | ||||||
|     } |     } | ||||||
|     Some((variant_def, missed_fields, exhaustive)) |     Some((variant_def, missed_fields, has_spread_expr)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn record_pattern_missing_fields( | pub fn record_pattern_missing_fields( | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ use hir_def::{ | ||||||
|     data::adt::VariantData, |     data::adt::VariantData, | ||||||
|     hir::{ |     hir::{ | ||||||
|         Array, AsmOperand, BinaryOp, BindingId, CaptureBy, Expr, ExprId, ExprOrPatId, Pat, PatId, |         Array, AsmOperand, BinaryOp, BindingId, CaptureBy, Expr, ExprId, ExprOrPatId, Pat, PatId, | ||||||
|         Statement, UnaryOp, |         Spread, Statement, UnaryOp, | ||||||
|     }, |     }, | ||||||
|     lang_item::LangItem, |     lang_item::LangItem, | ||||||
|     path::Path, |     path::Path, | ||||||
|  | @ -796,7 +796,7 @@ impl InferenceContext<'_> { | ||||||
|                 self.consume_expr(expr); |                 self.consume_expr(expr); | ||||||
|             } |             } | ||||||
|             Expr::RecordLit { fields, spread, .. } => { |             Expr::RecordLit { fields, spread, .. } => { | ||||||
|                 if let &Some(expr) = spread { |                 if let &Spread::Base(expr) = spread { | ||||||
|                     self.consume_expr(expr); |                     self.consume_expr(expr); | ||||||
|                 } |                 } | ||||||
|                 self.consume_exprs(fields.iter().map(|it| it.expr)); |                 self.consume_exprs(fields.iter().map(|it| it.expr)); | ||||||
|  |  | ||||||
|  | @ -10,7 +10,7 @@ use either::Either; | ||||||
| use hir_def::{ | use hir_def::{ | ||||||
|     hir::{ |     hir::{ | ||||||
|         ArithOp, Array, AsmOperand, AsmOptions, BinaryOp, ClosureKind, Expr, ExprId, ExprOrPatId, |         ArithOp, Array, AsmOperand, AsmOptions, BinaryOp, ClosureKind, Expr, ExprId, ExprOrPatId, | ||||||
|         LabelId, Literal, Pat, PatId, Statement, UnaryOp, |         LabelId, Literal, Pat, PatId, Spread, Statement, UnaryOp, | ||||||
|     }, |     }, | ||||||
|     lang_item::{LangItem, LangItemTarget}, |     lang_item::{LangItem, LangItemTarget}, | ||||||
|     path::{GenericArg, GenericArgs, Path}, |     path::{GenericArg, GenericArgs, Path}, | ||||||
|  | @ -775,7 +775,7 @@ impl InferenceContext<'_> { | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 if let Some(expr) = spread { |                 if let Spread::Base(expr) = spread { | ||||||
|                     self.infer_expr(*expr, &Expectation::has_type(ty.clone()), ExprIsRead::Yes); |                     self.infer_expr(*expr, &Expectation::has_type(ty.clone()), ExprIsRead::Yes); | ||||||
|                 } |                 } | ||||||
|                 ty |                 ty | ||||||
|  |  | ||||||
|  | @ -4,8 +4,8 @@ | ||||||
| use chalk_ir::{cast::Cast, Mutability}; | use chalk_ir::{cast::Cast, Mutability}; | ||||||
| use hir_def::{ | use hir_def::{ | ||||||
|     hir::{ |     hir::{ | ||||||
|         Array, AsmOperand, BinaryOp, BindingAnnotation, Expr, ExprId, Pat, PatId, Statement, |         Array, AsmOperand, BinaryOp, BindingAnnotation, Expr, ExprId, Pat, PatId, Spread, | ||||||
|         UnaryOp, |         Statement, UnaryOp, | ||||||
|     }, |     }, | ||||||
|     lang_item::LangItem, |     lang_item::LangItem, | ||||||
| }; | }; | ||||||
|  | @ -121,8 +121,12 @@ impl InferenceContext<'_> { | ||||||
|             Expr::Become { expr } => { |             Expr::Become { expr } => { | ||||||
|                 self.infer_mut_expr(*expr, Mutability::Not); |                 self.infer_mut_expr(*expr, Mutability::Not); | ||||||
|             } |             } | ||||||
|             Expr::RecordLit { path: _, fields, spread, ellipsis: _ } => { |             Expr::RecordLit { path: _, fields, spread } => { | ||||||
|                 self.infer_mut_not_expr_iter(fields.iter().map(|it| it.expr).chain(*spread)) |                 let spread_expr = match spread { | ||||||
|  |                     Spread::Base(expr) => Some(*expr), | ||||||
|  |                     _ => None, | ||||||
|  |                 }; | ||||||
|  |                 self.infer_mut_not_expr_iter(fields.iter().map(|it| it.expr).chain(spread_expr)) | ||||||
|             } |             } | ||||||
|             &Expr::Index { base, index } => { |             &Expr::Index { base, index } => { | ||||||
|                 if mutability == Mutability::Mut { |                 if mutability == Mutability::Mut { | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ use hir_def::{ | ||||||
|     expr_store::{Body, HygieneId}, |     expr_store::{Body, HygieneId}, | ||||||
|     hir::{ |     hir::{ | ||||||
|         ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal, |         ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal, | ||||||
|         LiteralOrConst, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField, |         LiteralOrConst, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField, Spread, | ||||||
|     }, |     }, | ||||||
|     lang_item::{LangItem, LangItemTarget}, |     lang_item::{LangItem, LangItemTarget}, | ||||||
|     path::Path, |     path::Path, | ||||||
|  | @ -823,16 +823,16 @@ impl<'ctx> MirLowerCtx<'ctx> { | ||||||
|             } |             } | ||||||
|             Expr::Become { .. } => not_supported!("tail-calls"), |             Expr::Become { .. } => not_supported!("tail-calls"), | ||||||
|             Expr::Yield { .. } => not_supported!("yield"), |             Expr::Yield { .. } => not_supported!("yield"), | ||||||
|             Expr::RecordLit { fields, path, spread, ellipsis: _ } => { |             Expr::RecordLit { fields, path, spread } => { | ||||||
|                 let spread_place = match spread { |                 let spread_place = match spread { | ||||||
|                     &Some(it) => { |                     &Spread::Base(it) => { | ||||||
|                         let Some((p, c)) = self.lower_expr_as_place(current, it, true)? else { |                         let Some((p, c)) = self.lower_expr_as_place(current, it, true)? else { | ||||||
|                             return Ok(None); |                             return Ok(None); | ||||||
|                         }; |                         }; | ||||||
|                         current = c; |                         current = c; | ||||||
|                         Some(p) |                         Some(p) | ||||||
|                     } |                     } | ||||||
|                     None => None, |                     _ => None, | ||||||
|                 }; |                 }; | ||||||
|                 let variant_id = |                 let variant_id = | ||||||
|                     self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| match path { |                     self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| match path { | ||||||
|  |  | ||||||
|  | @ -1023,7 +1023,7 @@ impl SourceAnalyzer { | ||||||
|         let expr_id = self.expr_id(db, &literal.clone().into())?; |         let expr_id = self.expr_id(db, &literal.clone().into())?; | ||||||
|         let substs = infer[expr_id].as_adt()?.1; |         let substs = infer[expr_id].as_adt()?.1; | ||||||
| 
 | 
 | ||||||
|         let (variant, missing_fields, _exhaustive) = match expr_id { |         let (variant, missing_fields, _) = match expr_id { | ||||||
|             ExprOrPatId::ExprId(expr_id) => { |             ExprOrPatId::ExprId(expr_id) => { | ||||||
|                 record_literal_missing_fields(db, infer, expr_id, &body[expr_id])? |                 record_literal_missing_fields(db, infer, expr_id, &body[expr_id])? | ||||||
|             } |             } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Shoyu Vanilla
						Shoyu Vanilla