|
1 | | -//! The operational semantics of the core language, implemented using |
2 | | -//! [normalisation by evaluation](https://en.wikipedia.org/wiki/Normalisation_by_evaluation). |
| 1 | +//! The semantics of the core language, implemented using [normalisation by |
| 2 | +//! evaluation](https://en.wikipedia.org/wiki/Normalisation_by_evaluation). |
3 | 3 |
|
4 | 4 | use scoped_arena::Scope; |
5 | 5 | use std::panic::panic_any; |
@@ -1072,20 +1072,7 @@ impl<'arena, 'env> ConversionEnv<'arena, 'env> { |
1072 | 1072 | | (_, Value::Stuck(Head::Prim(Prim::ReportedError), _)) => true, |
1073 | 1073 |
|
1074 | 1074 | (Value::Stuck(head0, spine0), Value::Stuck(head1, spine1)) => { |
1075 | | - use Elim::*; |
1076 | | - |
1077 | | - head0 == head1 |
1078 | | - && spine0.len() == spine1.len() |
1079 | | - && Iterator::zip(spine0.iter(), spine1.iter()).all(|(elim0, elim1)| { |
1080 | | - match (elim0, elim1) { |
1081 | | - (FunApp(expr0), FunApp(expr1)) => self.is_equal(expr0, expr1), |
1082 | | - (RecordProj(label0), RecordProj(label1)) => label0 == label1, |
1083 | | - (ConstMatch(branches0), ConstMatch(branches1)) => { |
1084 | | - self.is_equal_branches(branches0, branches1) |
1085 | | - } |
1086 | | - (_, _) => false, |
1087 | | - } |
1088 | | - }) |
| 1075 | + head0 == head1 && self.is_equal_spines(spine0, spine1) |
1089 | 1076 | } |
1090 | 1077 | (Value::Universe, Value::Universe) => true, |
1091 | 1078 |
|
@@ -1142,6 +1129,21 @@ impl<'arena, 'env> ConversionEnv<'arena, 'env> { |
1142 | 1129 | } |
1143 | 1130 | } |
1144 | 1131 |
|
| 1132 | + /// Check that two elimination spines are equal. |
| 1133 | + pub fn is_equal_spines(&mut self, spine0: &[Elim<'_>], spine1: &[Elim<'_>]) -> bool { |
| 1134 | + spine0.len() == spine1.len() |
| 1135 | + && Iterator::zip(spine0.iter(), spine1.iter()).all(|(elim0, elim1)| { |
| 1136 | + match (elim0, elim1) { |
| 1137 | + (Elim::FunApp(expr0), Elim::FunApp(expr1)) => self.is_equal(expr0, expr1), |
| 1138 | + (Elim::RecordProj(label0), Elim::RecordProj(label1)) => label0 == label1, |
| 1139 | + (Elim::ConstMatch(branches0), Elim::ConstMatch(branches1)) => { |
| 1140 | + self.is_equal_branches(branches0, branches1) |
| 1141 | + } |
| 1142 | + (_, _) => false, |
| 1143 | + } |
| 1144 | + }) |
| 1145 | + } |
| 1146 | + |
1145 | 1147 | /// Check that two [closures][Closure] are equal. |
1146 | 1148 | pub fn is_equal_closures(&mut self, closure0: &Closure<'_>, closure1: &Closure<'_>) -> bool { |
1147 | 1149 | let var = Spanned::empty(Arc::new(Value::local_var(self.local_exprs.next_level()))); |
@@ -1258,32 +1260,46 @@ impl<'arena, 'env> ConversionEnv<'arena, 'env> { |
1258 | 1260 | #[cfg(test)] |
1259 | 1261 | mod tests { |
1260 | 1262 | use super::*; |
1261 | | - use crate::core::Const; |
1262 | | - |
1263 | | - #[test] |
1264 | | - fn value_has_unify_and_is_equal_impls() { |
1265 | | - let value = Arc::new(Value::ConstLit(Const::Bool(false))); |
1266 | 1263 |
|
1267 | | - // This test exists in order to cause a test failure when `Value` is changed. If this test |
1268 | | - // has failed and you have added a new variant to Value it is a prompt to ensure that |
1269 | | - // variant is handled in: |
| 1264 | + #[allow(dead_code)] |
| 1265 | + fn value_has_unify_and_is_equal_impls(value: Value<'_>) { |
| 1266 | + // The following match will fail to be exhaustive after new variants |
| 1267 | + // are added to `Value`. When this happens, it’s a prompt to make sure |
| 1268 | + // that the variants are handled in: |
1270 | 1269 | // |
1271 | | - // - surface::elaboration::Env::unify |
| 1270 | + // - surface::elaboration::Context::unify |
1272 | 1271 | // - core::semantics::is_equal |
1273 | 1272 | // |
1274 | 1273 | // NOTE: Only update the match below when you've updated the above functions. |
1275 | | - match value.as_ref() { |
1276 | | - Value::Stuck(_, _) => {} |
| 1274 | + match value { |
| 1275 | + Value::Stuck(..) => {} |
1277 | 1276 | Value::Universe => {} |
1278 | | - Value::FunType(_, _, _) => {} |
1279 | | - Value::FunLit(_, _) => {} |
1280 | | - Value::RecordType(_, _) => {} |
1281 | | - Value::RecordLit(_, _) => {} |
1282 | | - Value::ArrayLit(_) => {} |
1283 | | - Value::FormatRecord(_, _) => {} |
1284 | | - Value::FormatCond(_, _, _) => {} |
1285 | | - Value::FormatOverlap(_, _) => {} |
1286 | | - Value::ConstLit(_) => {} |
| 1277 | + Value::FunType(..) => {} |
| 1278 | + Value::FunLit(..) => {} |
| 1279 | + Value::RecordType(..) => {} |
| 1280 | + Value::RecordLit(..) => {} |
| 1281 | + Value::ArrayLit(..) => {} |
| 1282 | + Value::FormatRecord(..) => {} |
| 1283 | + Value::FormatCond(..) => {} |
| 1284 | + Value::FormatOverlap(..) => {} |
| 1285 | + Value::ConstLit(..) => {} |
| 1286 | + } |
| 1287 | + } |
| 1288 | + |
| 1289 | + #[allow(dead_code)] |
| 1290 | + fn elim_has_unify_and_is_equal_impls(elim: Elim<'_>) { |
| 1291 | + // The following match will fail to be exhaustive after new variants |
| 1292 | + // are added to `Elim`. When this happens, it’s a prompt to make sure |
| 1293 | + // that the variants are handled in: |
| 1294 | + // |
| 1295 | + // - surface::elaboration::Context::unify |
| 1296 | + // - core::semantics::is_equal |
| 1297 | + // |
| 1298 | + // NOTE: Only update the match below when you've updated the above functions. |
| 1299 | + match elim { |
| 1300 | + Elim::FunApp(..) => {} |
| 1301 | + Elim::RecordProj(..) => {} |
| 1302 | + Elim::ConstMatch(..) => {} |
1287 | 1303 | } |
1288 | 1304 | } |
1289 | 1305 | } |
0 commit comments