fix: add a new assignment kind instead of using a boolean

This commit is contained in:
rvcas 2024-06-25 18:35:42 -04:00 committed by Lucas
parent f1cfc84e67
commit 5bdea11cc1
4 changed files with 25 additions and 12 deletions

View File

@ -1679,6 +1679,7 @@ pub type TypedAssignmentKind = AssignmentKind<()>;
#[derive(Debug, Clone, PartialEq, Eq, Copy, serde::Serialize, serde::Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Copy, serde::Serialize, serde::Deserialize)]
pub enum AssignmentKind<T> { pub enum AssignmentKind<T> {
Is,
Let { backpassing: T }, Let { backpassing: T },
Expect { backpassing: T }, Expect { backpassing: T },
} }
@ -1686,6 +1687,7 @@ pub enum AssignmentKind<T> {
impl From<UntypedAssignmentKind> for TypedAssignmentKind { impl From<UntypedAssignmentKind> for TypedAssignmentKind {
fn from(kind: UntypedAssignmentKind) -> TypedAssignmentKind { fn from(kind: UntypedAssignmentKind) -> TypedAssignmentKind {
match kind { match kind {
AssignmentKind::Is => AssignmentKind::Is,
AssignmentKind::Let { .. } => AssignmentKind::Let { backpassing: () }, AssignmentKind::Let { .. } => AssignmentKind::Let { backpassing: () },
AssignmentKind::Expect { .. } => AssignmentKind::Expect { backpassing: () }, AssignmentKind::Expect { .. } => AssignmentKind::Expect { backpassing: () },
} }
@ -1701,8 +1703,13 @@ impl<T> AssignmentKind<T> {
matches!(self, AssignmentKind::Expect { .. }) matches!(self, AssignmentKind::Expect { .. })
} }
pub fn if_is(&self) -> bool {
matches!(self, AssignmentKind::Is)
}
pub fn location_offset(&self) -> usize { pub fn location_offset(&self) -> usize {
match self { match self {
AssignmentKind::Is => 2,
AssignmentKind::Let { .. } => 3, AssignmentKind::Let { .. } => 3,
AssignmentKind::Expect { .. } => 6, AssignmentKind::Expect { .. } => 6,
} }
@ -1712,6 +1719,7 @@ impl<T> AssignmentKind<T> {
impl AssignmentKind<bool> { impl AssignmentKind<bool> {
pub fn is_backpassing(&self) -> bool { pub fn is_backpassing(&self) -> bool {
match self { match self {
Self::Is => unreachable!(),
Self::Let { backpassing } | Self::Expect { backpassing } => *backpassing, Self::Let { backpassing } | Self::Expect { backpassing } => *backpassing,
} }
} }
@ -1724,6 +1732,10 @@ impl<T: Default> AssignmentKind<T> {
} }
} }
pub fn is() -> Self {
AssignmentKind::Is
}
pub fn expect() -> Self { pub fn expect() -> Self {
AssignmentKind::Expect { AssignmentKind::Expect {
backpassing: Default::default(), backpassing: Default::default(),

View File

@ -703,6 +703,7 @@ impl<'comments> Formatter<'comments> {
kind: UntypedAssignmentKind, kind: UntypedAssignmentKind,
) -> Document<'a> { ) -> Document<'a> {
let keyword = match kind { let keyword = match kind {
AssignmentKind::Is => unreachable!(),
AssignmentKind::Let { .. } => "let", AssignmentKind::Let { .. } => "let",
AssignmentKind::Expect { .. } => "expect", AssignmentKind::Expect { .. } => "expect",
}; };

View File

@ -2691,7 +2691,7 @@ fn if_soft_cast_unused_pattern() {
} }
"#; "#;
let (warnings, _ast) = dbg!(check(parse(source_code))).unwrap(); let (warnings, _ast) = check(parse(source_code)).unwrap();
assert!(matches!( assert!(matches!(
warnings[0], warnings[0],
@ -2716,7 +2716,7 @@ fn if_soft_cast_not_data() {
} }
"#; "#;
let (warnings, _ast) = dbg!(check(parse(source_code))).unwrap(); let (warnings, _ast) = check(parse(source_code)).unwrap();
assert!(matches!(warnings[0], Warning::UseWhenInstead { .. })) assert!(matches!(warnings[0], Warning::UseWhenInstead { .. }))
} }

View File

@ -510,7 +510,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
location: _, location: _,
} = patterns.into_vec().swap_remove(0); } = patterns.into_vec().swap_remove(0);
self.infer_assignment(pattern, *value, kind, &annotation, location, true) self.infer_assignment(pattern, *value, kind, &annotation, location)
} }
UntypedExpr::Trace { UntypedExpr::Trace {
@ -1182,7 +1182,6 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
kind: UntypedAssignmentKind, kind: UntypedAssignmentKind,
annotation: &Option<Annotation>, annotation: &Option<Annotation>,
location: Span, location: Span,
check_exhaustiveness: bool,
) -> Result<TypedExpr, Error> { ) -> Result<TypedExpr, Error> {
let typed_value = self.infer(untyped_value.clone())?; let typed_value = self.infer(untyped_value.clone())?;
let mut value_typ = typed_value.tipo(); let mut value_typ = typed_value.tipo();
@ -1199,7 +1198,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
ann_typ.clone(), ann_typ.clone(),
value_typ.clone(), value_typ.clone(),
typed_value.type_defining_location(), typed_value.type_defining_location(),
(kind.is_let() && ann_typ.is_data()) || kind.is_expect(), (kind.is_let() && ann_typ.is_data()) || kind.is_expect() || kind.if_is(),
)?; )?;
value_typ = ann_typ.clone(); value_typ = ann_typ.clone();
@ -1240,11 +1239,13 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
// If `expect` is explicitly used, we still check exhaustiveness but instead of returning an // If `expect` is explicitly used, we still check exhaustiveness but instead of returning an
// error we emit a warning which explains that using `expect` is unnecessary. // error we emit a warning which explains that using `expect` is unnecessary.
match kind { match kind {
AssignmentKind::Let { .. } if check_exhaustiveness => self AssignmentKind::Is => (),
.environment AssignmentKind::Let { .. } => {
.check_exhaustiveness(&[&pattern], location, true)?, self.environment
.check_exhaustiveness(&[&pattern], location, true)?
}
AssignmentKind::Expect { .. } if check_exhaustiveness => { AssignmentKind::Expect { .. } => {
let is_exaustive_pattern = self let is_exaustive_pattern = self
.environment .environment
.check_exhaustiveness(&[&pattern], location, false) .check_exhaustiveness(&[&pattern], location, false)
@ -1292,7 +1293,6 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
}); });
} }
} }
_ => (),
} }
Ok(TypedExpr::Assignment { Ok(TypedExpr::Assignment {
@ -1749,10 +1749,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
let TypedExpr::Assignment { value, pattern, .. } = typer.infer_assignment( let TypedExpr::Assignment { value, pattern, .. } = typer.infer_assignment(
pattern, pattern,
branch.condition.clone(), branch.condition.clone(),
AssignmentKind::expect(), AssignmentKind::is(),
&annotation, &annotation,
location, location,
false,
)? )?
else { else {
unreachable!() unreachable!()
@ -2104,6 +2103,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
.into(), .into(),
// erase backpassing while preserving assignment kind. // erase backpassing while preserving assignment kind.
kind: match kind { kind: match kind {
AssignmentKind::Is => unreachable!(),
AssignmentKind::Let { .. } => AssignmentKind::let_(), AssignmentKind::Let { .. } => AssignmentKind::let_(),
AssignmentKind::Expect { .. } AssignmentKind::Expect { .. }
if pattern_is_var && annotation.is_none() => if pattern_is_var && annotation.is_none() =>