parent
c48f15a957
commit
e2bc3a9fc4
|
@ -147,7 +147,7 @@ impl Reference {
|
||||||
},
|
},
|
||||||
Type::Pair { fst, snd, .. } => Self {
|
Type::Pair { fst, snd, .. } => Self {
|
||||||
inner: format!(
|
inner: format!(
|
||||||
"Pair{fst}{snd}",
|
"Pair${fst}_{snd}",
|
||||||
fst = Self::from_type(fst, type_parameters),
|
fst = Self::from_type(fst, type_parameters),
|
||||||
snd = Self::from_type(snd, type_parameters)
|
snd = Self::from_type(snd, type_parameters)
|
||||||
),
|
),
|
||||||
|
|
|
@ -36,6 +36,18 @@ pub enum Declaration<T> {
|
||||||
Inline(Box<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> {
|
impl<'a, T> Declaration<T> {
|
||||||
pub fn reference(&'a self) -> Option<&'a Reference> {
|
pub fn reference(&'a self) -> Option<&'a Reference> {
|
||||||
match self {
|
match self {
|
||||||
|
@ -297,18 +309,22 @@ impl Annotated<Schema> {
|
||||||
// make all types abide by this convention.
|
// make all types abide by this convention.
|
||||||
let data = match definitions.try_lookup(&generic).cloned() {
|
let data = match definitions.try_lookup(&generic).cloned() {
|
||||||
Some(Annotated {
|
Some(Annotated {
|
||||||
annotated: Schema::Data(Data::List(Items::Many(xs))),
|
annotated: Schema::Pair(left, right),
|
||||||
..
|
..
|
||||||
}) if xs.len() == 2 => {
|
}) => {
|
||||||
definitions.remove(&generic);
|
definitions.remove(&generic);
|
||||||
Data::Map(
|
|
||||||
xs.first()
|
let left = left.map(|inner| match inner {
|
||||||
.expect("length (== 2) checked in pattern clause")
|
Schema::Data(data) => data,
|
||||||
.to_owned(),
|
_ => panic!("impossible: left inhabitant of pair isn't Data but: {inner:#?}"),
|
||||||
xs.last()
|
});
|
||||||
.expect("length (== 2) checked in pattern clause")
|
|
||||||
.to_owned(),
|
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))),
|
_ => Data::List(Items::One(Declaration::Referenced(generic))),
|
||||||
|
@ -350,6 +366,25 @@ impl Annotated<Schema> {
|
||||||
annotated,
|
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, .. } => {
|
Type::Tuple { elems, .. } => {
|
||||||
definitions.register(type_info, &type_parameters.clone(), |definitions| {
|
definitions.register(type_info, &type_parameters.clone(), |definitions| {
|
||||||
let elems = elems
|
let elems = elems
|
||||||
|
@ -368,6 +403,7 @@ impl Annotated<Schema> {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::Var { tipo, .. } => match tipo.borrow().deref() {
|
Type::Var { tipo, .. } => match tipo.borrow().deref() {
|
||||||
TypeVar::Link { tipo } => {
|
TypeVar::Link { tipo } => {
|
||||||
Annotated::do_from_type(tipo, modules, type_parameters, definitions)
|
Annotated::do_from_type(tipo, modules, type_parameters, definitions)
|
||||||
|
@ -383,8 +419,8 @@ impl Annotated<Schema> {
|
||||||
Err(Error::new(ErrorContext::UnboundTypeVariable, type_info))
|
Err(Error::new(ErrorContext::UnboundTypeVariable, type_info))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
Type::Fn { .. } => unreachable!(),
|
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.")]
|
#[error("I caught a free variable in the contract's interface boundary.")]
|
||||||
FreeTypeVariable,
|
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.")]
|
#[error("I figured you tried to export a function in your contract's binary interface.")]
|
||||||
UnexpectedFunction,
|
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())
|
.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!(
|
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.
|
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]
|
#[test]
|
||||||
fn list_2_tuples_as_map() {
|
fn list_2_tuples_as_list() {
|
||||||
assert_validator!(
|
assert_validator!(
|
||||||
r#"
|
r#"
|
||||||
type Dict<key, value> {
|
type Dict<key, value> {
|
||||||
|
@ -505,7 +505,26 @@ mod tests {
|
||||||
type UUID { UUID }
|
type UUID { UUID }
|
||||||
|
|
||||||
validator {
|
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
|
True
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue