mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-29 02:52:11 +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,10 +412,16 @@ impl Printer<'_> {
|
||||||
p.print_expr(field.expr);
|
p.print_expr(field.expr);
|
||||||
wln!(p, ",");
|
wln!(p, ",");
|
||||||
}
|
}
|
||||||
if let Some(spread) = spread {
|
match spread {
|
||||||
w!(p, "..");
|
Spread::No => {}
|
||||||
p.print_expr(*spread);
|
Spread::Yes => {
|
||||||
wln!(p);
|
w!(p, "..");
|
||||||
|
}
|
||||||
|
Spread::Base(expr) => {
|
||||||
|
w!(p, "..");
|
||||||
|
p.print_expr(*expr);
|
||||||
|
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