floats iter 3.4: typecheck rejects Pattern::Lit Float with FloatPatternNotAllowed
This commit is contained in:
@@ -511,4 +511,47 @@ mod tests {
|
|||||||
"io/print_float must accumulate IO effect, got {effects:?}"
|
"io/print_float must accumulate IO effect, got {effects:?}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iter 22-floats.3: pattern-matching on Float literals is hard-
|
||||||
|
/// rejected at typecheck per spec line 723-735 recommendation (a).
|
||||||
|
/// IEEE-`==` semantics make Float patterns semantically dubious
|
||||||
|
/// (NaN never matches; equality is bit-exact not approximate).
|
||||||
|
/// Surface lex / parser accept the syntax (iter 2); typecheck
|
||||||
|
/// surfaces the error here.
|
||||||
|
#[test]
|
||||||
|
fn reject_float_pattern_in_match() {
|
||||||
|
use ailang_core::ast::{Arm, Pattern};
|
||||||
|
let bits = 1.5_f64.to_bits();
|
||||||
|
let scrut = lit_float(bits);
|
||||||
|
let arm = Arm {
|
||||||
|
pat: Pattern::Lit { lit: Literal::Float { bits } },
|
||||||
|
body: lit_int(0),
|
||||||
|
};
|
||||||
|
let term = Term::Match {
|
||||||
|
scrutinee: Box::new(scrut),
|
||||||
|
arms: vec![arm],
|
||||||
|
};
|
||||||
|
let mut env = Env::default();
|
||||||
|
install(&mut env);
|
||||||
|
let mut locals: IndexMap<String, Type> = IndexMap::new();
|
||||||
|
let mut effects: BTreeSet<String> = BTreeSet::new();
|
||||||
|
let mut subst = Subst::default();
|
||||||
|
let mut counter: u32 = 0;
|
||||||
|
let mut residuals = Vec::new();
|
||||||
|
let err = crate::synth(
|
||||||
|
&term,
|
||||||
|
&env,
|
||||||
|
&mut locals,
|
||||||
|
&mut effects,
|
||||||
|
"<test>",
|
||||||
|
&mut subst,
|
||||||
|
&mut counter,
|
||||||
|
&mut residuals,
|
||||||
|
)
|
||||||
|
.expect_err("must reject");
|
||||||
|
assert!(
|
||||||
|
matches!(err, crate::CheckError::FloatPatternNotAllowed),
|
||||||
|
"expected FloatPatternNotAllowed, got {err:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -370,6 +370,15 @@ pub enum CheckError {
|
|||||||
#[error("primitive type `{0}` requires a wildcard or variable arm in match")]
|
#[error("primitive type `{0}` requires a wildcard or variable arm in match")]
|
||||||
PrimitiveNeedsWildcard(String),
|
PrimitiveNeedsWildcard(String),
|
||||||
|
|
||||||
|
/// A `Pattern::Lit` matched against a `Literal::Float`. Float
|
||||||
|
/// patterns are semantically dubious (NaN never matches via
|
||||||
|
/// IEEE-`==`; equality is bit-exact not approximate), so the
|
||||||
|
/// typechecker hard-rejects them. The surface lex / parser
|
||||||
|
/// accept the syntax (iter 2); this diagnostic surfaces at
|
||||||
|
/// typecheck time. Code: `float-pattern-not-allowed`.
|
||||||
|
#[error("float-literal patterns are not allowed: use ordering operators (`<`, `>`, ...) and `is_nan` to discriminate floats")]
|
||||||
|
FloatPatternNotAllowed,
|
||||||
|
|
||||||
/// A `Pattern::Ctor` was matched against a value of a different ADT.
|
/// A `Pattern::Ctor` was matched against a value of a different ADT.
|
||||||
/// Code: `pattern-type-mismatch`.
|
/// Code: `pattern-type-mismatch`.
|
||||||
#[error("cannot match constructor pattern `{ctor}` against type `{ty}`")]
|
#[error("cannot match constructor pattern `{ctor}` against type `{ty}`")]
|
||||||
@@ -521,6 +530,7 @@ impl CheckError {
|
|||||||
CheckError::CtorArity { .. } => "arity-mismatch",
|
CheckError::CtorArity { .. } => "arity-mismatch",
|
||||||
CheckError::NonExhaustive { .. } => "non-exhaustive-match",
|
CheckError::NonExhaustive { .. } => "non-exhaustive-match",
|
||||||
CheckError::PrimitiveNeedsWildcard(_) => "primitive-needs-wildcard",
|
CheckError::PrimitiveNeedsWildcard(_) => "primitive-needs-wildcard",
|
||||||
|
CheckError::FloatPatternNotAllowed => "float-pattern-not-allowed",
|
||||||
CheckError::PatternTypeMismatch { .. } => "pattern-type-mismatch",
|
CheckError::PatternTypeMismatch { .. } => "pattern-type-mismatch",
|
||||||
CheckError::DuplicateType(_) => "duplicate-type",
|
CheckError::DuplicateType(_) => "duplicate-type",
|
||||||
CheckError::DuplicateCtor { .. } => "duplicate-ctor",
|
CheckError::DuplicateCtor { .. } => "duplicate-ctor",
|
||||||
@@ -2309,7 +2319,9 @@ fn type_check_pattern(
|
|||||||
Literal::Bool { .. } => Type::bool_(),
|
Literal::Bool { .. } => Type::bool_(),
|
||||||
Literal::Str { .. } => Type::str_(),
|
Literal::Str { .. } => Type::str_(),
|
||||||
Literal::Unit => Type::unit(),
|
Literal::Unit => Type::unit(),
|
||||||
Literal::Float { .. } => Type::float(),
|
Literal::Float { .. } => {
|
||||||
|
return Err(CheckError::FloatPatternNotAllowed);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
expect_eq(expected, <)?;
|
expect_eq(expected, <)?;
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
|
|||||||
Reference in New Issue
Block a user