Handle (recursive) generic types during reification.
Also moved a bunch of functions from code-gen back into _tipo_, as they're better suited and generic enough to be reused elsewhere.
This commit is contained in:
parent
a3fbe6c155
commit
23a22a65cb
|
@ -299,6 +299,19 @@ pub struct FunctionAccessKey {
|
|||
pub type TypedDataType = DataType<Rc<Type>>;
|
||||
|
||||
impl TypedDataType {
|
||||
pub fn data() -> Self {
|
||||
DataType {
|
||||
constructors: vec![],
|
||||
doc: None,
|
||||
location: Span::empty(),
|
||||
name: "Data".to_string(),
|
||||
opaque: false,
|
||||
parameters: vec![],
|
||||
public: true,
|
||||
typed_parameters: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bool() -> Self {
|
||||
DataType {
|
||||
constructors: vec![
|
||||
|
|
|
@ -1211,6 +1211,16 @@ pub fn prelude_functions(id_gen: &IdGenerator) -> IndexMap<FunctionAccessKey, Ty
|
|||
pub fn prelude_data_types(id_gen: &IdGenerator) -> IndexMap<DataTypeKey, TypedDataType> {
|
||||
let mut data_types = IndexMap::new();
|
||||
|
||||
// Data
|
||||
let data_data_type = TypedDataType::data();
|
||||
data_types.insert(
|
||||
DataTypeKey {
|
||||
module_name: "".to_string(),
|
||||
defined_type: "Data".to_string(),
|
||||
},
|
||||
data_data_type,
|
||||
);
|
||||
|
||||
// Ordering
|
||||
let ordering_data_type = TypedDataType::ordering();
|
||||
data_types.insert(
|
||||
|
|
|
@ -7,16 +7,20 @@ use crate::{
|
|||
UntypedRecordUpdateArg,
|
||||
},
|
||||
builtins::void,
|
||||
gen_uplc::builder::{
|
||||
check_replaceable_opaque_type, convert_opaque_type, lookup_data_type_by_tipo,
|
||||
},
|
||||
parser::token::Base,
|
||||
tipo::{ModuleValueConstructor, PatternConstructor, Type, TypeVar, ValueConstructor},
|
||||
tipo::{
|
||||
check_replaceable_opaque_type, convert_opaque_type, lookup_data_type_by_tipo,
|
||||
ModuleValueConstructor, PatternConstructor, Type, TypeVar, ValueConstructor,
|
||||
},
|
||||
};
|
||||
use indexmap::IndexMap;
|
||||
use pallas::ledger::primitives::alonzo::{Constr, PlutusData};
|
||||
use std::rc::Rc;
|
||||
use uplc::{ast::Data, machine::value::from_pallas_bigint, KeyValuePairs};
|
||||
use std::{fmt::Debug, rc::Rc};
|
||||
use uplc::{
|
||||
ast::Data,
|
||||
machine::{runtime::convert_tag_to_constr, value::from_pallas_bigint},
|
||||
KeyValuePairs,
|
||||
};
|
||||
use vec1::Vec1;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
@ -578,135 +582,18 @@ pub const DEFAULT_TODO_STR: &str = "aiken::todo";
|
|||
pub const DEFAULT_ERROR_STR: &str = "aiken::error";
|
||||
|
||||
impl UntypedExpr {
|
||||
// Reify some opaque 'Constant' into an 'UntypedExpr', using a Type annotation. We also need
|
||||
// an extra map to lookup record & enum constructor's names as they're completely erased when
|
||||
// in their PlutusData form, and the Type annotation only contains type name.
|
||||
//
|
||||
// The function performs some sanity check to ensure that the type does indeed somewhat
|
||||
// correspond to the data being given.
|
||||
pub fn reify_constant(
|
||||
data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
|
||||
cst: uplc::ast::Constant,
|
||||
tipo: &Type,
|
||||
) -> Result<Self, String> {
|
||||
if let Type::Var { tipo } = tipo {
|
||||
if let TypeVar::Link { tipo } = &*tipo.borrow() {
|
||||
return UntypedExpr::reify_constant(data_types, cst, tipo);
|
||||
}
|
||||
}
|
||||
|
||||
match cst {
|
||||
uplc::ast::Constant::Data(data) => UntypedExpr::reify_data(data_types, data, tipo),
|
||||
|
||||
uplc::ast::Constant::Integer(i) => {
|
||||
UntypedExpr::reify_data(data_types, Data::integer(i), tipo)
|
||||
}
|
||||
|
||||
uplc::ast::Constant::ByteString(bytes) => {
|
||||
UntypedExpr::reify_data(data_types, Data::bytestring(bytes), tipo)
|
||||
}
|
||||
|
||||
uplc::ast::Constant::ProtoList(_, args) => match tipo {
|
||||
Type::App {
|
||||
module,
|
||||
name,
|
||||
args: type_args,
|
||||
..
|
||||
} if module.is_empty() && name.as_str() == "List" => {
|
||||
if let [inner] = &type_args[..] {
|
||||
Ok(UntypedExpr::List {
|
||||
location: Span::empty(),
|
||||
elements: args
|
||||
.into_iter()
|
||||
.map(|arg| UntypedExpr::reify_constant(data_types, arg, inner))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
tail: None,
|
||||
})
|
||||
} else {
|
||||
Err(
|
||||
"invalid List type annotation: the list has multiple type-parameters."
|
||||
.to_string(),
|
||||
)
|
||||
}
|
||||
}
|
||||
Type::Tuple { elems } => Ok(UntypedExpr::Tuple {
|
||||
location: Span::empty(),
|
||||
elems: args
|
||||
.into_iter()
|
||||
.zip(elems)
|
||||
.map(|(arg, arg_type)| {
|
||||
UntypedExpr::reify_constant(data_types, arg, arg_type)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
}),
|
||||
_ => Err(format!(
|
||||
"invalid type annotation. expected List but got: {tipo:?}"
|
||||
)),
|
||||
},
|
||||
|
||||
uplc::ast::Constant::ProtoPair(_, _, left, right) => match tipo {
|
||||
Type::Tuple { elems } => Ok(UntypedExpr::Tuple {
|
||||
location: Span::empty(),
|
||||
elems: [left.as_ref(), right.as_ref()]
|
||||
.into_iter()
|
||||
.zip(elems)
|
||||
.map(|(arg, arg_type)| {
|
||||
UntypedExpr::reify_constant(data_types, arg.to_owned(), arg_type)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
}),
|
||||
_ => Err(format!(
|
||||
"invalid type annotation. expected Tuple but got: {tipo:?}"
|
||||
)),
|
||||
},
|
||||
|
||||
uplc::ast::Constant::Unit => Ok(UntypedExpr::Var {
|
||||
location: Span::empty(),
|
||||
name: "Void".to_string(),
|
||||
}),
|
||||
|
||||
uplc::ast::Constant::Bool(is_true) => Ok(UntypedExpr::Var {
|
||||
location: Span::empty(),
|
||||
name: if is_true { "True" } else { "False" }.to_string(),
|
||||
}),
|
||||
|
||||
uplc::ast::Constant::String(value) => Ok(UntypedExpr::String {
|
||||
location: Span::empty(),
|
||||
value,
|
||||
}),
|
||||
|
||||
uplc::ast::Constant::Bls12_381G1Element(pt) => Ok(UntypedExpr::CurvePoint {
|
||||
location: Span::empty(),
|
||||
point: Curve::Bls12_381(Bls12_381Point::G1(*pt)).into(),
|
||||
preferred_format: ByteArrayFormatPreference::HexadecimalString,
|
||||
}),
|
||||
|
||||
uplc::ast::Constant::Bls12_381G2Element(pt) => Ok(UntypedExpr::CurvePoint {
|
||||
location: Span::empty(),
|
||||
point: Curve::Bls12_381(Bls12_381Point::G2(*pt)).into(),
|
||||
preferred_format: ByteArrayFormatPreference::HexadecimalString,
|
||||
}),
|
||||
|
||||
uplc::ast::Constant::Bls12_381MlResult(ml) => {
|
||||
let mut bytes = Vec::new();
|
||||
|
||||
bytes.extend((*ml).to_bendian());
|
||||
|
||||
// NOTE: We don't actually have a syntax for representing MillerLoop results, so we
|
||||
// just fake it as a constructor with a bytearray. Note also that the bytearray is
|
||||
// *large*.
|
||||
Ok(UntypedExpr::Call {
|
||||
location: Span::empty(),
|
||||
arguments: vec![CallArg {
|
||||
label: None,
|
||||
location: Span::empty(),
|
||||
value: UntypedExpr::ByteArray {
|
||||
location: Span::empty(),
|
||||
bytes,
|
||||
preferred_format: ByteArrayFormatPreference::HexadecimalString,
|
||||
},
|
||||
}],
|
||||
fun: Box::new(UntypedExpr::Var {
|
||||
name: "MillerLoopResult".to_string(),
|
||||
location: Span::empty(),
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
UntypedExpr::do_reify_constant(&mut IndexMap::new(), data_types, cst, tipo)
|
||||
}
|
||||
|
||||
// Reify some opaque 'PlutusData' into an 'UntypedExpr', using a Type annotation. We also need
|
||||
|
@ -720,9 +607,36 @@ impl UntypedExpr {
|
|||
data: PlutusData,
|
||||
tipo: &Type,
|
||||
) -> Result<Self, String> {
|
||||
if let Type::Var { tipo } = tipo {
|
||||
if let TypeVar::Link { tipo } = &*tipo.borrow() {
|
||||
return UntypedExpr::reify_data(data_types, data, tipo);
|
||||
UntypedExpr::do_reify_data(&mut IndexMap::new(), data_types, data, tipo)
|
||||
}
|
||||
|
||||
fn reify_with<T, F>(
|
||||
generics: &mut IndexMap<u64, Rc<Type>>,
|
||||
data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
|
||||
t: T,
|
||||
tipo: &Type,
|
||||
with: F,
|
||||
) -> Result<Self, String>
|
||||
where
|
||||
T: Debug,
|
||||
F: Fn(
|
||||
&mut IndexMap<u64, Rc<Type>>,
|
||||
&IndexMap<&DataTypeKey, &TypedDataType>,
|
||||
T,
|
||||
&Type,
|
||||
) -> Result<Self, String>,
|
||||
{
|
||||
if let Type::Var { tipo: var_tipo } = tipo {
|
||||
match &*var_tipo.borrow() {
|
||||
TypeVar::Link { tipo } => {
|
||||
return Self::reify_with(generics, data_types, t, tipo, with);
|
||||
}
|
||||
TypeVar::Generic { id } => {
|
||||
if let Some(tipo) = generics.get(id) {
|
||||
return Self::reify_with(generics, data_types, t, &tipo.clone(), with);
|
||||
}
|
||||
}
|
||||
_ => unreachable!("unbound type during reification {tipo:?} -> {t:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -740,7 +654,7 @@ impl UntypedExpr {
|
|||
|
||||
let inner_type = convert_opaque_type(&tipo.clone().into(), data_types, false);
|
||||
|
||||
let value = UntypedExpr::reify_data(data_types, data, &inner_type)?;
|
||||
let value = Self::reify_with(generics, data_types, t, &inner_type, with)?;
|
||||
|
||||
return Ok(UntypedExpr::Call {
|
||||
location: Span::empty(),
|
||||
|
@ -756,121 +670,176 @@ impl UntypedExpr {
|
|||
});
|
||||
}
|
||||
|
||||
with(generics, data_types, t, tipo)
|
||||
}
|
||||
|
||||
fn do_reify_constant(
|
||||
generics: &mut IndexMap<u64, Rc<Type>>,
|
||||
data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
|
||||
cst: uplc::ast::Constant,
|
||||
tipo: &Type,
|
||||
) -> Result<Self, String> {
|
||||
Self::reify_with(
|
||||
generics,
|
||||
data_types,
|
||||
cst,
|
||||
tipo,
|
||||
|generics, data_types, cst, tipo| match cst {
|
||||
uplc::ast::Constant::Data(data) => {
|
||||
UntypedExpr::do_reify_data(generics, data_types, data, tipo)
|
||||
}
|
||||
|
||||
uplc::ast::Constant::Integer(i) => {
|
||||
UntypedExpr::do_reify_data(generics, data_types, Data::integer(i), tipo)
|
||||
}
|
||||
|
||||
uplc::ast::Constant::ByteString(bytes) => {
|
||||
UntypedExpr::do_reify_data(generics, data_types, Data::bytestring(bytes), tipo)
|
||||
}
|
||||
|
||||
uplc::ast::Constant::ProtoList(_, args) => match tipo {
|
||||
Type::App {
|
||||
module,
|
||||
name,
|
||||
args: type_args,
|
||||
..
|
||||
} if module.is_empty() && name.as_str() == "List" => {
|
||||
if let [inner] = &type_args[..] {
|
||||
Ok(UntypedExpr::List {
|
||||
location: Span::empty(),
|
||||
elements: args
|
||||
.into_iter()
|
||||
.map(|arg| {
|
||||
UntypedExpr::do_reify_constant(
|
||||
generics, data_types, arg, inner,
|
||||
)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
tail: None,
|
||||
})
|
||||
} else {
|
||||
Err(
|
||||
"invalid List type annotation: the list has multiple type-parameters."
|
||||
.to_string(),
|
||||
)
|
||||
}
|
||||
}
|
||||
Type::Tuple { elems } => Ok(UntypedExpr::Tuple {
|
||||
location: Span::empty(),
|
||||
elems: args
|
||||
.into_iter()
|
||||
.zip(elems)
|
||||
.map(|(arg, arg_type)| {
|
||||
UntypedExpr::do_reify_constant(generics, data_types, arg, arg_type)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
}),
|
||||
_ => Err(format!(
|
||||
"invalid type annotation. expected List but got: {tipo:?}"
|
||||
)),
|
||||
},
|
||||
|
||||
uplc::ast::Constant::ProtoPair(_, _, left, right) => match tipo {
|
||||
Type::Tuple { elems } => Ok(UntypedExpr::Tuple {
|
||||
location: Span::empty(),
|
||||
elems: [left.as_ref(), right.as_ref()]
|
||||
.into_iter()
|
||||
.zip(elems)
|
||||
.map(|(arg, arg_type)| {
|
||||
UntypedExpr::do_reify_constant(
|
||||
generics,
|
||||
data_types,
|
||||
arg.to_owned(),
|
||||
arg_type,
|
||||
)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
}),
|
||||
_ => Err(format!(
|
||||
"invalid type annotation. expected Tuple but got: {tipo:?}"
|
||||
)),
|
||||
},
|
||||
|
||||
uplc::ast::Constant::Unit => Ok(UntypedExpr::Var {
|
||||
location: Span::empty(),
|
||||
name: "Void".to_string(),
|
||||
}),
|
||||
|
||||
uplc::ast::Constant::Bool(is_true) => Ok(UntypedExpr::Var {
|
||||
location: Span::empty(),
|
||||
name: if is_true { "True" } else { "False" }.to_string(),
|
||||
}),
|
||||
|
||||
uplc::ast::Constant::String(value) => Ok(UntypedExpr::String {
|
||||
location: Span::empty(),
|
||||
value,
|
||||
}),
|
||||
|
||||
uplc::ast::Constant::Bls12_381G1Element(pt) => Ok(UntypedExpr::CurvePoint {
|
||||
location: Span::empty(),
|
||||
point: Curve::Bls12_381(Bls12_381Point::G1(*pt)).into(),
|
||||
preferred_format: ByteArrayFormatPreference::HexadecimalString,
|
||||
}),
|
||||
|
||||
uplc::ast::Constant::Bls12_381G2Element(pt) => Ok(UntypedExpr::CurvePoint {
|
||||
location: Span::empty(),
|
||||
point: Curve::Bls12_381(Bls12_381Point::G2(*pt)).into(),
|
||||
preferred_format: ByteArrayFormatPreference::HexadecimalString,
|
||||
}),
|
||||
|
||||
uplc::ast::Constant::Bls12_381MlResult(ml) => {
|
||||
let mut bytes = Vec::new();
|
||||
|
||||
bytes.extend((*ml).to_bendian());
|
||||
|
||||
// NOTE: We don't actually have a syntax for representing MillerLoop results, so we
|
||||
// just fake it as a constructor with a bytearray. Note also that the bytearray is
|
||||
// *large*.
|
||||
Ok(UntypedExpr::Call {
|
||||
location: Span::empty(),
|
||||
arguments: vec![CallArg {
|
||||
label: None,
|
||||
location: Span::empty(),
|
||||
value: UntypedExpr::ByteArray {
|
||||
location: Span::empty(),
|
||||
bytes,
|
||||
preferred_format: ByteArrayFormatPreference::HexadecimalString,
|
||||
},
|
||||
}],
|
||||
fun: Box::new(UntypedExpr::Var {
|
||||
name: "MillerLoopResult".to_string(),
|
||||
location: Span::empty(),
|
||||
}),
|
||||
})
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn reify_blind(data: PlutusData) -> Self {
|
||||
match data {
|
||||
PlutusData::BigInt(ref i) => Ok(UntypedExpr::UInt {
|
||||
PlutusData::BigInt(ref i) => UntypedExpr::UInt {
|
||||
location: Span::empty(),
|
||||
base: Base::Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
value: from_pallas_bigint(i).to_string(),
|
||||
}),
|
||||
},
|
||||
|
||||
PlutusData::BoundedBytes(bytes) => Ok(UntypedExpr::ByteArray {
|
||||
PlutusData::BoundedBytes(bytes) => UntypedExpr::ByteArray {
|
||||
location: Span::empty(),
|
||||
bytes: bytes.into(),
|
||||
preferred_format: ByteArrayFormatPreference::HexadecimalString,
|
||||
}),
|
||||
|
||||
PlutusData::Array(args) => match tipo {
|
||||
Type::App {
|
||||
module,
|
||||
name,
|
||||
args: type_args,
|
||||
..
|
||||
} if module.is_empty() && name.as_str() == "List" => {
|
||||
if let [inner] = &type_args[..] {
|
||||
Ok(UntypedExpr::List {
|
||||
location: Span::empty(),
|
||||
elements: args
|
||||
.into_iter()
|
||||
.map(|arg| UntypedExpr::reify_data(data_types, arg, inner))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
tail: None,
|
||||
})
|
||||
} else {
|
||||
Err(
|
||||
"invalid List type annotation: the list has multiple type-parameters."
|
||||
.to_string(),
|
||||
)
|
||||
}
|
||||
}
|
||||
Type::Tuple { elems } => Ok(UntypedExpr::Tuple {
|
||||
location: Span::empty(),
|
||||
elems: args
|
||||
.into_iter()
|
||||
.zip(elems)
|
||||
.map(|(arg, arg_type)| UntypedExpr::reify_data(data_types, arg, arg_type))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
}),
|
||||
_ => Err(format!(
|
||||
"invalid type annotation. expected List but got: {tipo:?}"
|
||||
)),
|
||||
},
|
||||
|
||||
PlutusData::Constr(Constr {
|
||||
tag,
|
||||
any_constructor,
|
||||
fields,
|
||||
}) => {
|
||||
let ix = if tag == 102 {
|
||||
any_constructor.unwrap() as usize
|
||||
} else if tag < 128 {
|
||||
tag as usize - 121
|
||||
} else {
|
||||
tag as usize - 1280 + 7
|
||||
};
|
||||
|
||||
if let Type::App { .. } = tipo {
|
||||
if let Some(DataType { constructors, .. }) =
|
||||
lookup_data_type_by_tipo(data_types, tipo)
|
||||
{
|
||||
let constructor = &constructors[ix];
|
||||
|
||||
return if fields.is_empty() {
|
||||
Ok(UntypedExpr::Var {
|
||||
location: Span::empty(),
|
||||
name: constructor.name.to_string(),
|
||||
})
|
||||
} else {
|
||||
let arguments = fields
|
||||
.into_iter()
|
||||
.zip(constructor.arguments.iter())
|
||||
.map(
|
||||
|(
|
||||
field,
|
||||
RecordConstructorArg {
|
||||
ref label,
|
||||
ref tipo,
|
||||
..
|
||||
},
|
||||
)| {
|
||||
UntypedExpr::reify_data(data_types, field, tipo).map(
|
||||
|value| CallArg {
|
||||
label: label.clone(),
|
||||
location: Span::empty(),
|
||||
value,
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
Ok(UntypedExpr::Call {
|
||||
location: Span::empty(),
|
||||
arguments,
|
||||
fun: Box::new(UntypedExpr::Var {
|
||||
name: constructor.name.to_string(),
|
||||
location: Span::empty(),
|
||||
}),
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Err(format!(
|
||||
"invalid type annotation {tipo:?} for constructor: {tag:?} with {fields:?}"
|
||||
))
|
||||
}
|
||||
PlutusData::Array(elems) => UntypedExpr::List {
|
||||
location: Span::empty(),
|
||||
elements: elems
|
||||
.into_iter()
|
||||
.map(UntypedExpr::reify_blind)
|
||||
.collect::<Vec<_>>(),
|
||||
tail: None,
|
||||
},
|
||||
|
||||
PlutusData::Map(indef_or_def) => {
|
||||
let kvs = match indef_or_def {
|
||||
|
@ -878,19 +847,229 @@ impl UntypedExpr {
|
|||
KeyValuePairs::Indef(kvs) => kvs,
|
||||
};
|
||||
|
||||
UntypedExpr::reify_data(
|
||||
data_types,
|
||||
PlutusData::Array(
|
||||
kvs.into_iter()
|
||||
.map(|(k, v)| PlutusData::Array(vec![k, v]))
|
||||
.collect(),
|
||||
),
|
||||
tipo,
|
||||
)
|
||||
UntypedExpr::List {
|
||||
location: Span::empty(),
|
||||
elements: kvs
|
||||
.into_iter()
|
||||
.map(|(k, v)| UntypedExpr::Tuple {
|
||||
location: Span::empty(),
|
||||
elems: vec![UntypedExpr::reify_blind(k), UntypedExpr::reify_blind(v)],
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
tail: None,
|
||||
}
|
||||
}
|
||||
|
||||
PlutusData::Constr(Constr {
|
||||
tag,
|
||||
any_constructor,
|
||||
fields,
|
||||
}) => {
|
||||
let ix = convert_tag_to_constr(tag).or(any_constructor).unwrap() as usize;
|
||||
|
||||
let fields = fields
|
||||
.into_iter()
|
||||
.map(|field| CallArg {
|
||||
location: Span::empty(),
|
||||
label: None,
|
||||
value: UntypedExpr::reify_blind(field),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut arguments = vec![CallArg {
|
||||
location: Span::empty(),
|
||||
label: None,
|
||||
value: UntypedExpr::UInt {
|
||||
location: Span::empty(),
|
||||
value: ix.to_string(),
|
||||
base: Base::Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
},
|
||||
}];
|
||||
arguments.extend(fields);
|
||||
|
||||
UntypedExpr::Call {
|
||||
location: Span::empty(),
|
||||
arguments,
|
||||
fun: UntypedExpr::Var {
|
||||
name: "Constr".to_string(),
|
||||
location: Span::empty(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn do_reify_data(
|
||||
generics: &mut IndexMap<u64, Rc<Type>>,
|
||||
data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
|
||||
data: PlutusData,
|
||||
tipo: &Type,
|
||||
) -> Result<Self, String> {
|
||||
if let Type::App { name, module, .. } = tipo {
|
||||
if module.is_empty() && name == "Data" {
|
||||
return Ok(Self::reify_blind(data));
|
||||
}
|
||||
}
|
||||
|
||||
Self::reify_with(
|
||||
generics,
|
||||
data_types,
|
||||
data,
|
||||
tipo,
|
||||
|generics, data_types, data, tipo| match data {
|
||||
PlutusData::BigInt(ref i) => Ok(UntypedExpr::UInt {
|
||||
location: Span::empty(),
|
||||
base: Base::Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
value: from_pallas_bigint(i).to_string(),
|
||||
}),
|
||||
|
||||
PlutusData::BoundedBytes(bytes) => Ok(UntypedExpr::ByteArray {
|
||||
location: Span::empty(),
|
||||
bytes: bytes.into(),
|
||||
preferred_format: ByteArrayFormatPreference::HexadecimalString,
|
||||
}),
|
||||
|
||||
PlutusData::Array(args) => match tipo {
|
||||
Type::App {
|
||||
module,
|
||||
name,
|
||||
args: type_args,
|
||||
..
|
||||
} if module.is_empty() && name.as_str() == "List" => {
|
||||
if let [inner] = &type_args[..] {
|
||||
Ok(UntypedExpr::List {
|
||||
location: Span::empty(),
|
||||
elements: args
|
||||
.into_iter()
|
||||
.map(|arg| {
|
||||
UntypedExpr::do_reify_data(generics, data_types, arg, inner)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
tail: None,
|
||||
})
|
||||
} else {
|
||||
Err(
|
||||
"invalid List type annotation: the list has multiple type-parameters."
|
||||
.to_string(),
|
||||
)
|
||||
}
|
||||
}
|
||||
Type::Tuple { elems } => Ok(UntypedExpr::Tuple {
|
||||
location: Span::empty(),
|
||||
elems: args
|
||||
.into_iter()
|
||||
.zip(elems)
|
||||
.map(|(arg, arg_type)| {
|
||||
UntypedExpr::do_reify_data(generics, data_types, arg, arg_type)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
}),
|
||||
_ => Err(format!(
|
||||
"invalid type annotation. expected List but got: {tipo:?}"
|
||||
)),
|
||||
},
|
||||
|
||||
PlutusData::Constr(Constr {
|
||||
tag,
|
||||
any_constructor,
|
||||
fields,
|
||||
}) => {
|
||||
let ix = convert_tag_to_constr(tag).or(any_constructor).unwrap() as usize;
|
||||
|
||||
if let Type::App { args, .. } = tipo {
|
||||
if let Some(DataType {
|
||||
constructors,
|
||||
typed_parameters,
|
||||
..
|
||||
}) = lookup_data_type_by_tipo(data_types, tipo)
|
||||
{
|
||||
let constructor = &constructors[ix];
|
||||
|
||||
typed_parameters
|
||||
.iter()
|
||||
.zip(args)
|
||||
.for_each(|(generic, arg)| {
|
||||
if let Some(ix) = generic.get_generic() {
|
||||
if !generics.contains_key(&ix) {
|
||||
generics.insert(ix, arg.clone());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return if fields.is_empty() {
|
||||
Ok(UntypedExpr::Var {
|
||||
location: Span::empty(),
|
||||
name: constructor.name.to_string(),
|
||||
})
|
||||
} else {
|
||||
let arguments =
|
||||
fields
|
||||
.into_iter()
|
||||
.zip(constructor.arguments.iter())
|
||||
.map(
|
||||
|(
|
||||
field,
|
||||
RecordConstructorArg {
|
||||
ref label,
|
||||
ref tipo,
|
||||
..
|
||||
},
|
||||
)| {
|
||||
UntypedExpr::do_reify_data(
|
||||
generics, data_types, field, tipo,
|
||||
)
|
||||
.map(|value| CallArg {
|
||||
label: label.clone(),
|
||||
location: Span::empty(),
|
||||
value,
|
||||
})
|
||||
},
|
||||
)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
Ok(UntypedExpr::Call {
|
||||
location: Span::empty(),
|
||||
arguments,
|
||||
fun: Box::new(UntypedExpr::Var {
|
||||
name: constructor.name.to_string(),
|
||||
location: Span::empty(),
|
||||
}),
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Err(format!(
|
||||
"invalid type annotation {tipo:?} for constructor: {tag:?} with {fields:?}"
|
||||
))
|
||||
}
|
||||
|
||||
PlutusData::Map(indef_or_def) => {
|
||||
let kvs = match indef_or_def {
|
||||
KeyValuePairs::Def(kvs) => kvs,
|
||||
KeyValuePairs::Indef(kvs) => kvs,
|
||||
};
|
||||
|
||||
UntypedExpr::do_reify_data(
|
||||
generics,
|
||||
data_types,
|
||||
PlutusData::Array(
|
||||
kvs.into_iter()
|
||||
.map(|(k, v)| PlutusData::Array(vec![k, v]))
|
||||
.collect(),
|
||||
),
|
||||
tipo,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn todo(reason: Option<Self>, location: Span) -> Self {
|
||||
UntypedExpr::Trace {
|
||||
location,
|
||||
|
|
|
@ -6,9 +6,8 @@ use self::{
|
|||
air::Air,
|
||||
builder::{
|
||||
air_holds_msg, cast_validator_args, constants_ir, convert_type_to_data, extract_constant,
|
||||
lookup_data_type_by_tipo, modify_cyclic_calls, modify_self_calls, rearrange_list_clauses,
|
||||
AssignmentProperties, ClauseProperties, CodeGenSpecialFuncs, CycleFunctionNames,
|
||||
HoistableFunction, Variant,
|
||||
modify_cyclic_calls, modify_self_calls, rearrange_list_clauses, AssignmentProperties,
|
||||
ClauseProperties, CodeGenSpecialFuncs, CycleFunctionNames, HoistableFunction, Variant,
|
||||
},
|
||||
tree::{AirMsg, AirTree, TreePath},
|
||||
};
|
||||
|
@ -23,15 +22,16 @@ use crate::{
|
|||
gen_uplc::{
|
||||
air::ExpectLevel,
|
||||
builder::{
|
||||
check_replaceable_opaque_type, convert_opaque_type, erase_opaque_type_operations,
|
||||
find_and_replace_generics, find_list_clause_or_default_first, get_arg_type_name,
|
||||
get_generic_id_and_type, get_generic_variant_name, get_line_columns_by_span,
|
||||
get_src_code_by_span, known_data_to_type, monomorphize, pattern_has_conditions,
|
||||
wrap_as_multi_validator, wrap_validator_condition, CodeGenFunction, SpecificClause,
|
||||
erase_opaque_type_operations, find_list_clause_or_default_first,
|
||||
get_generic_variant_name, get_line_columns_by_span, get_src_code_by_span,
|
||||
known_data_to_type, monomorphize, pattern_has_conditions, wrap_as_multi_validator,
|
||||
wrap_validator_condition, CodeGenFunction, SpecificClause,
|
||||
},
|
||||
},
|
||||
line_numbers::LineNumbers,
|
||||
tipo::{
|
||||
check_replaceable_opaque_type, convert_opaque_type, find_and_replace_generics,
|
||||
get_arg_type_name, get_generic_id_and_type, lookup_data_type_by_tipo,
|
||||
ModuleValueConstructor, PatternConstructor, Type, TypeInfo, ValueConstructor,
|
||||
ValueConstructorVariant,
|
||||
},
|
||||
|
@ -3905,9 +3905,11 @@ impl<'a> CodeGenerator<'a> {
|
|||
} else if constructor.tipo.is_void() {
|
||||
Some(Term::Constant(UplcConstant::Unit.into()))
|
||||
} else {
|
||||
let data_type =
|
||||
builder::lookup_data_type_by_tipo(&self.data_types, &constructor.tipo)
|
||||
.unwrap();
|
||||
let data_type = crate::tipo::lookup_data_type_by_tipo(
|
||||
&self.data_types,
|
||||
&constructor.tipo,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (constr_index, constr_type) = data_type
|
||||
.constructors
|
||||
|
|
|
@ -4,14 +4,18 @@ use super::{
|
|||
};
|
||||
use crate::{
|
||||
ast::{
|
||||
AssignmentKind, BinOp, ClauseGuard, Constant, DataType, DataTypeKey, FunctionAccessKey,
|
||||
Pattern, Span, TraceLevel, TypedArg, TypedClause, TypedClauseGuard, TypedDataType,
|
||||
TypedPattern, UnOp,
|
||||
AssignmentKind, BinOp, ClauseGuard, Constant, DataTypeKey, FunctionAccessKey, Pattern,
|
||||
Span, TraceLevel, TypedArg, TypedClause, TypedClauseGuard, TypedDataType, TypedPattern,
|
||||
UnOp,
|
||||
},
|
||||
builtins::{bool, data, function, int, list, string, void},
|
||||
expr::TypedExpr,
|
||||
line_numbers::{LineColumn, LineNumbers},
|
||||
tipo::{PatternConstructor, Type, TypeVar, ValueConstructor, ValueConstructorVariant},
|
||||
tipo::{
|
||||
check_replaceable_opaque_type, convert_opaque_type, find_and_replace_generics,
|
||||
lookup_data_type_by_tipo, PatternConstructor, Type, ValueConstructor,
|
||||
ValueConstructorVariant,
|
||||
},
|
||||
};
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use itertools::{Itertools, Position};
|
||||
|
@ -274,239 +278,6 @@ impl Default for CodeGenSpecialFuncs {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_generic_id_and_type(tipo: &Type, param: &Type) -> Vec<(u64, Rc<Type>)> {
|
||||
let mut generics_ids = vec![];
|
||||
|
||||
if let Some(id) = tipo.get_generic() {
|
||||
generics_ids.push((id, param.clone().into()));
|
||||
return generics_ids;
|
||||
}
|
||||
|
||||
for (tipo, param_type) in tipo
|
||||
.get_inner_types()
|
||||
.iter()
|
||||
.zip(param.get_inner_types().iter())
|
||||
{
|
||||
generics_ids.append(&mut get_generic_id_and_type(tipo, param_type));
|
||||
}
|
||||
generics_ids
|
||||
}
|
||||
|
||||
pub fn lookup_data_type_by_tipo(
|
||||
data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
|
||||
tipo: &Type,
|
||||
) -> Option<DataType<Rc<Type>>> {
|
||||
match tipo {
|
||||
Type::Fn { ret, .. } => match ret.as_ref() {
|
||||
Type::App { module, name, .. } => {
|
||||
let data_type_key = DataTypeKey {
|
||||
module_name: module.clone(),
|
||||
defined_type: name.clone(),
|
||||
};
|
||||
data_types.get(&data_type_key).map(|item| (*item).clone())
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
Type::App { module, name, .. } => {
|
||||
let data_type_key = DataTypeKey {
|
||||
module_name: module.clone(),
|
||||
defined_type: name.clone(),
|
||||
};
|
||||
|
||||
data_types.get(&data_type_key).map(|item| (*item).clone())
|
||||
}
|
||||
Type::Var { tipo } => {
|
||||
if let TypeVar::Link { tipo } = &*tipo.borrow() {
|
||||
lookup_data_type_by_tipo(data_types, tipo)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_arg_type_name(tipo: &Type) -> String {
|
||||
match tipo {
|
||||
Type::App { name, args, .. } => {
|
||||
let inner_args = args.iter().map(|arg| get_arg_type_name(arg)).collect_vec();
|
||||
format!("{}_{}", name, inner_args.join("_"))
|
||||
}
|
||||
Type::Var { tipo } => match tipo.borrow().clone() {
|
||||
TypeVar::Link { tipo } => get_arg_type_name(tipo.as_ref()),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Type::Tuple { elems } => {
|
||||
let inner_args = elems.iter().map(|arg| get_arg_type_name(arg)).collect_vec();
|
||||
inner_args.join("_")
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_opaque_type(
|
||||
t: &Rc<Type>,
|
||||
data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
|
||||
deep: bool,
|
||||
) -> Rc<Type> {
|
||||
if check_replaceable_opaque_type(t, data_types) && matches!(t.as_ref(), Type::App { .. }) {
|
||||
let data_type = lookup_data_type_by_tipo(data_types, t).unwrap();
|
||||
let new_type_fields = data_type.typed_parameters;
|
||||
|
||||
let mut mono_type_vec = vec![];
|
||||
|
||||
for (tipo, param) in new_type_fields.iter().zip(t.arg_types().unwrap()) {
|
||||
mono_type_vec.append(&mut get_generic_id_and_type(tipo, ¶m));
|
||||
}
|
||||
let mono_types = mono_type_vec.into_iter().collect();
|
||||
|
||||
let generic_type = &data_type.constructors[0].arguments[0].tipo;
|
||||
|
||||
let mono_type = find_and_replace_generics(generic_type, &mono_types);
|
||||
|
||||
if deep {
|
||||
convert_opaque_type(&mono_type, data_types, deep)
|
||||
} else {
|
||||
mono_type
|
||||
}
|
||||
} else {
|
||||
match t.as_ref() {
|
||||
Type::App {
|
||||
public,
|
||||
module,
|
||||
name,
|
||||
args,
|
||||
} => {
|
||||
let mut new_args = vec![];
|
||||
for arg in args {
|
||||
let arg = convert_opaque_type(arg, data_types, deep);
|
||||
new_args.push(arg);
|
||||
}
|
||||
Type::App {
|
||||
public: *public,
|
||||
module: module.clone(),
|
||||
name: name.clone(),
|
||||
args: new_args,
|
||||
}
|
||||
.into()
|
||||
}
|
||||
Type::Fn { args, ret } => {
|
||||
let mut new_args = vec![];
|
||||
for arg in args {
|
||||
let arg = convert_opaque_type(arg, data_types, deep);
|
||||
new_args.push(arg);
|
||||
}
|
||||
|
||||
let ret = convert_opaque_type(ret, data_types, deep);
|
||||
|
||||
Type::Fn {
|
||||
args: new_args,
|
||||
ret,
|
||||
}
|
||||
.into()
|
||||
}
|
||||
Type::Var { tipo: var_tipo } => {
|
||||
if let TypeVar::Link { tipo } = &var_tipo.borrow().clone() {
|
||||
convert_opaque_type(tipo, data_types, deep)
|
||||
} else {
|
||||
t.clone()
|
||||
}
|
||||
}
|
||||
Type::Tuple { elems } => {
|
||||
let mut new_elems = vec![];
|
||||
for arg in elems {
|
||||
let arg = convert_opaque_type(arg, data_types, deep);
|
||||
new_elems.push(arg);
|
||||
}
|
||||
Type::Tuple { elems: new_elems }.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_replaceable_opaque_type(
|
||||
t: &Type,
|
||||
data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
|
||||
) -> bool {
|
||||
let data_type = lookup_data_type_by_tipo(data_types, t);
|
||||
|
||||
if let Some(data_type) = data_type {
|
||||
assert!(!data_type.constructors.is_empty());
|
||||
let data_type_args = &data_type.constructors[0].arguments;
|
||||
data_type_args.len() == 1 && data_type.opaque && data_type.constructors.len() == 1
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_and_replace_generics(
|
||||
tipo: &Rc<Type>,
|
||||
mono_types: &IndexMap<u64, Rc<Type>>,
|
||||
) -> Rc<Type> {
|
||||
if let Some(id) = tipo.get_generic() {
|
||||
// If a generic does not have a type we know of
|
||||
// like a None in option then just use same type
|
||||
mono_types.get(&id).unwrap_or(tipo).clone()
|
||||
} else if tipo.is_generic() {
|
||||
match &**tipo {
|
||||
Type::App {
|
||||
args,
|
||||
public,
|
||||
module,
|
||||
name,
|
||||
} => {
|
||||
let mut new_args = vec![];
|
||||
for arg in args {
|
||||
let arg = find_and_replace_generics(arg, mono_types);
|
||||
new_args.push(arg);
|
||||
}
|
||||
let t = Type::App {
|
||||
args: new_args,
|
||||
public: *public,
|
||||
module: module.clone(),
|
||||
name: name.clone(),
|
||||
};
|
||||
t.into()
|
||||
}
|
||||
Type::Fn { args, ret } => {
|
||||
let mut new_args = vec![];
|
||||
for arg in args {
|
||||
let arg = find_and_replace_generics(arg, mono_types);
|
||||
new_args.push(arg);
|
||||
}
|
||||
|
||||
let ret = find_and_replace_generics(ret, mono_types);
|
||||
|
||||
let t = Type::Fn {
|
||||
args: new_args,
|
||||
ret,
|
||||
};
|
||||
|
||||
t.into()
|
||||
}
|
||||
Type::Tuple { elems } => {
|
||||
let mut new_elems = vec![];
|
||||
for elem in elems {
|
||||
let elem = find_and_replace_generics(elem, mono_types);
|
||||
new_elems.push(elem);
|
||||
}
|
||||
let t = Type::Tuple { elems: new_elems };
|
||||
t.into()
|
||||
}
|
||||
Type::Var { tipo: var_tipo } => {
|
||||
let var_type = var_tipo.as_ref().borrow().clone();
|
||||
|
||||
match var_type {
|
||||
TypeVar::Link { tipo } => find_and_replace_generics(&tipo, mono_types),
|
||||
TypeVar::Generic { .. } | TypeVar::Unbound { .. } => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tipo.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn constants_ir(literal: &Constant) -> AirTree {
|
||||
match literal {
|
||||
Constant::Int { value, .. } => AirTree::int(value),
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
use self::{environment::Environment, pretty::Printer};
|
||||
use crate::{
|
||||
ast::{Annotation, Constant, DefinitionLocation, ModuleKind, Span},
|
||||
ast::{
|
||||
Annotation, Constant, DataType, DataTypeKey, DefinitionLocation, ModuleKind, Span,
|
||||
TypedDataType,
|
||||
},
|
||||
builtins::{G1_ELEMENT, G2_ELEMENT, MILLER_LOOP_RESULT},
|
||||
tipo::fields::FieldMap,
|
||||
};
|
||||
use indexmap::IndexMap;
|
||||
use itertools::Itertools;
|
||||
use std::{cell::RefCell, collections::HashMap, ops::Deref, rc::Rc};
|
||||
use uplc::{ast::Type as UplcType, builtins::DefaultFunction};
|
||||
|
||||
|
@ -437,6 +442,240 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn lookup_data_type_by_tipo(
|
||||
data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
|
||||
tipo: &Type,
|
||||
) -> Option<DataType<Rc<Type>>> {
|
||||
match tipo {
|
||||
Type::Fn { ret, .. } => match ret.as_ref() {
|
||||
Type::App { module, name, .. } => {
|
||||
let data_type_key = DataTypeKey {
|
||||
module_name: module.clone(),
|
||||
defined_type: name.clone(),
|
||||
};
|
||||
data_types.get(&data_type_key).map(|item| (*item).clone())
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
Type::App { module, name, .. } => {
|
||||
let data_type_key = DataTypeKey {
|
||||
module_name: module.clone(),
|
||||
defined_type: name.clone(),
|
||||
};
|
||||
|
||||
data_types.get(&data_type_key).map(|item| (*item).clone())
|
||||
}
|
||||
Type::Var { tipo } => {
|
||||
if let TypeVar::Link { tipo } = &*tipo.borrow() {
|
||||
lookup_data_type_by_tipo(data_types, tipo)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_generic_id_and_type(tipo: &Type, param: &Type) -> Vec<(u64, Rc<Type>)> {
|
||||
let mut generics_ids = vec![];
|
||||
|
||||
if let Some(id) = tipo.get_generic() {
|
||||
generics_ids.push((id, param.clone().into()));
|
||||
return generics_ids;
|
||||
}
|
||||
|
||||
for (tipo, param_type) in tipo
|
||||
.get_inner_types()
|
||||
.iter()
|
||||
.zip(param.get_inner_types().iter())
|
||||
{
|
||||
generics_ids.append(&mut get_generic_id_and_type(tipo, param_type));
|
||||
}
|
||||
generics_ids
|
||||
}
|
||||
|
||||
pub fn get_arg_type_name(tipo: &Type) -> String {
|
||||
match tipo {
|
||||
Type::App { name, args, .. } => {
|
||||
let inner_args = args.iter().map(|arg| get_arg_type_name(arg)).collect_vec();
|
||||
format!("{}_{}", name, inner_args.join("_"))
|
||||
}
|
||||
Type::Var { tipo } => match tipo.borrow().clone() {
|
||||
TypeVar::Link { tipo } => get_arg_type_name(tipo.as_ref()),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Type::Tuple { elems } => {
|
||||
let inner_args = elems.iter().map(|arg| get_arg_type_name(arg)).collect_vec();
|
||||
inner_args.join("_")
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_opaque_type(
|
||||
t: &Rc<Type>,
|
||||
data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
|
||||
deep: bool,
|
||||
) -> Rc<Type> {
|
||||
if check_replaceable_opaque_type(t, data_types) && matches!(t.as_ref(), Type::App { .. }) {
|
||||
let data_type = lookup_data_type_by_tipo(data_types, t).unwrap();
|
||||
|
||||
let new_type_fields = data_type.typed_parameters;
|
||||
|
||||
let mut mono_type_vec = vec![];
|
||||
|
||||
for (tipo, param) in new_type_fields.iter().zip(t.arg_types().unwrap()) {
|
||||
mono_type_vec.append(&mut get_generic_id_and_type(tipo, ¶m));
|
||||
}
|
||||
let mono_types = mono_type_vec.into_iter().collect();
|
||||
|
||||
let generic_type = &data_type.constructors[0].arguments[0].tipo;
|
||||
|
||||
let mono_type = find_and_replace_generics(generic_type, &mono_types);
|
||||
|
||||
if deep {
|
||||
convert_opaque_type(&mono_type, data_types, deep)
|
||||
} else {
|
||||
mono_type
|
||||
}
|
||||
} else {
|
||||
match t.as_ref() {
|
||||
Type::App {
|
||||
public,
|
||||
module,
|
||||
name,
|
||||
args,
|
||||
} => {
|
||||
let mut new_args = vec![];
|
||||
for arg in args {
|
||||
let arg = convert_opaque_type(arg, data_types, deep);
|
||||
new_args.push(arg);
|
||||
}
|
||||
Type::App {
|
||||
public: *public,
|
||||
module: module.clone(),
|
||||
name: name.clone(),
|
||||
args: new_args,
|
||||
}
|
||||
.into()
|
||||
}
|
||||
Type::Fn { args, ret } => {
|
||||
let mut new_args = vec![];
|
||||
for arg in args {
|
||||
let arg = convert_opaque_type(arg, data_types, deep);
|
||||
new_args.push(arg);
|
||||
}
|
||||
|
||||
let ret = convert_opaque_type(ret, data_types, deep);
|
||||
|
||||
Type::Fn {
|
||||
args: new_args,
|
||||
ret,
|
||||
}
|
||||
.into()
|
||||
}
|
||||
Type::Var { tipo: var_tipo } => {
|
||||
if let TypeVar::Link { tipo } = &var_tipo.borrow().clone() {
|
||||
convert_opaque_type(tipo, data_types, deep)
|
||||
} else {
|
||||
t.clone()
|
||||
}
|
||||
}
|
||||
Type::Tuple { elems } => {
|
||||
let mut new_elems = vec![];
|
||||
for arg in elems {
|
||||
let arg = convert_opaque_type(arg, data_types, deep);
|
||||
new_elems.push(arg);
|
||||
}
|
||||
Type::Tuple { elems: new_elems }.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_replaceable_opaque_type(
|
||||
t: &Type,
|
||||
data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
|
||||
) -> bool {
|
||||
let data_type = lookup_data_type_by_tipo(data_types, t);
|
||||
|
||||
if let Some(data_type) = data_type {
|
||||
if let [constructor] = &data_type.constructors[..] {
|
||||
return constructor.arguments.len() == 1 && data_type.opaque;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn find_and_replace_generics(
|
||||
tipo: &Rc<Type>,
|
||||
mono_types: &IndexMap<u64, Rc<Type>>,
|
||||
) -> Rc<Type> {
|
||||
if let Some(id) = tipo.get_generic() {
|
||||
// If a generic does not have a type we know of
|
||||
// like a None in option then just use same type
|
||||
mono_types.get(&id).unwrap_or(tipo).clone()
|
||||
} else if tipo.is_generic() {
|
||||
match &**tipo {
|
||||
Type::App {
|
||||
args,
|
||||
public,
|
||||
module,
|
||||
name,
|
||||
} => {
|
||||
let mut new_args = vec![];
|
||||
for arg in args {
|
||||
let arg = find_and_replace_generics(arg, mono_types);
|
||||
new_args.push(arg);
|
||||
}
|
||||
let t = Type::App {
|
||||
args: new_args,
|
||||
public: *public,
|
||||
module: module.clone(),
|
||||
name: name.clone(),
|
||||
};
|
||||
t.into()
|
||||
}
|
||||
Type::Fn { args, ret } => {
|
||||
let mut new_args = vec![];
|
||||
for arg in args {
|
||||
let arg = find_and_replace_generics(arg, mono_types);
|
||||
new_args.push(arg);
|
||||
}
|
||||
|
||||
let ret = find_and_replace_generics(ret, mono_types);
|
||||
|
||||
let t = Type::Fn {
|
||||
args: new_args,
|
||||
ret,
|
||||
};
|
||||
|
||||
t.into()
|
||||
}
|
||||
Type::Tuple { elems } => {
|
||||
let mut new_elems = vec![];
|
||||
for elem in elems {
|
||||
let elem = find_and_replace_generics(elem, mono_types);
|
||||
new_elems.push(elem);
|
||||
}
|
||||
let t = Type::Tuple { elems: new_elems };
|
||||
t.into()
|
||||
}
|
||||
Type::Var { tipo: var_tipo } => {
|
||||
let var_type = var_tipo.as_ref().borrow().clone();
|
||||
|
||||
match var_type {
|
||||
TypeVar::Link { tipo } => find_and_replace_generics(&tipo, mono_types),
|
||||
TypeVar::Generic { .. } | TypeVar::Unbound { .. } => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tipo.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum TypeVar {
|
||||
/// Unbound is an unbound variable. It is one specific type but we don't
|
||||
|
@ -594,10 +833,12 @@ impl TypeVar {
|
|||
Self::Link { tipo } => tipo.get_inner_types(),
|
||||
Self::Unbound { .. } => vec![],
|
||||
var => {
|
||||
vec![Type::Var {
|
||||
tipo: RefCell::new(var.clone()).into(),
|
||||
}
|
||||
.into()]
|
||||
vec![
|
||||
Type::Var {
|
||||
tipo: RefCell::new(var.clone()).into(),
|
||||
}
|
||||
.into(),
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
use crate::line_numbers::LineNumbers;
|
||||
use std::{cmp::Ordering, collections::HashMap, rc::Rc};
|
||||
use vec1::Vec1;
|
||||
|
||||
use super::{
|
||||
environment::{assert_no_labeled_arguments, collapse_links, EntityKind, Environment},
|
||||
error::{Error, Warning},
|
||||
hydrator::Hydrator,
|
||||
pattern::PatternTyper,
|
||||
pipe::PipeTyper,
|
||||
RecordAccessor, Type, ValueConstructor, ValueConstructorVariant,
|
||||
};
|
||||
use crate::{
|
||||
ast::{
|
||||
Annotation, Arg, ArgName, AssignmentKind, BinOp, Bls12_381Point, ByteArrayFormatPreference,
|
||||
|
@ -13,17 +17,11 @@ use crate::{
|
|||
builtins::{bool, byte_array, function, g1_element, g2_element, int, list, string, tuple},
|
||||
expr::{FnStyle, TypedExpr, UntypedExpr},
|
||||
format,
|
||||
line_numbers::LineNumbers,
|
||||
tipo::fields::FieldMap,
|
||||
};
|
||||
|
||||
use super::{
|
||||
environment::{assert_no_labeled_arguments, collapse_links, EntityKind, Environment},
|
||||
error::{Error, Warning},
|
||||
hydrator::Hydrator,
|
||||
pattern::PatternTyper,
|
||||
pipe::PipeTyper,
|
||||
RecordAccessor, Type, ValueConstructor, ValueConstructorVariant,
|
||||
};
|
||||
use std::{cmp::Ordering, collections::HashMap, rc::Rc};
|
||||
use vec1::Vec1;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ExprTyper<'a, 'b> {
|
||||
|
@ -593,7 +591,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
_ => {
|
||||
return Err(Error::RecordUpdateInvalidConstructor {
|
||||
location: constructor.location(),
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1135,7 +1133,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
}
|
||||
|
||||
ValueConstructorVariant::ModuleConstant { literal, .. } => {
|
||||
return Ok(ClauseGuard::Constant(literal.clone()))
|
||||
return Ok(ClauseGuard::Constant(literal.clone()));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@ use aiken_lang::{
|
|||
builtins::bool,
|
||||
expr::{TypedExpr, UntypedExpr},
|
||||
format::Formatter,
|
||||
gen_uplc::{builder::convert_opaque_type, CodeGenerator},
|
||||
tipo::Type,
|
||||
gen_uplc::CodeGenerator,
|
||||
tipo::{convert_opaque_type, Type},
|
||||
};
|
||||
use cryptoxide::{blake2b::Blake2b, digest::Digest};
|
||||
use indexmap::IndexMap;
|
||||
|
|
Loading…
Reference in New Issue