dada_ir_sym/check/predicates/
require_unique.rs1use dada_ir_ast::diagnostic::Errors;
2use dada_util::boxed_async_fn;
3
4use crate::{
5 check::{
6 env::Env,
7 predicates::{
8 Predicate,
9 var_infer::{require_infer_is, require_var_is},
10 },
11 red::RedTy,
12 report::{Because, OrElse},
13 to_red::ToRedTy,
14 },
15 ir::{
16 classes::SymAggregateStyle,
17 types::{SymGenericTerm, SymPerm, SymPermKind, SymTy},
18 },
19};
20
21use super::is_provably_unique::{place_is_provably_unique, term_is_provably_unique};
22
23pub(crate) async fn require_term_is_unique<'db>(
24 env: &mut Env<'db>,
25 term: SymGenericTerm<'db>,
26 or_else: &dyn OrElse<'db>,
27) -> Errors<()> {
28 match term {
29 SymGenericTerm::Type(sym_ty) => require_ty_is_unique(env, sym_ty, or_else).await,
30 SymGenericTerm::Perm(sym_perm) => require_perm_is_unique(env, sym_perm, or_else).await,
31 SymGenericTerm::Place(place) => panic!("unexpected place term: {place:?}"),
32 SymGenericTerm::Error(reported) => Err(reported),
33 }
34}
35
36#[boxed_async_fn]
37async fn require_ty_is_unique<'db>(
38 env: &mut Env<'db>,
39 term: SymTy<'db>,
40 or_else: &dyn OrElse<'db>,
41) -> Errors<()> {
42 env.indent("require_ty_is_unique", &[&term], async |env| {
43 let db = env.db();
44 let (red_ty, perm) = term.to_red_ty(env);
45 match red_ty {
46 RedTy::Error(reported) => Err(reported),
48
49 RedTy::Never => require_perm_is_unique(env, perm, or_else).await,
51
52 RedTy::Infer(infer) => {
54 require_infer_is(env, perm, infer, Predicate::Unique, or_else).await
55 }
56
57 RedTy::Var(var) => {
58 env.require_both(
60 async |env| require_perm_is_unique(env, perm, or_else).await,
61 async |env| require_var_is(env, var, Predicate::Unique, or_else),
62 )
63 .await
64 }
65
66 RedTy::Named(sym_ty_name, ref generics) => match sym_ty_name.style(db) {
68 SymAggregateStyle::Struct => {
69 require_some_generic_is_unique(env, perm, generics, or_else).await
70 }
71 SymAggregateStyle::Class => require_perm_is_unique(env, perm, or_else).await,
72 },
73
74 RedTy::Perm => require_perm_is_unique(env, perm, or_else).await,
75 }
76 })
77 .await
78}
79
80async fn require_some_generic_is_unique<'db>(
81 env: &mut Env<'db>,
82 perm: SymPerm<'db>,
83 generics: &[SymGenericTerm<'db>],
84 or_else: &dyn OrElse<'db>,
85) -> Errors<()> {
86 let db = env.db();
87 env.require(
88 async |env| {
89 env.exists(generics, async |env, &generic| {
90 term_is_provably_unique(env, perm.apply_to(db, generic)).await
91 })
92 .await
93 },
94 |_env| Because::JustSo,
95 or_else,
96 )
97 .await
98}
99
100#[boxed_async_fn]
101async fn require_perm_is_unique<'db>(
102 env: &mut Env<'db>,
103 perm: SymPerm<'db>,
104 or_else: &dyn OrElse<'db>,
105) -> Errors<()> {
106 env.indent("require_perm_is_unique", &[&perm], async |env| {
107 let db = env.db();
108 match *perm.kind(db) {
109 SymPermKind::Error(reported) => Err(reported),
110
111 SymPermKind::My => Ok(()),
112
113 SymPermKind::Our => Err(or_else.report(env, Because::JustSo)),
114
115 SymPermKind::Referenced(_) => Err(or_else.report(env, Because::JustSo)),
116
117 SymPermKind::Mutable(ref places) => {
118 env.require(
120 async |env| {
121 env.exists(places, async |env, &place| {
122 place_is_provably_unique(env, place).await
123 })
124 .await
125 },
126 |_env| Because::LeasedFromCopyIsCopy(places.to_vec()),
127 or_else,
128 )
129 .await
130 }
131
132 SymPermKind::Apply(lhs, rhs) => {
134 env.require_both(
135 async |env| require_perm_is_unique(env, lhs, or_else).await,
136 async |env| require_perm_is_unique(env, rhs, or_else).await,
137 )
138 .await
139 }
140
141 SymPermKind::Var(var) => require_var_is(env, var, Predicate::Unique, or_else),
143 SymPermKind::Infer(infer) => {
144 require_infer_is(env, SymPerm::my(db), infer, Predicate::Unique, or_else).await
145 }
146
147 SymPermKind::Or(_, _) => todo!(),
148 }
149 })
150 .await
151}