Formatting and comments.

This commit is contained in:
2023-08-13 19:55:14 -07:00
parent f8b73fcdfd
commit 127ac1f22e
5 changed files with 79 additions and 44 deletions

View File

@@ -5,9 +5,9 @@ use crate::ir::Program;
use crate::syntax::arbitrary::GenerationEnvironment; use crate::syntax::arbitrary::GenerationEnvironment;
use cranelift_jit::JITModule; use cranelift_jit::JITModule;
use cranelift_object::ObjectModule; use cranelift_object::ObjectModule;
use std::path::Path;
#[cfg(test)] #[cfg(test)]
use proptest::arbitrary::Arbitrary; use proptest::arbitrary::Arbitrary;
use std::path::Path;
use target_lexicon::Triple; use target_lexicon::Triple;
impl Backend<JITModule> { impl Backend<JITModule> {

View File

@@ -121,7 +121,7 @@ extern "C" fn runtime_print(
Err(_) => format!("{} = {}<unknown type>", reconstituted, value), Err(_) => format!("{} = {}<unknown type>", reconstituted, value),
}; };
if let Some(output_buffer) = unsafe{ output_buffer.as_mut() } { if let Some(output_buffer) = unsafe { output_buffer.as_mut() } {
writeln!(output_buffer, "{}", output).unwrap(); writeln!(output_buffer, "{}", output).unwrap();
} else { } else {
println!("{}", output); println!("{}", output);

View File

@@ -13,12 +13,13 @@ const VALID_VARIABLE_NAMES: &str = r"[a-z][a-zA-Z0-9_]*";
impl ConstantType { impl ConstantType {
fn get_operators(&self) -> &'static [(&'static str, usize)] { fn get_operators(&self) -> &'static [(&'static str, usize)] {
match self { match self {
ConstantType::I8| ConstantType::I16 | ConstantType::I32 | ConstantType::I64 => ConstantType::I8 | ConstantType::I16 | ConstantType::I32 | ConstantType::I64 => {
&[("+", 2), ("-", 1), ("-", 2), ("*", 2), ("/", 2)], &[("+", 2), ("-", 1), ("-", 2), ("*", 2), ("/", 2)]
ConstantType::U8| ConstantType::U16 | ConstantType::U32 | ConstantType::U64 => }
&[("+", 2), ("-", 2), ("*", 2), ("/", 2)], ConstantType::U8 | ConstantType::U16 | ConstantType::U32 | ConstantType::U64 => {
&[("+", 2), ("-", 2), ("*", 2), ("/", 2)]
}
} }
} }
} }
@@ -55,7 +56,10 @@ impl Arbitrary for Program {
type Strategy = BoxedStrategy<Self>; type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(genenv: Self::Parameters) -> Self::Strategy { fn arbitrary_with(genenv: Self::Parameters) -> Self::Strategy {
proptest::collection::vec(ProgramStatementInfo::arbitrary(), genenv.block_length.clone()) proptest::collection::vec(
ProgramStatementInfo::arbitrary(),
genenv.block_length.clone(),
)
.prop_flat_map(move |mut items| { .prop_flat_map(move |mut items| {
let mut statements = Vec::new(); let mut statements = Vec::new();
let mut genenv = genenv.clone(); let mut genenv = genenv.clone();
@@ -169,15 +173,18 @@ impl Arbitrary for Expression {
// now we generate our recursive types, given our leaf strategy // now we generate our recursive types, given our leaf strategy
leaf_strategy leaf_strategy
.prop_recursive(3, 10, 2, move |strat| { .prop_recursive(3, 10, 2, move |strat| {
(select(genenv.return_type.get_operators()), strat.clone(), strat).prop_map( (
|((oper, count), left, right)| { select(genenv.return_type.get_operators()),
strat.clone(),
strat,
)
.prop_map(|((oper, count), left, right)| {
let mut args = vec![left, right]; let mut args = vec![left, right];
while args.len() > count { while args.len() > count {
args.pop(); args.pop();
} }
Expression::Primitive(Location::manufactured(), oper.to_string(), args) Expression::Primitive(Location::manufactured(), oper.to_string(), args)
}, })
)
}) })
.boxed() .boxed()
} }

View File

@@ -1,9 +1,9 @@
/// A type inference pass for NGR
mod ast; mod ast;
mod convert; mod convert;
mod finalize; mod finalize;
mod solve; mod solve;
use self::convert::convert_program; use self::convert::convert_program;
use self::finalize::finalize_program; use self::finalize::finalize_program;
use self::solve::solve_constraints; use self::solve::solve_constraints;
@@ -11,9 +11,9 @@ pub use self::solve::{TypeInferenceError, TypeInferenceResult, TypeInferenceWarn
use crate::ir::ast as ir; use crate::ir::ast as ir;
use crate::syntax; use crate::syntax;
#[cfg(test)] #[cfg(test)]
use proptest::prelude::Arbitrary;
#[cfg(test)]
use crate::syntax::arbitrary::GenerationEnvironment; use crate::syntax::arbitrary::GenerationEnvironment;
#[cfg(test)]
use proptest::prelude::Arbitrary;
impl syntax::Program { impl syntax::Program {
/// Infer the types for the syntactic AST, returning either a type-checked program in /// Infer the types for the syntactic AST, returning either a type-checked program in

View File

@@ -5,6 +5,7 @@ use codespan_reporting::diagnostic::Diagnostic;
use internment::ArcIntern; use internment::ArcIntern;
use std::{collections::HashMap, fmt}; use std::{collections::HashMap, fmt};
/// A type inference constraint that we're going to need to solve.
#[derive(Debug)] #[derive(Debug)]
pub enum Constraint { pub enum Constraint {
/// The given type must be printable using the `print` built-in /// The given type must be printable using the `print` built-in
@@ -48,6 +49,11 @@ impl fmt::Display for Constraint {
pub type TypeResolutions = HashMap<ArcIntern<String>, PrimitiveType>; pub type TypeResolutions = HashMap<ArcIntern<String>, PrimitiveType>;
/// The results of type inference; like [`Result`], but with a bit more information.
///
/// This result is parameterized, because sometimes it's handy to return slightly
/// different things; there's a [`TypeInferenceResult::map`] function for performing
/// those sorts of conversions.
pub enum TypeInferenceResult<Result> { pub enum TypeInferenceResult<Result> {
Success { Success {
result: Result, result: Result,
@@ -62,6 +68,8 @@ pub enum TypeInferenceResult<Result> {
impl<R> TypeInferenceResult<R> { impl<R> TypeInferenceResult<R> {
// If this was a successful type inference, run the function over the result to // If this was a successful type inference, run the function over the result to
// create a new result. // create a new result.
//
// This is the moral equivalent of [`Result::map`], but for type inference results.
pub fn map<U, F>(self, f: F) -> TypeInferenceResult<U> pub fn map<U, F>(self, f: F) -> TypeInferenceResult<U>
where where
F: FnOnce(R) -> U, F: FnOnce(R) -> U,
@@ -89,11 +97,17 @@ impl<R> TypeInferenceResult<R> {
} }
} }
/// The various kinds of errors that can occur while doing type inference.
pub enum TypeInferenceError { pub enum TypeInferenceError {
/// The user provide a constant that is too large for its inferred type.
ConstantTooLarge(Location, PrimitiveType, u64), ConstantTooLarge(Location, PrimitiveType, u64),
/// The two types needed to be equivalent, but weren't.
NotEquivalent(Location, PrimitiveType, PrimitiveType), NotEquivalent(Location, PrimitiveType, PrimitiveType),
/// We cannot safely cast the first type to the second type.
CannotSafelyCast(Location, PrimitiveType, PrimitiveType), CannotSafelyCast(Location, PrimitiveType, PrimitiveType),
/// The primitive invocation provided the wrong number of arguments.
WrongPrimitiveArity(Location, ir::Primitive, usize, usize, usize), WrongPrimitiveArity(Location, ir::Primitive, usize, usize, usize),
/// We had a constraint we just couldn't solve.
CouldNotSolve(Constraint), CouldNotSolve(Constraint),
} }
@@ -164,6 +178,10 @@ impl From<TypeInferenceError> for Diagnostic<usize> {
} }
} }
/// Warnings that we might want to tell the user about.
///
/// These are fine, probably, but could indicate some behavior the user might not
/// expect, and so they might want to do something about them.
pub enum TypeInferenceWarning { pub enum TypeInferenceWarning {
DefaultedTo(Location, Type), DefaultedTo(Location, Type),
} }
@@ -178,6 +196,16 @@ impl From<TypeInferenceWarning> for Diagnostic<usize> {
} }
} }
/// Solve all the constraints in the provided database.
///
/// This process can take a bit, so you might not want to do it multiple times. Basically,
/// it's going to grind on these constraints until either it figures them out, or it stops
/// making progress. I haven't done the math on the constraints to even figure out if this
/// is guaranteed to halt, though, let alone terminate in some reasonable amount of time.
///
/// The return value is a type inference result, which pairs some warnings with either a
/// successful set of type resolutions (mappings from type variables to their values), or
/// a series of inference errors.
pub fn solve_constraints( pub fn solve_constraints(
mut constraint_db: Vec<Constraint>, mut constraint_db: Vec<Constraint>,
) -> TypeInferenceResult<TypeResolutions> { ) -> TypeInferenceResult<TypeResolutions> {