1use itertools::Itertools;
18
19use crate::etypes::{
20 Component, Ctx, Defined, Func, Handleable, Name, QualifiedInstance, ResourceId, TypeBound,
21 Tyvar, Value,
22};
23use crate::tv::ResolvedTyvar;
24
25#[derive(Debug)]
27#[allow(dead_code)]
28pub enum Error<'r> {
29 MissingValue(Value<'r>),
32 MissingRecordField(Name<'r>),
34 MissingVariantCase(Name<'r>),
36 MismatchedValue(Value<'r>, Value<'r>),
38 MismatchedDefined(Box<Defined<'r>>, Box<Defined<'r>>),
40 MismatchedResources(ResourceId, ResourceId),
42 MismatchedVars(Tyvar, Tyvar),
45 MismatchedResourceVar(Tyvar, ResourceId),
48 NotResource(Handleable),
52}
53
54impl<'p, 'a> Ctx<'p, 'a> {
63 pub fn subtype_value<'r>(
64 &self,
65 vt1: &'r Value<'a>,
66 vt2: &'r Value<'a>,
67 ) -> Result<(), Error<'a>> {
68 use Value::*;
69 use itertools::EitherOrBoth::*;
70 match (vt1, vt2) {
71 (Bool, Bool) => Ok(()),
72 (S(w1), S(w2)) if w1 == w2 => Ok(()),
73 (U(w1), U(w2)) if w1 == w2 => Ok(()),
74 (F(w1), F(w2)) if w1 == w2 => Ok(()),
75 (Char, Char) => Ok(()),
76 (String, String) => Ok(()),
77 (List(vt1), List(vt2)) => self.subtype_value(vt1, vt2),
78 (Record(rfs1), Record(rfs2)) => {
79 for rf2 in rfs2.iter() {
80 match rfs1.iter().find(|rf| rf2.name.name == rf.name.name) {
81 None => return Err(Error::MissingRecordField(rf2.name)),
82 Some(rf1) => self.subtype_value(&rf1.ty, &rf2.ty)?,
83 }
84 }
85 Ok(())
86 }
87 (Tuple(vts1), Tuple(vts2)) => {
88 vts1.iter()
89 .zip_longest(vts2.iter())
90 .try_for_each(|vs| match vs {
91 Both(vt1, vt2) => self.subtype_value(vt1, vt2),
92 Left(_) => Ok(()),
93 Right(vt2) => Err(Error::MissingValue(vt2.clone())),
94 })
95 }
96 (Flags(ns1), Flags(ns2)) => ns2
97 .iter()
98 .find(|n2| !ns1.iter().any(|n| n.name == n2.name))
99 .map_or(Ok(()), |n| Err(Error::MissingRecordField(*n))),
100 (Variant(vcs1), Variant(vcs2)) => {
101 for vc1 in vcs1.iter() {
102 match vcs2.iter().find(|vc| vc1.name.name == vc.name.name) {
103 None => return Err(Error::MissingVariantCase(vc1.name)),
104 Some(vc2) => self.subtype_value_option(&vc1.ty, &vc2.ty)?,
105 }
106 }
107 Ok(())
108 }
109 (Enum(ns1), Enum(ns2)) => ns1
110 .iter()
111 .find(|n1| !ns2.iter().any(|n| n.name == n1.name))
112 .map_or(Ok(()), |n| Err(Error::MissingVariantCase(*n))),
113 (Option(vt1), Option(vt2)) => self.subtype_value(vt1, vt2),
114 (Result(vt11, vt12), Result(vt21, vt22)) => self
115 .subtype_value_option(vt11, vt21)
116 .and(self.subtype_value_option(vt12, vt22)),
117 (Own(ht1), Own(ht2)) | (Borrow(ht1), Borrow(ht2)) => {
118 self.subtype_handleable_is_resource(ht1)?;
119 self.subtype_handleable_is_resource(ht2)?;
120 self.subtype_handleable(ht1, ht2)
121 }
122 (Var(_, vt1), vt2) => self.subtype_value(vt1, vt2),
123 (vt1, Var(_, vt2)) => self.subtype_value(vt1, vt2),
124 _ => Err(Error::MismatchedValue(vt1.clone(), vt2.clone())),
125 }
126 }
127 pub fn subtype_value_option<'r>(
128 &self,
129 vt1: &'r Option<Value<'a>>,
130 vt2: &'r Option<Value<'a>>,
131 ) -> Result<(), Error<'a>> {
132 match (vt1, vt2) {
133 (None, None) => Ok(()),
134 (None, Some(vt2)) => Err(Error::MissingValue(vt2.clone())),
135 (Some(_), None) => Ok(()),
136 (Some(vt1), Some(vt2)) => self.subtype_value(vt1, vt2),
137 }
138 }
139 pub fn subtype_var_var<'r>(&self, v1: &'r Tyvar, v2: &'r Tyvar) -> Result<(), Error<'a>> {
140 match (self.resolve_tyvar(v1), self.resolve_tyvar(v2)) {
141 (ResolvedTyvar::Definite(dt1), ResolvedTyvar::Definite(dt2)) => {
142 self.subtype_defined(&dt1, &dt2)
143 }
144 (ResolvedTyvar::E(o1, i1, _), ResolvedTyvar::E(o2, i2, _)) if o1 == o2 && i1 == i2 => {
145 Ok(())
146 }
147 (ResolvedTyvar::U(o1, i1, _), ResolvedTyvar::U(o2, i2, _)) if o1 == o2 && i1 == i2 => {
148 Ok(())
149 }
150 (ResolvedTyvar::Bound(_), _) | (_, ResolvedTyvar::Bound(_)) => {
151 panic!("internal invariant violation: stray bvar in subtype_var_var")
152 }
153 _ => Err(Error::MismatchedVars(v1.clone(), v2.clone())),
154 }
155 }
156 pub fn subtype_var_resource<'r>(
157 &self,
158 v1: &'r Tyvar,
159 rid2: &'r ResourceId,
160 ) -> Result<(), Error<'a>> {
161 match self.resolve_tyvar(v1) {
162 ResolvedTyvar::Definite(Defined::Handleable(Handleable::Resource(rid1)))
163 if rid1 == *rid2 =>
164 {
165 Ok(())
166 }
167 _ => Err(Error::MismatchedResourceVar(v1.clone(), *rid2)),
168 }
169 }
170 pub fn subtype_resource_var<'r>(
171 &self,
172 rid1: &'r ResourceId,
173 v2: &'r Tyvar,
174 ) -> Result<(), Error<'a>> {
175 match self.resolve_tyvar(v2) {
176 ResolvedTyvar::Definite(Defined::Handleable(Handleable::Resource(rid2)))
177 if *rid1 == rid2 =>
178 {
179 Ok(())
180 }
181 _ => Err(Error::MismatchedResourceVar(v2.clone(), *rid1)),
182 }
183 }
184 pub fn subtype_handleable<'r>(
185 &self,
186 ht1: &'r Handleable,
187 ht2: &'r Handleable,
188 ) -> Result<(), Error<'a>> {
189 match (ht1, ht2) {
190 (Handleable::Var(v1), Handleable::Var(v2)) => self.subtype_var_var(v1, v2),
191 (Handleable::Var(v1), Handleable::Resource(rid2)) => {
192 self.subtype_var_resource(v1, rid2)
193 }
194 (Handleable::Resource(rid1), Handleable::Var(v2)) => {
195 self.subtype_resource_var(rid1, v2)
196 }
197 (Handleable::Resource(rid1), Handleable::Resource(rid2)) => {
198 if rid1 == rid2 {
199 Ok(())
200 } else {
201 Err(Error::MismatchedResources(*rid1, *rid2))
202 }
203 }
204 }
205 }
206 pub fn subtype_func<'r>(
207 &self,
208 _ft1: &'r Func<'a>,
209 _ft2: &'r Func<'a>,
210 ) -> Result<(), Error<'a>> {
211 panic!("func <: func should be impossible to encounter during type elaboration")
212 }
213 pub fn subtype_qualified_instance<'r>(
214 &self,
215 _qi1: &'r QualifiedInstance<'a>,
216 _qi2: &'r QualifiedInstance<'a>,
217 ) -> Result<(), Error<'a>> {
218 panic!("qinstance <: qinstance should be impossible to encounter during type elaboration")
219 }
220 pub fn subtype_component<'r>(
221 &self,
222 _ct1: &'r Component<'a>,
223 _ct2: &'r Component<'a>,
224 ) -> Result<(), Error<'a>> {
225 panic!("component <: component should be impossible to encounter during type elaboration")
226 }
227 pub fn subtype_defined<'r>(
228 &self,
229 dt1: &'r Defined<'a>,
230 dt2: &'r Defined<'a>,
231 ) -> Result<(), Error<'a>> {
232 match (dt1, dt2) {
233 (Defined::Handleable(ht1), Defined::Handleable(ht2)) => {
234 self.subtype_handleable(ht1, ht2)
235 }
236 (Defined::Value(vt1), Defined::Value(vt2)) => self.subtype_value(vt1, vt2),
237 (Defined::Func(ft1), Defined::Func(ft2)) => self.subtype_func(ft1, ft2),
238 (Defined::Instance(it1), Defined::Instance(it2)) => {
239 self.subtype_qualified_instance(it1, it2)
240 }
241 (Defined::Component(ct1), Defined::Component(ct2)) => self.subtype_component(ct1, ct2),
242 _ => Err(Error::MismatchedDefined(
243 Box::new(dt1.clone()),
244 Box::new(dt2.clone()),
245 )),
246 }
247 }
248 pub fn subtype_handleable_is_resource<'r>(&self, ht: &'r Handleable) -> Result<(), Error<'a>> {
249 match ht {
250 Handleable::Resource(_) => Ok(()),
251 Handleable::Var(tv) => match self.resolve_tyvar(tv) {
252 ResolvedTyvar::Definite(Defined::Handleable(Handleable::Resource(_))) => Ok(()),
253 ResolvedTyvar::E(_, _, TypeBound::SubResource) => Ok(()),
254 ResolvedTyvar::U(_, _, TypeBound::SubResource) => Ok(()),
255 _ => Err(Error::NotResource(ht.clone())),
256 },
257 }
258 }
259}