From c134b20c9cbc88a36e77acb8522e8dc4573bd906 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Sun, 26 Jan 2025 17:23:23 +0900 Subject: [PATCH] Merge record lit's ellipsis into pre-existing spread's variant --- crates/hir-def/src/expr_store.rs | 6 +++--- crates/hir-def/src/expr_store/lower.rs | 12 +++++++----- crates/hir-def/src/expr_store/pretty.rs | 18 ++++++++++++------ crates/hir-def/src/hir.rs | 10 ++++++++-- crates/hir-ty/src/diagnostics/expr.rs | 13 ++++++++----- crates/hir-ty/src/infer/closure.rs | 4 ++-- crates/hir-ty/src/infer/expr.rs | 4 ++-- crates/hir-ty/src/infer/mutability.rs | 12 ++++++++---- crates/hir-ty/src/mir/lower.rs | 8 ++++---- crates/hir/src/source_analyzer.rs | 2 +- 10 files changed, 55 insertions(+), 34 deletions(-) diff --git a/crates/hir-def/src/expr_store.rs b/crates/hir-def/src/expr_store.rs index 9df6eaade7..d0695d0eac 100644 --- a/crates/hir-def/src/expr_store.rs +++ b/crates/hir-def/src/expr_store.rs @@ -25,7 +25,7 @@ use crate::{ db::DefDatabase, hir::{ Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label, LabelId, Pat, - PatId, RecordFieldPat, Statement, + PatId, RecordFieldPat, Spread, Statement, }, nameres::DefMap, path::{ModPath, Path}, @@ -362,7 +362,7 @@ impl ExpressionStore { for field in fields.iter() { f(field.expr); } - if let &Some(expr) = spread { + if let &Spread::Base(expr) = spread { f(expr); } } @@ -490,7 +490,7 @@ impl ExpressionStore { for field in fields.iter() { f(field.expr); } - if let &Some(expr) = spread { + if let &Spread::Base(expr) = spread { f(expr); } } diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index 65580bce4d..3ce00b78a9 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -45,7 +45,7 @@ use crate::{ }, Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind, 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, lang_item::LangItem, @@ -602,11 +602,13 @@ impl ExprCollector<'_> { Some(RecordLitField { name, expr }) }) .collect(); - let spread = nfl.spread().map(|s| self.collect_expr(s)); - let ellipsis = nfl.dotdot_token().is_some(); - Expr::RecordLit { path, fields, spread, ellipsis } + let spread = nfl.spread().map(|s| self.collect_expr(s)).map_or_else( + || if nfl.dotdot_token().is_some() { Spread::Yes } else { Spread::No }, + Spread::Base, + ); + Expr::RecordLit { path, fields, spread } } 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) diff --git a/crates/hir-def/src/expr_store/pretty.rs b/crates/hir-def/src/expr_store/pretty.rs index 9a8a8c2cd0..1b3a1bb4dc 100644 --- a/crates/hir-def/src/expr_store/pretty.rs +++ b/crates/hir-def/src/expr_store/pretty.rs @@ -8,7 +8,7 @@ use span::Edition; use crate::{ hir::{ Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, LiteralOrConst, Movability, - Statement, + Spread, Statement, }, pretty::{print_generic_args, print_path, print_type_ref}, VariantId, @@ -398,7 +398,7 @@ impl Printer<'_> { self.print_expr(*expr); } } - Expr::RecordLit { path, fields, spread, ellipsis: _ } => { + Expr::RecordLit { path, fields, spread } => { match path { Some(path) => self.print_path(path), None => w!(self, "�"), @@ -412,10 +412,16 @@ impl Printer<'_> { p.print_expr(field.expr); wln!(p, ","); } - if let Some(spread) = spread { - w!(p, ".."); - p.print_expr(*spread); - wln!(p); + match spread { + Spread::No => {} + Spread::Yes => { + w!(p, ".."); + } + Spread::Base(expr) => { + w!(p, ".."); + p.print_expr(*expr); + wln!(p); + } } }); w!(self, "}}"); diff --git a/crates/hir-def/src/hir.rs b/crates/hir-def/src/hir.rs index 1e2417ecdf..e09ce67a89 100644 --- a/crates/hir-def/src/hir.rs +++ b/crates/hir-def/src/hir.rs @@ -251,8 +251,7 @@ pub enum Expr { RecordLit { path: Option>, fields: Box<[RecordLitField]>, - spread: Option, - ellipsis: bool, + spread: Spread, }, Field { expr: ExprId, @@ -479,6 +478,13 @@ pub struct RecordLitField { pub expr: ExprId, } +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum Spread { + No, + Yes, + Base(ExprId), +} + #[derive(Debug, Clone, Eq, PartialEq)] pub enum Statement { Let { diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs index d8700e2777..dd55febbf0 100644 --- a/crates/hir-ty/src/diagnostics/expr.rs +++ b/crates/hir-ty/src/diagnostics/expr.rs @@ -8,6 +8,7 @@ use base_db::CrateId; use chalk_solve::rust_ir::AdtKind; use either::Either; use hir_def::{ + hir::Spread, lang_item::LangItem, resolver::{HasResolver, ValueNs}, AdtId, AssocItemId, DefWithBodyId, HasModule, ItemContainerId, Lookup, @@ -546,9 +547,11 @@ pub fn record_literal_missing_fields( infer: &InferenceResult, id: ExprId, expr: &Expr, -) -> Option<(VariantId, Vec, /*exhaustive*/ bool)> { - let (fields, exhaustive, ellipsis) = match expr { - Expr::RecordLit { fields, spread, ellipsis, .. } => (fields, spread.is_none(), *ellipsis), +) -> Option<(VariantId, Vec, /*has spread expr*/ bool)> { + let (fields, has_spread_expr, has_ellipsis) = match expr { + Expr::RecordLit { fields, spread, .. } => { + (fields, matches!(spread, Spread::Base(_)), matches!(spread, Spread::Yes)) + } _ => return None, }; @@ -564,7 +567,7 @@ pub fn record_literal_missing_fields( .fields() .iter() .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 } else { Some(f) @@ -574,7 +577,7 @@ pub fn record_literal_missing_fields( if missed_fields.is_empty() { return None; } - Some((variant_def, missed_fields, exhaustive)) + Some((variant_def, missed_fields, has_spread_expr)) } pub fn record_pattern_missing_fields( diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index 9283c46d0f..0e9aed4160 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -12,7 +12,7 @@ use hir_def::{ data::adt::VariantData, hir::{ Array, AsmOperand, BinaryOp, BindingId, CaptureBy, Expr, ExprId, ExprOrPatId, Pat, PatId, - Statement, UnaryOp, + Spread, Statement, UnaryOp, }, lang_item::LangItem, path::Path, @@ -796,7 +796,7 @@ impl InferenceContext<'_> { self.consume_expr(expr); } Expr::RecordLit { fields, spread, .. } => { - if let &Some(expr) = spread { + if let &Spread::Base(expr) = spread { self.consume_expr(expr); } self.consume_exprs(fields.iter().map(|it| it.expr)); diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index b951443897..8b3ec1ff2a 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -10,7 +10,7 @@ use either::Either; use hir_def::{ hir::{ 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}, 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); } ty diff --git a/crates/hir-ty/src/infer/mutability.rs b/crates/hir-ty/src/infer/mutability.rs index 5b6c3cd152..e95a425498 100644 --- a/crates/hir-ty/src/infer/mutability.rs +++ b/crates/hir-ty/src/infer/mutability.rs @@ -4,8 +4,8 @@ use chalk_ir::{cast::Cast, Mutability}; use hir_def::{ hir::{ - Array, AsmOperand, BinaryOp, BindingAnnotation, Expr, ExprId, Pat, PatId, Statement, - UnaryOp, + Array, AsmOperand, BinaryOp, BindingAnnotation, Expr, ExprId, Pat, PatId, Spread, + Statement, UnaryOp, }, lang_item::LangItem, }; @@ -121,8 +121,12 @@ impl InferenceContext<'_> { Expr::Become { expr } => { self.infer_mut_expr(*expr, Mutability::Not); } - Expr::RecordLit { path: _, fields, spread, ellipsis: _ } => { - self.infer_mut_not_expr_iter(fields.iter().map(|it| it.expr).chain(*spread)) + Expr::RecordLit { path: _, fields, 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 } => { if mutability == Mutability::Mut { diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 85e8d17203..5d89ebd4ef 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -9,7 +9,7 @@ use hir_def::{ expr_store::{Body, HygieneId}, hir::{ 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}, path::Path, @@ -823,16 +823,16 @@ impl<'ctx> MirLowerCtx<'ctx> { } Expr::Become { .. } => not_supported!("tail-calls"), Expr::Yield { .. } => not_supported!("yield"), - Expr::RecordLit { fields, path, spread, ellipsis: _ } => { + Expr::RecordLit { fields, path, spread } => { let spread_place = match spread { - &Some(it) => { + &Spread::Base(it) => { let Some((p, c)) = self.lower_expr_as_place(current, it, true)? else { return Ok(None); }; current = c; Some(p) } - None => None, + _ => None, }; let variant_id = self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| match path { diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 496b6566bd..653c858e58 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -1023,7 +1023,7 @@ impl SourceAnalyzer { let expr_id = self.expr_id(db, &literal.clone().into())?; 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) => { record_literal_missing_fields(db, infer, expr_id, &body[expr_id])? }