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::{
builtins::{self, bool},
expr::{TypedExpr, UntypedExpr},
tipo::{fields::FieldMap, PatternConstructor, Type, TypeInfo, ValueConstructor},
tipo::{PatternConstructor, Type, TypeInfo},
};
pub const ASSERT_VARIABLE: &str = "_try";
@ -244,17 +244,17 @@ pub struct Use<PackageName> {
pub unqualified: Vec<UnqualifiedImport>,
}
pub type TypedModuleConstant = ModuleConstant<Arc<Type>, String>;
pub type UntypedModuleConstant = ModuleConstant<(), ()>;
pub type TypedModuleConstant = ModuleConstant<Arc<Type>>;
pub type UntypedModuleConstant = ModuleConstant<()>;
#[derive(Debug, Clone, PartialEq)]
pub struct ModuleConstant<T, ConstantRecordTag> {
pub struct ModuleConstant<T> {
pub doc: Option<String>,
pub location: Span,
pub public: bool,
pub name: String,
pub annotation: Option<Annotation>,
pub value: Box<Constant<T, ConstantRecordTag>>,
pub value: Box<Constant>,
pub tipo: T,
}
@ -270,11 +270,11 @@ pub struct Validator<T, Expr> {
pub params: Vec<Arg<T>>,
}
pub type TypedDefinition = Definition<Arc<Type>, TypedExpr, String, String>;
pub type UntypedDefinition = Definition<(), UntypedExpr, (), ()>;
pub type TypedDefinition = Definition<Arc<Type>, TypedExpr, String>;
pub type UntypedDefinition = Definition<(), UntypedExpr, ()>;
#[derive(Debug, Clone, PartialEq)]
pub enum Definition<T, Expr, ConstantRecordTag, PackageName> {
pub enum Definition<T, Expr, PackageName> {
Fn(Function<T, Expr>),
TypeAlias(TypeAlias<T>),
@ -283,14 +283,14 @@ pub enum Definition<T, Expr, ConstantRecordTag, PackageName> {
Use(Use<PackageName>),
ModuleConstant(ModuleConstant<T, ConstantRecordTag>),
ModuleConstant(ModuleConstant<T>),
Test(Function<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 {
match self {
Definition::Fn(Function { location, .. })
@ -324,91 +324,31 @@ pub struct DefinitionLocation<'module> {
pub span: Span,
}
pub type TypedConstant = Constant<Arc<Type>, String>;
pub type UntypedConstant = Constant<(), ()>;
#[derive(Debug, Clone, PartialEq)]
pub enum Constant<T, RecordTag> {
Int {
location: Span,
value: String,
},
pub enum Constant {
Int { location: Span, value: String },
String {
location: Span,
value: String,
},
String { location: Span, value: String },
Tuple {
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,
},
ByteArray { location: Span, bytes: Vec<u8> },
}
impl TypedConstant {
impl Constant {
pub fn tipo(&self) -> Arc<Type> {
match self {
Constant::Int { .. } => builtins::int(),
Constant::String { .. } => builtins::string(),
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 {
match self {
Constant::Int { location, .. }
| Constant::Tuple { location, .. }
| Constant::List { location, .. }
| Constant::String { location, .. }
| Constant::Record { location, .. }
| Constant::ByteArray { location, .. }
| Constant::Var { location, .. } => *location,
| Constant::ByteArray { location, .. } => *location,
}
}
pub fn is_simple(&self) -> bool {
matches!(
self,
Self::Int { .. } | Self::ByteArray { .. } | Self::String { .. }
)
}
}
pub type TypedCallArg = CallArg<TypedExpr>;
@ -836,15 +776,15 @@ pub type MultiPattern<PatternConstructor, Type> = Vec<Pattern<PatternConstructor
pub type UntypedMultiPattern = MultiPattern<(), ()>;
pub type TypedMultiPattern = MultiPattern<PatternConstructor, Arc<Type>>;
pub type TypedClause = Clause<TypedExpr, PatternConstructor, Arc<Type>, String>;
pub type UntypedClause = Clause<UntypedExpr, (), (), ()>;
pub type TypedClause = Clause<TypedExpr, PatternConstructor, Arc<Type>>;
pub type UntypedClause = Clause<UntypedExpr, (), ()>;
#[derive(Debug, Clone, PartialEq)]
pub struct Clause<Expr, PatternConstructor, Type, RecordTag> {
pub struct Clause<Expr, PatternConstructor, Type> {
pub location: Span,
pub pattern: MultiPattern<PatternConstructor, Type>,
pub alternative_patterns: Vec<MultiPattern<PatternConstructor, Type>>,
pub guard: Option<ClauseGuard<Type, RecordTag>>,
pub guard: Option<ClauseGuard<Type>>,
pub then: Expr,
}
@ -861,11 +801,11 @@ impl TypedClause {
}
}
pub type UntypedClauseGuard = ClauseGuard<(), ()>;
pub type TypedClauseGuard = ClauseGuard<Arc<Type>, String>;
pub type UntypedClauseGuard = ClauseGuard<()>;
pub type TypedClauseGuard = ClauseGuard<Arc<Type>>;
#[derive(Debug, Clone, PartialEq)]
pub enum ClauseGuard<Type, RecordTag> {
pub enum ClauseGuard<Type> {
Not {
location: Span,
value: Box<Self>,
@ -925,10 +865,10 @@ pub enum ClauseGuard<Type, RecordTag> {
name: String,
},
Constant(Constant<Type, RecordTag>),
Constant(Constant),
}
impl<A, B> ClauseGuard<A, B> {
impl<A> ClauseGuard<A> {
pub fn location(&self) -> Span {
match self {
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(
clauses: Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>, String>>,
) -> Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>, String>> {
clauses: Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>>>,
) -> Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>>> {
let mut sorted_clauses = 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(
literal: &Constant<Arc<Type>, String>,
ir_stack: &mut Vec<Air>,
scope: Vec<u64>,
) {
pub fn constants_ir(literal: &Constant, ir_stack: &mut Vec<Air>, scope: Vec<u64>) {
match literal {
Constant::Int { value, .. } => {
ir_stack.push(Air::Int {
@ -1084,32 +1080,12 @@ pub fn constants_ir(
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, .. } => {
ir_stack.push(Air::ByteArray {
scope,
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(
clause_guard: &ClauseGuard<Arc<Type>, String>,
clause_guard: &ClauseGuard<Arc<Type>>,
clause_guard_vec: &mut Vec<Air>,
scope: Vec<u64>,
) {

View File

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

View File

@ -7,10 +7,10 @@ use crate::{
ast::{
Annotation, Arg, ArgName, AssignmentKind, BinOp, CallArg, ClauseGuard, Constant, DataType,
Definition, Function, IfBranch, ModuleConstant, Pattern, RecordConstructor,
RecordConstructorArg, RecordUpdateSpread, Span, TraceKind, TypeAlias, TypedArg,
TypedConstant, UnOp, UnqualifiedImport, UntypedArg, UntypedClause, UntypedClauseGuard,
UntypedDefinition, UntypedFunction, UntypedModule, UntypedPattern, UntypedRecordUpdateArg,
Use, Validator, CAPTURE_VARIABLE,
RecordConstructorArg, RecordUpdateSpread, Span, TraceKind, TypeAlias, TypedArg, UnOp,
UnqualifiedImport, UntypedArg, UntypedClause, UntypedClauseGuard, UntypedDefinition,
UntypedFunction, UntypedModule, UntypedPattern, UntypedRecordUpdateArg, Use, Validator,
CAPTURE_VARIABLE,
},
docvec,
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 {
Constant::ByteArray { bytes, .. } => self.bytearray(bytes),
Constant::Int { value, .. } => value.to_doc(),
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();
name.to_doc()
.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> {
match op {
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> {
recursive(|r| {
fn constant_value_parser() -> impl Parser<Token, ast::Constant, Error = ParseError> {
let constant_string_parser =
select! {Token::String {value} => value}.map_with_span(|value, span| {
ast::UntypedConstant::String {
ast::Constant::String {
location: span,
value,
}
});
let constant_int_parser =
select! {Token::Int {value} => value}.map_with_span(|value, span| {
ast::UntypedConstant::Int {
select! {Token::Int {value} => value}.map_with_span(|value, span| ast::Constant::Int {
location: span,
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 =
bytearray_parser().map_with_span(|bytes, span| ast::UntypedConstant::ByteArray {
bytearray_parser().map_with_span(|bytes, span| ast::Constant::ByteArray {
location: span,
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((
constant_string_parser,
constant_int_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> {
@ -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| {
let var_parser = select! {
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 crate::{
ast::{Constant, DefinitionLocation, ModuleKind, Span, TypedConstant},
ast::{Constant, DefinitionLocation, ModuleKind, Span},
tipo::fields::FieldMap,
};
@ -584,7 +584,7 @@ pub enum ValueConstructorVariant {
ModuleConstant {
location: Span,
module: String,
literal: Constant<Arc<Type>, String>,
literal: Constant,
},
/// A function belonging to the module
@ -744,7 +744,7 @@ pub enum ModuleValueConstructor {
},
Constant {
literal: TypedConstant,
literal: Constant,
location: Span,
},
}

View File

@ -6,9 +6,9 @@ use crate::{
ast::{
Annotation, Arg, ArgName, AssignmentKind, BinOp, CallArg, Clause, ClauseGuard, Constant,
IfBranch, RecordUpdateSpread, Span, TraceKind, Tracing, TypedArg, TypedCallArg,
TypedClause, TypedClauseGuard, TypedConstant, TypedIfBranch, TypedMultiPattern,
TypedRecordUpdateArg, UnOp, UntypedArg, UntypedClause, UntypedClauseGuard, UntypedConstant,
UntypedIfBranch, UntypedMultiPattern, UntypedPattern, UntypedRecordUpdateArg,
TypedClause, TypedClauseGuard, TypedIfBranch, TypedMultiPattern, TypedRecordUpdateArg,
UnOp, UntypedArg, UntypedClause, UntypedClauseGuard, UntypedIfBranch, UntypedMultiPattern,
UntypedPattern, UntypedRecordUpdateArg,
},
builtins::{bool, byte_array, function, int, list, string, tuple},
expr::{TypedExpr, UntypedExpr},
@ -22,8 +22,7 @@ use super::{
hydrator::Hydrator,
pattern::PatternTyper,
pipe::PipeTyper,
ModuleValueConstructor, PatternConstructor, RecordAccessor, Type, ValueConstructor,
ValueConstructorVariant,
PatternConstructor, RecordAccessor, Type, ValueConstructor, ValueConstructorVariant,
};
#[derive(Debug)]
@ -48,7 +47,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
&mut self,
subjects_count: usize,
subjects: &[Arc<Type>],
typed_clauses: &[Clause<TypedExpr, PatternConstructor, Arc<Type>, String>],
typed_clauses: &[Clause<TypedExpr, PatternConstructor, Arc<Type>>],
location: Span,
) -> Result<(), Vec<String>> {
// 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))
}
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
// function that uses this function internally
pub fn infer_const(
&mut self,
annotation: &Option<Annotation>,
value: UntypedConstant,
) -> Result<TypedConstant, Error> {
value: Constant,
) -> Result<Constant, Error> {
let inferred = match value {
Constant::Int {
location, value, ..
@ -1370,216 +1353,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
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::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.
@ -1597,30 +1371,6 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
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(
&mut self,
branches: Vec1<UntypedIfBranch>,

View File

@ -689,7 +689,7 @@ impl<'a> CodeGenerator<'a> {
&mut self,
ir_stack: &mut Vec<Air>,
clause_properties: &mut ClauseProperties,
clauses: &[Clause<TypedExpr, PatternConstructor, Arc<Type>, String>],
clauses: &[Clause<TypedExpr, PatternConstructor, Arc<Type>>],
subject_type: &Arc<Type>,
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"
}