Allow any expression as constants

This is only a start. It compiles, but with a few TODOs left open. In particular, it doesn't currently handle constants depending on other constants or functions; nor does it hoist constants.
This commit is contained in:
KtorZ 2024-08-02 17:23:14 +02:00
parent 79cf0b8d97
commit cd0a9440e8
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
17 changed files with 192 additions and 282 deletions

View File

@ -161,6 +161,7 @@ impl TypedModule {
pub fn register_definitions( pub fn register_definitions(
&self, &self,
functions: &mut IndexMap<FunctionAccessKey, TypedFunction>, functions: &mut IndexMap<FunctionAccessKey, TypedFunction>,
constants: &mut IndexMap<FunctionAccessKey, TypedExpr>,
data_types: &mut IndexMap<DataTypeKey, TypedDataType>, data_types: &mut IndexMap<DataTypeKey, TypedDataType>,
) { ) {
for def in self.definitions() { for def in self.definitions() {
@ -203,7 +204,17 @@ impl TypedModule {
} }
} }
Definition::TypeAlias(_) | Definition::ModuleConstant(_) | Definition::Use(_) => {} Definition::ModuleConstant(ModuleConstant { name, value, .. }) => {
constants.insert(
FunctionAccessKey {
module_name: self.name.clone(),
function_name: name.clone(),
},
value.clone(),
);
}
Definition::TypeAlias(_) | Definition::Use(_) => {}
} }
} }
} }
@ -459,18 +470,17 @@ pub struct Use<PackageName> {
pub unqualified: Vec<UnqualifiedImport>, pub unqualified: Vec<UnqualifiedImport>,
} }
pub type TypedModuleConstant = ModuleConstant<Rc<Type>>; pub type TypedModuleConstant = ModuleConstant<TypedExpr>;
pub type UntypedModuleConstant = ModuleConstant<()>; pub type UntypedModuleConstant = ModuleConstant<UntypedExpr>;
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct ModuleConstant<T> { pub struct ModuleConstant<Expr> {
pub doc: Option<String>, pub doc: Option<String>,
pub location: Span, pub location: Span,
pub public: bool, pub public: bool,
pub name: String, pub name: String,
pub annotation: Option<Annotation>, pub annotation: Option<Annotation>,
pub value: Box<Constant>, pub value: Expr,
pub tipo: T,
} }
pub type TypedValidator = Validator<Rc<Type>, TypedArg, TypedExpr>; pub type TypedValidator = Validator<Rc<Type>, TypedArg, TypedExpr>;
@ -746,7 +756,7 @@ pub enum Definition<T, Arg, Expr, PackageName> {
Use(Use<PackageName>), Use(Use<PackageName>),
ModuleConstant(ModuleConstant<T>), ModuleConstant(ModuleConstant<Expr>),
Test(Function<T, Expr, ArgVia<Arg, Expr>>), Test(Function<T, Expr, ArgVia<Arg, Expr>>),
@ -843,55 +853,6 @@ pub struct DefinitionLocation<'module> {
pub span: Span, pub span: Span,
} }
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum Constant {
Int {
location: Span,
value: String,
base: Base,
},
String {
location: Span,
value: String,
},
ByteArray {
location: Span,
bytes: Vec<u8>,
preferred_format: ByteArrayFormatPreference,
},
CurvePoint {
location: Span,
point: Box<Curve>,
preferred_format: ByteArrayFormatPreference,
},
}
impl Constant {
pub fn tipo(&self) -> Rc<Type> {
match self {
Constant::Int { .. } => Type::int(),
Constant::String { .. } => Type::string(),
Constant::ByteArray { .. } => Type::byte_array(),
Constant::CurvePoint { point, .. } => match point.as_ref() {
Curve::Bls12_381(Bls12_381Point::G1(_)) => Type::g1_element(),
Curve::Bls12_381(Bls12_381Point::G2(_)) => Type::g2_element(),
},
}
}
pub fn location(&self) -> Span {
match self {
Constant::Int { location, .. }
| Constant::String { location, .. }
| Constant::ByteArray { location, .. }
| Constant::CurvePoint { location, .. } => *location,
}
}
}
pub type TypedCallArg = CallArg<TypedExpr>; pub type TypedCallArg = CallArg<TypedExpr>;
pub type ParsedCallArg = CallArg<Option<UntypedExpr>>; pub type ParsedCallArg = CallArg<Option<UntypedExpr>>;

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
ast::{ ast::{
Annotation, ArgBy, ArgName, ArgVia, AssignmentKind, AssignmentPattern, BinOp, Annotation, ArgBy, ArgName, ArgVia, AssignmentKind, AssignmentPattern, BinOp,
ByteArrayFormatPreference, CallArg, Constant, CurveType, DataType, Definition, Function, ByteArrayFormatPreference, CallArg, CurveType, DataType, Definition, Function,
LogicalOpChainKind, ModuleConstant, OnTestFailure, Pattern, RecordConstructor, LogicalOpChainKind, ModuleConstant, OnTestFailure, Pattern, RecordConstructor,
RecordConstructorArg, RecordUpdateSpread, Span, TraceKind, TypeAlias, TypedArg, RecordConstructorArg, RecordUpdateSpread, Span, TraceKind, TypeAlias, TypedArg,
TypedValidator, UnOp, UnqualifiedImport, UntypedArg, UntypedArgVia, UntypedAssignmentKind, TypedValidator, UnOp, UnqualifiedImport, UntypedArg, UntypedArgVia, UntypedAssignmentKind,
@ -9,7 +9,7 @@ use crate::{
UntypedPattern, UntypedRecordUpdateArg, Use, Validator, CAPTURE_VARIABLE, UntypedPattern, UntypedRecordUpdateArg, Use, Validator, CAPTURE_VARIABLE,
}, },
docvec, docvec,
expr::{FnStyle, UntypedExpr, DEFAULT_ERROR_STR, DEFAULT_TODO_STR}, expr::{FnStyle, TypedExpr, UntypedExpr, DEFAULT_ERROR_STR, DEFAULT_TODO_STR},
parser::{ parser::{
extra::{Comment, ModuleExtra}, extra::{Comment, ModuleExtra},
token::Base, token::Base,
@ -338,34 +338,20 @@ impl<'comments> Formatter<'comments> {
}) })
} }
fn const_expr<'a>(&mut self, value: &'a Constant) -> Document<'a> { fn const_expr<'a>(&mut self, _value: &'a UntypedExpr) -> Document<'a> {
match value { todo!(
Constant::ByteArray { "format const_expr: surround complex expressions with a block, and leave simple expression without"
bytes, );
preferred_format,
..
} => self.bytearray(bytes, None, preferred_format),
Constant::CurvePoint {
point,
preferred_format,
..
} => self.bytearray(
&point.compress(),
Some(point.as_ref().into()),
preferred_format,
),
Constant::Int { value, base, .. } => self.int(value, base),
Constant::String { value, .. } => self.string(value),
}
} }
pub fn docs_const_expr<'a>(&mut self, name: &'a str, value: &'a Constant) -> Document<'a> { pub fn docs_const_expr<'a>(&mut self, name: &'a str, value: &'a TypedExpr) -> Document<'a> {
let mut printer = tipo::pretty::Printer::new(); let mut printer = tipo::pretty::Printer::new();
name.to_doc() name.to_doc()
.append(": ") .append(": ")
.append(printer.print(&value.tipo())) .append(printer.print(&value.tipo()))
.append(" = ") // TODO: Show full expression in docs when simple enough
.append(self.const_expr(value)) // .append(" = ")
// .append(self.const_expr(value))
} }
fn documented_definition<'a>(&mut self, s: &'a UntypedDefinition) -> Document<'a> { fn documented_definition<'a>(&mut self, s: &'a UntypedDefinition) -> Document<'a> {

View File

@ -5,9 +5,9 @@ pub mod tree;
use self::{ use self::{
air::Air, air::Air,
builder::{ builder::{
cast_validator_args, constants_ir, convert_type_to_data, extract_constant, cast_validator_args, convert_type_to_data, extract_constant, modify_cyclic_calls,
modify_cyclic_calls, modify_self_calls, rearrange_list_clauses, AssignmentProperties, modify_self_calls, rearrange_list_clauses, AssignmentProperties, ClauseProperties,
ClauseProperties, CodeGenSpecialFuncs, CycleFunctionNames, HoistableFunction, Variant, CodeGenSpecialFuncs, CycleFunctionNames, HoistableFunction, Variant,
}, },
tree::{AirTree, TreePath}, tree::{AirTree, TreePath},
}; };
@ -58,6 +58,7 @@ pub struct CodeGenerator<'a> {
plutus_version: PlutusVersion, plutus_version: PlutusVersion,
/// immutable index maps /// immutable index maps
functions: IndexMap<&'a FunctionAccessKey, &'a TypedFunction>, functions: IndexMap<&'a FunctionAccessKey, &'a TypedFunction>,
constants: IndexMap<&'a FunctionAccessKey, &'a TypedExpr>,
data_types: IndexMap<&'a DataTypeKey, &'a TypedDataType>, data_types: IndexMap<&'a DataTypeKey, &'a TypedDataType>,
module_types: IndexMap<&'a str, &'a TypeInfo>, module_types: IndexMap<&'a str, &'a TypeInfo>,
module_src: IndexMap<&'a str, &'a (String, LineNumbers)>, module_src: IndexMap<&'a str, &'a (String, LineNumbers)>,
@ -82,6 +83,7 @@ impl<'a> CodeGenerator<'a> {
pub fn new( pub fn new(
plutus_version: PlutusVersion, plutus_version: PlutusVersion,
functions: IndexMap<&'a FunctionAccessKey, &'a TypedFunction>, functions: IndexMap<&'a FunctionAccessKey, &'a TypedFunction>,
constants: IndexMap<&'a FunctionAccessKey, &'a TypedExpr>,
data_types: IndexMap<&'a DataTypeKey, &'a TypedDataType>, data_types: IndexMap<&'a DataTypeKey, &'a TypedDataType>,
module_types: IndexMap<&'a str, &'a TypeInfo>, module_types: IndexMap<&'a str, &'a TypeInfo>,
module_src: IndexMap<&'a str, &'a (String, LineNumbers)>, module_src: IndexMap<&'a str, &'a (String, LineNumbers)>,
@ -90,6 +92,7 @@ impl<'a> CodeGenerator<'a> {
CodeGenerator { CodeGenerator {
plutus_version, plutus_version,
functions, functions,
constants,
data_types, data_types,
module_types, module_types,
module_src, module_src,
@ -268,12 +271,7 @@ impl<'a> CodeGenerator<'a> {
TypedExpr::Var { TypedExpr::Var {
constructor, name, .. constructor, name, ..
} => match &constructor.variant { } => AirTree::var(constructor.clone(), name, ""),
ValueConstructorVariant::ModuleConstant { literal, .. } => {
constants_ir(literal)
}
_ => AirTree::var(constructor.clone(), name, ""),
},
TypedExpr::Fn { args, body, .. } => AirTree::anon_func( TypedExpr::Fn { args, body, .. } => AirTree::anon_func(
args.iter() args.iter()
@ -743,8 +741,16 @@ impl<'a> CodeGenerator<'a> {
AirTree::builtin(*builtin, tipo.clone(), vec![]) AirTree::builtin(*builtin, tipo.clone(), vec![])
} }
} }
ModuleValueConstructor::Constant { literal, .. } => { ModuleValueConstructor::Constant { module, name, .. } => {
builder::constants_ir(literal) let type_info = self.module_types.get(module_name.as_str()).unwrap();
let value = type_info.values.get(name).unwrap();
AirTree::var(
ValueConstructor::public(tipo.clone(), value.variant.clone()),
format!("{module}_{name}"),
"",
)
} }
}, },
@ -4245,8 +4251,52 @@ impl<'a> CodeGenerator<'a> {
} }
.into(), .into(),
)), )),
ValueConstructorVariant::ModuleConstant { .. } => { ValueConstructorVariant::ModuleConstant { module, name, .. } => {
unreachable!("{:#?}, {}", constructor, name) let access_key = FunctionAccessKey {
module_name: module.clone(),
function_name: name.clone(),
};
let definition = self
.constants
.get(&access_key)
.unwrap_or_else(|| panic!("unknown constant {module}.{name}"));
let mut value =
AirTree::no_op(self.build(definition, &access_key.module_name, &[]));
value.traverse_tree_with(
&mut |air_tree, _| {
erase_opaque_type_operations(air_tree, &self.data_types);
},
true,
);
let term = self
.uplc_code_gen(value.to_vec())
.constr_fields_exposer()
.constr_index_exposer();
let mut program: Program<Name> = Program {
version: (1, 0, 0),
term: self.special_functions.apply_used_functions(term),
};
let mut interner = CodeGenInterner::new();
interner.program(&mut program);
let eval_program: Program<NamedDeBruijn> =
program.remove_no_inlines().try_into().unwrap();
Some(
eval_program
.eval(ExBudget::max())
.result()
.unwrap_or_else(|e| panic!("Failed to evaluate constant: {e:#?}"))
.try_into()
.unwrap(),
)
} }
ValueConstructorVariant::ModuleFn { ValueConstructorVariant::ModuleFn {
name: func_name, name: func_name,

View File

@ -4,8 +4,8 @@ use super::{
}; };
use crate::{ use crate::{
ast::{ ast::{
Constant, DataTypeKey, FunctionAccessKey, Pattern, Span, TraceLevel, TypedArg, DataTypeKey, FunctionAccessKey, Pattern, Span, TraceLevel, TypedArg, TypedAssignmentKind,
TypedAssignmentKind, TypedClause, TypedDataType, TypedPattern, TypedClause, TypedDataType, TypedPattern,
}, },
expr::TypedExpr, expr::TypedExpr,
line_numbers::{LineColumn, LineNumbers}, line_numbers::{LineColumn, LineNumbers},
@ -287,15 +287,6 @@ impl Default for CodeGenSpecialFuncs {
} }
} }
pub fn constants_ir(literal: &Constant) -> AirTree {
match literal {
Constant::Int { value, .. } => AirTree::int(value),
Constant::String { value, .. } => AirTree::string(value),
Constant::ByteArray { bytes, .. } => AirTree::byte_array(bytes.clone()),
Constant::CurvePoint { point, .. } => AirTree::curve(*point.as_ref()),
}
}
pub fn get_generic_variant_name(t: &Rc<Type>) -> String { pub fn get_generic_variant_name(t: &Rc<Type>) -> String {
let uplc_type = t.get_uplc_type(); let uplc_type = t.get_uplc_type();

View File

@ -1,10 +1,8 @@
use chumsky::prelude::*;
use uplc::machine::runtime::Compressable;
use crate::{ use crate::{
ast, ast,
parser::{annotation, error::ParseError, literal, token::Token, utils}, parser::{annotation, error::ParseError, expr::pure_expression, token::Token, utils},
}; };
use chumsky::prelude::*;
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> { pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
utils::optional_flag(Token::Pub) utils::optional_flag(Token::Pub)
@ -16,7 +14,9 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
.or_not(), .or_not(),
) )
.then_ignore(just(Token::Equal)) .then_ignore(just(Token::Equal))
.then(value()) .then(recursive(|expression| {
recursive(|sequence| pure_expression(sequence, expression))
}))
.map_with_span(|(((public, name), annotation), value), span| { .map_with_span(|(((public, name), annotation), value), span| {
ast::UntypedDefinition::ModuleConstant(ast::ModuleConstant { ast::UntypedDefinition::ModuleConstant(ast::ModuleConstant {
doc: None, doc: None,
@ -24,67 +24,11 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
public, public,
name, name,
annotation, annotation,
value: Box::new(value), value,
tipo: (),
}) })
}) })
} }
pub fn value() -> impl Parser<Token, ast::Constant, Error = ParseError> {
let constant_string_parser =
select! {Token::String {value} => value}.map_with_span(|value, span| {
ast::Constant::String {
location: span,
value,
}
});
let constant_int_parser =
literal::int().map_with_span(|(value, base), location| ast::Constant::Int {
location,
value,
base,
});
let constant_bytearray_parser = literal::bytearray(
|bytes, preferred_format, curve, location, emit| match curve {
Some(curve @ ast::CurveType::Bls12_381(point)) => {
let point = match point {
ast::Bls12_381PointType::G1 => {
blst::blst_p1::uncompress(&bytes).map(ast::Bls12_381Point::G1)
}
ast::Bls12_381PointType::G2 => {
blst::blst_p2::uncompress(&bytes).map(ast::Bls12_381Point::G2)
}
};
let point = point.unwrap_or_else(|_err| {
emit(ParseError::point_not_on_curve(curve, location));
ast::Bls12_381Point::default()
});
ast::Constant::CurvePoint {
location,
point: ast::Curve::Bls12_381(point).into(),
preferred_format,
}
}
None => ast::Constant::ByteArray {
location,
bytes,
preferred_format,
},
},
);
choice((
constant_string_parser,
constant_int_parser,
constant_bytearray_parser,
))
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::assert_definition; use crate::assert_definition;

View File

@ -49,6 +49,5 @@ ModuleConstant(
), ),
preferred_format: HexadecimalString, preferred_format: HexadecimalString,
}, },
tipo: (),
}, },
) )

View File

@ -91,6 +91,5 @@ ModuleConstant(
), ),
preferred_format: HexadecimalString, preferred_format: HexadecimalString,
}, },
tipo: (),
}, },
) )

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
ast, ast,
parser::{definition, error::ParseError, token::Token}, parser::{error::ParseError, literal, token::Token},
}; };
use chumsky::prelude::*; use chumsky::prelude::*;
@ -12,13 +12,11 @@ pub fn parser() -> impl Parser<Token, ast::UntypedClauseGuard, Error = ParseErro
} }
.map_with_span(|_name, _span| ast::UntypedClauseGuard {}); .map_with_span(|_name, _span| ast::UntypedClauseGuard {});
let constant_parser = definition::constant::value().map(|_| ast::UntypedClauseGuard {});
let block_parser = expression let block_parser = expression
.clone() .clone()
.delimited_by(just(Token::LeftParen), just(Token::RightParen)); .delimited_by(just(Token::LeftParen), just(Token::RightParen));
let leaf_parser = choice((var_parser, constant_parser, block_parser)).boxed(); let leaf_parser = choice((var_parser, constant(), block_parser)).boxed();
let unary_op = just(Token::Bang); let unary_op = just(Token::Bang);
@ -57,3 +55,20 @@ pub fn parser() -> impl Parser<Token, ast::UntypedClauseGuard, Error = ParseErro
.foldl(|_left, (_tok, _right)| ast::UntypedClauseGuard {}) .foldl(|_left, (_tok, _right)| ast::UntypedClauseGuard {})
}) })
} }
// NOTE: This is only there for backward-compatibility, in order to provide nicer error message
// when a clause guard is found. However, Aiken no longer supports clause guards.
pub fn constant() -> impl Parser<Token, ast::UntypedClauseGuard, Error = ParseError> {
let constant_string_parser =
select! {Token::String {value} => value}.map(|_| ast::UntypedClauseGuard {});
let constant_int_parser = literal::int().map(|_| ast::UntypedClauseGuard {});
let constant_bytearray_parser = literal::bytearray(|_, _, _, _, _| ast::UntypedClauseGuard {});
choice((
constant_string_parser,
constant_int_parser,
constant_bytearray_parser,
))
}

View File

@ -1,8 +1,8 @@
use self::{environment::Environment, pretty::Printer}; use self::{environment::Environment, pretty::Printer};
use crate::{ use crate::{
ast::{ ast::{
well_known, Annotation, Constant, DataType, DataTypeKey, DefinitionLocation, ModuleKind, well_known, Annotation, DataType, DataTypeKey, DefinitionLocation, ModuleKind, Span,
Span, TypedDataType, TypedDataType,
}, },
tipo::fields::FieldMap, tipo::fields::FieldMap,
}; };
@ -1101,11 +1101,13 @@ impl TypeVar {
Self::Link { tipo } => tipo.get_inner_types(), Self::Link { tipo } => tipo.get_inner_types(),
Self::Unbound { .. } => vec![], Self::Unbound { .. } => vec![],
var => { var => {
vec![Type::Var { vec![
Type::Var {
tipo: RefCell::new(var.clone()).into(), tipo: RefCell::new(var.clone()).into(),
alias: None, alias: None,
} }
.into()] .into(),
]
} }
} }
} }
@ -1216,7 +1218,7 @@ pub enum ValueConstructorVariant {
ModuleConstant { ModuleConstant {
location: Span, location: Span,
module: String, module: String,
literal: Constant, name: String,
}, },
/// A function belonging to the module /// A function belonging to the module
@ -1262,11 +1264,14 @@ impl ValueConstructorVariant {
location: *location, location: *location,
}, },
// TODO: remove this clone with an rc clone
Self::ModuleConstant { Self::ModuleConstant {
literal, location, .. name,
module,
location,
..
} => ModuleValueConstructor::Constant { } => ModuleValueConstructor::Constant {
literal: literal.clone(), name: name.clone(),
module: module.clone(),
location: *location, location: *location,
}, },
@ -1400,8 +1405,9 @@ pub enum ModuleValueConstructor {
}, },
Constant { Constant {
literal: Constant,
location: Span, location: Span,
module: String,
name: String,
}, },
} }

View File

@ -11,11 +11,11 @@ use super::{
use crate::{ use crate::{
ast::{ ast::{
self, Annotation, ArgName, AssignmentKind, AssignmentPattern, BinOp, Bls12_381Point, self, Annotation, ArgName, AssignmentKind, AssignmentPattern, BinOp, Bls12_381Point,
ByteArrayFormatPreference, CallArg, Constant, Curve, Function, IfBranch, ByteArrayFormatPreference, CallArg, Curve, Function, IfBranch, LogicalOpChainKind, Pattern,
LogicalOpChainKind, Pattern, RecordUpdateSpread, Span, TraceKind, TraceLevel, Tracing, RecordUpdateSpread, Span, TraceKind, TraceLevel, Tracing, TypedArg, TypedCallArg,
TypedArg, TypedCallArg, TypedClause, TypedIfBranch, TypedPattern, TypedRecordUpdateArg, TypedClause, TypedIfBranch, TypedPattern, TypedRecordUpdateArg, TypedValidator, UnOp,
TypedValidator, UnOp, UntypedArg, UntypedAssignmentKind, UntypedClause, UntypedFunction, UntypedArg, UntypedAssignmentKind, UntypedClause, UntypedFunction, UntypedIfBranch,
UntypedIfBranch, UntypedPattern, UntypedRecordUpdateArg, UntypedPattern, UntypedRecordUpdateArg,
}, },
builtins::{from_default_function, BUILTIN}, builtins::{from_default_function, BUILTIN},
expr::{FnStyle, TypedExpr, UntypedExpr}, expr::{FnStyle, TypedExpr, UntypedExpr},
@ -1176,7 +1176,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
Ok((typed_arg, extra_assignment)) Ok((typed_arg, extra_assignment))
} }
fn infer_assignment( pub fn infer_assignment(
&mut self, &mut self,
untyped_pattern: UntypedPattern, untyped_pattern: UntypedPattern,
untyped_value: UntypedExpr, untyped_value: UntypedExpr,
@ -1466,64 +1466,6 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
Ok(typed_patterns) Ok(typed_patterns)
} }
// TODO: extract the type annotation checking into a infer_module_const
// function that uses this function internally
pub fn infer_const(
&mut self,
annotation: &Option<Annotation>,
value: Constant,
) -> Result<Constant, Error> {
let inferred = match value {
Constant::Int {
location,
value,
base,
} => Ok(Constant::Int {
location,
value,
base,
}),
Constant::String { location, value } => Ok(Constant::String { location, value }),
Constant::ByteArray {
location,
bytes,
preferred_format,
} => {
let _ = self.infer_bytearray(bytes.clone(), preferred_format, location)?;
Ok(Constant::ByteArray {
location,
bytes,
preferred_format,
})
}
Constant::CurvePoint {
location,
point,
preferred_format,
} => Ok(Constant::CurvePoint {
location,
point,
preferred_format,
}),
}?;
// Check type annotation is accurate.
if let Some(ann) = annotation {
let const_ann = self.type_from_annotation(ann)?;
self.unify(
const_ann.clone(),
inferred.tipo(),
inferred.location(),
const_ann.is_data(),
)?;
};
Ok(inferred)
}
fn infer_if( fn infer_if(
&mut self, &mut self,
branches: Vec1<UntypedIfBranch>, branches: Vec1<UntypedIfBranch>,

View File

@ -9,9 +9,10 @@ use crate::{
ast::{ ast::{
Annotation, ArgName, ArgVia, DataType, Definition, Function, ModuleConstant, ModuleKind, Annotation, ArgName, ArgVia, DataType, Definition, Function, ModuleConstant, ModuleKind,
RecordConstructor, RecordConstructorArg, Tracing, TypeAlias, TypedArg, TypedDefinition, RecordConstructor, RecordConstructorArg, Tracing, TypeAlias, TypedArg, TypedDefinition,
TypedModule, TypedValidator, UntypedArg, UntypedDefinition, UntypedModule, TypedModule, TypedValidator, UntypedArg, UntypedDefinition, UntypedModule, UntypedPattern,
UntypedValidator, Use, Validator, UntypedValidator, Use, Validator,
}, },
expr::{TypedExpr, UntypedAssignmentKind},
tipo::{expr::infer_function, Span, Type, TypeVar}, tipo::{expr::infer_function, Span, Type, TypeVar},
IdGenerator, IdGenerator,
}; };
@ -619,10 +620,22 @@ fn infer_definition(
annotation, annotation,
public, public,
value, value,
tipo: _,
}) => { }) => {
let typed_expr = let typed_assignment = ExprTyper::new(environment, tracing).infer_assignment(
ExprTyper::new(environment, tracing).infer_const(&annotation, *value)?; UntypedPattern::Var {
location,
name: name.clone(),
},
value,
UntypedAssignmentKind::Let { backpassing: false },
&annotation,
location,
)?;
let typed_expr = match typed_assignment {
TypedExpr::Assignment { value, .. } => value,
_ => unreachable!("infer_assignment inferred something else than an assignment?"),
};
let tipo = typed_expr.tipo(); let tipo = typed_expr.tipo();
@ -630,7 +643,7 @@ fn infer_definition(
public, public,
variant: ValueConstructorVariant::ModuleConstant { variant: ValueConstructorVariant::ModuleConstant {
location, location,
literal: typed_expr.clone(), name: name.to_owned(),
module: module_name.to_owned(), module: module_name.to_owned(),
}, },
tipo: tipo.clone(), tipo: tipo.clone(),
@ -650,8 +663,7 @@ fn infer_definition(
name, name,
annotation, annotation,
public, public,
value: Box::new(typed_expr), value: *typed_expr,
tipo,
})) }))
} }
} }

View File

@ -1,8 +1,6 @@
use crate::{github::repo::LatestRelease, package_name::PackageName, paths, Error}; use crate::{github::repo::LatestRelease, package_name::PackageName, paths, Error};
use aiken_lang::{ use aiken_lang::{
ast::{ ast::{Annotation, ByteArrayFormatPreference, ModuleConstant, Span, UntypedDefinition},
Annotation, ByteArrayFormatPreference, Constant, ModuleConstant, Span, UntypedDefinition,
},
expr::UntypedExpr, expr::UntypedExpr,
parser::token::Base, parser::token::Base,
}; };
@ -78,24 +76,14 @@ impl SimpleExpr {
let (value, annotation) = match self { let (value, annotation) = match self {
SimpleExpr::Bool(..) => todo!("requires https://github.com/aiken-lang/aiken/pull/992"), SimpleExpr::Bool(..) => todo!("requires https://github.com/aiken-lang/aiken/pull/992"),
SimpleExpr::Int(i) => ( SimpleExpr::Int(_) => (
// TODO: Replace with 'self.as_untyped_expr()' after https://github.com/aiken-lang/aiken/pull/992 // TODO: Replace with 'self.as_untyped_expr()' after https://github.com/aiken-lang/aiken/pull/992
Constant::Int { self.as_untyped_expr(),
location,
value: format!("{i}"),
base: Base::Decimal {
numeric_underscore: false,
},
},
Some(Annotation::int(location)), Some(Annotation::int(location)),
), ),
SimpleExpr::ByteArray(bs, preferred_format) => ( SimpleExpr::ByteArray(_, _) => (
// TODO: Replace with 'self.as_untyped_expr()' after https://github.com/aiken-lang/aiken/pull/992 // TODO: Replace with 'self.as_untyped_expr()' after https://github.com/aiken-lang/aiken/pull/992
Constant::ByteArray { self.as_untyped_expr(),
location,
bytes: bs.to_vec(),
preferred_format: *preferred_format,
},
Some(Annotation::bytearray(location)), Some(Annotation::bytearray(location)),
), ),
SimpleExpr::List(..) => todo!("requires https://github.com/aiken-lang/aiken/pull/992"), SimpleExpr::List(..) => todo!("requires https://github.com/aiken-lang/aiken/pull/992"),
@ -107,8 +95,7 @@ impl SimpleExpr {
public: true, public: true,
name: identifier.to_string(), name: identifier.to_string(),
annotation, annotation,
value: Box::new(value), value,
tipo: (),
}) })
} }
} }

View File

@ -36,7 +36,7 @@ use aiken_lang::{
TypedFunction, UntypedDefinition, TypedFunction, UntypedDefinition,
}, },
builtins, builtins,
expr::UntypedExpr, expr::{TypedExpr, UntypedExpr},
format::{Formatter, MAX_COLUMNS}, format::{Formatter, MAX_COLUMNS},
gen_uplc::CodeGenerator, gen_uplc::CodeGenerator,
line_numbers::LineNumbers, line_numbers::LineNumbers,
@ -98,6 +98,7 @@ where
checks_count: Option<usize>, checks_count: Option<usize>,
event_listener: T, event_listener: T,
functions: IndexMap<FunctionAccessKey, TypedFunction>, functions: IndexMap<FunctionAccessKey, TypedFunction>,
constants: IndexMap<FunctionAccessKey, TypedExpr>,
data_types: IndexMap<DataTypeKey, TypedDataType>, data_types: IndexMap<DataTypeKey, TypedDataType>,
module_sources: HashMap<String, (String, LineNumbers)>, module_sources: HashMap<String, (String, LineNumbers)>,
} }
@ -149,6 +150,7 @@ where
checks_count: None, checks_count: None,
event_listener, event_listener,
functions, functions,
constants: IndexMap::new(),
data_types, data_types,
module_sources: HashMap::new(), module_sources: HashMap::new(),
} }
@ -158,6 +160,7 @@ where
CodeGenerator::new( CodeGenerator::new(
self.config.plutus, self.config.plutus,
utils::indexmap::as_ref_values(&self.functions), utils::indexmap::as_ref_values(&self.functions),
utils::indexmap::as_ref_values(&self.constants),
utils::indexmap::as_ref_values(&self.data_types), utils::indexmap::as_ref_values(&self.data_types),
utils::indexmap::as_str_ref_values(&self.module_types), utils::indexmap::as_str_ref_values(&self.module_types),
utils::indexmap::as_str_ref_values(&self.module_sources), utils::indexmap::as_str_ref_values(&self.module_sources),
@ -805,6 +808,7 @@ where
&mut self.module_sources, &mut self.module_sources,
&mut self.module_types, &mut self.module_types,
&mut self.functions, &mut self.functions,
&mut self.constants,
&mut self.data_types, &mut self.data_types,
)?; )?;

View File

@ -5,6 +5,7 @@ use aiken_lang::{
Tracing, TypedDataType, TypedFunction, TypedModule, TypedValidator, UntypedModule, Tracing, TypedDataType, TypedFunction, TypedModule, TypedValidator, UntypedModule,
Validator, Validator,
}, },
expr::TypedExpr,
line_numbers::LineNumbers, line_numbers::LineNumbers,
parser::extra::{comments_before, Comment, ModuleExtra}, parser::extra::{comments_before, Comment, ModuleExtra},
tipo::TypeInfo, tipo::TypeInfo,
@ -49,6 +50,7 @@ impl ParsedModule {
module_sources: &mut HashMap<String, (String, LineNumbers)>, module_sources: &mut HashMap<String, (String, LineNumbers)>,
module_types: &mut HashMap<String, TypeInfo>, module_types: &mut HashMap<String, TypeInfo>,
functions: &mut IndexMap<FunctionAccessKey, TypedFunction>, functions: &mut IndexMap<FunctionAccessKey, TypedFunction>,
constants: &mut IndexMap<FunctionAccessKey, TypedExpr>,
data_types: &mut IndexMap<DataTypeKey, TypedDataType>, data_types: &mut IndexMap<DataTypeKey, TypedDataType>,
) -> Result<(CheckedModule, Vec<Warning>), Error> { ) -> Result<(CheckedModule, Vec<Warning>), Error> {
let mut warnings = Vec::new(); let mut warnings = Vec::new();
@ -92,7 +94,7 @@ impl ParsedModule {
module_types.insert(self.name.clone(), ast.type_info.clone()); module_types.insert(self.name.clone(), ast.type_info.clone());
// Register function definitions & data-types for easier access later. // Register function definitions & data-types for easier access later.
ast.register_definitions(functions, data_types); ast.register_definitions(functions, constants, data_types);
Ok(( Ok((
CheckedModule { CheckedModule {

View File

@ -62,7 +62,8 @@ mod test {
let mut functions = builtins::prelude_functions(&id_gen, &module_types); let mut functions = builtins::prelude_functions(&id_gen, &module_types);
let mut data_types = builtins::prelude_data_types(&id_gen); let mut data_types = builtins::prelude_data_types(&id_gen);
ast.register_definitions(&mut functions, &mut data_types); let mut constants = IndexMap::new();
ast.register_definitions(&mut functions, &mut constants, &mut data_types);
let mut module_sources = HashMap::new(); let mut module_sources = HashMap::new();
module_sources.insert( module_sources.insert(
@ -87,6 +88,7 @@ mod test {
let mut generator = CodeGenerator::new( let mut generator = CodeGenerator::new(
PlutusVersion::default(), PlutusVersion::default(),
utils::indexmap::as_ref_values(&functions), utils::indexmap::as_ref_values(&functions),
utils::indexmap::as_ref_values(&constants),
utils::indexmap::as_ref_values(&data_types), utils::indexmap::as_ref_values(&data_types),
utils::indexmap::as_str_ref_values(&module_types), utils::indexmap::as_str_ref_values(&module_types),
utils::indexmap::as_str_ref_values(&module_sources), utils::indexmap::as_str_ref_values(&module_sources),
@ -240,13 +242,14 @@ mod test {
} }
"#}); "#});
assert!(prop assert!(
.run::<()>( prop.run::<()>(
42, 42,
PropertyTest::DEFAULT_MAX_SUCCESS, PropertyTest::DEFAULT_MAX_SUCCESS,
&PlutusVersion::default() &PlutusVersion::default()
) )
.is_success()); .is_success()
);
} }
#[test] #[test]

View File

@ -9,6 +9,7 @@ use aiken_lang::{
DataTypeKey, FunctionAccessKey, ModuleKind, TraceLevel, Tracing, TypedDataType, DataTypeKey, FunctionAccessKey, ModuleKind, TraceLevel, Tracing, TypedDataType,
TypedFunction, TypedFunction,
}, },
expr::TypedExpr,
gen_uplc::CodeGenerator, gen_uplc::CodeGenerator,
line_numbers::LineNumbers, line_numbers::LineNumbers,
parser, parser,
@ -28,6 +29,7 @@ pub struct TestProject {
pub package: PackageName, pub package: PackageName,
pub id_gen: IdGenerator, pub id_gen: IdGenerator,
pub functions: IndexMap<FunctionAccessKey, TypedFunction>, pub functions: IndexMap<FunctionAccessKey, TypedFunction>,
pub constants: IndexMap<FunctionAccessKey, TypedExpr>,
pub data_types: IndexMap<DataTypeKey, TypedDataType>, pub data_types: IndexMap<DataTypeKey, TypedDataType>,
pub module_types: HashMap<String, TypeInfo>, pub module_types: HashMap<String, TypeInfo>,
pub module_sources: HashMap<String, (String, LineNumbers)>, pub module_sources: HashMap<String, (String, LineNumbers)>,
@ -48,12 +50,14 @@ impl TestProject {
let functions = builtins::prelude_functions(&id_gen, &module_types); let functions = builtins::prelude_functions(&id_gen, &module_types);
let data_types = builtins::prelude_data_types(&id_gen); let data_types = builtins::prelude_data_types(&id_gen);
let constants = IndexMap::new();
TestProject { TestProject {
package, package,
id_gen, id_gen,
module_types, module_types,
functions, functions,
constants,
data_types, data_types,
module_sources: HashMap::new(), module_sources: HashMap::new(),
} }
@ -63,6 +67,7 @@ impl TestProject {
CodeGenerator::new( CodeGenerator::new(
PlutusVersion::default(), PlutusVersion::default(),
utils::indexmap::as_ref_values(&self.functions), utils::indexmap::as_ref_values(&self.functions),
utils::indexmap::as_ref_values(&self.constants),
utils::indexmap::as_ref_values(&self.data_types), utils::indexmap::as_ref_values(&self.data_types),
utils::indexmap::as_str_ref_values(&self.module_types), utils::indexmap::as_str_ref_values(&self.module_types),
utils::indexmap::as_str_ref_values(&self.module_sources), utils::indexmap::as_str_ref_values(&self.module_sources),
@ -104,7 +109,11 @@ impl TestProject {
.expect("Failed to type-check module"); .expect("Failed to type-check module");
// Register function definitions & data-types for easier access later. // Register function definitions & data-types for easier access later.
ast.register_definitions(&mut self.functions, &mut self.data_types); ast.register_definitions(
&mut self.functions,
&mut self.constants,
&mut self.data_types,
);
// Register module sources for an easier access later. // Register module sources for an easier access later.
self.module_sources.insert( self.module_sources.insert(

View File

@ -19,7 +19,7 @@ pub enum Error {
format!( format!(
"\n{:>13} {}", "\n{:>13} {}",
"Trace", "Trace",
if trace.contains("\n") { if trace.contains('\n') {
trace.lines() trace.lines()
.enumerate() .enumerate()
.map(|(ix, row)| { .map(|(ix, row)| {