Remove complex and compound constants.

This is not supported by the code generation, so it's a bit of a lie
  to have them in the language in the first place. There's arguably not
  even any use for constant records, list and tuples to begin with. So
  this cleans this up everywhere for the sake of moving forward with the
  alpha release.

  This now reduces constants to:

  - Integer
  - ByteArray
  - String

  Anything else can be declared via a function anyway. We can revisit
  this choice later.... or not.
This commit is contained in:
KtorZ 2023-02-17 17:30:24 +01:00
parent 560c17d5aa
commit cd4ceb219c
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
9 changed files with 81 additions and 618 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::Constant::String {
ast::UntypedConstant::String {
location: span,
value,
}
});
let constant_int_parser =
select! {Token::Int {value} => value}.map_with_span(|value, span| {
ast::UntypedConstant::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, location: span,
elements, value,
}); }
});
let constant_bytearray_parser = let constant_int_parser =
bytearray_parser().map_with_span(|bytes, span| ast::UntypedConstant::ByteArray { select! {Token::Int {value} => value}.map_with_span(|value, span| ast::Constant::Int {
location: span, location: span,
bytes, value,
}); });
let constant_list_parser = r let constant_bytearray_parser =
.clone() bytearray_parser().map_with_span(|bytes, span| ast::Constant::ByteArray {
.separated_by(just(Token::Comma)) location: span,
.allow_trailing() bytes,
.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((
choice(( constant_string_parser,
select! {Token::Name { name } => name} constant_int_parser,
.then_ignore(just(Token::Dot)) constant_bytearray_parser,
.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> { 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

@ -1,15 +1,17 @@
type Foo { const int_constant = 42
foo: Int,
test int() {
int_constant == 42
} }
const foo_constant = Foo { foo: 42 } const bytearray_constant = #"abcd"
test foo() { test bytearray() {
foo_constant == Foo { foo: 42 } bytearray_constant == #"abcd"
} }
const tuple_constant = (1, 2, 3) const string_constant = "FOO"
test bar() { test string() {
tuple_constant == (1, 2, 3) string_constant == "FOO"
} }