dada_ir_sym/check/predicates/
require_lent.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::{
22 is_provably_lent::{place_is_provably_lent, term_is_provably_lent},
23 is_provably_unique::{place_is_provably_unique, term_is_provably_unique},
24};
25
26pub(crate) async fn require_term_is_lent<'db>(
27 env: &mut Env<'db>,
28 term: SymGenericTerm<'db>,
29 or_else: &dyn OrElse<'db>,
30) -> Errors<()> {
31 match term {
32 SymGenericTerm::Type(sym_ty) => require_ty_is_lent(env, sym_ty, or_else).await,
33 SymGenericTerm::Perm(sym_perm) => require_perm_is_lent(env, sym_perm, or_else).await,
34 SymGenericTerm::Place(place) => panic!("unexpected place term: {place:?}"),
35 SymGenericTerm::Error(reported) => Err(reported),
36 }
37}
38
39async fn require_application_is_lent<'db>(
42 env: &mut Env<'db>,
43 lhs: SymGenericTerm<'db>,
44 rhs: SymGenericTerm<'db>,
45 or_else: &dyn OrElse<'db>,
46) -> Errors<()> {
47 env.require(
48 async |env| {
49 env.either(
50 async |env| term_is_provably_lent(env, rhs).await,
51 async |env| {
52 env.both(
53 async |env| term_is_provably_unique(env, rhs).await,
54 async |env| term_is_provably_lent(env, lhs).await,
55 )
56 .await
57 },
58 )
59 .await
60 },
61 |_env| Because::JustSo,
62 or_else,
63 )
64 .await
65}
66
67#[boxed_async_fn]
68async fn require_ty_is_lent<'db>(
69 env: &mut Env<'db>,
70 term: SymTy<'db>,
71 or_else: &dyn OrElse<'db>,
72) -> Errors<()> {
73 env.indent("require_ty_is_lent", &[&term], async |env| {
74 let db = env.db();
75 let (red_ty, perm) = term.to_red_ty(env);
76 match red_ty {
77 RedTy::Error(reported) => Err(reported),
79
80 RedTy::Never => require_perm_is_lent(env, perm, or_else).await,
82
83 RedTy::Infer(infer) => {
85 require_infer_is(env, perm, infer, Predicate::Lent, or_else).await
86 }
87
88 RedTy::Var(var) => {
90 if env.var_is_declared_to_be(var, Predicate::Lent) {
91 Ok(())
92 } else if env.var_is_declared_to_be(var, Predicate::Unique) {
93 require_perm_is_lent(env, perm, or_else).await
97 } else {
98 Err(or_else.report(env, Because::NoWhereClause(var, Predicate::Lent)))
99 }
100 }
101
102 RedTy::Named(sym_ty_name, _) => match sym_ty_name.style(db) {
104 SymAggregateStyle::Struct => {
105 Err(or_else.report(env, Because::StructsAreNotLent(sym_ty_name)))
110 }
111 SymAggregateStyle::Class => {
112 require_perm_is_lent(env, perm, or_else).await
117 }
118 },
119
120 RedTy::Perm => require_perm_is_lent(env, perm, or_else).await,
121 }
122 })
123 .await
124}
125
126#[boxed_async_fn]
127async fn require_perm_is_lent<'db>(
128 env: &mut Env<'db>,
129 perm: SymPerm<'db>,
130 or_else: &dyn OrElse<'db>,
131) -> Errors<()> {
132 env.indent("require_perm_is_lent", &[&perm], async |env| {
133 let db = env.db();
134 match *perm.kind(db) {
135 SymPermKind::Error(reported) => Err(reported),
137
138 SymPermKind::My => Err(or_else.report(env, Because::PermIsNot(perm, Predicate::Lent))),
140
141 SymPermKind::Our => Ok(()),
143
144 SymPermKind::Referenced(ref places) | SymPermKind::Mutable(ref places) => {
146 env.require(
151 async |env| {
152 env.for_all(places, async |env, &place| {
153 env.either(
154 async |env| place_is_provably_unique(env, place).await,
157 async |env| place_is_provably_lent(env, place).await,
159 )
160 .await
161 })
162 .await
163 },
164 |_env| Because::PermIsNot(perm, Predicate::Lent),
165 or_else,
166 )
167 .await
168 }
169
170 SymPermKind::Apply(lhs, rhs) => {
172 require_application_is_lent(env, lhs.into(), rhs.into(), or_else).await
173 }
174
175 SymPermKind::Var(var) => require_var_is(env, var, Predicate::Lent, or_else),
177 SymPermKind::Infer(infer) => {
178 require_infer_is(env, SymPerm::my(db), infer, Predicate::Lent, or_else).await
179 }
180 SymPermKind::Or(_, _) => todo!(),
181 }
182 })
183 .await
184}