Skip to content

Commit 5d3ca27

Browse files
committed
Const-check inline-refined top-level constants at compile time
A constant declared with an inline refined signature (x : Int 1 where \a -> a > 1) and a literal body was not checked: the inline Refined annotation erases to its base type in ast_type_to_ty, so the nominal refined-type introduction guard never fired and a violating literal silently inhabited the refined type. Evaluate the predicate against a literal or named-const body at the declaration binding and report a compile error when it fails.
1 parent 1445883 commit 5d3ca27

1 file changed

Lines changed: 22 additions & 0 deletions

File tree

crates/knot-compiler/src/infer.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11815,6 +11815,28 @@ impl Infer {
1181511815
None => (self.fresh(), Vec::new(), Vec::new()),
1181611816
};
1181711817
self.check_expr(body, &expected);
11818+
// Compile-time check: a top-level constant whose signature is
11819+
// an inline refined type (`x : Int 1 where \a -> a > 1`) and
11820+
// whose body is a literal (or named const) is checked against
11821+
// the predicate now, so `x 0` is a compile error rather than a
11822+
// silent refined-typed 0. (The inline `Refined` erases to its
11823+
// base in `ast_type_to_ty`, so this can't piggyback on the
11824+
// nominal-type introduction guard.)
11825+
if let Some(ts) = ty
11826+
&& let ast::TypeKind::Refined { predicate, .. } = &ts.ty.node
11827+
&& let Some(lit) =
11828+
crate::codegen::extract_literal_with_consts(body, &self.const_literals)
11829+
&& let Some(false) =
11830+
crate::codegen::eval_refine_predicate_pub(predicate, &lit)
11831+
{
11832+
self.error(
11833+
format!(
11834+
"constant {} does not satisfy the refinement predicate",
11835+
lit.display()
11836+
),
11837+
body.span,
11838+
);
11839+
}
1181811840
// Record-field funs with `^`-field constraints: register
1181911841
// each under its record path (`fns.greet`) so the
1182011842
// callsite resolver can find it through a field-access

0 commit comments

Comments
 (0)