Skip to content

Commit

Permalink
Use __ as a prefix for compiler intrinsics (FuelLabs#1536)
Browse files Browse the repository at this point in the history
* Disallow functions that begin with a double underscore.
  • Loading branch information
sezna authored May 14, 2022
1 parent afcc521 commit d8c5e5e
Showing 37 changed files with 228 additions and 68 deletions.
23 changes: 13 additions & 10 deletions sway-core/src/convert_parse_tree.rs
Original file line number Diff line number Diff line change
@@ -19,8 +19,8 @@ use {
AbiCastArgs, AngleBrackets, AsmBlock, Assignable, Braces, CodeBlockContents, Dependency,
DoubleColonToken, Expr, ExprArrayDescriptor, ExprStructField, ExprTupleDescriptor, FnArg,
FnArgs, FnSignature, GenericArgs, GenericParams, IfCondition, IfExpr, ImpureToken,
Instruction, ItemAbi, ItemConst, ItemEnum, ItemFn, ItemImpl, ItemKind, ItemStorage,
ItemStruct, ItemTrait, ItemUse, LitInt, LitIntType, MatchBranchKind, PathExpr,
Instruction, Intrinsic, ItemAbi, ItemConst, ItemEnum, ItemFn, ItemImpl, ItemKind,
ItemStorage, ItemStruct, ItemTrait, ItemUse, LitInt, LitIntType, MatchBranchKind, PathExpr,
PathExprSegment, PathType, PathTypeSegment, Pattern, PatternStructField, Program,
ProgramKind, PubToken, QualifiedPathRoot, Statement, StatementLet, Traits, Ty, TypeField,
UseTree,
@@ -100,15 +100,15 @@ pub enum ConvertParseTreeError {
GenericsNotSupportedHere { span: Span },
#[error("fully qualified paths are not supported here")]
FullyQualifiedPathsNotSupportedHere { span: Span },
#[error("size_of does not take arguments")]
#[error("__size_of does not take arguments")]
SizeOfTooManyArgs { span: Span },
#[error("size_of requires exactly one generic argument")]
#[error("__size_of requires exactly one generic argument")]
SizeOfOneGenericArg { span: Span },
#[error("is_reference_type does not take arguments")]
#[error("__is_reference_type does not take arguments")]
IsReferenceTypeTooManyArgs { span: Span },
#[error("is_reference_type requires exactly one generic argument")]
#[error("__is_reference_type requires exactly one generic argument")]
IsReferenceTypeOneGenericArg { span: Span },
#[error("size_of_val requires exactly one argument")]
#[error("__size_of_val requires exactly one argument")]
SizeOfValOneArg { span: Span },
#[error("tuple index out of range")]
TupleIndexOutOfRange { span: Span },
@@ -1175,7 +1175,8 @@ fn expr_to_expression(ec: &mut ErrorContext, expr: Expr) -> Result<Expression, E
None => {
if call_path.prefixes.is_empty()
&& !call_path.is_absolute
&& call_path.suffix.as_str() == "size_of"
&& Intrinsic::try_from_str(call_path.suffix.as_str())
== Some(Intrinsic::SizeOf)
{
if !arguments.is_empty() {
let error = ConvertParseTreeError::SizeOfTooManyArgs { span };
@@ -1202,7 +1203,8 @@ fn expr_to_expression(ec: &mut ErrorContext, expr: Expr) -> Result<Expression, E
}
} else if call_path.prefixes.is_empty()
&& !call_path.is_absolute
&& call_path.suffix.as_str() == "is_reference_type"
&& Intrinsic::try_from_str(call_path.suffix.as_str())
== Some(Intrinsic::IsReferenceType)
{
if !arguments.is_empty() {
let error = ConvertParseTreeError::IsReferenceTypeTooManyArgs { span };
@@ -1230,7 +1232,8 @@ fn expr_to_expression(ec: &mut ErrorContext, expr: Expr) -> Result<Expression, E
}
} else if call_path.prefixes.is_empty()
&& !call_path.is_absolute
&& call_path.suffix.as_str() == "size_of_val"
&& Intrinsic::try_from_str(call_path.suffix.as_str())
== Some(Intrinsic::SizeOfVal)
{
let exp = match <[_; 1]>::try_from(arguments) {
Ok([exp]) => Box::new(exp),
4 changes: 2 additions & 2 deletions sway-core/src/parse_tree/expression/mod.rs
Original file line number Diff line number Diff line change
@@ -1424,8 +1424,8 @@ pub(crate) fn parse_built_in_expr(
);
let exp = Expression::BuiltinGetTypeProperty {
builtin: match keyword.as_str() {
"size_of" => BuiltinProperty::SizeOfType,
"is_reference_type" => BuiltinProperty::IsRefType,
"__size_of" => BuiltinProperty::SizeOfType,
"__is_reference_type" => BuiltinProperty::IsRefType,
_otherwise => unreachable!("unexpected built in keyword: {keyword}"),
},
type_name,
6 changes: 3 additions & 3 deletions sway-core/src/sway.pest
Original file line number Diff line number Diff line change
@@ -27,9 +27,9 @@ true_keyword = {"true"}
false_keyword = {"false"}
const_decl_keyword = {"const"}
impurity_keyword = {"impure"}
size_of_type_keyword = {"size_of"}
size_of_val_keyword = {"size_of_val"}
is_ref_type_keyword = {"is_reference_type"}
size_of_type_keyword = {"__size_of"}
size_of_val_keyword = {"__size_of_val"}
is_ref_type_keyword = {"__is_reference_type"}

// top level
program = {SOI ~ (library|contract|script|predicate)? ~ EOI}
4 changes: 2 additions & 2 deletions sway-lib-std/src/assert.sw
Original file line number Diff line number Diff line change
@@ -16,8 +16,8 @@ pub fn assert(a: bool) {
/// A wrapper for `assert` that allows logging a custom value `v` if condition `c` is not true.
pub fn require<T>(c: bool, v: T) {
if !c {
let ref_type = is_reference_type::<T>();
let size = size_of::<T>();
let ref_type = __is_reference_type::<T>();
let size = __size_of::<T>();
if ref_type {
asm(r1: v, r2: size) {
logd zero zero r1 r2;
62 changes: 32 additions & 30 deletions sway-parse/src/error.rs
Original file line number Diff line number Diff line change
@@ -2,66 +2,68 @@ use crate::priv_prelude::*;

#[derive(Debug, Error, Clone, PartialEq, Hash)]
pub enum ParseErrorKind {
#[error("expected an import name, group of imports, or `*`")]
#[error("Expected an import name, group of imports, or `*`.")]
ExpectedImportNameGroupOrGlob,
#[error("expected an item")]
#[error("Expected an item.")]
ExpectedAnItem,
#[error("expected a comma or closing parenthesis in function arguments")]
#[error("Expected a comma or closing parenthesis in function arguments.")]
ExpectedCommaOrCloseParenInFnArgs,
#[error("unrecognized op code")]
#[error("Unrecognized op code.")]
UnrecognizedOpCode,
#[error("unexpected token in statement")]
#[error("Unexpected token in statement.")]
UnexpectedTokenInStatement,
#[error("this expression cannot be assigned to")]
#[error("This expression cannot be assigned to.")]
UnassignableExpression,
#[error("unexpected token after array index")]
#[error("Unexpected token after array index.")]
UnexpectedTokenAfterArrayIndex,
#[error("invalid literal to use as a field name")]
#[error("Invalid literal to use as a field name.")]
InvalidLiteralFieldName,
#[error("integer field names cannot have type suffixes")]
#[error("Integer field names cannot have type suffixes.")]
IntFieldWithTypeSuffix,
#[error("expected a field name")]
#[error("Expected a field name.")]
ExpectedFieldName,
#[error("expected a comma or closing parenthesis in this tuple or parenthesized expression")]
#[error("Expected a comma or closing parenthesis in this tuple or parenthesized expression.")]
ExpectedCommaOrCloseParenInTupleOrParenExpression,
#[error("expected an expression")]
#[error("Expected an expression.")]
ExpectedExpression,
#[error("unexpected token after array length")]
#[error("Unexpected token after array length.")]
UnexpectedTokenAfterArrayLength,
#[error("expected a comma, semicolon or closing bracket when parsing this array")]
#[error("Expected a comma, semicolon or closing bracket when parsing this array.")]
ExpectedCommaSemicolonOrCloseBracketInArray,
#[error("unexpected token after asm return type")]
#[error("Unexpected token after asm return type.")]
UnexpectedTokenAfterAsmReturnType,
#[error("malformed asm immediate value")]
#[error("Malformed asm immediate value.")]
MalformedAsmImmediate,
#[error("expected an identifier")]
#[error("Expected an identifier.")]
ExpectedIdent,
#[error("unexpected token after str length")]
#[error("Unexpected token after str length.")]
UnexpectedTokenAfterStrLength,
#[error("expected a type")]
#[error("Expected a type.")]
ExpectedType,
#[error("unexpected token after array type length")]
#[error("Unexpected token after array type length.")]
UnexpectedTokenAfterArrayTypeLength,
#[error("expected an opening brace")]
#[error("Expected an opening brace.")]
ExpectedOpenBrace,
#[error("expected an opening parenthesis")]
#[error("Expected an opening parenthesis.")]
ExpectedOpenParen,
#[error("expected an opening square bracket")]
#[error("Expected an opening square bracket.")]
ExpectedOpenBracket,
#[error("expected a literal")]
#[error("Expected a literal.")]
ExpectedLiteral,
#[error("expected a program kind (script, contract, predicate or library)")]
#[error("Expected a program kind (script, contract, predicate or library).")]
ExpectedProgramKind,
#[error("expected `{}`", kinds.iter().map(PunctKind::as_char).collect::<String>())]
#[error("Expected `{}`.", kinds.iter().map(PunctKind::as_char).collect::<String>())]
ExpectedPunct { kinds: Vec<PunctKind> },
#[error("expected `{}`", word)]
#[error("Expected `{}`.", word)]
ExpectedKeyword { word: &'static str },
#[error("unexpected token after abi address")]
#[error("Unexpected token after abi address.")]
UnexpectedTokenAfterAbiAddress,
#[error("expected an attribute")]
#[error("Expected an attribute.")]
ExpectedAnAttribute,
#[error("unexpected token after an attribute")]
#[error("Unexpected token after an attribute.")]
UnexpectedTokenAfterAttribute,
#[error("Identifiers cannot begin with a double underscore, as that naming convention is reserved for compiler intrinsics.")]
InvalidDoubleUnderscore,
}

#[derive(Debug, Error, Clone, PartialEq, Hash)]
18 changes: 18 additions & 0 deletions sway-parse/src/intrinsics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#[derive(Eq, PartialEq)]
pub enum Intrinsic {
IsReferenceType,
SizeOf,
SizeOfVal,
}

impl Intrinsic {
pub fn try_from_str(raw: &str) -> Option<Intrinsic> {
use Intrinsic::*;
Some(match raw {
"__is_reference_type" => IsReferenceType,
"__size_of" => SizeOf,
"__size_of_val" => SizeOfVal,
_ => return None,
})
}
}
2 changes: 1 addition & 1 deletion sway-parse/src/item/mod.rs
Original file line number Diff line number Diff line change
@@ -257,7 +257,7 @@ impl Parse for FnSignature {
let visibility = parser.take();
let impure = parser.take();
let fn_token = parser.parse()?;
let name = parser.parse()?;
let name: Ident = parser.parse()?;
let generics = if parser.peek::<OpenAngleBracketToken>().is_some() {
Some(parser.parse()?)
} else {
2 changes: 2 additions & 0 deletions sway-parse/src/lib.rs
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ pub mod dependency;
mod error;
pub mod expr;
pub mod generics;
pub mod intrinsics;
mod item;
pub mod keywords;
mod literal;
@@ -32,6 +33,7 @@ pub use crate::{
ExprTupleDescriptor, IfCondition, IfExpr, MatchBranch, MatchBranchKind,
},
generics::{GenericArgs, GenericParams},
intrinsics::*,
item::{
item_abi::ItemAbi,
item_const::ItemConst,
14 changes: 12 additions & 2 deletions sway-parse/src/parse.rs
Original file line number Diff line number Diff line change
@@ -87,8 +87,18 @@ impl Peek for Ident {

impl Parse for Ident {
fn parse(parser: &mut Parser) -> ParseResult<Ident> {
match parser.take() {
Some(ident) => Ok(ident),
match parser.take::<Ident>() {
Some(ident) => {
let ident_str = ident.as_str();
if ident_str.starts_with("__") && Intrinsic::try_from_str(ident_str).is_none() {
return Err(parser.emit_error_with_span(
ParseErrorKind::InvalidDoubleUnderscore,
ident.span().clone(),
));
}

Ok(ident)
}
None => Err(parser.emit_error(ParseErrorKind::ExpectedIdent)),
}
}
1 change: 1 addition & 0 deletions sway-parse/src/priv_prelude.rs
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ pub use {
CodeBlockContents, Expr,
},
generics::{GenericArgs, GenericParams},
intrinsics::*,
item::{
item_abi::ItemAbi,
item_const::ItemConst,
6 changes: 6 additions & 0 deletions test/src/e2e_vm_tests/mod.rs
Original file line number Diff line number Diff line change
@@ -437,6 +437,12 @@ pub fn run(filter_regex: Option<regex::Regex>) {
"should_fail/different_contract_caller_types",
"should_fail/insufficient_type_info",
"should_fail/primitive_type_argument",
"should_fail/double_underscore_fn",
"should_fail/double_underscore_trait_fn",
"should_fail/double_underscore_impl_self_fn",
"should_fail/double_underscore_var",
"should_fail/double_underscore_struct",
"should_fail/double_underscore_enum",
];
number_of_tests_run += negative_project_names.iter().fold(0, |acc, name| {
if filter(name) {
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
out
target
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[[package]]
name = 'double_underscore_enum'
dependencies = []
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[project]
authors = ["Fuel Labs <[email protected]>"]
entry = "main.sw"
license = "Apache-2.0"
name = "double_underscore_enum"
implicit-std = false
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
script;

enum __MyEnum {
Foo: (),
Bar: (),
}
fn main() {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
out
target
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[[package]]
name = 'double_underscore_fn'
dependencies = []
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[project]
authors = ["Fuel Labs <[email protected]>"]
entry = "main.sw"
license = "Apache-2.0"
name = "double_underscore_fn"
implicit-std = false
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
script;

fn main() {
__test()
}

fn __test() {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
out
target
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[[package]]
name = 'double_underscore_fn'
dependencies = []
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[project]
authors = ["Fuel Labs <[email protected]>"]
entry = "main.sw"
license = "Apache-2.0"
name = "double_underscore_fn"
implicit-std = false
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
script;

struct MyStruct {
test: u64,
}

impl MyStruct {
fn __double_underscore(self, x: bool) -> bool {
bool
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
out
target
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[[package]]
name = 'double_underscore_struct'
dependencies = []
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[project]
authors = ["Fuel Labs <[email protected]>"]
entry = "main.sw"
license = "Apache-2.0"
name = "double_underscore_struct"
implicit-std = false
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
script;

struct __MyStruct {
a: u64,
}
fn main() {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
out
target
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[[package]]
name = 'double_underscore_fn'
dependencies = []
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[project]
authors = ["Fuel Labs <[email protected]>"]
entry = "main.sw"
license = "Apache-2.0"
name = "double_underscore_fn"
implicit-std = false
Loading

0 comments on commit d8c5e5e

Please sign in to comment.