properly fix Expr equality (which ignores SourceSpans)

This commit is contained in:
Alain Zscheile 2023-09-26 12:04:09 +02:00
parent f49ebe6a09
commit 52c4891c5b
3 changed files with 81 additions and 55 deletions

View file

@ -15,24 +15,60 @@ pub use pat::{FullPattern, Pattern};
pub mod typeck;
use core::cmp;
use miette::SourceSpan;
use std::collections::VecDeque;
#[derive(Clone, Debug)]
pub struct Record<V> {
pub span: SourceSpan,
pub fields: Vec<(Option<Box<str>>, V)>,
/// A SourceSpan which is always equal to all other SourceSpans
/// (to be used to ignore span differences in expression comparisons)
#[derive(Clone, Copy, Debug)]
pub struct EvEqSourceSpan(pub SourceSpan);
impl cmp::PartialEq for EvEqSourceSpan {
#[inline(always)]
fn eq(&self, _: &Self) -> bool {
true
}
#[inline(always)]
fn ne(&self, _: &Self) -> bool {
false
}
}
impl<V: core::cmp::PartialEq> core::cmp::PartialEq for Record<V> {
fn eq(&self, rhs: &Self) -> bool {
self.fields == rhs.fields
impl From<(usize, usize)> for EvEqSourceSpan {
#[inline]
fn from(x: (usize, usize)) -> Self {
Self(x.into())
}
fn ne(&self, rhs: &Self) -> bool {
self.fields != rhs.fields
}
impl From<core::ops::Range<usize>> for EvEqSourceSpan {
#[inline]
fn from(x: core::ops::Range<usize>) -> Self {
Self(x.into())
}
}
impl From<EvEqSourceSpan> for SourceSpan {
#[inline(always)]
fn from(x: EvEqSourceSpan) -> SourceSpan {
x.0
}
}
impl<'a> From<&'a EvEqSourceSpan> for SourceSpan {
#[inline(always)]
fn from(x: &'a EvEqSourceSpan) -> SourceSpan {
x.0
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Record<V> {
pub span: EvEqSourceSpan,
pub fields: Vec<(Option<Box<str>>, V)>,
}
#[derive(Clone, Debug, PartialEq)]
pub enum Expr {
TyTy,
@ -47,13 +83,13 @@ pub enum Expr {
TyLambda {
pat: FullPattern,
body_span: SourceSpan,
body_span: EvEqSourceSpan,
exp: Box<Expr>,
},
SelfRecur {
pat: FullPattern,
inner_span: SourceSpan,
inner_span: EvEqSourceSpan,
inner: Box<Expr>,
},
@ -64,7 +100,7 @@ pub enum Expr {
Apply {
lam: Box<Expr>,
args: Vec<(SourceSpan, Expr)>,
args: Vec<(EvEqSourceSpan, Expr)>,
},
Ref(usize),
@ -73,9 +109,9 @@ pub enum Expr {
TyRecord(Record<Expr>),
Select {
prim_span: SourceSpan,
prim_span: EvEqSourceSpan,
prim: Box<Expr>,
then: VecDeque<(SourceSpan, Box<str>)>,
then: VecDeque<(EvEqSourceSpan, Box<str>)>,
},
}
@ -269,7 +305,7 @@ fn parse_minexpr(env: &mut ParseEnv<'_>) -> Result<Expr, Perr> {
match kind {
Tok::DotIdent(i) => {
let ioffset_end = env.lxr.offset();
let span: SourceSpan = (usize::try_from(offset).unwrap()..ioffset_end).into();
let span: EvEqSourceSpan = (usize::try_from(offset).unwrap()..ioffset_end).into();
if let Expr::Select { then, .. } = &mut ret {
then.push_back((span, i));
} else {

View file

@ -4,13 +4,12 @@
* SPDX-License-Identifier: Apache-2.0
*/
use super::{Expr, Record};
use crate::parser::{
unexpected_token, Env as ParseEnv, Error as Perr, ErrorKind as Pek, MaybeParse, Offset, Parse,
Token, TokenKind as Tok,
};
use crate::typeck::{BinderState, TyContext};
use miette::SourceSpan;
use crate::{EvEqSourceSpan, Expr, Record};
#[derive(Clone, Debug)]
pub enum Pattern {
@ -42,33 +41,10 @@ impl core::cmp::PartialEq for Pattern {
}
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct FullPattern {
pub pat: Pattern,
pub pty: Option<Box<(SourceSpan, Expr)>>,
}
impl core::cmp::PartialEq for FullPattern {
fn eq(&self, rhs: &Self) -> bool {
if self.pat != rhs.pat {
return false;
}
match (&self.pty, &rhs.pty) {
(None, None) => true,
(Some(_), None) | (None, Some(_)) => false,
(Some(lt), Some(rt)) => lt.1 == rt.1,
}
}
fn ne(&self, rhs: &Self) -> bool {
if self.pat == rhs.pat {
return false;
}
match (&self.pty, &rhs.pty) {
(None, None) => false,
(Some(_), None) | (None, Some(_)) => true,
(Some(lt), Some(rt)) => lt.1 != rt.1,
}
}
pub pty: Option<Box<(EvEqSourceSpan, Expr)>>,
}
impl Pattern {
@ -188,7 +164,7 @@ impl MaybeParse for Pattern {
Tok::PatIgnore => Pattern::Ignore,
Tok::Dot => {
if let Some(r) = Record::<Pattern>::maybe_parse(env)? {
Pattern::Record(r)
Pattern::Record(r)
} else {
let Token { kind, offset } = env.lxr.next_in_noeof(".pattern")?;
return Err(unexpected_token(offset, kind, ".pattern"));

View file

@ -122,13 +122,19 @@ impl FullPattern {
) -> Result<(), Error> {
if pr.fields.len() != tr.fields.len() {
return Err(Error::RecordLengthMismatch {
lengths: vec![(pr.span, pr.fields.len()), (tr.span, tr.fields.len())],
lengths: vec![
(pr.span.into(), pr.fields.len()),
(tr.span.into(), tr.fields.len()),
],
});
}
for (pv, tv) in pr.fields.iter().zip(tr.fields.iter()) {
if pv.0 != tv.0 {
return Err(Error::RecordFieldNameMismatch {
names: vec![(pr.span, pv.0.clone()), (tr.span, tv.0.clone())],
names: vec![
(pr.span.into(), pv.0.clone()),
(tr.span.into(), tv.0.clone()),
],
});
}
intern(&pv.1, &tv.1, &tr.span, ctx)?;
@ -139,11 +145,11 @@ impl FullPattern {
fn intern(
pat: &Pattern,
ty: &Expr,
tspan: &SourceSpan,
tspan: &EvEqSourceSpan,
ctx: &mut TyContext,
) -> Result<(), Error> {
if ty.weak_is_type() == Some(false) {
return Err(Error::ExprNotaType(*tspan, ty.clone()));
return Err(Error::ExprNotaType(tspan.into(), ty.clone()));
}
match (pat, ty) {
// catch-all
@ -161,7 +167,7 @@ impl FullPattern {
// recursion
(Pattern::Record(pr), Expr::TyRecord(tr)) => intern_record(pr, tr, ctx),
(Pattern::Record(_), _) => Err(Error::ExprNotaType(*tspan, ty.clone())),
(Pattern::Record(_), _) => Err(Error::ExprNotaType(tspan.into(), ty.clone())),
}
}
@ -177,10 +183,10 @@ impl FullPattern {
impl Expr {
fn type_check(
&mut self,
self_span: SourceSpan,
self_span: EvEqSourceSpan,
ctx: &mut TyContext,
expect: &Expr,
expect_span: SourceSpan,
expect_span: EvEqSourceSpan,
) -> Result<(), Error> {
// TODO: implement this properly
if let Some(got) = self.type_infer(ctx)? {
@ -188,7 +194,10 @@ impl Expr {
Ok(())
} else {
Err(Error::TypesMismatch {
cases: vec![(self_span, got), (expect_span, expect.clone())],
cases: vec![
(self_span.into(), got),
(expect_span.into(), expect.clone()),
],
})
}
} else {
@ -224,7 +233,7 @@ impl Expr {
match rcd.lookup(RecordEntry::Name(&i)) {
None => {
return Err(Error::SelectNotFound {
span,
span: span.into(),
name: i,
val: Expr::Record(rcd.clone()),
})
@ -280,7 +289,7 @@ impl Expr {
if let (Some((loc, x)), Some(y)) = (pat.pty.as_ref().map(|x| &**x), &tmp) {
if x != y {
return Err(Error::TypesMismatch {
cases: vec![(*loc, x.clone()), (*inner_span, y.clone())],
cases: vec![(loc.into(), x.clone()), ((*inner_span).into(), y.clone())],
});
}
}
@ -321,7 +330,12 @@ impl Expr {
let span = *span;
let pat = match &mut lam_t {
Expr::TyLambda { pat, .. } => pat,
_ => return Err(Error::InvalidInvoke { span, ty: lam_t }),
_ => {
return Err(Error::InvalidInvoke {
span: span.into(),
ty: lam_t,
})
}
};
// TODO: figure out subtpying
if let Some(y) = &mut pat.pty {
@ -377,7 +391,7 @@ impl Expr {
};
assert!(!then.is_empty());
for (ispan, i) in &*then {
let span = *ispan;
let span = ispan.into();
match pt {
pt @ (Expr::TyTy
| Expr::Tbool