Skip to content

Commit

Permalink
fix: Separate Identifier and AliasName
Browse files Browse the repository at this point in the history
Introduce a new wrapper type, AliasName, for strings that are valid
alias names. This makes sure that alias names are correctly sampled
by the Arbitrary trait.

Fixes BlockstreamResearch#102
  • Loading branch information
uncomputable committed Dec 12, 2024
1 parent 436f610 commit 90963f6
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 30 deletions.
12 changes: 6 additions & 6 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::error::{Error, RichError, Span, WithSpan};
use crate::num::{NonZeroPow2Usize, Pow2Usize};
use crate::parse::MatchPattern;
use crate::pattern::Pattern;
use crate::str::{FunctionName, Identifier, ModuleName, WitnessName};
use crate::str::{AliasName, FunctionName, Identifier, ModuleName, WitnessName};
use crate::types::{
AliasedType, ResolvedType, StructuralType, TypeConstructible, TypeDeconstructible, UIntType,
};
Expand Down Expand Up @@ -485,7 +485,7 @@ impl<'a> TreeLike for ExprTree<'a> {
#[derive(Clone, Debug, Eq, PartialEq, Default)]
struct Scope {
variables: Vec<HashMap<Identifier, ResolvedType>>,
aliases: HashMap<Identifier, ResolvedType>,
aliases: HashMap<AliasName, ResolvedType>,
parameters: HashMap<WitnessName, ResolvedType>,
witnesses: HashMap<WitnessName, ResolvedType>,
functions: HashMap<FunctionName, CustomFunction>,
Expand Down Expand Up @@ -569,7 +569,7 @@ impl Scope {
/// There are any undefined aliases.
pub fn resolve(&self, ty: &AliasedType) -> Result<ResolvedType, Error> {
let get_alias =
|name: &Identifier| -> Option<ResolvedType> { self.aliases.get(name).cloned() };
|name: &AliasName| -> Option<ResolvedType> { self.aliases.get(name).cloned() };
ty.resolve(get_alias).map_err(Error::UndefinedAlias)
}

Expand All @@ -578,9 +578,9 @@ impl Scope {
/// ## Errors
///
/// There are any undefined aliases.
pub fn insert_alias(&mut self, alias: Identifier, ty: AliasedType) -> Result<(), Error> {
pub fn insert_alias(&mut self, name: AliasName, ty: AliasedType) -> Result<(), Error> {
let resolved_ty = self.resolve(&ty)?;
self.aliases.insert(alias, resolved_ty);
self.aliases.insert(name, resolved_ty);
Ok(())
}

Expand Down Expand Up @@ -1082,7 +1082,7 @@ impl AbstractSyntaxTree for Call {
let args_tys = crate::jet::source_type(jet)
.iter()
.map(AliasedType::resolve_builtin)
.collect::<Result<Vec<ResolvedType>, Identifier>>()
.collect::<Result<Vec<ResolvedType>, AliasName>>()
.map_err(Error::UndefinedAlias)
.with_span(from)?;
check_argument_types(from.args(), &args_tys).with_span(from)?;
Expand Down
4 changes: 2 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use simplicity::hashes::{sha256, Hash, HashEngine};
use simplicity::{elements, Cmr};

use crate::parse::{MatchPattern, Rule};
use crate::str::{FunctionName, Identifier, JetName, ModuleName, WitnessName};
use crate::str::{AliasName, FunctionName, Identifier, JetName, ModuleName, WitnessName};
use crate::types::{ResolvedType, UIntType};

/// Position of an object inside a file.
Expand Down Expand Up @@ -323,7 +323,7 @@ pub enum Error {
ExpressionNotConstant,
IntegerOutOfBounds(UIntType),
UndefinedVariable(Identifier),
UndefinedAlias(Identifier),
UndefinedAlias(AliasName),
VariableReuseInPattern(Identifier),
WitnessReused(WitnessName),
WitnessTypeMismatch(WitnessName, ResolvedType, ResolvedType),
Expand Down
15 changes: 8 additions & 7 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ use crate::impl_eq_hash;
use crate::num::NonZeroPow2Usize;
use crate::pattern::Pattern;
use crate::str::{
Binary, Decimal, FunctionName, Hexadecimal, Identifier, JetName, ModuleName, WitnessName,
AliasName, Binary, Decimal, FunctionName, Hexadecimal, Identifier, JetName, ModuleName,
WitnessName,
};
use crate::types::{AliasedType, BuiltinAlias, TypeConstructible, UIntType};

Expand Down Expand Up @@ -201,14 +202,14 @@ pub enum CallName {
#[derive(Clone, Debug)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct TypeAlias {
name: Identifier,
name: AliasName,
ty: AliasedType,
span: Span,
}

impl TypeAlias {
/// Access the name of the alias.
pub fn name(&self) -> &Identifier {
pub fn name(&self) -> &AliasName {
&self.name
}

Expand Down Expand Up @@ -809,6 +810,7 @@ macro_rules! impl_parse_wrapped_string {
impl_parse_wrapped_string!(FunctionName, function_name);
impl_parse_wrapped_string!(Identifier, identifier);
impl_parse_wrapped_string!(WitnessName, witness_name);
impl_parse_wrapped_string!(AliasName, alias_name);
impl_parse_wrapped_string!(ModuleName, module_name);

/// Copy of [`FromStr`] that internally uses the PEST parser.
Expand Down Expand Up @@ -1064,7 +1066,7 @@ impl PestParse for TypeAlias {
let span = Span::from(&pair);
let mut it = pair.into_inner();
let _type_keyword = it.next().unwrap();
let name = Identifier::parse(it.next().unwrap().into_inner().next().unwrap())?;
let name = AliasName::parse(it.next().unwrap())?;
let ty = AliasedType::parse(it.next().unwrap())?;
Ok(Self { name, ty, span })
}
Expand Down Expand Up @@ -1329,9 +1331,8 @@ impl PestParse for AliasedType {
for data in pair.post_order_iter() {
match data.node.0.as_rule() {
Rule::alias_name => {
let pair = data.node.0.into_inner().next().unwrap();
let identifier = Identifier::parse(pair)?;
output.push(Item::Type(AliasedType::alias(identifier)));
let name = AliasName::parse(data.node.0)?;
output.push(Item::Type(AliasedType::alias(name)));
}
Rule::builtin_alias => {
let builtin = BuiltinAlias::parse(data.node.0)?;
Expand Down
63 changes: 63 additions & 0 deletions src/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,69 @@ impl<'a> arbitrary::Arbitrary<'a> for JetName {
}
}

/// The name of a type alias.
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct AliasName(Arc<str>);

wrapped_string!(AliasName, "name of a type alias");

#[cfg(feature = "arbitrary")]
impl<'a> arbitrary::Arbitrary<'a> for AliasName {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
const RESERVED_NAMES: [&str; 37] = [
"Either",
"Option",
"bool",
"List",
"u128",
"u256",
"u16",
"u32",
"u64",
"u1",
"u2",
"u4",
"u8",
"Ctx8",
"Pubkey",
"Message64",
"Message",
"Signature",
"Scalar",
"Fe",
"Gej",
"Ge",
"Point",
"Height",
"Time",
"Distance",
"Duration",
"Lock",
"Outpoint",
"Confidential1",
"ExplicitAsset",
"Asset1",
"ExplicitAmount",
"Amount1",
"ExplicitNonce",
"Nonce",
"TokenAmount1",
];

let len = u.int_in_range(1..=10)?;
let mut string = String::with_capacity(len);
for _ in 0..len {
let offset = u.int_in_range(0..=25)?;
string.push((b'a' + offset) as char)
}
if RESERVED_NAMES.contains(&string.as_str()) {
string.push('_');
}

Ok(Self::from_str_unchecked(string.as_str()))
}
}

/// A string of decimal digits.
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct Decimal(Arc<str>);
Expand Down
30 changes: 15 additions & 15 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use simplicity::types::{CompleteBound, Final};

use crate::array::{BTreeSlice, Partition};
use crate::num::{NonZeroPow2Usize, Pow2Usize};
use crate::str::Identifier;
use crate::str::AliasName;

/// Primitives of the Simfony type system, excluding type aliases.
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
Expand Down Expand Up @@ -494,7 +494,7 @@ pub struct AliasedType(AliasedInner);
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
enum AliasedInner {
/// Type alias.
Alias(Identifier),
Alias(AliasName),
/// Builtin type alias.
Builtin(BuiltinAlias),
/// Type primitive.
Expand Down Expand Up @@ -533,9 +533,9 @@ pub enum BuiltinAlias {

impl AliasedType {
/// Access a user-defined alias.
pub const fn as_alias(&self) -> Option<&Identifier> {
pub const fn as_alias(&self) -> Option<&AliasName> {
match &self.0 {
AliasedInner::Alias(identifier) => Some(identifier),
AliasedInner::Alias(name) => Some(name),
_ => None,
}
}
Expand All @@ -549,8 +549,8 @@ impl AliasedType {
}

/// Create a type alias from the given `identifier`.
pub const fn alias(identifier: Identifier) -> Self {
Self(AliasedInner::Alias(identifier))
pub const fn alias(name: AliasName) -> Self {
Self(AliasedInner::Alias(name))
}

/// Create a builtin type alias.
Expand All @@ -559,15 +559,15 @@ impl AliasedType {
}

/// Resolve all aliases in the type based on the given map of `aliases` to types.
pub fn resolve<F>(&self, mut get_alias: F) -> Result<ResolvedType, Identifier>
pub fn resolve<F>(&self, mut get_alias: F) -> Result<ResolvedType, AliasName>
where
F: FnMut(&Identifier) -> Option<ResolvedType>,
F: FnMut(&AliasName) -> Option<ResolvedType>,
{
let mut output = vec![];
for data in self.post_order_iter() {
match &data.node.0 {
AliasedInner::Alias(alias) => {
let resolved = get_alias(alias).ok_or(alias.clone())?;
AliasedInner::Alias(name) => {
let resolved = get_alias(name).ok_or(name.clone())?;
output.push(resolved);
}
AliasedInner::Builtin(builtin) => {
Expand Down Expand Up @@ -608,7 +608,7 @@ impl AliasedType {
}

/// Resolve all aliases in the type based on the builtin type aliases only.
pub fn resolve_builtin(&self) -> Result<ResolvedType, Identifier> {
pub fn resolve_builtin(&self) -> Result<ResolvedType, AliasName> {
self.resolve(|_| None)
}
}
Expand Down Expand Up @@ -741,8 +741,8 @@ impl From<UIntType> for AliasedType {
}
}

impl From<Identifier> for AliasedType {
fn from(value: Identifier) -> Self {
impl From<AliasName> for AliasedType {
fn from(value: AliasName) -> Self {
Self::alias(value)
}
}
Expand All @@ -760,14 +760,14 @@ impl crate::ArbitraryRec for AliasedType {

match budget.checked_sub(1) {
None => match u.int_in_range(0..=3)? {
0 => Identifier::arbitrary(u).map(Self::alias),
0 => AliasName::arbitrary(u).map(Self::alias),
1 => BuiltinAlias::arbitrary(u).map(Self::builtin),
2 => Ok(Self::boolean()),
3 => UIntType::arbitrary(u).map(Self::from),
_ => unreachable!(),
},
Some(new_budget) => match u.int_in_range(0..=8)? {
0 => Identifier::arbitrary(u).map(Self::alias),
0 => AliasName::arbitrary(u).map(Self::alias),
1 => BuiltinAlias::arbitrary(u).map(Self::builtin),
2 => Ok(Self::boolean()),
3 => UIntType::arbitrary(u).map(Self::from),
Expand Down

0 comments on commit 90963f6

Please sign in to comment.