Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/types/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ There are three type structures in SimplicityHL:
explicitly call `unify` on the Simplicity type inference engine to enforce this.

* `AliasedType` is a copy of `ResolvedType` where everything is a (re)name. Essentially they are
"AST types". They feature primarily in parse.rs and ast.rs. Before these can be used, we call
"AST types". They feature primarily in parse.rs and ast/. Before these can be used, we call
`aliased_type.resolve()` to get a `ResolvedType`.

SimplicityHL does *not* currently support any form of nominal typing. All structurally equal types
are considered interchangeable.

6 changes: 4 additions & 2 deletions src/types/aliased.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ impl BuiltinAlias {
use BuiltinAlias as B;
use UIntType::*;

match self {
let resolved = match self {
B::Ctx8 => ResolvedType::tuple([
ResolvedType::list(U8.into(), NonZeroPow2Usize::new(64).unwrap()),
ResolvedType::tuple([U64.into(), U256.into()]),
Expand All @@ -393,7 +393,9 @@ impl BuiltinAlias {
B::Amount1 | B::TokenAmount1 => {
ResolvedType::either(ResolvedType::tuple([U1.into(), U256.into()]), U64.into())
}
}
};

resolved.with_builtin_alias(self)
}
}

Expand Down
28 changes: 28 additions & 0 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,34 @@ mod tests {
assert_eq!("Option<!>", &option_never.to_string());
}

#[test]
fn builtin_alias_tag_is_not_part_of_the_type() {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};

let hash = |ty: &ResolvedType| {
let mut hasher = DefaultHasher::new();
ty.hash(&mut hasher);
hasher.finish()
};

let pubkey = BuiltinAlias::Pubkey.resolve();
let u256 = ResolvedType::u256();
assert_eq!(Some(BuiltinAlias::Pubkey), pubkey.builtin_alias());
assert_eq!(None, u256.builtin_alias());
assert_eq!(pubkey, u256);
assert!(pubkey.same_as(&u256));
assert_eq!(hash(&pubkey), hash(&u256));
assert_eq!("u256", &pubkey.to_string());

let point = BuiltinAlias::Point.resolve();
assert_eq!(Some(BuiltinAlias::Point), point.builtin_alias());
assert_eq!(
ResolvedType::tuple([ResolvedType::u1(), ResolvedType::u256()]),
point
);
}

#[test]
fn never_type() {
assert!(ResolvedType::never().is_never());
Expand Down
40 changes: 37 additions & 3 deletions src/types/resolved.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use core::fmt;
use core::hash::{Hash, Hasher};
use std::collections::HashSet;
use std::sync::Arc;

Expand All @@ -7,13 +8,31 @@ use miniscript::iter::{Tree, TreeLike};
use super::{
EnumInfo, StructuralType, TypeConstructible, TypeDeconstructible, TypeInner, UIntType,
};
use crate::num::NonZeroPow2Usize;
use crate::{num::NonZeroPow2Usize, types::BuiltinAlias};

/// SimplicityHL type without type aliases.
#[derive(PartialEq, Eq, Hash, Clone)]
#[derive(Clone)]
pub struct ResolvedType {
inner: TypeInner<Arc<Self>>,
flags: TypeFlags,
builtin: Option<BuiltinAlias>,
}

/// The builtin alias is metadata for tooling, not part of the type,
/// so `Pubkey` and `u256` stay interchangeable.
impl PartialEq for ResolvedType {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner && self.flags == other.flags
}
}

impl Eq for ResolvedType {}

impl Hash for ResolvedType {
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner.hash(state);
self.flags.hash(state);
}
}

/// Facts about a type, computed once from its parts when the type is built.
Expand Down Expand Up @@ -61,13 +80,27 @@ impl ResolvedType {
}),
};

Self { inner, flags }
Self {
inner,
flags,
builtin: None,
}
}

/// Access the inner type primitive.
pub fn as_inner(&self) -> &TypeInner<Arc<Self>> {
&self.inner
}

/// Access the builtin alias that this type was resolved from, such as `Pubkey` or `Fe`.
pub const fn builtin_alias(&self) -> Option<BuiltinAlias> {
self.builtin
}

pub(crate) fn with_builtin_alias(mut self, alias: BuiltinAlias) -> Self {
self.builtin = Some(alias);
self
}
}

/// Nominal enum types.
Expand Down Expand Up @@ -111,6 +144,7 @@ impl ResolvedType {
has_never: true,
has_never_in_enum: false,
},
builtin: None,
}
}

Expand Down
Loading