parent
c48f15a957
commit
e2bc3a9fc4
|
@ -147,7 +147,7 @@ impl Reference {
|
|||
},
|
||||
Type::Pair { fst, snd, .. } => Self {
|
||||
inner: format!(
|
||||
"Pair{fst}{snd}",
|
||||
"Pair${fst}_{snd}",
|
||||
fst = Self::from_type(fst, type_parameters),
|
||||
snd = Self::from_type(snd, type_parameters)
|
||||
),
|
||||
|
|
|
@ -36,6 +36,18 @@ pub enum Declaration<T> {
|
|||
Inline(Box<T>),
|
||||
}
|
||||
|
||||
impl<A> Declaration<A> {
|
||||
pub fn map<F, B>(self, transform: F) -> Declaration<B>
|
||||
where
|
||||
F: FnOnce(A) -> B,
|
||||
{
|
||||
match self {
|
||||
Declaration::Referenced(reference) => Declaration::Referenced(reference),
|
||||
Declaration::Inline(inner) => Declaration::Inline(transform(*inner).into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Declaration<T> {
|
||||
pub fn reference(&'a self) -> Option<&'a Reference> {
|
||||
match self {
|
||||
|
@ -297,18 +309,22 @@ impl Annotated<Schema> {
|
|||
// make all types abide by this convention.
|
||||
let data = match definitions.try_lookup(&generic).cloned() {
|
||||
Some(Annotated {
|
||||
annotated: Schema::Data(Data::List(Items::Many(xs))),
|
||||
annotated: Schema::Pair(left, right),
|
||||
..
|
||||
}) if xs.len() == 2 => {
|
||||
}) => {
|
||||
definitions.remove(&generic);
|
||||
Data::Map(
|
||||
xs.first()
|
||||
.expect("length (== 2) checked in pattern clause")
|
||||
.to_owned(),
|
||||
xs.last()
|
||||
.expect("length (== 2) checked in pattern clause")
|
||||
.to_owned(),
|
||||
)
|
||||
|
||||
let left = left.map(|inner| match inner {
|
||||
Schema::Data(data) => data,
|
||||
_ => panic!("impossible: left inhabitant of pair isn't Data but: {inner:#?}"),
|
||||
});
|
||||
|
||||
let right = right.map(|inner| match inner {
|
||||
Schema::Data(data) => data,
|
||||
_ => panic!("impossible: right inhabitant of pair isn't Data but: {inner:#?}"),
|
||||
});
|
||||
|
||||
Data::Map(left, right)
|
||||
}
|
||||
|
||||
_ => Data::List(Items::One(Declaration::Referenced(generic))),
|
||||
|
@ -350,6 +366,25 @@ impl Annotated<Schema> {
|
|||
annotated,
|
||||
})
|
||||
}),
|
||||
|
||||
Type::Pair { fst, snd, .. } => {
|
||||
definitions.register(type_info, &type_parameters.clone(), |definitions| {
|
||||
let left = Annotated::do_from_type(fst, modules, type_parameters, definitions)
|
||||
.map(Declaration::Referenced)
|
||||
.map_err(|e| e.backtrack(type_info))?;
|
||||
|
||||
let right = Annotated::do_from_type(snd, modules, type_parameters, definitions)
|
||||
.map(Declaration::Referenced)
|
||||
.map_err(|e| e.backtrack(type_info))?;
|
||||
|
||||
Ok(Annotated {
|
||||
title: Some("Pair".to_owned()),
|
||||
description: None,
|
||||
annotated: Schema::Pair(left, right),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Type::Tuple { elems, .. } => {
|
||||
definitions.register(type_info, &type_parameters.clone(), |definitions| {
|
||||
let elems = elems
|
||||
|
@ -368,6 +403,7 @@ impl Annotated<Schema> {
|
|||
})
|
||||
})
|
||||
}
|
||||
|
||||
Type::Var { tipo, .. } => match tipo.borrow().deref() {
|
||||
TypeVar::Link { tipo } => {
|
||||
Annotated::do_from_type(tipo, modules, type_parameters, definitions)
|
||||
|
@ -383,8 +419,8 @@ impl Annotated<Schema> {
|
|||
Err(Error::new(ErrorContext::UnboundTypeVariable, type_info))
|
||||
}
|
||||
},
|
||||
|
||||
Type::Fn { .. } => unreachable!(),
|
||||
Type::Pair { .. } => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -922,9 +958,6 @@ pub enum ErrorContext {
|
|||
#[error("I caught a free variable in the contract's interface boundary.")]
|
||||
FreeTypeVariable,
|
||||
|
||||
#[error("I had the misfortune to find an invalid type in an interface boundary.")]
|
||||
ExpectedData,
|
||||
|
||||
#[error("I figured you tried to export a function in your contract's binary interface.")]
|
||||
UnexpectedFunction,
|
||||
|
||||
|
@ -1002,18 +1035,6 @@ If your contract doesn't need datum or redeemer, you can always give them the ty
|
|||
.if_supports_color(Stdout, |s| s.bold())
|
||||
),
|
||||
|
||||
ErrorContext::ExpectedData => format!(
|
||||
r#"While figuring out the outward-facing specification for your contract, I found a type that cannot actually be represented as valid Untyped Plutus Core (the low-level language Cardano uses to execute smart-contracts. For example, it isn't possible to have a list or a tuple of {type_String} because the underlying execution engine doesn't allow it.
|
||||
|
||||
There are few restrictions like this one. In this instance, here's the types I followed and that led me to this problem:
|
||||
|
||||
╰─▶ {breadcrumbs}"#,
|
||||
type_String = "String"
|
||||
.if_supports_color(Stdout, |s| s.bright_blue())
|
||||
.if_supports_color(Stdout, |s| s.bold()),
|
||||
breadcrumbs = Error::fmt_breadcrumbs(&self.breadcrumbs)
|
||||
),
|
||||
|
||||
ErrorContext::UnexpectedFunction => format!(
|
||||
r#"I can't allow that. Functions aren't serializable as data on-chain and thus cannot be used within your datum and/or redeemer types.
|
||||
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
---
|
||||
source: crates/aiken-project/src/blueprint/validator.rs
|
||||
description: "Code:\n\ntype Dict<key, value> {\n inner: List<(ByteArray, value)>\n}\n\ntype UUID { UUID }\n\nvalidator {\n fn list_2_tuples_as_list(redeemer: Dict<UUID, Int>, ctx: Void) {\n True\n }\n}\n"
|
||||
---
|
||||
{
|
||||
"title": "test_module.list_2_tuples_as_list",
|
||||
"redeemer": {
|
||||
"title": "redeemer",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/test_module~1Dict$test_module~1UUID_Int"
|
||||
}
|
||||
},
|
||||
"compiledCode": "59019c010000323232323232323232232253330054a22930a9980324811856616c696461746f722072657475726e65642066616c736500136563253330043370e900018031baa0011325333009001153300600416132533300a300c002132498c8cc004004008894ccc03000452613233003003300f0023232533300e001153300b00916132325333010001153300d00b1613253330113013002149854cc03803058c94cccccc05000454cc0380305854cc0380305854cc038030584dd68008a998070060b180880098088011929999998090008a998060050b0a998060050b0a998060050b0a998060050b09bae001300f0015333333010001153300a00816153300a00816137580022a660140102c2a660140102c601a0022a6600e00a2c64a66666601a0022a6600e00a2c2a6600e00a2c26eb000454cc01c0145854cc01c01458c028004c01cdd50008a998028018b299999980500088008a998020010b0a998020010b0a998020010b0a998020010b2491972656465656d65723a20446963743c555549442c20496e743e005734ae7155ceaab9e5573eae855d12ba41",
|
||||
"hash": "6027685dde99d967b45333852fe9f59531237d85fcb6b6feb2890672",
|
||||
"definitions": {
|
||||
"ByteArray": {
|
||||
"dataType": "bytes"
|
||||
},
|
||||
"Int": {
|
||||
"dataType": "integer"
|
||||
},
|
||||
"List$Tuple$ByteArray_Int": {
|
||||
"dataType": "list",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Tuple$ByteArray_Int"
|
||||
}
|
||||
},
|
||||
"Tuple$ByteArray_Int": {
|
||||
"title": "Tuple",
|
||||
"dataType": "list",
|
||||
"items": [
|
||||
{
|
||||
"$ref": "#/definitions/ByteArray"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/Int"
|
||||
}
|
||||
]
|
||||
},
|
||||
"test_module/Dict$test_module/UUID_Int": {
|
||||
"title": "Dict",
|
||||
"anyOf": [
|
||||
{
|
||||
"title": "Dict",
|
||||
"dataType": "constructor",
|
||||
"index": 0,
|
||||
"fields": [
|
||||
{
|
||||
"title": "inner",
|
||||
"$ref": "#/definitions/List$Tuple$ByteArray_Int"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
---
|
||||
source: crates/aiken-project/src/blueprint/validator.rs
|
||||
description: "Code:\n\ntype Dict<key, value> {\n inner: List<Pair<ByteArray, value>>\n}\n\ntype UUID { UUID }\n\nvalidator {\n fn list_pairs_as_map(redeemer: Dict<UUID, Int>, ctx: Void) {\n True\n }\n}\n"
|
||||
---
|
||||
{
|
||||
"title": "test_module.list_pairs_as_map",
|
||||
"redeemer": {
|
||||
"title": "redeemer",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/test_module~1Dict$test_module~1UUID_Int"
|
||||
}
|
||||
},
|
||||
"compiledCode": "59014e010000323232323232323232232253330054a22930a9980324811856616c696461746f722072657475726e65642066616c736500136563253330043370e900018031baa0011325333009001153300600416132533300a300c002132498c8cc004004008894ccc03000452613233003003300f0023232325333333012001153300c00a16153300c00a16153300c00a161375a0022a660180142c601a00464a6666660220022a660160122c2a660160122c2a660160122c2a660160122c26eb8004c02c004c03400454cc01c01458c94cccccc03400454cc01c014584dd58008a998038028b0a998038028b0a998038028b180500098039baa001153300500316533333300a001100115330040021615330040021615330040021615330040021649011972656465656d65723a20446963743c555549442c20496e743e005734ae7155ceaab9e5573eae855d12ba41",
|
||||
"hash": "de6d51e2a272ec0ab73566bbb32700ad5864fdd01290dd925e35ebb4",
|
||||
"definitions": {
|
||||
"ByteArray": {
|
||||
"dataType": "bytes"
|
||||
},
|
||||
"Int": {
|
||||
"dataType": "integer"
|
||||
},
|
||||
"List$Pair$ByteArray_Int": {
|
||||
"dataType": "map",
|
||||
"keys": {
|
||||
"$ref": "#/definitions/ByteArray"
|
||||
},
|
||||
"values": {
|
||||
"$ref": "#/definitions/Int"
|
||||
}
|
||||
},
|
||||
"test_module/Dict$test_module/UUID_Int": {
|
||||
"title": "Dict",
|
||||
"anyOf": [
|
||||
{
|
||||
"title": "Dict",
|
||||
"dataType": "constructor",
|
||||
"index": 0,
|
||||
"fields": [
|
||||
{
|
||||
"title": "inner",
|
||||
"$ref": "#/definitions/List$Pair$ByteArray_Int"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -495,7 +495,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn list_2_tuples_as_map() {
|
||||
fn list_2_tuples_as_list() {
|
||||
assert_validator!(
|
||||
r#"
|
||||
type Dict<key, value> {
|
||||
|
@ -505,7 +505,26 @@ mod tests {
|
|||
type UUID { UUID }
|
||||
|
||||
validator {
|
||||
fn list_2_tuples_as_map(redeemer: Dict<UUID, Int>, ctx: Void) {
|
||||
fn list_2_tuples_as_list(redeemer: Dict<UUID, Int>, ctx: Void) {
|
||||
True
|
||||
}
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn list_pairs_as_map() {
|
||||
assert_validator!(
|
||||
r#"
|
||||
type Dict<key, value> {
|
||||
inner: List<Pair<ByteArray, value>>
|
||||
}
|
||||
|
||||
type UUID { UUID }
|
||||
|
||||
validator {
|
||||
fn list_pairs_as_map(redeemer: Dict<UUID, Int>, ctx: Void) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue