Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
9609889
Merge pull request #1 from coord-e/more-annot
coord-e Aug 17, 2025
6961597
Move rty::FormulaWithAtoms to chc::Body
coord-e Aug 17, 2025
0709cec
rty::Refinement = rty::Formula<RefinedTypeVar>
coord-e Aug 17, 2025
383ccc7
Assumption = rty::Formula<PlaceTypeVar>
coord-e Aug 17, 2025
d79e825
Merge pull request #3 from coord-e/unify-formula
coord-e Aug 28, 2025
821cab2
Introduce PlaceTypeBuilder to simplify PlaceType construction
coord-e Aug 26, 2025
2571c37
Merge pull request #2 from coord-e/refactor-types
coord-e Aug 30, 2025
24d307c
Add documentation to src/annot.rs
coord-e Aug 28, 2025
ac1e098
Add documentation to src/chc.rs
coord-e Aug 28, 2025
7c10c7b
Add documentation to src/chc/*.rs
coord-e Aug 30, 2025
3bcd10c
Add documentation to src/pretty.rs
coord-e Aug 30, 2025
fc933e0
Merge pull request #4 from coord-e/doc-some
coord-e Aug 30, 2025
73226a9
Fix term order in Add
coord-e Aug 30, 2025
c42766f
Add documentation to src/rty.rs and src/rty/*.rs
coord-e Sep 7, 2025
1a5130e
Add documentation to src/{analyze,refine,refine/basic_block}.rs
coord-e Sep 7, 2025
0e6b907
Add documentation of src/analyze/{annot,crate_,did_cache,local_def}.rs
coord-e Sep 7, 2025
ed72bbd
Merge pull request #5 from coord-e/doc-some
coord-e Sep 7, 2025
e896fdc
Handle parens in annotations properly
coord-e Sep 15, 2025
317955f
Handle associativity
coord-e Sep 15, 2025
0db538c
Add GitHub Actions workflow to host docs in GitHub pages
coord-e Sep 15, 2025
e518af5
Merge pull request #7 from coord-e/docs-pages
coord-e Sep 15, 2025
ad85386
Merge pull request #6 from coord-e/parse-ambig
coord-e Sep 15, 2025
8487ab4
Support enums with lifetime params
coord-e Sep 23, 2025
acddb41
Rename TypeParams to TypeArgs
coord-e Sep 23, 2025
4ec9873
Refactor construction of type templates
coord-e Oct 24, 2025
69d3455
Handle parameter shifting in TypeBuilder
coord-e Oct 24, 2025
df2a843
Enhance docs
coord-e Oct 25, 2025
391eef4
Merge pull request #9 from coord-e/type-param-shift
coord-e Oct 25, 2025
bb61183
Enable to handle annotated polymorphic function
coord-e Oct 24, 2025
91a957c
Enable to handle unannotated polymorphic function
coord-e Oct 24, 2025
dd67486
Implement Eq and Hash for Type
coord-e Nov 9, 2025
23f5e52
Rename TypeArgs to RefinedTypeArgs
coord-e Nov 9, 2025
b4b1c9b
Fixes to allow nested polymorphic calls
coord-e Nov 9, 2025
cd004d2
Add many more test cases
coord-e Nov 9, 2025
d50710f
Merge pull request #8 from coord-e/params
coord-e Nov 23, 2025
2d4e198
Include existential quantification in Formula
coord-e Sep 9, 2025
4060e06
Parse existentials
coord-e Sep 14, 2025
7270ca4
Test parsing existentials
coord-e Dec 10, 2025
069b4c1
Merge pull request #11 from coord-e/existential-in-annot
coord-e Dec 14, 2025
e4db838
Enable to handle some promoted constants
coord-e Nov 23, 2025
92b702f
Merge pull request #12 from coord-e/promoted-constants
coord-e Dec 14, 2025
d848715
Instantiate body instead of using ParamTypeMapper
coord-e Dec 14, 2025
daba7b7
Remove ParamTypeMapper and stop relaying TypeBuilder
coord-e Dec 14, 2025
ed03484
Revert "Implement Eq and Hash for Type"
coord-e Dec 14, 2025
a723c37
Merge pull request #13 from coord-e/subst-body
coord-e Dec 14, 2025
4c9e5d8
Resolve trait method DefId in type_call
coord-e Nov 23, 2025
96e96f4
add: test for annotations of predicates
coeff-aij Dec 25, 2025
0133b8e
add: definitions to check if functions are marked as predicates
coeff-aij Dec 25, 2025
d5b5dbd
add: gather functions marked as predicates into Analyzer::predicates
coeff-aij Dec 25, 2025
b03b58c
Enable to type lifted closure functions
coord-e Nov 23, 2025
47bf162
Enable to type closures
coord-e Nov 23, 2025
8c533e0
Add rty::FunctionAbi and attach it to rty::FunctionType
coord-e Nov 23, 2025
53aeadd
Enable to type closure calls
coord-e Nov 23, 2025
c5abc9d
Enable to type unit via ZeroSized
coord-e Nov 23, 2025
c6d49c8
Ensure bb fn type params are sorted by locals
coord-e Nov 23, 2025
0d92953
Merge pull request #10 from coord-e/closures
coord-e Dec 28, 2025
4ee1d9a
Enable to add guard to Atom
coord-e Dec 30, 2025
933bd10
Add guard of discriminant when expanding variant field types
coord-e Dec 30, 2025
ec34a5e
Merge pull request #16 from coord-e/unused-variant-predicate
coord-e Dec 30, 2025
70c8705
Register enum_defs on-demand
coord-e Dec 28, 2025
50b3f23
Use latest enum_defs from Env
coord-e Dec 28, 2025
fade2d5
Add more test cases
coord-e Dec 28, 2025
39954df
Populate enum_defs before analyzing BB
coord-e Dec 29, 2025
04b379c
Don't attach value formula when ty is singleton
coord-e Dec 29, 2025
2ca04c6
Fix missing unbox
coord-e Dec 30, 2025
3b25de5
Merge pull request #17 from coord-e/enum-on-demand
coord-e Dec 30, 2025
5101b46
Enable to parse enum constructors in annotations
coord-e Dec 14, 2025
5f5f102
Merge pull request #14 from coord-e/enum-in-annot
coord-e Dec 30, 2025
a48be41
Implement #[thrust::extern_spec_fn]
coord-e Nov 24, 2025
c8c6cf0
Merge pull request #15 from coord-e/extern-spec
coord-e Dec 30, 2025
8089bfb
Parse <t> and <t1, t2> in annotations
coord-e Dec 30, 2025
e0e13f3
Parse sort params in ad-hoc way
coord-e Dec 30, 2025
c3a550a
Parse boolean literals in annotation
coord-e Dec 31, 2025
aec6494
Parse pointer sorts in annotation
coord-e Dec 31, 2025
53a77c6
fixup! Parse sort params in ad-hoc way
coord-e Dec 31, 2025
70b2f48
Merge pull request #19 from coord-e/more-annot-2
coord-e Dec 31, 2025
bf9fab7
Merge main
coeff-aij Jan 4, 2026
750c415
add: collect signatures of predicates additionaly
coeff-aij Jan 4, 2026
5172b97
add: logging for found predicates
coeff-aij Jan 4, 2026
6d55087
add: definition for user-defined predicates in CHC
coeff-aij Jan 9, 2026
a47f30d
add: an implementation for unboxing user-defined predicates
coeff-aij Jan 9, 2026
2dc500f
Merge branch 'main' into annotation-predicates
coeff-aij Jan 9, 2026
8625b7f
Merge branch 'main' into annotation-predicates
coeff-aij Jan 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions gcd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
fn gcd(mut a: i32, mut b: i32) -> i32 {
while a != b {
let (l, r) = if a < b {
(&mut a, &b)
} else {
(&mut b, &a)
};
*l -= *r;
}
a
}

#[thrust::callable]
fn check_gcd(a: i32, b: i32) {
assert!(gcd(a, b) <= a);
}

fn main() {}
4 changes: 4 additions & 0 deletions src/analyze/annot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ pub fn callable_path() -> [Symbol; 2] {
[Symbol::intern("thrust"), Symbol::intern("callable")]
}

pub fn predicate_path() -> [Symbol; 2] {
[Symbol::intern("thrust"), Symbol::intern("predicate")]
}

pub fn extern_spec_fn_path() -> [Symbol; 2] {
[Symbol::intern("thrust"), Symbol::intern("extern_spec_fn")]
}
Expand Down
17 changes: 14 additions & 3 deletions src/analyze/crate_.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Analyze a local crate.

use std::collections::HashSet;
use std::collections::{HashSet, HashMap};

use rustc_middle::ty::{self as mir_ty, TyCtxt};
use rustc_middle::ty::{self as mir_ty, TyCtxt, FnSig};
use rustc_span::def_id::{DefId, LocalDefId};

use crate::analyze;
Expand All @@ -23,6 +23,7 @@ pub struct Analyzer<'tcx, 'ctx> {
tcx: TyCtxt<'tcx>,
ctx: &'ctx mut analyze::Analyzer<'tcx>,
trusted: HashSet<DefId>,
predicates: HashMap<DefId, FnSig<'tcx>>,
}

impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
Expand All @@ -45,6 +46,10 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
self.trusted.insert(local_def_id.to_def_id());
}

if analyzer.is_annotated_as_predicate() {
self.predicates.insert(local_def_id.to_def_id(), sig);
}

if analyzer.is_annotated_as_extern_spec_fn() {
assert!(analyzer.is_fully_annotated());
self.trusted.insert(local_def_id.to_def_id());
Expand Down Expand Up @@ -73,6 +78,11 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
tracing::info!(?local_def_id, "trusted");
continue;
}
if self.predicates.contains_key(&local_def_id.to_def_id()) {
let sig = self.predicates.get(&local_def_id.to_def_id()).unwrap();
tracing::info!(?local_def_id, ?sig, "predicate");
continue;
}
let Some(expected) = self.ctx.concrete_def_ty(local_def_id.to_def_id()) else {
// when the local_def_id is deferred it would be skipped
continue;
Expand Down Expand Up @@ -180,7 +190,8 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
pub fn new(ctx: &'ctx mut analyze::Analyzer<'tcx>) -> Self {
let tcx = ctx.tcx;
let trusted = HashSet::default();
Self { ctx, tcx, trusted }
let predicates = HashMap::default();
Self { ctx, tcx, trusted, predicates }
}

pub fn run(&mut self) {
Expand Down
10 changes: 10 additions & 0 deletions src/analyze/local_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,16 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> {
.is_some()
}

pub fn is_annotated_as_predicate(&self) -> bool {
self.tcx
.get_attrs_by_path(
self.local_def_id.to_def_id(),
&analyze::annot::predicate_path(),
)
.next()
.is_some()
}

pub fn is_annotated_as_extern_spec_fn(&self) -> bool {
self.tcx
.get_attrs_by_path(
Expand Down
82 changes: 82 additions & 0 deletions src/chc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -902,12 +902,87 @@ impl MatcherPred {
}
}

// TODO: DatatypeSymbolをほぼそのままコピーする形になっているので、エイリアスなどで共通化すべき?
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct UserDefinedPredSymbol {
inner: String,
}

impl std::fmt::Display for UserDefinedPredSymbol {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.inner.fmt(f)
}
}

impl<'a, 'b, D> Pretty<'a, D, termcolor::ColorSpec> for &'b UserDefinedPredSymbol
where
D: pretty::DocAllocator<'a, termcolor::ColorSpec>,
{
fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, termcolor::ColorSpec> {
allocator.text(self.inner.clone())
}
}

impl UserDefinedPredSymbol {
pub fn new(inner: String) -> Self {
Self { inner }
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct UserDefinedPred {
symbol: UserDefinedPredSymbol,
args: Vec<Sort>,
}

impl<'a> std::fmt::Display for UserDefinedPred {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.symbol.inner)
}
}

impl<'a, 'b, D> Pretty<'a, D, termcolor::ColorSpec> for &'b UserDefinedPred
where
D: pretty::DocAllocator<'a, termcolor::ColorSpec>,
D::Doc: Clone,
{
fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, termcolor::ColorSpec> {
let args = allocator.intersperse(
self.args.iter().map(|a| a.pretty(allocator)),
allocator.text(", "),
);
allocator
.text("user_defined_pred")
.append(
allocator
.text(self.symbol.inner.clone())
.append(args.angles())
.angles(),
)
.group()
}
}

impl UserDefinedPred {
pub fn new(symbol: UserDefinedPredSymbol, args: Vec<Sort>) -> Self {
Self {
symbol,
args,
}
}

pub fn name(&self) -> &str {
&self.symbol.inner
}
}

/// A predicate.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Pred {
Known(KnownPred),
Var(PredVarId),
Matcher(MatcherPred),
UserDefined(UserDefinedPredSymbol),
}

impl std::fmt::Display for Pred {
Expand All @@ -916,6 +991,7 @@ impl std::fmt::Display for Pred {
Pred::Known(p) => p.fmt(f),
Pred::Var(p) => p.fmt(f),
Pred::Matcher(p) => p.fmt(f),
Pred::UserDefined(p) => p.fmt(f),
}
}
}
Expand All @@ -930,6 +1006,7 @@ where
Pred::Known(p) => p.pretty(allocator),
Pred::Var(p) => p.pretty(allocator),
Pred::Matcher(p) => p.pretty(allocator),
Pred::UserDefined(p) => p.pretty(allocator),
}
}
}
Expand Down Expand Up @@ -958,6 +1035,7 @@ impl Pred {
Pred::Known(p) => p.name().into(),
Pred::Var(p) => p.to_string().into(),
Pred::Matcher(p) => p.name().into(),
Pred::UserDefined(p) => p.inner.clone().into(),
}
}

Expand All @@ -966,6 +1044,7 @@ impl Pred {
Pred::Known(p) => p.is_negative(),
Pred::Var(_) => false,
Pred::Matcher(_) => false,
Pred::UserDefined(_) => false,
}
}

Expand All @@ -974,6 +1053,7 @@ impl Pred {
Pred::Known(p) => p.is_infix(),
Pred::Var(_) => false,
Pred::Matcher(_) => false,
Pred::UserDefined(_) => false,
}
}

Expand All @@ -982,6 +1062,7 @@ impl Pred {
Pred::Known(p) => p.is_top(),
Pred::Var(_) => false,
Pred::Matcher(_) => false,
Pred::UserDefined(_) => false,
}
}

Expand All @@ -990,6 +1071,7 @@ impl Pred {
Pred::Known(p) => p.is_bottom(),
Pred::Var(_) => false,
Pred::Matcher(_) => false,
Pred::UserDefined(_) => false,
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/chc/unbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ fn unbox_pred(pred: Pred) -> Pred {
Pred::Known(pred) => Pred::Known(pred),
Pred::Var(pred) => Pred::Var(pred),
Pred::Matcher(pred) => unbox_matcher_pred(pred),
Pred::UserDefined(pred) => Pred::UserDefined(pred),
}
}

Expand Down
24 changes: 24 additions & 0 deletions tests/ui/pass/annot_preds.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//@check-pass
//@compile-flags: -Adead_code -C debug-assertions=off

#[thrust::predicate]
fn is_double(x: i64, doubled_x: i64) -> bool {
x * 2 == doubled_x
// "(=(
// (* (x 2))
// doubled_x
// ))"
}

#[thrust::requires(true)]
#[thrust::ensures(result == 2 * x)]
// #[thrust::ensures(is_double(x, result))]
fn double(x: i64) -> i64 {
x + x
}

fn main() {
let a = 3;
assert!(double(a) == 6);
assert!(is_double(a, double(a)));
}