diff --git a/sway-core/src/asm_generation/expression/mod.rs b/sway-core/src/asm_generation/expression/mod.rs index 101443a4a18..481f1e8820a 100644 --- a/sway-core/src/asm_generation/expression/mod.rs +++ b/sway-core/src/asm_generation/expression/mod.rs @@ -1,11 +1,10 @@ use super::*; use crate::{ asm_lang::*, - parse_tree::{CallPath, Literal}, + parse_tree::{BuiltinProperty, CallPath, Literal}, semantic_analysis::{ ast_node::{ - SizeOfVariant, TypedAsmRegisterDeclaration, TypedCodeBlock, TypedEnumVariant, - TypedExpressionVariant, + TypedAsmRegisterDeclaration, TypedCodeBlock, TypedEnumVariant, TypedExpressionVariant, }, TypedExpression, }, @@ -340,8 +339,26 @@ pub(crate) fn convert_expression_to_asm( namespace, register_sequencer, ), - TypedExpressionVariant::SizeOf { variant } => convert_size_of_expression_to_asm( - variant, + TypedExpressionVariant::TypeProperty { property, type_id } => match property { + BuiltinProperty::SizeOfType => convert_size_of_to_asm( + None, + type_id, + namespace, + return_register, + register_sequencer, + exp.span.clone(), + ), + BuiltinProperty::IsRefType => convert_is_ref_type_to_asm( + type_id, + namespace, + return_register, + register_sequencer, + exp.span.clone(), + ), + }, + TypedExpressionVariant::SizeOfValue { expr } => convert_size_of_to_asm( + Some(expr), + &expr.return_type, namespace, return_register, register_sequencer, @@ -422,34 +439,62 @@ fn convert_literal_to_asm( }] } -fn convert_size_of_expression_to_asm( - variant: &SizeOfVariant, +fn convert_is_ref_type_to_asm( + type_id: &TypeId, namespace: &mut AsmNamespace, return_register: &VirtualRegister, register_sequencer: &mut RegisterSequencer, span: Span, ) -> CompileResult> { - let mut warnings = vec![]; + let warnings = vec![]; let mut errors = vec![]; - let mut asm_buf = vec![]; - let type_id = match variant { - SizeOfVariant::Val(exp) => { - asm_buf.push(Op::new_comment("size_of_val".to_string())); - let mut ops = check!( - convert_expression_to_asm(exp, namespace, return_register, register_sequencer), - vec![], - warnings, - errors - ); - asm_buf.append(&mut ops); - exp.return_type + let mut asm_buf = vec![Op::new_comment("is_ref_type".to_string())]; + let ty = match resolve_type(*type_id, &span) { + Ok(o) => o, + Err(e) => { + errors.push(e.into()); + return err(warnings, errors); } - SizeOfVariant::Type(ty) => { - asm_buf.push(Op::new_comment("size_of".to_string())); - *ty + }; + let is_ref_type = match ty.is_copy_type(&span) { + Ok(is_copy) => !is_copy, + Err(e) => { + errors.push(e); + return err(warnings, errors); } }; - let ty = match resolve_type(type_id, &span) { + let mut ops = convert_literal_to_asm( + &Literal::Boolean(is_ref_type), + namespace, + return_register, + register_sequencer, + span, + ); + asm_buf.append(&mut ops); + ok(asm_buf, warnings, errors) +} + +fn convert_size_of_to_asm( + expr: Option<&TypedExpression>, + type_id: &TypeId, + namespace: &mut AsmNamespace, + return_register: &VirtualRegister, + register_sequencer: &mut RegisterSequencer, + span: Span, +) -> CompileResult> { + let mut warnings = vec![]; + let mut errors = vec![]; + let mut asm_buf = vec![Op::new_comment("size_of_val".to_string())]; + if let Some(expr) = expr { + let mut ops = check!( + convert_expression_to_asm(expr, namespace, return_register, register_sequencer), + vec![], + warnings, + errors + ); + asm_buf.append(&mut ops); + } + let ty = match resolve_type(*type_id, &span) { Ok(o) => o, Err(e) => { errors.push(e.into()); diff --git a/sway-core/src/asm_generation/expression/subfield.rs b/sway-core/src/asm_generation/expression/subfield.rs index bbc7043b40e..0212b281e45 100644 --- a/sway-core/src/asm_generation/expression/subfield.rs +++ b/sway-core/src/asm_generation/expression/subfield.rs @@ -160,7 +160,14 @@ pub(crate) fn convert_subfield_to_asm( } }; - asm_buf.push(if resolved_type_of_this_field.is_copy_type() { + let field_has_copy_type = match resolved_type_of_this_field.is_copy_type(&span) { + Ok(is_copy) => is_copy, + Err(e) => { + errors.push(e); + return err(warnings, errors); + } + }; + asm_buf.push(if field_has_copy_type { let offset_in_words = match VirtualImmediate12::new(offset_in_words, span.clone()) { Ok(o) => o, Err(e) => { diff --git a/sway-core/src/asm_generation/mod.rs b/sway-core/src/asm_generation/mod.rs index ee8fb6e2836..6380274dca4 100644 --- a/sway-core/src/asm_generation/mod.rs +++ b/sway-core/src/asm_generation/mod.rs @@ -1430,7 +1430,15 @@ fn ret_or_retd_value( ); } - if main_func_ret_ty.is_copy_type() { + let main_func_ret_ty_is_copy_type = match main_func_ret_ty.is_copy_type(&func.return_type_span) + { + Ok(is_copy) => is_copy, + Err(e) => { + errors.push(e); + return err(warnings, errors); + } + }; + if main_func_ret_ty_is_copy_type { asm_buf.push(Op { owning_span: None, opcode: Either::Left(VirtualOp::RET(return_register)), diff --git a/sway-core/src/control_flow_analysis/dead_code_analysis.rs b/sway-core/src/control_flow_analysis/dead_code_analysis.rs index 2f80e18adff..4d6affe981e 100644 --- a/sway-core/src/control_flow_analysis/dead_code_analysis.rs +++ b/sway-core/src/control_flow_analysis/dead_code_analysis.rs @@ -4,8 +4,8 @@ use crate::{ parse_tree::{CallPath, Visibility}, semantic_analysis::{ ast_node::{ - SizeOfVariant, TypedAbiDeclaration, TypedCodeBlock, TypedConstantDeclaration, - TypedDeclaration, TypedEnumDeclaration, TypedExpression, TypedExpressionVariant, + TypedAbiDeclaration, TypedCodeBlock, TypedConstantDeclaration, TypedDeclaration, + TypedEnumDeclaration, TypedExpression, TypedExpressionVariant, TypedFunctionDeclaration, TypedReassignment, TypedReturnStatement, TypedStructDeclaration, TypedStructExpressionField, TypedTraitDeclaration, TypedVariableDeclaration, TypedWhileLoop, @@ -1006,21 +1006,19 @@ fn connect_expression( } Ok(vec![this_ix]) } - SizeOf { variant } => match variant { - SizeOfVariant::Type(_) => Ok(vec![]), - SizeOfVariant::Val(exp) => { - let exp = connect_expression( - &(*exp).expression, - graph, - leaves, - exit_node, - "size_of", - tree_type, - exp.span.clone(), - )?; - Ok(exp) - } - }, + TypeProperty { .. } => Ok(Vec::new()), + SizeOfValue { expr } => { + let expr = connect_expression( + &(*expr).expression, + graph, + leaves, + exit_node, + "size_of", + tree_type, + expr.span.clone(), + )?; + Ok(expr) + } a => { println!("Unimplemented: {:?}", a); Err(CompileError::Unimplemented( diff --git a/sway-core/src/optimize.rs b/sway-core/src/optimize.rs index d6ffe668d64..362f107813e 100644 --- a/sway-core/src/optimize.rs +++ b/sway-core/src/optimize.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use crate::{ asm_generation::from_ir::ir_type_size_in_bytes, - parse_tree::{AsmOp, AsmRegister, LazyOp, Literal, Visibility}, + parse_tree::{AsmOp, AsmRegister, BuiltinProperty, LazyOp, Literal, Visibility}, semantic_analysis::{ast_node::*, *}, type_engine::*, }; @@ -637,33 +637,31 @@ impl FnCompiler { let span_md_idx = MetadataIndex::from_span(context, &access.span()); self.compile_storage_access(context, &access.fields, &access.ix, span_md_idx) } - TypedExpressionVariant::SizeOf { variant } => { - match variant { - SizeOfVariant::Type(type_id) => { - let ir_type = convert_resolved_typeid_no_span(context, &type_id)?; - Ok(Constant::get_uint( - context, - 64, - ir_type_size_in_bytes(context, &ir_type), - None, - )) - } - SizeOfVariant::Val(exp) => { - let ir_type = - convert_resolved_typeid(context, &exp.return_type, &exp.span)?; - - // Compile the expression in case of side-effects but ignore its value. - self.compile_expression(context, *exp)?; - - Ok(Constant::get_uint( - context, - 64, - ir_type_size_in_bytes(context, &ir_type), - None, - )) + TypedExpressionVariant::TypeProperty { property, type_id } => { + let ir_type = convert_resolved_typeid_no_span(context, &type_id)?; + match property { + BuiltinProperty::SizeOfType => Ok(Constant::get_uint( + context, + 64, + ir_type_size_in_bytes(context, &ir_type), + None, + )), + BuiltinProperty::IsRefType => { + Ok(Constant::get_bool(context, !ir_type.is_copy_type(), None)) } } } + TypedExpressionVariant::SizeOfValue { expr } => { + // Compile the expression in case of side-effects but ignore its value. + let ir_type = convert_resolved_typeid(context, &expr.return_type, &expr.span)?; + self.compile_expression(context, *expr)?; + Ok(Constant::get_uint( + context, + 64, + ir_type_size_in_bytes(context, &ir_type), + None, + )) + } } } diff --git a/sway-core/src/parse_tree/expression/mod.rs b/sway-core/src/parse_tree/expression/mod.rs index 128d53a6ea6..5d3c3857765 100644 --- a/sway-core/src/parse_tree/expression/mod.rs +++ b/sway-core/src/parse_tree/expression/mod.rs @@ -173,13 +173,20 @@ pub enum Expression { exp: Box, span: Span, }, - SizeOfType { + BuiltinGetTypeProperty { + builtin: BuiltinProperty, type_name: TypeInfo, type_span: Span, span: Span, }, } +#[derive(Debug, Clone, PartialEq)] +pub enum BuiltinProperty { + SizeOfType, + IsRefType, +} + #[derive(Debug, Clone)] pub enum DelayedResolutionVariant { StructField(DelayedStructFieldResolution), @@ -312,7 +319,7 @@ impl Expression { StorageAccess { span, .. } => span, IfLet { span, .. } => span, SizeOfVal { span, .. } => span, - SizeOfType { span, .. } => span, + BuiltinGetTypeProperty { span, .. } => span, }) .clone() } @@ -1266,8 +1273,8 @@ impl Expression { warnings, errors ), - Rule::size_of_expr => check!( - parse_size_of_expr(expr, config), + Rule::built_in_expr => check!( + parse_built_in_expr(expr, config), return err(warnings, errors), warnings, errors @@ -1439,7 +1446,7 @@ pub(crate) fn parse_array_index( ) } -pub(crate) fn parse_size_of_expr( +pub(crate) fn parse_built_in_expr( item: Pair, config: Option<&BuildConfig>, ) -> CompileResult> { @@ -1471,10 +1478,12 @@ pub(crate) fn parse_size_of_expr( value: exp, } } - Rule::size_of_type_expr => { + // The size_of_type and is_ref_type_expr rules have identical grammar apart from the + // keyword. + Rule::size_of_type_expr | Rule::is_ref_type_expr => { let mut inner_iter = size_of.into_inner(); - let _keyword = inner_iter.next(); - let elem = inner_iter.next().expect("guarenteed by grammar"); + let keyword = inner_iter.next().expect("guaranteed by grammar"); + let elem = inner_iter.next().expect("guaranteed by grammar"); let type_span = Span { span: elem.as_span(), path: config.map(|c| c.path()), @@ -1485,7 +1494,12 @@ pub(crate) fn parse_size_of_expr( warnings, errors ); - let exp = Expression::SizeOfType { + let exp = Expression::BuiltinGetTypeProperty { + builtin: match keyword.as_str() { + "size_of" => BuiltinProperty::SizeOfType, + "is_reference_type" => BuiltinProperty::IsRefType, + _otherwise => unreachable!("unexpected built in keyword: {keyword}"), + }, type_name, type_span, span, diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index 8d5372adb72..0095beace0b 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -66,13 +66,11 @@ impl TypedExpression { .map(|x| x.deterministically_aborts()) .unwrap_or(false), AbiCast { address, .. } => address.deterministically_aborts(), - SizeOf { - variant: SizeOfVariant::Val(v), - } => v.deterministically_aborts(), + SizeOfValue { expr } => expr.deterministically_aborts(), StructFieldAccess { .. } | Literal(_) | StorageAccess { .. } - | SizeOf { .. } + | TypeProperty { .. } | VariableExpression { .. } | FunctionParameter | TupleElemAccess { .. } => false, @@ -171,7 +169,8 @@ impl TypedExpression { | TypedExpressionVariant::TupleElemAccess { .. } | TypedExpressionVariant::EnumInstantiation { .. } | TypedExpressionVariant::AbiCast { .. } - | TypedExpressionVariant::SizeOf { .. } + | TypedExpressionVariant::SizeOfValue { .. } + | TypedExpressionVariant::TypeProperty { .. } | TypedExpressionVariant::StructExpression { .. } | TypedExpressionVariant::VariableExpression { .. } | TypedExpressionVariant::StorageAccess { .. } @@ -500,11 +499,13 @@ impl TypedExpression { }, span, ), - Expression::SizeOfType { + Expression::BuiltinGetTypeProperty { + builtin, type_name, type_span, span, - } => Self::type_check_size_of_type( + } => Self::type_check_get_type_property( + builtin, TypeCheckArguments { checkee: (type_name, type_span), namespace, @@ -519,17 +520,6 @@ impl TypedExpression { }, span, ), - /* - a => { - let errors = vec![CompileError::Unimplemented( - "Unimplemented type checking for expression", - a.span(), - )]; - - let exp = error_recovery_expr(a.span()); - ok(exp, vec![], errors) - } - */ }; let mut typed_expression = match res.value { Some(r) => r, @@ -2320,8 +2310,8 @@ impl TypedExpression { errors ); let exp = TypedExpression { - expression: TypedExpressionVariant::SizeOf { - variant: SizeOfVariant::Val(Box::new(exp)), + expression: TypedExpressionVariant::SizeOfValue { + expr: Box::new(exp), }, return_type: crate::type_engine::insert_type(TypeInfo::UnsignedInteger( IntegerBits::SixtyFour, @@ -2332,7 +2322,8 @@ impl TypedExpression { ok(exp, warnings, errors) } - fn type_check_size_of_type( + fn type_check_get_type_property( + builtin: BuiltinProperty, arguments: TypeCheckArguments<'_, (TypeInfo, Span)>, span: Span, ) -> CompileResult { @@ -2350,13 +2341,18 @@ impl TypedExpression { warnings, errors, ); + let return_type = match builtin { + BuiltinProperty::SizeOfType => { + crate::type_engine::insert_type(TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)) + } + BuiltinProperty::IsRefType => crate::type_engine::insert_type(TypeInfo::Boolean), + }; let exp = TypedExpression { - expression: TypedExpressionVariant::SizeOf { - variant: SizeOfVariant::Type(type_id), + expression: TypedExpressionVariant::TypeProperty { + property: builtin, + type_id, }, - return_type: crate::type_engine::insert_type(TypeInfo::UnsignedInteger( - IntegerBits::SixtyFour, - )), + return_type, is_constant: IsConstant::No, span, }; diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression_variant.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression_variant.rs index 2de3fac95ee..7f2fb5e3432 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression_variant.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression_variant.rs @@ -105,8 +105,12 @@ pub(crate) enum TypedExpressionVariant { }, #[allow(dead_code)] StorageAccess(TypeCheckedStorageAccess), - SizeOf { - variant: SizeOfVariant, + TypeProperty { + property: BuiltinProperty, + type_id: TypeId, + }, + SizeOfValue { + expr: Box, }, } @@ -321,8 +325,18 @@ impl PartialEq for TypedExpressionVariant { .. }, ) => l_abi_name == r_abi_name && (**l_address) == (**r_address), - (Self::SizeOf { variant: l_variant }, Self::SizeOf { variant: r_variant }) => { - l_variant == r_variant + ( + Self::TypeProperty { + property: l_prop, + type_id: l_type_id, + }, + Self::TypeProperty { + property: r_prop, + type_id: r_type_id, + }, + ) => l_prop == r_prop && look_up_type_id(*l_type_id) == look_up_type_id(*r_type_id), + (Self::SizeOfValue { expr: l_expr }, Self::SizeOfValue { expr: r_expr }) => { + l_expr == r_expr } _ => false, } @@ -357,25 +371,6 @@ pub struct TypeCheckedStorageAccessDescriptor { pub(crate) span: Span, } -#[derive(Clone, Debug)] -pub(crate) enum SizeOfVariant { - Type(TypeId), - Val(Box), -} - -// NOTE: Hash and PartialEq must uphold the invariant: -// k1 == k2 -> hash(k1) == hash(k2) -// https://doc.rust-lang.org/std/collections/struct.HashMap.html -impl PartialEq for SizeOfVariant { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Self::Type(l0), Self::Type(r0)) => l0 == r0, - (Self::Val(l0), Self::Val(r0)) => (**l0) == (**r0), - _ => false, - } - } -} - #[derive(Clone, Debug)] pub(crate) struct TypedAsmRegisterDeclaration { pub(crate) initializer: Option, @@ -502,12 +497,16 @@ impl TypedExpressionVariant { TypedExpressionVariant::StorageAccess(access) => { format!("storage field {} access", access.storage_field_name()) } - TypedExpressionVariant::SizeOf { variant } => match variant { - SizeOfVariant::Val(exp) => format!("size_of_val({:?})", exp.pretty_print()), - SizeOfVariant::Type(type_name) => { - format!("size_of({:?})", type_name.friendly_type_str()) + TypedExpressionVariant::TypeProperty { property, type_id } => { + let type_str = look_up_type_id(*type_id).friendly_type_str(); + match property { + BuiltinProperty::SizeOfType => format!("size_of({type_str:?})"), + BuiltinProperty::IsRefType => format!("is_ref_type({type_str:?})"), } - }, + } + TypedExpressionVariant::SizeOfValue { expr } => { + format!("size_of_val({:?})", expr.pretty_print()) + } } } @@ -624,10 +623,16 @@ impl TypedExpressionVariant { AbiCast { address, .. } => address.copy_types(type_mapping), // storage is never generic and cannot be monomorphized StorageAccess { .. } => (), - SizeOf { variant } => match variant { - SizeOfVariant::Type(_) => (), - SizeOfVariant::Val(exp) => exp.copy_types(type_mapping), - }, + TypeProperty { type_id, .. } => { + *type_id = if let Some(matching_id) = + look_up_type_id(*type_id).matches_type_parameter(type_mapping) + { + insert_type(TypeInfo::Ref(matching_id)) + } else { + insert_type(look_up_type_id_raw(*type_id)) + }; + } + SizeOfValue { expr } => expr.copy_types(type_mapping), } } } diff --git a/sway-core/src/semantic_analysis/node_dependencies.rs b/sway-core/src/semantic_analysis/node_dependencies.rs index 284a8edd095..249fd3899e5 100644 --- a/sway-core/src/semantic_analysis/node_dependencies.rs +++ b/sway-core/src/semantic_analysis/node_dependencies.rs @@ -399,7 +399,7 @@ impl Dependencies { Expression::StorageAccess { .. } => self, Expression::IfLet { expr, .. } => self.gather_from_expr(expr), Expression::SizeOfVal { exp, .. } => self.gather_from_expr(exp), - Expression::SizeOfType { .. } => self, + Expression::BuiltinGetTypeProperty { .. } => self, } } diff --git a/sway-core/src/sway.pest b/sway-core/src/sway.pest index 96e1927b4c6..20dd623ea8c 100644 --- a/sway-core/src/sway.pest +++ b/sway-core/src/sway.pest @@ -29,6 +29,7 @@ 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"} // top level program = {SOI ~ (library|contract|script|predicate)? ~ EOI} @@ -60,10 +61,31 @@ call_path_ = {relative_call_path_|absolute_call_path_} relative_call_path_ = {ident ~ (path_separator ~ ident)+} absolute_call_path_ = {path_separator ~ ident ~ (path_separator ~ ident)+} -expr_inner = _{unary_op_expr|asm_expression|size_of_expr|match_expression|abi_cast|if_let_exp|if_exp|code_block|tuple_index|struct_expression|storage_access|delineated_path|func_app|literal_value|method_exp|struct_field_access|array_index|var_exp|array_exp|parenthesized_expression|tuple_expr} +expr_inner = _{ unary_op_expr + | asm_expression + | built_in_expr + | match_expression + | abi_cast + | if_let_exp + | if_exp + | code_block + | tuple_index + | struct_expression + | storage_access + | delineated_path + | func_app + | literal_value + | method_exp + | struct_field_access + | array_index + | var_exp + | array_exp + | parenthesized_expression + | tuple_expr + } parenthesized_expression = {"(" ~ expr ~ ")"} unary_op_expr = { unary_op ~ expr_inner } -// // op exps built in to expr to prevent left recursion +// op exps built in to expr to prevent left recursion expr = {expr_inner ~ (op ~ expr_inner)*} func_app = {call_path ~ type_args_with_path? ~ fn_args} fn_args = { "(" ~ (expr ~ ("," ~ expr)*)? ~ ")" } @@ -83,10 +105,11 @@ path_ident = {ident} array_index = {call_item ~ "[" ~ expr ~ "]" ~ ("[" ~ expr ~ "]")*} storage_access = {storage_keyword ~ "." ~ ident ~ ("." ~ ident)*} -// size_of -size_of_expr = {size_of_type_expr|size_of_val_expr} +// built in expressions +built_in_expr = {size_of_type_expr|size_of_val_expr|is_ref_type_expr} size_of_type_expr = {size_of_type_keyword ~ "::<" ~ type_name ~ ">" ~ "(" ~ ")"} size_of_val_expr = {size_of_val_keyword ~ "(" ~ expr ~ ")"} +is_ref_type_expr = {is_ref_type_keyword ~ "::<" ~ type_name ~ ">" ~ "(" ~ ")"} // abi blocks and abi casting abi_cast = {abi_keyword ~ "(" ~ call_path ~ "," ~ expr ~ ")"} diff --git a/sway-core/src/type_engine/type_info.rs b/sway-core/src/type_engine/type_info.rs index 349e0cf8c53..c25b7791358 100644 --- a/sway-core/src/type_engine/type_info.rs +++ b/sway-core/src/type_engine/type_info.rs @@ -681,11 +681,27 @@ impl TypeInfo { } } - pub(crate) fn is_copy_type(&self) -> bool { - matches!( - self, - TypeInfo::UnsignedInteger(_) | TypeInfo::Boolean | TypeInfo::Byte - ) + pub(crate) fn is_copy_type(&self, err_span: &Span) -> Result { + match self { + // Copy types. + TypeInfo::UnsignedInteger(_) + | TypeInfo::Numeric + | TypeInfo::Boolean + | TypeInfo::Byte => Ok(true), + TypeInfo::Tuple(_) if self.is_unit() => Ok(true), + + // Unknown types. + TypeInfo::Unknown + | TypeInfo::Custom { .. } + | TypeInfo::SelfType + | TypeInfo::UnknownGeneric { .. } => Err(CompileError::UnableToInferGeneric { + ty: self.friendly_type_str(), + span: err_span.clone(), + }), + + // Otherwise default to non-copy. + _otherwise => Ok(false), + } } pub fn is_uninhabited(&self) -> bool { diff --git a/test/src/e2e_vm_tests/mod.rs b/test/src/e2e_vm_tests/mod.rs index 456c80121f6..1f854fecb7e 100644 --- a/test/src/e2e_vm_tests/mod.rs +++ b/test/src/e2e_vm_tests/mod.rs @@ -286,6 +286,10 @@ pub fn run(filter_regex: Option) { "should_pass/language/nested_while_and_if", ProgramState::Return(1), ), + ( + "should_pass/language/is_reference_type", + ProgramState::Return(1), + ), ]; let mut number_of_tests_run = positive_project_names.iter().fold(0, |acc, (name, res)| { diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/is_reference_type/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/is_reference_type/Forc.lock new file mode 100644 index 00000000000..f81d62d08b5 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/is_reference_type/Forc.lock @@ -0,0 +1,11 @@ +[[package]] +name = 'core' +dependencies = [] + +[[package]] +name = 'is_reference_type' +dependencies = ['std'] + +[[package]] +name = 'std' +dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/is_reference_type/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/is_reference_type/Forc.toml new file mode 100644 index 00000000000..b46a10705d4 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/is_reference_type/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "is_reference_type" + +[dependencies] +std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/is_reference_type/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/is_reference_type/json_abi_oracle.json new file mode 100644 index 00000000000..0637a088a01 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/is_reference_type/json_abi_oracle.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/is_reference_type/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/is_reference_type/src/main.sw new file mode 100644 index 00000000000..5bbc1318d7c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/is_reference_type/src/main.sw @@ -0,0 +1,43 @@ +script; + +use std::assert::assert; + +struct S { + a: u64, +} + +enum E { + Variant: (), +} + +fn arg_is_reference(a: T) -> bool { + is_reference_type::() +} + +fn main() -> bool { + assert(!is_reference_type::<()>()); // Is Unit ref or not? + assert(!is_reference_type::()); + assert(!is_reference_type::()); + assert(!is_reference_type::()); + + assert(is_reference_type::()); + assert(is_reference_type::()); + assert(is_reference_type::()); + assert(is_reference_type::()); + assert(is_reference_type::<(bool, bool)>()); + assert(is_reference_type::<[u64; 2]>()); + + assert(!arg_is_reference(())); + assert(!arg_is_reference(false)); + assert(!arg_is_reference(0x2b)); + assert(!arg_is_reference(0)); + + assert(arg_is_reference("breakfast")); + assert(arg_is_reference(0xfefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe)); + assert(arg_is_reference(S { a: 42 })); + assert(arg_is_reference(E::Variant)); + assert(arg_is_reference((true, true))); + assert(arg_is_reference([5, 4, 3, 2, 1])); + + true +}