diff --git a/src/error.rs b/src/error.rs
index 1ded6fd..2671cf2 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -429,6 +429,7 @@ pub enum Error {
IntegerOutOfBounds(UIntType),
UndefinedVariable(Identifier),
RedefinedAlias(AliasName),
+ RedefinedAliasAsBuiltin(AliasName),
UndefinedAlias(AliasName),
VariableReuseInPattern(Identifier),
WitnessReused(WitnessName),
@@ -551,6 +552,10 @@ impl fmt::Display for Error {
f,
"Type alias `{identifier}` was defined multiple times"
),
+ Error::RedefinedAliasAsBuiltin(identifier) => write!(
+ f,
+ "Type alias `{identifier}` is already exists as built-in alias"
+ ),
Error::UndefinedAlias(identifier) => write!(
f,
"Type alias `{identifier}` is not defined"
diff --git a/src/parse.rs b/src/parse.rs
index c42c6f3..bb7cf65 100644
--- a/src/parse.rs
+++ b/src/parse.rs
@@ -26,7 +26,7 @@ use crate::str::{
AliasName, Binary, Decimal, FunctionName, Hexadecimal, Identifier, JetName, ModuleName,
WitnessName,
};
-use crate::types::{AliasedType, BuiltinAlias, TypeConstructible};
+use crate::types::{AliasedType, BuiltinAlias, TypeConstructible, UIntType};
/// A program is a sequence of items.
#[derive(Clone, Debug)]
@@ -1002,26 +1002,17 @@ impl ChumskyParse for AliasedType {
I: ValueInput<'tokens, Token = Token<'src>, Span = Span>,
{
let atom = select! {
- Token::Ident(ident) => {
- match ident
- {
- "u1" => AliasedType::u1(),
- "u2" => AliasedType::u2(),
- "u4" => AliasedType::u4(),
- "u8" => AliasedType::u8(),
- "u16" => AliasedType::u16(),
- "u32" => AliasedType::u32(),
- "u64" => AliasedType::u64(),
- "u128" => AliasedType::u128(),
- "u256" => AliasedType::u256(),
- "Ctx8" | "Pubkey" | "Message64" | "Message" | "Signature" | "Scalar" | "Fe" | "Gej"
- | "Ge" | "Point" | "Height" | "Time" | "Distance" | "Duration" | "Lock" | "Outpoint"
- | "Confidential1" | "ExplicitAsset" | "Asset1" | "ExplicitAmount" | "Amount1"
- | "ExplicitNonce" | "Nonce" | "TokenAmount1" => AliasedType::builtin(BuiltinAlias::from_str(ident).unwrap()),
- "bool" => AliasedType::boolean(),
- _ => AliasedType::alias(AliasName::from_str_unchecked(ident)),
+ Token::Ident(ident) => {
+ if ident == "bool" {
+ AliasedType::boolean()
+ } else if let Ok(uint_type) = UIntType::from_str(ident) {
+ AliasedType::from(uint_type)
+ } else if let Ok(builtin) = BuiltinAlias::from_str(ident) {
+ AliasedType::builtin(builtin)
+ } else {
+ AliasedType::alias(AliasName::from_str_unchecked(ident))
+ }
}
- },
};
let num = select! {
@@ -1461,7 +1452,25 @@ impl ChumskyParse for TypeAlias {
where
I: ValueInput<'tokens, Token = Token<'src>, Span = Span>,
{
- let name = AliasName::parser().map_with(|name, e| (name, e.span()));
+ let name = AliasName::parser()
+ .validate(|name, e, emit| {
+ let ident = name.as_inner();
+ let known_type = if ident == "bool" {
+ Some(AliasedType::boolean())
+ } else if let Ok(uint_type) = UIntType::from_str(ident) {
+ Some(AliasedType::from(uint_type))
+ } else if let Ok(builtin) = BuiltinAlias::from_str(ident) {
+ Some(AliasedType::builtin(builtin))
+ } else {
+ None
+ };
+
+ if known_type.is_some() {
+ emit.emit(Error::RedefinedAliasAsBuiltin(name.clone()).with_span(e.span()));
+ }
+ name
+ })
+ .map_with(|name, e| (name, e.span()));
just(Token::Type)
.ignore_then(name)
@@ -2163,3 +2172,19 @@ impl crate::ArbitraryRec for Match {
})
}
}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_reject_redefined_builtin_type() {
+ let ty = TypeAlias::parse_from_str("type Ctx8 = u32")
+ .expect_err("Redifining built-in alias should be rejected");
+
+ assert_eq!(
+ ty.error(),
+ &Error::RedefinedAliasAsBuiltin(AliasName::from_str_unchecked("Ctx8"))
+ );
+ }
+}
diff --git a/src/types.rs b/src/types.rs
index e68c9f0..ae778a4 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -37,7 +37,7 @@ impl TypeInner {
match self {
TypeInner::Either(_, _) => match n_children_yielded {
0 => f.write_str("Either<"),
- 1 => f.write_str(","),
+ 1 => f.write_str(", "),
n => {
debug_assert_eq!(n, 2);
f.write_str(">")
@@ -193,6 +193,25 @@ impl fmt::Display for UIntType {
}
}
+impl FromStr for UIntType {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result {
+ match s {
+ "u1" => Ok(UIntType::U1),
+ "u2" => Ok(UIntType::U2),
+ "u4" => Ok(UIntType::U4),
+ "u8" => Ok(UIntType::U8),
+ "u16" => Ok(UIntType::U16),
+ "u32" => Ok(UIntType::U32),
+ "u64" => Ok(UIntType::U64),
+ "u128" => Ok(UIntType::U128),
+ "u256" => Ok(UIntType::U256),
+ _ => Err("Unknown integer type".to_string()),
+ }
+ }
+}
+
impl TryFrom<&StructuralType> for UIntType {
type Error = ();
@@ -1094,5 +1113,7 @@ mod tests {
assert_eq!("[(); 3]", &array.to_string());
let list = ResolvedType::list(ResolvedType::unit(), NonZeroPow2Usize::TWO);
assert_eq!("List<(), 2>", &list.to_string());
+ let either = ResolvedType::either(ResolvedType::unit(), ResolvedType::u32());
+ assert_eq!("Either<(), u32>", &either.to_string());
}
}