Allow direct packing, unpacking of erased types

This commit is contained in:
Ayaz Hafiz 2023-07-02 13:17:44 -05:00
parent 1d1db83cc7
commit cd64134b0a
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
6 changed files with 296 additions and 185 deletions

View file

@ -29,6 +29,7 @@ pub enum UseKind {
ExpectLookup,
ErasedMake(ErasedField),
Erased,
FunctionPointer,
}
pub enum ProblemKind<'a> {
@ -119,6 +120,24 @@ pub enum ProblemKind<'a> {
num_needed: usize,
num_given: usize,
},
ErasedMakeValueNotBoxed {
symbol: Symbol,
def_layout: InLayout<'a>,
def_line: usize,
},
ErasedMakeCalleeNotFunctionPointer {
symbol: Symbol,
def_layout: InLayout<'a>,
def_line: usize,
},
ErasedLoadValueNotBoxed {
symbol: Symbol,
target_layout: InLayout<'a>,
},
ErasedLoadCalleeNotFunctionPointer {
symbol: Symbol,
target_layout: InLayout<'a>,
},
}
pub struct Problem<'a> {
@ -276,7 +295,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
match body {
Stmt::Let(x, e, x_layout, rest) => {
if let Some(e_layout) = self.check_expr(e) {
if let Some(e_layout) = self.check_expr(e, *x_layout) {
if self.not_equiv(e_layout, *x_layout) {
self.problem(ProblemKind::SymbolDefMismatch {
symbol: *x,
@ -393,7 +412,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
}
}
fn check_expr(&mut self, e: &Expr<'a>) -> Option<InLayout<'a>> {
fn check_expr(&mut self, e: &Expr<'a>, target_layout: InLayout<'a>) -> Option<InLayout<'a>> {
match e {
Expr::Literal(_) => None,
Expr::NullPointer => None,
@ -486,11 +505,10 @@ impl<'a, 'r> Ctx<'a, 'r> {
}
}
}),
&Expr::ErasedMake { value, callee } => {
self.check_erased_make(value, callee);
Some(Layout::ERASED)
&Expr::ErasedMake { value, callee } => Some(self.check_erased_make(value, callee)),
&Expr::ErasedLoad { symbol, field } => {
Some(self.check_erased_load(symbol, field, target_layout))
}
&Expr::ErasedLoad { symbol, field } => Some(self.check_erased_load(symbol, field)),
&Expr::FunctionPointer { lambda_name } => {
let lambda_symbol = lambda_name.name();
if !self.procs.iter().any(|((name, proc), _)| {
@ -500,7 +518,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
symbol: lambda_symbol,
});
}
Some(Layout::OPAQUE_PTR)
Some(target_layout)
}
&Expr::Reset {
symbol,
@ -691,7 +709,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
args: arg_layouts,
ret: *ret_layout,
}));
self.check_sym_layout(*pointer, expected_layout, UseKind::SwitchCond);
self.check_sym_layout(*pointer, expected_layout, UseKind::FunctionPointer);
for (arg, wanted_layout) in arguments.iter().zip(arg_layouts.iter()) {
self.check_sym_layout(*arg, *wanted_layout, UseKind::CallArg);
}
@ -756,28 +774,67 @@ impl<'a, 'r> Ctx<'a, 'r> {
}
}
fn check_erased_make(&mut self, value: Option<Symbol>, callee: Symbol) {
fn check_erased_make(&mut self, value: Option<Symbol>, callee: Symbol) -> InLayout<'a> {
if let Some(value) = value {
self.check_sym_layout(
value,
Layout::OPAQUE_PTR,
UseKind::ErasedMake(ErasedField::Value),
);
self.with_sym_layout(value, |this, def_line, layout| {
let repr = this.interner.get_repr(layout);
if !matches!(repr, LayoutRepr::Boxed(_)) {
this.problem(ProblemKind::ErasedMakeValueNotBoxed {
symbol: value,
def_layout: layout,
def_line,
});
}
Option::<()>::None
});
}
self.check_sym_layout(
callee,
Layout::OPAQUE_PTR,
UseKind::ErasedMake(ErasedField::Callee),
);
self.with_sym_layout(callee, |this, def_line, layout| {
let repr = this.interner.get_repr(layout);
if !matches!(repr, LayoutRepr::FunctionPointer(_)) {
this.problem(ProblemKind::ErasedMakeCalleeNotFunctionPointer {
symbol: callee,
def_layout: layout,
def_line,
});
}
Option::<()>::None
});
Layout::ERASED
}
fn check_erased_load(&mut self, symbol: Symbol, field: ErasedField) -> InLayout<'a> {
fn check_erased_load(
&mut self,
symbol: Symbol,
field: ErasedField,
target_layout: InLayout<'a>,
) -> InLayout<'a> {
self.check_sym_layout(symbol, Layout::ERASED, UseKind::Erased);
match field {
ErasedField::Value => Layout::OPAQUE_PTR,
ErasedField::Callee => Layout::OPAQUE_PTR,
ErasedField::Value => {
let repr = self.interner.get_repr(target_layout);
if !matches!(repr, LayoutRepr::Boxed(_)) {
self.problem(ProblemKind::ErasedLoadValueNotBoxed {
symbol,
target_layout,
});
}
}
ErasedField::Callee => {
let repr = self.interner.get_repr(target_layout);
if !matches!(repr, LayoutRepr::FunctionPointer(_)) {
self.problem(ProblemKind::ErasedLoadCalleeNotFunctionPointer {
symbol,
target_layout,
});
}
}
}
target_layout
}
}

View file

@ -415,6 +415,74 @@ where
f.as_string(num_given),
])
}
ProblemKind::ErasedMakeValueNotBoxed {
symbol,
def_layout,
def_line,
} => {
title = "ERASED VALUE IS NOT BOXED";
docs_before = vec![(
def_line,
f.concat([
f.reflow("The value "),
format_symbol(f, interns, symbol),
f.reflow(" defined here"),
]),
)];
f.concat([
f.reflow("must be boxed in order to be erased, but has layout "),
interner.to_doc_top(def_layout, f),
])
}
ProblemKind::ErasedMakeCalleeNotFunctionPointer {
symbol,
def_layout,
def_line,
} => {
title = "ERASED CALLEE IS NOT A FUNCTION POINTER";
docs_before = vec![(
def_line,
f.concat([
f.reflow("The value "),
format_symbol(f, interns, symbol),
f.reflow(" defined here"),
]),
)];
f.concat([
f.reflow(
"must be a function pointer in order to be an erasure callee, but has layout ",
),
interner.to_doc_top(def_layout, f),
])
}
ProblemKind::ErasedLoadValueNotBoxed {
symbol,
target_layout,
} => {
title = "ERASED VALUE IS NOT BOXED";
docs_before = vec![];
f.concat([
f.reflow("The erased value load "),
format_symbol(f, interns, symbol),
f.reflow(" has layout "),
interner.to_doc_top(target_layout, f),
f.reflow(", but should be boxed!"),
])
}
ProblemKind::ErasedLoadCalleeNotFunctionPointer {
symbol,
target_layout,
} => {
title = "ERASED CALLEE IS NOT A FUNCTION POINTER";
docs_before = vec![];
f.concat([
f.reflow("The erased callee load "),
format_symbol(f, interns, symbol),
f.reflow(" has layout "),
interner.to_doc_top(target_layout, f),
f.reflow(", but should be a function pointer!"),
])
}
};
(title, docs_before, doc)
}
@ -443,6 +511,7 @@ fn format_use_kind(use_kind: UseKind) -> &'static str {
ErasedField::Callee => "erased callee field",
},
UseKind::Erased => "erasure",
UseKind::FunctionPointer => "function pointer",
}
}