Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 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
42 changes: 15 additions & 27 deletions sway-core/src/control_flow_analysis/dead_code_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1029,44 +1029,32 @@ fn connect_expression(
}

fn connect_intrinsic_function(
kind: &TypedIntrinsicFunctionKind,
TypedIntrinsicFunctionKind {
kind, arguments, ..
}: &TypedIntrinsicFunctionKind,
graph: &mut ControlFlowGraph,
leaves: &[NodeIndex],
exit_node: Option<NodeIndex>,
tree_type: &TreeType,
) -> Result<Vec<NodeIndex>, CompileError> {
let result = match kind {
TypedIntrinsicFunctionKind::SizeOfVal { exp } => connect_expression(
let node = graph.add_node(kind.to_string().into());
for leaf in leaves {
graph.add_edge(*leaf, node, "".into());
}
let mut result = vec![node];
let _ = arguments.iter().try_fold(&mut result, |accum, exp| {
let mut res = connect_expression(
&(*exp).expression,
graph,
leaves,
exit_node,
"size_of",
"intrinsic",
tree_type,
exp.span.clone(),
)?,
TypedIntrinsicFunctionKind::SizeOfType { .. } => {
let node = graph.add_node("size of type".into());
for leaf in leaves {
graph.add_edge(*leaf, node, "".into());
}
vec![node]
}
TypedIntrinsicFunctionKind::IsRefType { .. } => {
let node = graph.add_node("is ref type".into());
for leaf in leaves {
graph.add_edge(*leaf, node, "".into());
}
vec![node]
}
TypedIntrinsicFunctionKind::GetStorageKey => {
let node = graph.add_node("Get storage key".into());
for leaf in leaves {
graph.add_edge(*leaf, node, "".into());
}
vec![node]
}
};
)?;
accum.append(&mut res);
Ok::<_, CompileError>(accum)
})?;
Ok(result)
}

Expand Down
159 changes: 32 additions & 127 deletions sway-core/src/convert_parse_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ use {
AbiDeclaration, AsmExpression, AsmOp, AsmRegister, AsmRegisterDeclaration, AstNode,
AstNodeContent, CallPath, CodeBlock, ConstantDeclaration, Declaration, EnumDeclaration,
EnumVariant, Expression, FunctionDeclaration, FunctionParameter, ImplSelf, ImplTrait,
ImportType, IncludeStatement, IntrinsicFunctionKind, LazyOp, Literal, MatchBranch,
MethodName, ParseTree, Purity, Reassignment, ReassignmentTarget, ReturnStatement,
Scrutinee, StorageDeclaration, StorageField, StructDeclaration, StructExpressionField,
StructField, StructScrutineeField, Supertrait, TraitDeclaration, TraitFn, TreeType,
TypeInfo, UseStatement, VariableDeclaration, Visibility, WhileLoop,
ImportType, IncludeStatement, LazyOp, Literal, MatchBranch, MethodName, ParseTree, Purity,
Reassignment, ReassignmentTarget, ReturnStatement, Scrutinee, StorageDeclaration,
StorageField, StructDeclaration, StructExpressionField, StructField, StructScrutineeField,
Supertrait, TraitDeclaration, TraitFn, TreeType, TypeInfo, UseStatement,
VariableDeclaration, Visibility, WhileLoop,
},
std::{
collections::HashMap,
Expand Down Expand Up @@ -102,16 +102,6 @@ pub enum ConvertParseTreeError {
GenericsNotSupportedHere { span: Span },
#[error("fully qualified paths are not supported here")]
FullyQualifiedPathsNotSupportedHere { span: Span },
#[error("__size_of does not take arguments")]
SizeOfTooManyArgs { span: Span },
#[error("__size_of requires exactly one generic argument")]
SizeOfOneGenericArg { span: Span },
#[error("__is_reference_type does not take arguments")]
IsReferenceTypeTooManyArgs { span: Span },
#[error("__is_reference_type requires exactly one generic argument")]
IsReferenceTypeOneGenericArg { span: Span },
#[error("__size_of_val requires exactly one argument")]
SizeOfValOneArg { span: Span },
#[error("tuple index out of range")]
TupleIndexOutOfRange { span: Span },
#[error("shift-left expressions are not implemented")]
Expand Down Expand Up @@ -199,11 +189,6 @@ impl Spanned for ConvertParseTreeError {
ConvertParseTreeError::FunctionArbitraryExpression { span } => span.clone(),
ConvertParseTreeError::GenericsNotSupportedHere { span } => span.clone(),
ConvertParseTreeError::FullyQualifiedPathsNotSupportedHere { span } => span.clone(),
ConvertParseTreeError::SizeOfTooManyArgs { span } => span.clone(),
ConvertParseTreeError::SizeOfOneGenericArg { span } => span.clone(),
ConvertParseTreeError::IsReferenceTypeTooManyArgs { span } => span.clone(),
ConvertParseTreeError::IsReferenceTypeOneGenericArg { span } => span.clone(),
ConvertParseTreeError::SizeOfValOneArg { span } => span.clone(),
ConvertParseTreeError::TupleIndexOutOfRange { span } => span.clone(),
ConvertParseTreeError::ShlNotImplemented { span } => span.clone(),
ConvertParseTreeError::ShrNotImplemented { span } => span.clone(),
Expand Down Expand Up @@ -1442,118 +1427,38 @@ fn expr_to_expression(ec: &mut ErrorContext, expr: Expr) -> Result<Expression, E
}
}
None => {
if call_path.prefixes.is_empty()
&& !call_path.is_absolute
&& Intrinsic::try_from_str(call_path.suffix.as_str())
== Some(Intrinsic::SizeOf)
{
if !arguments.is_empty() {
let error = ConvertParseTreeError::SizeOfTooManyArgs { span };
return Err(ec.error(error));
}
let ty = match {
generics_opt.and_then(|(_double_colon_token, generic_args)| {
iter_to_array(generic_args.parameters.into_inner())
})
} {
Some([ty]) => ty,
None => {
let error = ConvertParseTreeError::SizeOfOneGenericArg { span };
return Err(ec.error(error));
}
};
let type_span = ty.span();
let type_name = ty_to_type_info(ec, ty)?;
Expression::IntrinsicFunction {
kind: IntrinsicFunctionKind::SizeOfType {
type_name,
type_span,
},
span,
}
} else if call_path.prefixes.is_empty()
&& !call_path.is_absolute
&& Intrinsic::try_from_str(call_path.suffix.as_str())
== Some(Intrinsic::GetStorageKey)
{
if !arguments.is_empty() {
let error = ConvertParseTreeError::GetStorageKeyTooManyArgs { span };
return Err(ec.error(error));
}
if generics_opt.is_some() {
let error = ConvertParseTreeError::GenericsNotSupportedHere { span };
return Err(ec.error(error));
}
Expression::IntrinsicFunction {
kind: IntrinsicFunctionKind::GetStorageKey,
span,
}
} else if call_path.prefixes.is_empty()
&& !call_path.is_absolute
&& Intrinsic::try_from_str(call_path.suffix.as_str())
== Some(Intrinsic::IsReferenceType)
{
if !arguments.is_empty() {
let error = ConvertParseTreeError::IsReferenceTypeTooManyArgs { span };
return Err(ec.error(error));
}
let ty = match {
generics_opt.and_then(|(_double_colon_token, generic_args)| {
iter_to_array(generic_args.parameters.into_inner())
})
} {
Some([ty]) => ty,
None => {
let error =
ConvertParseTreeError::IsReferenceTypeOneGenericArg { span };
return Err(ec.error(error));
}
};
let type_span = ty.span();
let type_name = ty_to_type_info(ec, ty)?;
Expression::IntrinsicFunction {
kind: IntrinsicFunctionKind::IsRefType {
type_name,
type_span,
},
span,
}
} else if call_path.prefixes.is_empty()
&& !call_path.is_absolute
&& Intrinsic::try_from_str(call_path.suffix.as_str())
== Some(Intrinsic::SizeOfVal)
{
let exp = match <[_; 1]>::try_from(arguments) {
Ok([exp]) => Box::new(exp),
Err(..) => {
let error = ConvertParseTreeError::SizeOfValOneArg { span };
return Err(ec.error(error));
}
};
Expression::IntrinsicFunction {
kind: IntrinsicFunctionKind::SizeOfVal { exp },
span,
let type_arguments = match generics_opt {
Some((_double_colon_token, generic_args)) => {
generic_args_to_type_arguments(ec, generic_args)?
}
} else {
let type_arguments = match generics_opt {
Some((_double_colon_token, generic_args)) => {
generic_args_to_type_arguments(ec, generic_args)?
}
None => Vec::new(),
};
if call_path.prefixes.is_empty() {
Expression::FunctionApplication {
name: call_path,
None => Vec::new(),
};
match Intrinsic::try_from_str(call_path.suffix.as_str()) {
Some(intrinsic)
if call_path.prefixes.is_empty() && !call_path.is_absolute =>
{
Expression::IntrinsicFunction {
kind: intrinsic,
arguments,
type_arguments,
span,
}
} else {
Expression::DelineatedPath {
call_path,
args: arguments,
type_arguments,
span,
}
_ => {
if call_path.prefixes.is_empty() {
Expression::FunctionApplication {
name: call_path,
arguments,
type_arguments,
span,
}
} else {
Expression::DelineatedPath {
call_path,
args: arguments,
type_arguments,
span,
}
}
}
}
Expand Down
17 changes: 17 additions & 0 deletions sway-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,20 @@ pub enum CompileError {
NonConstantDeclValue { span: Span },
#[error("Declaring storage in a {program_kind} is not allowed.")]
StorageDeclarationInNonContract { program_kind: String, span: Span },
#[error("Unsupported argument type to intrinsic \"{name}\".")]
IntrinsicUnsupportedArgType { name: String, span: Span },
#[error("Call to \"{name}\" expects {expected} arguments")]
IntrinsicIncorrectNumArgs {
name: String,
expected: u64,
span: Span,
},
#[error("Call to \"{name}\" expects {expected} type arguments")]
IntrinsicIncorrectNumTArgs {
name: String,
expected: u64,
span: Span,
},
}

impl std::convert::From<TypeError> for CompileError {
Expand Down Expand Up @@ -1151,6 +1165,9 @@ impl Spanned for CompileError {
TupleIndexOutOfBounds { span, .. } => span.clone(),
NonConstantDeclValue { span } => span.clone(),
StorageDeclarationInNonContract { span, .. } => span.clone(),
IntrinsicUnsupportedArgType { span, .. } => span.clone(),
IntrinsicIncorrectNumArgs { span, .. } => span.clone(),
IntrinsicIncorrectNumTArgs { span, .. } => span.clone(),
}
}
}
Expand Down
39 changes: 31 additions & 8 deletions sway-core/src/ir_generation/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::{
type_engine::{insert_type, resolve_type, TypeId, TypeInfo},
};
use sway_ir::{Context, *};
use sway_parse::intrinsics::Intrinsic;
use sway_types::{
ident::Ident,
span::{Span, Spanned},
Expand Down Expand Up @@ -318,41 +319,63 @@ impl FnCompiler {
fn compile_intrinsic_function(
&mut self,
context: &mut Context,
kind: TypedIntrinsicFunctionKind,
TypedIntrinsicFunctionKind {
kind,
arguments,
type_arguments,
span: _,
}: TypedIntrinsicFunctionKind,
span: Span,
) -> Result<Value, CompileError> {
// We safely index into arguments and type_arguments arrays below
// because the type-checker ensures that the arguments are all there.
match kind {
TypedIntrinsicFunctionKind::SizeOfVal { exp } => {
Intrinsic::SizeOfVal => {
let exp = arguments[0].clone();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you specify what you mean by "the type checker did its job"? The phrase "did its job" doesn't convey exactly what we are assuming here.

// Compile the expression in case of side-effects but ignore its value.
let ir_type = convert_resolved_typeid(context, &exp.return_type, &exp.span)?;
self.compile_expression(context, *exp)?;
self.compile_expression(context, exp)?;
Ok(Constant::get_uint(
context,
64,
ir_type_size_in_bytes(context, &ir_type),
None,
))
}
TypedIntrinsicFunctionKind::SizeOfType { type_id, type_span } => {
let ir_type = convert_resolved_typeid(context, &type_id, &type_span)?;
Intrinsic::SizeOfType => {
let targ = type_arguments[0].clone();
let ir_type = convert_resolved_typeid(context, &targ.type_id, &targ.span)?;
Ok(Constant::get_uint(
context,
64,
ir_type_size_in_bytes(context, &ir_type),
None,
))
}
TypedIntrinsicFunctionKind::IsRefType { type_id, type_span } => {
let ir_type = convert_resolved_typeid(context, &type_id, &type_span)?;
Intrinsic::IsReferenceType => {
let targ = type_arguments[0].clone();
let ir_type = convert_resolved_typeid(context, &targ.type_id, &targ.span)?;
Ok(Constant::get_bool(context, !ir_type.is_copy_type(), None))
}
TypedIntrinsicFunctionKind::GetStorageKey => {
Intrinsic::GetStorageKey => {
let span_md_idx = MetadataIndex::from_span(context, &span);
Ok(self
.current_block
.ins(context)
.get_storage_key(span_md_idx, None))
}
Intrinsic::Eq => {
let lhs = arguments[0].clone();
let rhs = arguments[1].clone();
Comment on lines +369 to +370
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing we could do is codify the arguments into the enum itself, so we don't have a panic risk here.

e.g.

enum Intrinsic {
  Eq { lhs: TypedExpression, rhs: TypedExpression },
  SizeOf { type_argument: TypeInfo } 
}

etc...

I'm just suggesting this, but I wouldn't block this PR on it, as it could be a more major refactor. It would give us type safety here, though.

let lhs_value = self.compile_expression(context, lhs)?;
let rhs_value = self.compile_expression(context, rhs)?;
Ok(self.current_block.ins(context).cmp(
Predicate::Equal,
lhs_value,
rhs_value,
None,
))
}
}
}

Expand Down
18 changes: 0 additions & 18 deletions sway-core/src/parse_tree/expression/intrinsic_function.rs

This file was deleted.

Loading