Merge pull request #390 from aiken-lang/acceptance-test-060--record-and-tuple-constants

Remove complex constants.
This commit is contained in:
Matthias Benkort 2023-02-17 18:20:39 +01:00 committed by GitHub
commit 1aea586cab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 95 additions and 610 deletions

View File

@ -3,7 +3,7 @@ use std::{fmt, ops::Range, sync::Arc};
use crate::{ use crate::{
builtins::{self, bool}, builtins::{self, bool},
expr::{TypedExpr, UntypedExpr}, expr::{TypedExpr, UntypedExpr},
tipo::{fields::FieldMap, PatternConstructor, Type, TypeInfo, ValueConstructor}, tipo::{PatternConstructor, Type, TypeInfo},
}; };
pub const ASSERT_VARIABLE: &str = "_try"; pub const ASSERT_VARIABLE: &str = "_try";
@ -244,17 +244,17 @@ pub struct Use<PackageName> {
pub unqualified: Vec<UnqualifiedImport>, pub unqualified: Vec<UnqualifiedImport>,
} }
pub type TypedModuleConstant = ModuleConstant<Arc<Type>, String>; pub type TypedModuleConstant = ModuleConstant<Arc<Type>>;
pub type UntypedModuleConstant = ModuleConstant<(), ()>; pub type UntypedModuleConstant = ModuleConstant<()>;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct ModuleConstant<T, ConstantRecordTag> { pub struct ModuleConstant<T> {
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<T, ConstantRecordTag>>, pub value: Box<Constant>,
pub tipo: T, pub tipo: T,
} }
@ -270,11 +270,11 @@ pub struct Validator<T, Expr> {
pub params: Vec<Arg<T>>, pub params: Vec<Arg<T>>,
} }
pub type TypedDefinition = Definition<Arc<Type>, TypedExpr, String, String>; pub type TypedDefinition = Definition<Arc<Type>, TypedExpr, String>;
pub type UntypedDefinition = Definition<(), UntypedExpr, (), ()>; pub type UntypedDefinition = Definition<(), UntypedExpr, ()>;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Definition<T, Expr, ConstantRecordTag, PackageName> { pub enum Definition<T, Expr, PackageName> {
Fn(Function<T, Expr>), Fn(Function<T, Expr>),
TypeAlias(TypeAlias<T>), TypeAlias(TypeAlias<T>),
@ -283,14 +283,14 @@ pub enum Definition<T, Expr, ConstantRecordTag, PackageName> {
Use(Use<PackageName>), Use(Use<PackageName>),
ModuleConstant(ModuleConstant<T, ConstantRecordTag>), ModuleConstant(ModuleConstant<T>),
Test(Function<T, Expr>), Test(Function<T, Expr>),
Validator(Validator<T, Expr>), Validator(Validator<T, Expr>),
} }
impl<A, B, C, E> Definition<A, B, C, E> { impl<A, B, C> Definition<A, B, C> {
pub fn location(&self) -> Span { pub fn location(&self) -> Span {
match self { match self {
Definition::Fn(Function { location, .. }) Definition::Fn(Function { location, .. })
@ -324,91 +324,31 @@ pub struct DefinitionLocation<'module> {
pub span: Span, pub span: Span,
} }
pub type TypedConstant = Constant<Arc<Type>, String>;
pub type UntypedConstant = Constant<(), ()>;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Constant<T, RecordTag> { pub enum Constant {
Int { Int { location: Span, value: String },
location: Span,
value: String,
},
String { String { location: Span, value: String },
location: Span,
value: String,
},
Tuple { ByteArray { location: Span, bytes: Vec<u8> },
location: Span,
elements: Vec<Self>,
},
List {
location: Span,
elements: Vec<Self>,
tipo: T,
},
Record {
location: Span,
module: Option<String>,
name: String,
args: Vec<CallArg<Self>>,
tag: RecordTag,
tipo: T,
field_map: Option<FieldMap>,
},
ByteArray {
location: Span,
bytes: Vec<u8>,
},
Var {
location: Span,
module: Option<String>,
name: String,
constructor: Option<Box<ValueConstructor>>,
tipo: T,
},
} }
impl TypedConstant { impl Constant {
pub fn tipo(&self) -> Arc<Type> { pub fn tipo(&self) -> Arc<Type> {
match self { match self {
Constant::Int { .. } => builtins::int(), Constant::Int { .. } => builtins::int(),
Constant::String { .. } => builtins::string(), Constant::String { .. } => builtins::string(),
Constant::ByteArray { .. } => builtins::byte_array(), Constant::ByteArray { .. } => builtins::byte_array(),
Constant::Tuple { elements, .. } => {
builtins::tuple(elements.iter().map(|e| e.tipo()).collect())
}
Constant::List { tipo, .. }
| Constant::Record { tipo, .. }
| Constant::Var { tipo, .. } => tipo.clone(),
}
} }
} }
impl<A, B> Constant<A, B> {
pub fn location(&self) -> Span { pub fn location(&self) -> Span {
match self { match self {
Constant::Int { location, .. } Constant::Int { location, .. }
| Constant::Tuple { location, .. }
| Constant::List { location, .. }
| Constant::String { location, .. } | Constant::String { location, .. }
| Constant::Record { location, .. } | Constant::ByteArray { location, .. } => *location,
| Constant::ByteArray { location, .. }
| Constant::Var { location, .. } => *location,
} }
} }
pub fn is_simple(&self) -> bool {
matches!(
self,
Self::Int { .. } | Self::ByteArray { .. } | Self::String { .. }
)
}
} }
pub type TypedCallArg = CallArg<TypedExpr>; pub type TypedCallArg = CallArg<TypedExpr>;
@ -836,15 +776,15 @@ pub type MultiPattern<PatternConstructor, Type> = Vec<Pattern<PatternConstructor
pub type UntypedMultiPattern = MultiPattern<(), ()>; pub type UntypedMultiPattern = MultiPattern<(), ()>;
pub type TypedMultiPattern = MultiPattern<PatternConstructor, Arc<Type>>; pub type TypedMultiPattern = MultiPattern<PatternConstructor, Arc<Type>>;
pub type TypedClause = Clause<TypedExpr, PatternConstructor, Arc<Type>, String>; pub type TypedClause = Clause<TypedExpr, PatternConstructor, Arc<Type>>;
pub type UntypedClause = Clause<UntypedExpr, (), (), ()>; pub type UntypedClause = Clause<UntypedExpr, (), ()>;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Clause<Expr, PatternConstructor, Type, RecordTag> { pub struct Clause<Expr, PatternConstructor, Type> {
pub location: Span, pub location: Span,
pub pattern: MultiPattern<PatternConstructor, Type>, pub pattern: MultiPattern<PatternConstructor, Type>,
pub alternative_patterns: Vec<MultiPattern<PatternConstructor, Type>>, pub alternative_patterns: Vec<MultiPattern<PatternConstructor, Type>>,
pub guard: Option<ClauseGuard<Type, RecordTag>>, pub guard: Option<ClauseGuard<Type>>,
pub then: Expr, pub then: Expr,
} }
@ -861,11 +801,11 @@ impl TypedClause {
} }
} }
pub type UntypedClauseGuard = ClauseGuard<(), ()>; pub type UntypedClauseGuard = ClauseGuard<()>;
pub type TypedClauseGuard = ClauseGuard<Arc<Type>, String>; pub type TypedClauseGuard = ClauseGuard<Arc<Type>>;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum ClauseGuard<Type, RecordTag> { pub enum ClauseGuard<Type> {
Not { Not {
location: Span, location: Span,
value: Box<Self>, value: Box<Self>,
@ -925,10 +865,10 @@ pub enum ClauseGuard<Type, RecordTag> {
name: String, name: String,
}, },
Constant(Constant<Type, RecordTag>), Constant(Constant),
} }
impl<A, B> ClauseGuard<A, B> { impl<A> ClauseGuard<A> {
pub fn location(&self) -> Span { pub fn location(&self) -> Span {
match self { match self {
ClauseGuard::Constant(constant) => constant.location(), ClauseGuard::Constant(constant) => constant.location(),

View File

@ -397,8 +397,8 @@ pub fn convert_data_to_type(term: Term<Name>, field_type: &Arc<Type>) -> Term<Na
} }
pub fn rearrange_clauses( pub fn rearrange_clauses(
clauses: Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>, String>>, clauses: Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>>>,
) -> Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>, String>> { ) -> Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>>> {
let mut sorted_clauses = clauses; let mut sorted_clauses = clauses;
// if we have a list sort clauses so we can plug holes for cases not covered by clauses // if we have a list sort clauses so we can plug holes for cases not covered by clauses
@ -1066,11 +1066,7 @@ pub fn check_when_pattern_needs(
} }
} }
pub fn constants_ir( pub fn constants_ir(literal: &Constant, ir_stack: &mut Vec<Air>, scope: Vec<u64>) {
literal: &Constant<Arc<Type>, String>,
ir_stack: &mut Vec<Air>,
scope: Vec<u64>,
) {
match literal { match literal {
Constant::Int { value, .. } => { Constant::Int { value, .. } => {
ir_stack.push(Air::Int { ir_stack.push(Air::Int {
@ -1084,32 +1080,12 @@ pub fn constants_ir(
value: value.clone(), value: value.clone(),
}); });
} }
Constant::Tuple { .. } => {
todo!()
}
Constant::List { elements, tipo, .. } => {
ir_stack.push(Air::List {
scope: scope.clone(),
count: elements.len(),
tipo: tipo.clone(),
tail: false,
});
for element in elements {
constants_ir(element, ir_stack, scope.clone());
}
}
Constant::Record { .. } => {
// ir_stack.push(Air::Record { scope, });
todo!()
}
Constant::ByteArray { bytes, .. } => { Constant::ByteArray { bytes, .. } => {
ir_stack.push(Air::ByteArray { ir_stack.push(Air::ByteArray {
scope, scope,
bytes: bytes.clone(), bytes: bytes.clone(),
}); });
} }
Constant::Var { .. } => todo!(),
}; };
} }
@ -2072,7 +2048,7 @@ pub fn replace_opaque_type(t: &mut Arc<Type>, data_types: IndexMap<DataTypeKey,
} }
pub fn handle_clause_guard( pub fn handle_clause_guard(
clause_guard: &ClauseGuard<Arc<Type>, String>, clause_guard: &ClauseGuard<Arc<Type>>,
clause_guard_vec: &mut Vec<Air>, clause_guard_vec: &mut Vec<Air>,
scope: Vec<u64>, scope: Vec<u64>,
) { ) {

View File

@ -103,7 +103,7 @@ pub enum TypedExpr {
location: Span, location: Span,
tipo: Arc<Type>, tipo: Arc<Type>,
subjects: Vec<Self>, subjects: Vec<Self>,
clauses: Vec<Clause<Self, PatternConstructor, Arc<Type>, String>>, clauses: Vec<Clause<Self, PatternConstructor, Arc<Type>>>,
}, },
If { If {
@ -390,7 +390,7 @@ pub enum UntypedExpr {
When { When {
location: Span, location: Span,
subjects: Vec<Self>, subjects: Vec<Self>,
clauses: Vec<Clause<Self, (), (), ()>>, clauses: Vec<Clause<Self, (), ()>>,
}, },
If { If {

View File

@ -7,10 +7,10 @@ use crate::{
ast::{ ast::{
Annotation, Arg, ArgName, AssignmentKind, BinOp, CallArg, ClauseGuard, Constant, DataType, Annotation, Arg, ArgName, AssignmentKind, BinOp, CallArg, ClauseGuard, Constant, DataType,
Definition, Function, IfBranch, ModuleConstant, Pattern, RecordConstructor, Definition, Function, IfBranch, ModuleConstant, Pattern, RecordConstructor,
RecordConstructorArg, RecordUpdateSpread, Span, TraceKind, TypeAlias, TypedArg, RecordConstructorArg, RecordUpdateSpread, Span, TraceKind, TypeAlias, TypedArg, UnOp,
TypedConstant, UnOp, UnqualifiedImport, UntypedArg, UntypedClause, UntypedClauseGuard, UnqualifiedImport, UntypedArg, UntypedClause, UntypedClauseGuard, UntypedDefinition,
UntypedDefinition, UntypedFunction, UntypedModule, UntypedPattern, UntypedRecordUpdateArg, UntypedFunction, UntypedModule, UntypedPattern, UntypedRecordUpdateArg, Use, Validator,
Use, Validator, CAPTURE_VARIABLE, CAPTURE_VARIABLE,
}, },
docvec, docvec,
expr::{UntypedExpr, DEFAULT_ERROR_STR, DEFAULT_TODO_STR}, expr::{UntypedExpr, DEFAULT_ERROR_STR, DEFAULT_TODO_STR},
@ -324,82 +324,15 @@ impl<'comments> Formatter<'comments> {
}) })
} }
fn const_expr<'a, A, B>(&mut self, value: &'a Constant<A, B>) -> Document<'a> { fn const_expr<'a>(&mut self, value: &'a Constant) -> Document<'a> {
match value { match value {
Constant::ByteArray { bytes, .. } => self.bytearray(bytes), Constant::ByteArray { bytes, .. } => self.bytearray(bytes),
Constant::Int { value, .. } => value.to_doc(), Constant::Int { value, .. } => value.to_doc(),
Constant::String { value, .. } => self.string(value), Constant::String { value, .. } => self.string(value),
Constant::List { elements, .. } => {
let comma: fn() -> Document<'a> = if elements.iter().all(Constant::is_simple) {
|| flex_break(",", ", ")
} else {
|| break_(",", ", ")
};
let elements_document = join(elements.iter().map(|e| self.const_expr(e)), comma());
list(elements_document, elements.len(), None)
}
Constant::Record {
name,
args,
module: None,
..
} if args.is_empty() => name.to_doc(),
Constant::Record {
name,
args,
module: Some(m),
..
} if args.is_empty() => m.to_doc().append(".").append(name.as_str()),
Constant::Record {
name,
args,
module: None,
..
} => name
.to_doc()
.append(wrap_args(
args.iter()
.map(|a| (self.constant_call_arg(a), a.label.is_some())),
))
.group(),
Constant::Record {
name,
args,
module: Some(m),
..
} => m
.to_doc()
.append(".")
.append(name.as_str())
.append(wrap_args(
args.iter()
.map(|a| (self.constant_call_arg(a), a.label.is_some())),
))
.group(),
Constant::Var {
name, module: None, ..
} => name.to_doc(),
Constant::Var {
name,
module: Some(module),
..
} => docvec![module, ".", name],
Constant::Tuple { elements, .. } => {
wrap_args(elements.iter().map(|e| (self.const_expr(e), false))).group()
}
} }
} }
pub fn docs_const_expr<'a>(&mut self, name: &'a str, value: &'a TypedConstant) -> Document<'a> { pub fn docs_const_expr<'a>(&mut self, name: &'a str, value: &'a Constant) -> Document<'a> {
let mut printer = tipo::pretty::Printer::new(); let mut printer = tipo::pretty::Printer::new();
name.to_doc() name.to_doc()
.append(": ") .append(": ")
@ -1631,13 +1564,6 @@ impl<'comments> Formatter<'comments> {
} }
} }
fn constant_call_arg<'a, A, B>(&mut self, arg: &'a CallArg<Constant<A, B>>) -> Document<'a> {
match &arg.label {
None => self.const_expr(&arg.value),
Some(s) => s.to_doc().append(": ").append(self.const_expr(&arg.value)),
}
}
fn un_op<'a>(&mut self, value: &'a UntypedExpr, op: &'a UnOp) -> Document<'a> { fn un_op<'a>(&mut self, value: &'a UntypedExpr, op: &'a UnOp) -> Document<'a> {
match op { match op {
UnOp::Not => docvec!["!", self.wrap_unary_op(value)], UnOp::Not => docvec!["!", self.wrap_unary_op(value)],

View File

@ -386,162 +386,32 @@ fn constant_parser() -> impl Parser<Token, ast::UntypedDefinition, Error = Parse
}) })
} }
fn constant_value_parser() -> impl Parser<Token, ast::UntypedConstant, Error = ParseError> { fn constant_value_parser() -> impl Parser<Token, ast::Constant, Error = ParseError> {
recursive(|r| {
let constant_string_parser = let constant_string_parser =
select! {Token::String {value} => value}.map_with_span(|value, span| { select! {Token::String {value} => value}.map_with_span(|value, span| {
ast::UntypedConstant::String { ast::Constant::String {
location: span, location: span,
value, value,
} }
}); });
let constant_int_parser = let constant_int_parser =
select! {Token::Int {value} => value}.map_with_span(|value, span| { select! {Token::Int {value} => value}.map_with_span(|value, span| ast::Constant::Int {
ast::UntypedConstant::Int {
location: span, location: span,
value, value,
}
});
let constant_tuple_parser = r
.clone()
.separated_by(just(Token::Comma))
.at_least(2)
.allow_trailing()
.delimited_by(
choice((just(Token::LeftParen), just(Token::NewLineLeftParen))),
just(Token::RightParen),
)
.map_with_span(|elements, span| ast::UntypedConstant::Tuple {
location: span,
elements,
}); });
let constant_bytearray_parser = let constant_bytearray_parser =
bytearray_parser().map_with_span(|bytes, span| ast::UntypedConstant::ByteArray { bytearray_parser().map_with_span(|bytes, span| ast::Constant::ByteArray {
location: span, location: span,
bytes, bytes,
}); });
let constant_list_parser = r
.clone()
.separated_by(just(Token::Comma))
.allow_trailing()
.delimited_by(just(Token::LeftSquare), just(Token::RightSquare))
.map_with_span(|elements, span| ast::UntypedConstant::List {
location: span,
elements,
tipo: (),
});
let constant_record_parser = choice((
choice((
select! {Token::Name { name } => name}
.then_ignore(just(Token::Dot))
.or_not()
.then(select! {Token::UpName { name } => name})
.then(
select! {Token::Name {name} => name}
.then_ignore(just(Token::Colon))
.or_not()
.then(r.clone())
.validate(|(label_opt, value), span, emit| {
let label = if label_opt.is_some() {
label_opt
} else if let ast::UntypedConstant::Var { name, .. } = &value {
Some(name.clone())
} else {
emit(ParseError::expected_input_found(
value.location(),
None,
Some(error::Pattern::RecordPunning),
));
None
};
ast::CallArg {
location: span,
value,
label,
}
})
.separated_by(just(Token::Comma))
.allow_trailing()
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
)
.map_with_span(
|((module, name), args), span| ast::UntypedConstant::Record {
location: span,
module,
name,
args,
tag: (),
tipo: (),
field_map: None,
},
),
select! {Token::Name { name } => name}
.then_ignore(just(Token::Dot))
.or_not()
.then(select! {Token::UpName { name } => name})
.then(
r.clone()
.map_with_span(|value, span| ast::CallArg {
location: span,
value,
label: None,
})
.separated_by(just(Token::Comma))
.allow_trailing()
.delimited_by(just(Token::LeftParen), just(Token::RightParen)),
)
.map_with_span(
|((module, name), args), span| ast::UntypedConstant::Record {
location: span,
module,
name,
args,
tag: (),
tipo: (),
field_map: None,
},
),
)),
select! {Token::Name { name } => name}
.then_ignore(just(Token::Dot))
.then(select! {Token::Name{name} => name})
.map_with_span(|(module, name), span: Span| ast::UntypedConstant::Var {
location: span.union(span),
module: Some(module),
name,
constructor: None,
tipo: (),
}),
));
let constant_var_parser =
select! {Token::Name {name} => name}.map_with_span(|name, span| {
ast::UntypedConstant::Var {
location: span,
module: None,
name,
constructor: None,
tipo: (),
}
});
choice(( choice((
constant_string_parser, constant_string_parser,
constant_int_parser, constant_int_parser,
constant_bytearray_parser, constant_bytearray_parser,
constant_tuple_parser,
constant_list_parser,
constant_record_parser,
constant_var_parser,
)) ))
})
} }
pub fn bytearray_parser() -> impl Parser<Token, Vec<u8>, Error = ParseError> { pub fn bytearray_parser() -> impl Parser<Token, Vec<u8>, Error = ParseError> {
@ -1407,8 +1277,7 @@ pub fn expr_parser(
}) })
} }
pub fn when_clause_guard_parser() -> impl Parser<Token, ast::ClauseGuard<(), ()>, Error = ParseError> pub fn when_clause_guard_parser() -> impl Parser<Token, ast::ClauseGuard<()>, Error = ParseError> {
{
recursive(|r| { recursive(|r| {
let var_parser = select! { let var_parser = select! {
Token::Name { name } => name, Token::Name { name } => name,

View File

@ -3,7 +3,7 @@ use std::{cell::RefCell, collections::HashMap, ops::Deref, sync::Arc};
use uplc::{ast::Type as UplcType, builtins::DefaultFunction}; use uplc::{ast::Type as UplcType, builtins::DefaultFunction};
use crate::{ use crate::{
ast::{Constant, DefinitionLocation, ModuleKind, Span, TypedConstant}, ast::{Constant, DefinitionLocation, ModuleKind, Span},
tipo::fields::FieldMap, tipo::fields::FieldMap,
}; };
@ -584,7 +584,7 @@ pub enum ValueConstructorVariant {
ModuleConstant { ModuleConstant {
location: Span, location: Span,
module: String, module: String,
literal: Constant<Arc<Type>, String>, literal: Constant,
}, },
/// A function belonging to the module /// A function belonging to the module
@ -744,7 +744,7 @@ pub enum ModuleValueConstructor {
}, },
Constant { Constant {
literal: TypedConstant, literal: Constant,
location: Span, location: Span,
}, },
} }

View File

@ -6,9 +6,9 @@ use crate::{
ast::{ ast::{
Annotation, Arg, ArgName, AssignmentKind, BinOp, CallArg, Clause, ClauseGuard, Constant, Annotation, Arg, ArgName, AssignmentKind, BinOp, CallArg, Clause, ClauseGuard, Constant,
IfBranch, RecordUpdateSpread, Span, TraceKind, Tracing, TypedArg, TypedCallArg, IfBranch, RecordUpdateSpread, Span, TraceKind, Tracing, TypedArg, TypedCallArg,
TypedClause, TypedClauseGuard, TypedConstant, TypedIfBranch, TypedMultiPattern, TypedClause, TypedClauseGuard, TypedIfBranch, TypedMultiPattern, TypedRecordUpdateArg,
TypedRecordUpdateArg, UnOp, UntypedArg, UntypedClause, UntypedClauseGuard, UntypedConstant, UnOp, UntypedArg, UntypedClause, UntypedClauseGuard, UntypedIfBranch, UntypedMultiPattern,
UntypedIfBranch, UntypedMultiPattern, UntypedPattern, UntypedRecordUpdateArg, UntypedPattern, UntypedRecordUpdateArg,
}, },
builtins::{bool, byte_array, function, int, list, string, tuple}, builtins::{bool, byte_array, function, int, list, string, tuple},
expr::{TypedExpr, UntypedExpr}, expr::{TypedExpr, UntypedExpr},
@ -22,8 +22,7 @@ use super::{
hydrator::Hydrator, hydrator::Hydrator,
pattern::PatternTyper, pattern::PatternTyper,
pipe::PipeTyper, pipe::PipeTyper,
ModuleValueConstructor, PatternConstructor, RecordAccessor, Type, ValueConstructor, PatternConstructor, RecordAccessor, Type, ValueConstructor, ValueConstructorVariant,
ValueConstructorVariant,
}; };
#[derive(Debug)] #[derive(Debug)]
@ -48,7 +47,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
&mut self, &mut self,
subjects_count: usize, subjects_count: usize,
subjects: &[Arc<Type>], subjects: &[Arc<Type>],
typed_clauses: &[Clause<TypedExpr, PatternConstructor, Arc<Type>, String>], typed_clauses: &[Clause<TypedExpr, PatternConstructor, Arc<Type>>],
location: Span, location: Span,
) -> Result<(), Vec<String>> { ) -> Result<(), Vec<String>> {
// Because exhaustiveness checking in presence of multiple subjects is similar // Because exhaustiveness checking in presence of multiple subjects is similar
@ -1338,29 +1337,13 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
Ok((typed_pattern, typed_alternatives)) Ok((typed_pattern, typed_alternatives))
} }
fn infer_const_tuple(
&mut self,
untyped_elements: Vec<UntypedConstant>,
location: Span,
) -> Result<TypedConstant, Error> {
let mut elements = Vec::with_capacity(untyped_elements.len());
for element in untyped_elements {
let element = self.infer_const(&None, element)?;
elements.push(element);
}
Ok(Constant::Tuple { elements, location })
}
// TODO: extract the type annotation checking into a infer_module_const // TODO: extract the type annotation checking into a infer_module_const
// function that uses this function internally // function that uses this function internally
pub fn infer_const( pub fn infer_const(
&mut self, &mut self,
annotation: &Option<Annotation>, annotation: &Option<Annotation>,
value: UntypedConstant, value: Constant,
) -> Result<TypedConstant, Error> { ) -> Result<Constant, Error> {
let inferred = match value { let inferred = match value {
Constant::Int { Constant::Int {
location, value, .. location, value, ..
@ -1370,216 +1353,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
location, value, .. location, value, ..
} => Ok(Constant::String { location, value }), } => Ok(Constant::String { location, value }),
Constant::Tuple {
elements, location, ..
} => self.infer_const_tuple(elements, location),
Constant::List {
elements, location, ..
} => self.infer_const_list(elements, location),
Constant::ByteArray { location, bytes } => Ok(Constant::ByteArray { location, bytes }), Constant::ByteArray { location, bytes } => Ok(Constant::ByteArray { location, bytes }),
Constant::Record {
module,
location,
name,
args,
// field_map, is always None here because untyped not yet unified
..
} if args.is_empty() => {
// Register the module as having been used if it was imported
if let Some(ref module) = &module {
self.environment.unused_modules.remove(module);
}
// Type check the record constructor
let constructor = self.infer_value_constructor(&module, &name, &location)?;
let (tag, field_map) = match &constructor.variant {
ValueConstructorVariant::Record {
name, field_map, ..
} => (name.clone(), field_map.clone()),
ValueConstructorVariant::ModuleFn { .. }
| ValueConstructorVariant::LocalVariable { .. } => {
return Err(Error::NonLocalClauseGuardVariable { location, name })
}
// TODO: remove this clone. Could use an rc instead
ValueConstructorVariant::ModuleConstant { literal, .. } => {
return Ok(literal.clone())
}
};
Ok(Constant::Record {
module,
location,
name,
args: vec![],
tipo: constructor.tipo,
tag,
field_map,
})
}
Constant::Record {
module,
location,
name,
mut args,
// field_map, is always None here because untyped not yet unified
..
} => {
// Register the module as having been used if it was imported
if let Some(ref module) = &module {
self.environment.unused_modules.remove(module);
}
let constructor = self.infer_value_constructor(&module, &name, &location)?;
let (tag, field_map) = match &constructor.variant {
ValueConstructorVariant::Record {
name, field_map, ..
} => (name.clone(), field_map.clone()),
ValueConstructorVariant::ModuleFn { .. }
| ValueConstructorVariant::LocalVariable { .. } => {
return Err(Error::NonLocalClauseGuardVariable { location, name })
}
// TODO: remove this clone. Could be an rc instead
ValueConstructorVariant::ModuleConstant { literal, .. } => {
return Ok(literal.clone())
}
};
// Pretty much all the other infer functions operate on UntypedExpr
// or TypedExpr rather than ClauseGuard. To make things easier we
// build the TypedExpr equivalent of the constructor and use that
// TODO: resvisit this. It is rather awkward at present how we
// have to convert to this other data structure.
let fun = match &module {
Some(module_name) => {
let tipo = Arc::clone(&constructor.tipo);
let module_name = self
.environment
.imported_modules
.get(module_name)
.expect("Failed to find previously located module import")
.1
.name
.clone();
let module_value_constructor = ModuleValueConstructor::Record {
name: name.clone(),
field_map: field_map.clone(),
arity: args.len(),
tipo: Arc::clone(&tipo),
location: constructor.variant.location(),
};
TypedExpr::ModuleSelect {
label: name.clone(),
module_alias: module_name.clone(),
module_name,
tipo,
constructor: module_value_constructor,
location,
}
}
None => TypedExpr::Var {
constructor,
location,
name: name.clone(),
},
};
// This is basically the same code as do_infer_call_with_known_fun()
// except the args are typed with infer_clause_guard() here.
// This duplication is a bit awkward but it works!
// Potentially this could be improved later
match self.get_field_map(&fun, location)? {
// The fun has a field map so labelled arguments may be present and need to be reordered.
Some(field_map) => field_map.reorder(&mut args, location)?,
// The fun has no field map and so we error if arguments have been labelled
None => assert_no_labeled_arguments(&args)
.map(|(location, label)| {
Err(Error::UnexpectedLabeledArg { location, label })
})
.unwrap_or(Ok(()))?,
}
let (mut args_types, return_type) = self.environment.match_fun_type(
fun.tipo(),
args.len(),
fun.location(),
location,
)?;
let mut typed_args = Vec::new();
for (tipo, arg) in args_types.iter_mut().zip(args) {
let CallArg {
label,
value,
location,
} = arg;
let value = self.infer_const(&None, value)?;
self.unify(tipo.clone(), value.tipo(), value.location(), tipo.is_data())?;
typed_args.push(CallArg {
label,
value,
location,
});
}
Ok(Constant::Record {
module,
location,
name,
args: typed_args,
tipo: return_type,
tag,
field_map,
})
}
Constant::Var {
location,
module,
name,
..
} => {
// Register the module as having been used if it was imported
if let Some(ref module) = &module {
self.environment.unused_modules.remove(module);
}
// Infer the type of this constant
let constructor = self.infer_value_constructor(&module, &name, &location)?;
match constructor.variant {
ValueConstructorVariant::ModuleConstant { .. }
| ValueConstructorVariant::ModuleFn { .. } => Ok(Constant::Var {
location,
module,
name,
tipo: Arc::clone(&constructor.tipo),
constructor: Some(Box::from(constructor)),
}),
// constructor.variant cannot be a LocalVariable because module constants can
// only be defined at module scope. It also cannot be a Record because then
// this constant would have been parsed as a Constant::Record. Therefore this
// code is unreachable.
_ => unreachable!(),
}
}
}?; }?;
// Check type annotation is accurate. // Check type annotation is accurate.
@ -1597,30 +1371,6 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
Ok(inferred) Ok(inferred)
} }
fn infer_const_list(
&mut self,
untyped_elements: Vec<UntypedConstant>,
location: Span,
) -> Result<TypedConstant, Error> {
let tipo = self.new_unbound_var();
let mut elements = Vec::with_capacity(untyped_elements.len());
for element in untyped_elements {
let element = self.infer_const(&None, element)?;
self.unify(tipo.clone(), element.tipo(), element.location(), false)?;
elements.push(element);
}
Ok(Constant::List {
elements,
location,
tipo: list(tipo),
})
}
fn infer_if( fn infer_if(
&mut self, &mut self,
branches: Vec1<UntypedIfBranch>, branches: Vec1<UntypedIfBranch>,

View File

@ -689,7 +689,7 @@ impl<'a> CodeGenerator<'a> {
&mut self, &mut self,
ir_stack: &mut Vec<Air>, ir_stack: &mut Vec<Air>,
clause_properties: &mut ClauseProperties, clause_properties: &mut ClauseProperties,
clauses: &[Clause<TypedExpr, PatternConstructor, Arc<Type>, String>], clauses: &[Clause<TypedExpr, PatternConstructor, Arc<Type>>],
subject_type: &Arc<Type>, subject_type: &Arc<Type>,
scope: Vec<u64>, scope: Vec<u64>,
) { ) {

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,2 @@
name = "aiken-lang/acceptance_test_060"
version = "0.0.0"

View File

@ -0,0 +1,17 @@
const int_constant = 42
test int() {
int_constant == 42
}
const bytearray_constant = #"abcd"
test bytearray() {
bytearray_constant == #"abcd"
}
const string_constant = "FOO"
test string() {
string_constant == "FOO"
}