From 52c4891c5b28248edd41e6695fb889ba494a3204 Mon Sep 17 00:00:00 2001 From: Alain Zscheile Date: Tue, 26 Sep 2023 12:04:09 +0200 Subject: [PATCH] properly fix Expr equality (which ignores SourceSpans) --- crates/yn-qgy4hbz-core/src/lib.rs | 66 +++++++++++++++++++++------- crates/yn-qgy4hbz-core/src/pat.rs | 32 ++------------ crates/yn-qgy4hbz-core/src/typeck.rs | 38 +++++++++++----- 3 files changed, 81 insertions(+), 55 deletions(-) diff --git a/crates/yn-qgy4hbz-core/src/lib.rs b/crates/yn-qgy4hbz-core/src/lib.rs index 4066ab5..2387b5b 100644 --- a/crates/yn-qgy4hbz-core/src/lib.rs +++ b/crates/yn-qgy4hbz-core/src/lib.rs @@ -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 { - pub span: SourceSpan, - pub fields: Vec<(Option>, 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 core::cmp::PartialEq for Record { - 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> for EvEqSourceSpan { + #[inline] + fn from(x: core::ops::Range) -> Self { + Self(x.into()) } } +impl From 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 { + pub span: EvEqSourceSpan, + pub fields: Vec<(Option>, 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, }, SelfRecur { pat: FullPattern, - inner_span: SourceSpan, + inner_span: EvEqSourceSpan, inner: Box, }, @@ -64,7 +100,7 @@ pub enum Expr { Apply { lam: Box, - args: Vec<(SourceSpan, Expr)>, + args: Vec<(EvEqSourceSpan, Expr)>, }, Ref(usize), @@ -73,9 +109,9 @@ pub enum Expr { TyRecord(Record), Select { - prim_span: SourceSpan, + prim_span: EvEqSourceSpan, prim: Box, - then: VecDeque<(SourceSpan, Box)>, + then: VecDeque<(EvEqSourceSpan, Box)>, }, } @@ -269,7 +305,7 @@ fn parse_minexpr(env: &mut ParseEnv<'_>) -> Result { 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 { diff --git a/crates/yn-qgy4hbz-core/src/pat.rs b/crates/yn-qgy4hbz-core/src/pat.rs index a04f97b..f6d768e 100644 --- a/crates/yn-qgy4hbz-core/src/pat.rs +++ b/crates/yn-qgy4hbz-core/src/pat.rs @@ -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>, -} - -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>, } impl Pattern { @@ -188,7 +164,7 @@ impl MaybeParse for Pattern { Tok::PatIgnore => Pattern::Ignore, Tok::Dot => { if let Some(r) = Record::::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")); diff --git a/crates/yn-qgy4hbz-core/src/typeck.rs b/crates/yn-qgy4hbz-core/src/typeck.rs index a5b6c4b..57f455c 100644 --- a/crates/yn-qgy4hbz-core/src/typeck.rs +++ b/crates/yn-qgy4hbz-core/src/typeck.rs @@ -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