Skip to content

Commit

Permalink
Parse __ptr[T] and __slice[T] (FuelLabs#4522)
Browse files Browse the repository at this point in the history
Just parsing for typed pointers and slices. Went with long and distinct
names for now but we could change them to something like `&T` and `&[T]`
in the future.

The only tricky part was this, where I had to fix how we parse `impl`
items:
https://github.com/FuelLabs/sway/pull/4522/files#diff-51ff5479fa74960c097173172a99b15be1dbd4d858960e619eca1ae740816552
  • Loading branch information
AlicanC authored May 7, 2023
1 parent 85040f5 commit 657a10b
Show file tree
Hide file tree
Showing 16 changed files with 254 additions and 7 deletions.
2 changes: 2 additions & 0 deletions sway-ast/src/keywords.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ define_keyword!(BreakToken, "break");
define_keyword!(ContinueToken, "continue");
define_keyword!(ConfigurableToken, "configurable");
define_keyword!(TypeToken, "type");
define_keyword!(PtrToken, "__ptr");
define_keyword!(SliceToken, "__slice");

/// The type is a keyword.
pub trait Token: Spanned + Sized {
Expand Down
10 changes: 10 additions & 0 deletions sway-ast/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ pub enum Ty {
Infer {
underscore_token: UnderscoreToken,
},
Ptr {
ptr_token: PtrToken,
ty: SquareBrackets<Box<Ty>>,
},
Slice {
slice_token: SliceToken,
ty: SquareBrackets<Box<Ty>>,
},
}

impl Spanned for Ty {
Expand All @@ -23,6 +31,8 @@ impl Spanned for Ty {
Ty::Array(array_type) => array_type.span(),
Ty::Str { str_token, length } => Span::join(str_token.span(), length.span()),
Ty::Infer { underscore_token } => underscore_token.span(),
Ty::Ptr { ptr_token, ty } => Span::join(ptr_token.span(), ty.span()),
Ty::Slice { slice_token, ty } => Span::join(slice_token.span(), ty.span()),
}
}
}
Expand Down
12 changes: 12 additions & 0 deletions sway-core/src/abi_generation/evm_json_abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,18 @@ pub fn json_abi_str(
Storage { .. } => "contract storage".into(),
RawUntypedPtr => "raw untyped ptr".into(),
RawUntypedSlice => "raw untyped slice".into(),
Ptr(ty) => {
format!(
"__ptr {}",
json_abi_str_type_arg(ty, type_engine, decl_engine)
)
}
Slice(ty) => {
format!(
"__slice {}",
json_abi_str_type_arg(ty, type_engine, decl_engine)
)
}
Alias { ty, .. } => json_abi_str_type_arg(ty, type_engine, decl_engine),
}
}
Expand Down
6 changes: 6 additions & 0 deletions sway-core/src/abi_generation/fuel_json_abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,12 @@ impl TypeInfo {
Storage { .. } => "contract storage".into(),
RawUntypedPtr => "raw untyped ptr".into(),
RawUntypedSlice => "raw untyped slice".into(),
Ptr(ty) => {
format!("__ptr {}", ty.json_abi_str(ctx, type_engine, decl_engine))
}
Slice(ty) => {
format!("__slice {}", ty.json_abi_str(ctx, type_engine, decl_engine))
}
Alias { ty, .. } => ty.json_abi_str(ctx, type_engine, decl_engine),
}
}
Expand Down
2 changes: 2 additions & 0 deletions sway-core/src/ir_generation/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ fn convert_resolved_type(
}
TypeInfo::RawUntypedPtr => Type::get_uint64(context),
TypeInfo::RawUntypedSlice => Type::get_slice(context),
TypeInfo::Ptr(_) => Type::get_uint64(context),
TypeInfo::Slice(_) => Type::get_slice(context),
TypeInfo::Alias { ty, .. } => {
convert_resolved_typeid(type_engine, decl_engine, context, &ty.type_id, span)?
}
Expand Down
4 changes: 3 additions & 1 deletion sway-core/src/monomorphize/solve/solver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,9 @@ impl<'a> Solver<'a> {
| TypeInfo::B256
| TypeInfo::Contract
| TypeInfo::RawUntypedPtr
| TypeInfo::RawUntypedSlice => {}
| TypeInfo::RawUntypedSlice
| TypeInfo::Ptr(..)
| TypeInfo::Slice(..) => {}
}

Ok(InstructionResult::from_instructions(instructions))
Expand Down
2 changes: 2 additions & 0 deletions sway-core/src/semantic_analysis/node_dependencies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,8 @@ fn type_info_name(type_info: &TypeInfo) -> String {
TypeInfo::Storage { .. } => "contract storage",
TypeInfo::RawUntypedPtr => "raw untyped ptr",
TypeInfo::RawUntypedSlice => "raw untyped slice",
TypeInfo::Ptr(..) => "__ptr",
TypeInfo::Slice(..) => "__slice",
TypeInfo::Alias { .. } => "alias",
}
.to_string()
Expand Down
10 changes: 10 additions & 0 deletions sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1279,6 +1279,14 @@ fn ty_to_type_info(
TypeInfo::Str(expr_to_length(context, handler, *length.into_inner())?)
}
Ty::Infer { .. } => TypeInfo::Unknown,
Ty::Ptr { ty, .. } => {
let type_argument = ty_to_type_argument(context, handler, engines, *ty.into_inner())?;
TypeInfo::Ptr(type_argument)
}
Ty::Slice { ty, .. } => {
let type_argument = ty_to_type_argument(context, handler, engines, *ty.into_inner())?;
TypeInfo::Slice(type_argument)
}
};
Ok(type_info)
}
Expand Down Expand Up @@ -3590,6 +3598,8 @@ fn ty_to_type_parameter(
Ty::Tuple(..) => panic!("tuple types are not allowed in this position"),
Ty::Array(..) => panic!("array types are not allowed in this position"),
Ty::Str { .. } => panic!("str types are not allowed in this position"),
Ty::Ptr { .. } => panic!("__ptr types are not allowed in this position"),
Ty::Slice { .. } => panic!("__slice types are not allowed in this position"),
};
let custom_type = type_engine.insert(
decl_engine,
Expand Down
8 changes: 8 additions & 0 deletions sway-core/src/type_system/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,14 @@ impl ReplaceSelfType for TypeId {
type_engine.insert(decl_engine, TypeInfo::Alias { name, ty })
})
}
TypeInfo::Ptr(mut ty) => helper(ty.type_id, engines, self_type).map(|type_id| {
ty.type_id = type_id;
type_engine.insert(decl_engine, TypeInfo::Ptr(ty))
}),
TypeInfo::Slice(mut ty) => helper(ty.type_id, engines, self_type).map(|type_id| {
ty.type_id = type_id;
type_engine.insert(decl_engine, TypeInfo::Slice(ty))
}),
TypeInfo::Unknown
| TypeInfo::UnknownGeneric { .. }
| TypeInfo::Str(_)
Expand Down
38 changes: 37 additions & 1 deletion sway-core/src/type_system/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,16 @@ pub enum TypeInfo {
Storage {
fields: Vec<ty::TyStructField>,
},
/// Raw untyped pointers.
/// Pointers.
/// These are represented in memory as u64 but are a different type since pointers only make
/// sense in the context they were created in. Users can obtain pointers via standard library
/// functions such `alloc` or `stack_ptr`. These functions are implemented using asm blocks
/// which can create pointers by (eg.) reading logically-pointer-valued registers, using the
/// gtf instruction, or manipulating u64s.
RawUntypedPtr,
RawUntypedSlice,
Ptr(TypeArgument),
Slice(TypeArgument),
/// Type Alias. This type and the type `ty` it encapsulates always coerce. They are effectively
/// interchangeable
Alias {
Expand Down Expand Up @@ -209,6 +211,12 @@ impl HashWithEngines for TypeInfo {
name.hash(state);
ty.hash(state, engines);
}
TypeInfo::Ptr(ty) => {
ty.hash(state, engines);
}
TypeInfo::Slice(ty) => {
ty.hash(state, engines);
}
TypeInfo::Numeric
| TypeInfo::Boolean
| TypeInfo::B256
Expand Down Expand Up @@ -464,6 +472,12 @@ impl DisplayWithEngines for TypeInfo {
Storage { .. } => "storage".into(),
RawUntypedPtr => "pointer".into(),
RawUntypedSlice => "slice".into(),
Ptr(ty) => {
format!("__ptr[{}]", engines.help_out(ty))
}
Slice(ty) => {
format!("__slice[{}]", engines.help_out(ty))
}
Alias { name, .. } => name.to_string(),
};
write!(f, "{s}")
Expand Down Expand Up @@ -534,6 +548,12 @@ impl DebugWithEngines for TypeInfo {
Storage { .. } => "contract storage".into(),
RawUntypedPtr => "raw untyped ptr".into(),
RawUntypedSlice => "raw untyped slice".into(),
Ptr(ty) => {
format!("__ptr[{:?}]", engines.help_out(ty))
}
Slice(ty) => {
format!("__slice[{:?}]", engines.help_out(ty))
}
Alias { name, ty } => {
format!("type {} = {:?}", name, engines.help_out(ty))
}
Expand Down Expand Up @@ -571,6 +591,8 @@ impl TypeInfo {
TypeInfo::RawUntypedSlice => 19,
TypeInfo::TypeParam(_) => 20,
TypeInfo::Alias { .. } => 21,
TypeInfo::Ptr(..) => 22,
TypeInfo::Slice(..) => 23,
}
}

Expand Down Expand Up @@ -936,6 +958,8 @@ impl TypeInfo {
| TypeInfo::Numeric
| TypeInfo::RawUntypedPtr
| TypeInfo::RawUntypedSlice
| TypeInfo::Ptr(..)
| TypeInfo::Slice(..)
| TypeInfo::Contract
| TypeInfo::ErrorRecovery
| TypeInfo::Array(_, _)
Expand Down Expand Up @@ -979,6 +1003,8 @@ impl TypeInfo {
TypeInfo::Unknown
| TypeInfo::RawUntypedPtr
| TypeInfo::RawUntypedSlice
| TypeInfo::Ptr(..)
| TypeInfo::Slice(..)
| TypeInfo::ContractCaller { .. }
| TypeInfo::Custom { .. }
| TypeInfo::SelfType
Expand Down Expand Up @@ -1015,6 +1041,8 @@ impl TypeInfo {
| TypeInfo::B256
| TypeInfo::RawUntypedPtr
| TypeInfo::RawUntypedSlice
| TypeInfo::Ptr(_)
| TypeInfo::Slice(_)
| TypeInfo::Custom { .. }
| TypeInfo::Str(_)
| TypeInfo::Array(_, _)
Expand Down Expand Up @@ -1171,6 +1199,12 @@ impl TypeInfo {
}
}
}
TypeInfo::Ptr(ty) => {
found.extend(ty.type_id.extract_any_including_self(engines, filter_fn));
}
TypeInfo::Slice(ty) => {
found.extend(ty.type_id.extract_any_including_self(engines, filter_fn));
}
}
found
}
Expand Down Expand Up @@ -1507,6 +1541,8 @@ impl TypeInfo {
| TypeInfo::B256
| TypeInfo::RawUntypedPtr
| TypeInfo::RawUntypedSlice
| TypeInfo::Ptr(..)
| TypeInfo::Slice(..)
| TypeInfo::ErrorRecovery => false,
TypeInfo::Unknown
| TypeInfo::UnknownGeneric { .. }
Expand Down
8 changes: 8 additions & 0 deletions sway-core/src/type_system/substitute/subst_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,14 @@ impl TypeSubstMap {
type_engine.insert(decl_engine, TypeInfo::Alias { name, ty })
})
}
TypeInfo::Ptr(mut ty) => self.find_match(ty.type_id, engines).map(|type_id| {
ty.type_id = type_id;
type_engine.insert(decl_engine, TypeInfo::Ptr(ty))
}),
TypeInfo::Slice(mut ty) => self.find_match(ty.type_id, engines).map(|type_id| {
ty.type_id = type_id;
type_engine.insert(decl_engine, TypeInfo::Slice(ty))
}),
TypeInfo::Unknown
| TypeInfo::Str(..)
| TypeInfo::UnsignedInteger(..)
Expand Down
6 changes: 6 additions & 0 deletions sway-error/src/parser_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ pub enum ParseErrorKind {
UnexpectedClass,
#[error("Field projections, e.g., `foo.bar` cannot have type arguments.")]
FieldProjectionWithGenericArgs,
#[error("Unexpected token after __ptr type.")]
UnexpectedTokenAfterPtrType,
#[error("Unexpected token after __slice type.")]
UnexpectedTokenAfterSliceType,
#[error("Expected a path type.")]
ExpectedPathType,
}

#[derive(Debug, Error, Clone, PartialEq, Eq, Hash)]
Expand Down
58 changes: 55 additions & 3 deletions sway-parse/src/item/item_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,15 @@ impl Parse for ItemImpl {
fn parse(parser: &mut Parser) -> ParseResult<ItemImpl> {
let impl_token = parser.parse()?;
let generic_params_opt = parser.guarded_parse::<OpenAngleBracketToken, _>()?;
let path_type = parser.parse()?;
let ty = parser.parse()?;
let (trait_opt, ty) = match parser.take() {
Some(for_token) => (Some((path_type, for_token)), parser.parse()?),
None => (None, Ty::Path(path_type)),
Some(for_token) => match ty {
Ty::Path(path_type) => (Some((path_type, for_token)), parser.parse()?),
_ => {
return Err(parser.emit_error(ParseErrorKind::ExpectedPathType));
}
},
None => (None, ty),
};
let where_clause_opt = parser.guarded_parse::<WhereToken, _>()?;
let contents: Braces<Vec<Annotated<ItemImplItem>>> = parser.parse()?;
Expand All @@ -48,3 +53,50 @@ impl Parse for ItemImpl {
})
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::parse;
use assert_matches::*;

#[test]
fn parse_impl_ptr() {
let item = parse::<ItemImpl>(
r#"
impl __ptr[T] {}
"#,
);
assert_matches!(item.ty, Ty::Ptr { .. });
}

#[test]
fn parse_impl_for_ptr() {
let item = parse::<ItemImpl>(
r#"
impl Foo for __ptr[T] {}
"#,
);
assert_matches!(item.ty, Ty::Ptr { .. });
}

#[test]
fn parse_impl_slice() {
let item = parse::<ItemImpl>(
r#"
impl __slice[T] {}
"#,
);
assert_matches!(item.ty, Ty::Slice { .. });
}

#[test]
fn parse_impl_for_slice() {
let item = parse::<ItemImpl>(
r#"
impl Foo for __slice[T] {}
"#,
);
assert_matches!(item.ty, Ty::Slice { .. });
}
}
4 changes: 3 additions & 1 deletion sway-parse/src/keywords.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ keyword_impls! {
BreakToken,
ContinueToken,
ConfigurableToken,
TypeToken
TypeToken,
PtrToken,
SliceToken
}

fn peek_token<T: Token>(peeker: Peeker<'_>) -> Option<T> {
Expand Down
Loading

0 comments on commit 657a10b

Please sign in to comment.