diff --git a/crates/solidity/outputs/cargo/crate/src/backend/ir/ast/node_extensions/identifiers.rs b/crates/solidity/outputs/cargo/crate/src/backend/ir/ast/node_extensions/identifiers.rs index c7e889ef3e..026ee54f3b 100644 --- a/crates/solidity/outputs/cargo/crate/src/backend/ir/ast/node_extensions/identifiers.rs +++ b/crates/solidity/outputs/cargo/crate/src/backend/ir/ast/node_extensions/identifiers.rs @@ -1,7 +1,7 @@ use std::rc::Rc; use super::super::IdentifierPathStruct; -use super::Definition; +use super::{Definition, Type}; use crate::backend::SemanticAnalysis; use crate::cst::{NodeId, TerminalKind, TerminalNode, TextIndex}; @@ -75,6 +75,10 @@ impl IdentifierStruct { self.semantic.references_binding_to(self.ir_node.id()) } + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.id()) + } + pub fn text_offset(&self) -> TextIndex { self.semantic .get_text_offset_by_node_id(self.ir_node.id()) diff --git a/crates/solidity/outputs/cargo/crate/src/backend/ir/ast/node_extensions/mod.rs b/crates/solidity/outputs/cargo/crate/src/backend/ir/ast/node_extensions/mod.rs index f9b4c6bacd..3d7965bafd 100644 --- a/crates/solidity/outputs/cargo/crate/src/backend/ir/ast/node_extensions/mod.rs +++ b/crates/solidity/outputs/cargo/crate/src/backend/ir/ast/node_extensions/mod.rs @@ -12,6 +12,9 @@ pub use identifiers::{ Identifier, IdentifierStruct, Reference, YulIdentifier, YulIdentifierStruct, }; +mod types; +pub use types::Type; + impl SourceUnitStruct { pub fn file_id(&self) -> String { self.semantic diff --git a/crates/solidity/outputs/cargo/crate/src/backend/ir/ast/node_extensions/types.rs b/crates/solidity/outputs/cargo/crate/src/backend/ir/ast/node_extensions/types.rs new file mode 100644 index 0000000000..950247721e --- /dev/null +++ b/crates/solidity/outputs/cargo/crate/src/backend/ir/ast/node_extensions/types.rs @@ -0,0 +1,348 @@ +use std::rc::Rc; + +use paste::paste; + +use super::Definition; +use crate::backend::types::{self, DataLocation, FunctionTypeKind, TypeId}; +use crate::backend::SemanticAnalysis; + +// __SLANG_TYPE_TYPES__ keep in sync with binder types +#[derive(Clone)] +pub enum Type { + Address(AddressType), + Array(ArrayType), + Boolean(BooleanType), + ByteArray(ByteArrayType), + Bytes(BytesType), + Contract(ContractType), + Enum(EnumType), + FixedPointNumber(FixedPointNumberType), + Function(FunctionType), + Integer(IntegerType), + Interface(InterfaceType), + Literal(LiteralType), + Mapping(MappingType), + String(StringType), + Struct(StructType), + Tuple(TupleType), + UserDefinedValue(UserDefinedValueType), + Void(VoidType), +} + +macro_rules! define_type_variant { + ($type:ident) => { + paste! { + #[derive(Clone)] + pub struct [<$type Type>] { + type_id: TypeId, + semantic: Rc, + } + + impl [<$type Type>] { + #[allow(unused)] + fn internal_type(&self) -> &types::Type { + self.semantic.types.get_type_by_id(self.type_id) + } + } + } + }; +} + +define_type_variant!(Address); +define_type_variant!(Array); +define_type_variant!(Boolean); +define_type_variant!(ByteArray); +define_type_variant!(Bytes); +define_type_variant!(Contract); +define_type_variant!(Enum); +define_type_variant!(FixedPointNumber); +define_type_variant!(Function); +define_type_variant!(Integer); +define_type_variant!(Interface); +define_type_variant!(Literal); +define_type_variant!(Mapping); +define_type_variant!(String); +define_type_variant!(Struct); +define_type_variant!(Tuple); +define_type_variant!(UserDefinedValue); +define_type_variant!(Void); + +impl Type { + pub fn create(type_id: TypeId, semantic: &Rc) -> Self { + let type_ = semantic.types().get_type_by_id(type_id); + let semantic = Rc::clone(semantic); + match type_ { + types::Type::Address { .. } => Self::Address(AddressType { type_id, semantic }), + types::Type::Array { .. } => Self::Array(ArrayType { type_id, semantic }), + types::Type::Boolean => Self::Boolean(BooleanType { type_id, semantic }), + types::Type::ByteArray { .. } => Self::ByteArray(ByteArrayType { type_id, semantic }), + types::Type::Bytes { .. } => Self::Bytes(BytesType { type_id, semantic }), + types::Type::Contract { .. } => Self::Contract(ContractType { type_id, semantic }), + types::Type::Enum { .. } => Self::Enum(EnumType { type_id, semantic }), + types::Type::FixedPointNumber { .. } => { + Self::FixedPointNumber(FixedPointNumberType { type_id, semantic }) + } + types::Type::Function(_) => Self::Function(FunctionType { type_id, semantic }), + types::Type::Integer { .. } => Self::Integer(IntegerType { type_id, semantic }), + types::Type::Interface { .. } => Self::Interface(InterfaceType { type_id, semantic }), + types::Type::Literal(_) => Self::Literal(LiteralType { type_id, semantic }), + types::Type::Mapping { .. } => Self::Mapping(MappingType { type_id, semantic }), + types::Type::String { .. } => Self::String(StringType { type_id, semantic }), + types::Type::Struct { .. } => Self::Struct(StructType { type_id, semantic }), + types::Type::Tuple { .. } => Self::Tuple(TupleType { type_id, semantic }), + types::Type::UserDefinedValue { .. } => { + Self::UserDefinedValue(UserDefinedValueType { type_id, semantic }) + } + types::Type::Void => Self::Void(VoidType { type_id, semantic }), + } + } + + pub fn type_id(&self) -> TypeId { + match self { + Type::Address(details) => details.type_id, + Type::Array(details) => details.type_id, + Type::Boolean(details) => details.type_id, + Type::ByteArray(details) => details.type_id, + Type::Bytes(details) => details.type_id, + Type::Contract(details) => details.type_id, + Type::Enum(details) => details.type_id, + Type::FixedPointNumber(details) => details.type_id, + Type::Function(details) => details.type_id, + Type::Integer(details) => details.type_id, + Type::Interface(details) => details.type_id, + Type::Literal(details) => details.type_id, + Type::Mapping(details) => details.type_id, + Type::String(details) => details.type_id, + Type::Struct(details) => details.type_id, + Type::Tuple(details) => details.type_id, + Type::UserDefinedValue(details) => details.type_id, + Type::Void(details) => details.type_id, + } + } +} + +impl AddressType { + pub fn payable(&self) -> bool { + let types::Type::Address { payable } = self.internal_type() else { + unreachable!("invalid address type"); + }; + *payable + } +} + +impl ArrayType { + pub fn element_type(&self) -> Type { + let types::Type::Array { element_type, .. } = self.internal_type() else { + unreachable!("invalid array type"); + }; + Type::create(*element_type, &self.semantic) + } + pub fn location(&self) -> DataLocation { + let types::Type::Array { location, .. } = self.internal_type() else { + unreachable!("invalid array type"); + }; + *location + } +} + +impl BooleanType {} + +impl ByteArrayType { + pub fn width(&self) -> u32 { + let types::Type::ByteArray { width } = self.internal_type() else { + unreachable!("invalid byte array type"); + }; + *width + } +} + +impl BytesType { + pub fn location(&self) -> DataLocation { + let types::Type::Bytes { location } = self.internal_type() else { + unreachable!("invalid bytes type"); + }; + *location + } +} + +impl ContractType { + pub fn definition(&self) -> Definition { + let types::Type::Contract { definition_id } = self.internal_type() else { + unreachable!("invalid contract type"); + }; + Definition::try_create(*definition_id, &self.semantic).expect("invalid contract definition") + } +} + +impl EnumType { + pub fn definition(&self) -> Definition { + let types::Type::Enum { definition_id } = self.internal_type() else { + unreachable!("invalid enum type"); + }; + Definition::try_create(*definition_id, &self.semantic).expect("invalid enum definition") + } +} + +impl FixedPointNumberType { + pub fn signed(&self) -> bool { + let types::Type::FixedPointNumber { signed, .. } = self.internal_type() else { + unreachable!("invalid fixed point number type"); + }; + *signed + } + pub fn bits(&self) -> u32 { + let types::Type::FixedPointNumber { bits, .. } = self.internal_type() else { + unreachable!("invalid fixed point number type"); + }; + *bits + } + pub fn precision_bits(&self) -> u32 { + let types::Type::FixedPointNumber { precision_bits, .. } = self.internal_type() else { + unreachable!("invalid fixed point number type"); + }; + *precision_bits + } +} + +impl FunctionType { + pub fn associated_definition(&self) -> Option { + let types::Type::Function(function_type) = self.internal_type() else { + unreachable!("invalid function type"); + }; + function_type.definition_id.map(|definition_id| { + Definition::try_create(definition_id, &self.semantic) + .expect("invalid function definition") + }) + } + + pub fn implicit_receiver_type(&self) -> Option { + let types::Type::Function(function_type) = self.internal_type() else { + unreachable!("invalid function type"); + }; + function_type + .implicit_receiver_type + .map(|type_id| Type::create(type_id, &self.semantic)) + } + + pub fn parameter_types(&self) -> Vec { + let types::Type::Function(function_type) = self.internal_type() else { + unreachable!("invalid function type"); + }; + function_type + .parameter_types + .iter() + .map(|type_id| Type::create(*type_id, &self.semantic)) + .collect() + } + + pub fn return_type(&self) -> Type { + let types::Type::Function(function_type) = self.internal_type() else { + unreachable!("invalid function type"); + }; + Type::create(function_type.return_type, &self.semantic) + } + + pub fn external(&self) -> bool { + let types::Type::Function(function_type) = self.internal_type() else { + unreachable!("invalid function type"); + }; + function_type.external + } + + pub fn kind(&self) -> FunctionTypeKind { + let types::Type::Function(function_type) = self.internal_type() else { + unreachable!("invalid function type"); + }; + function_type.kind + } +} + +impl IntegerType { + pub fn signed(&self) -> bool { + let types::Type::Integer { signed, .. } = self.internal_type() else { + unreachable!("invalid integer type"); + }; + *signed + } + pub fn bits(&self) -> u32 { + let types::Type::Integer { bits, .. } = self.internal_type() else { + unreachable!("invalid integer type"); + }; + *bits + } +} + +impl InterfaceType { + pub fn definition(&self) -> Definition { + let types::Type::Interface { definition_id } = self.internal_type() else { + unreachable!("invalid interface type"); + }; + Definition::try_create(*definition_id, &self.semantic) + .expect("invalid interface definition") + } +} + +impl LiteralType {} + +impl MappingType { + pub fn key_type(&self) -> Type { + let types::Type::Mapping { key_type_id, .. } = self.internal_type() else { + unreachable!("invalid mapping type"); + }; + Type::create(*key_type_id, &self.semantic) + } + pub fn value_type(&self) -> Type { + let types::Type::Mapping { value_type_id, .. } = self.internal_type() else { + unreachable!("invalid mapping type"); + }; + Type::create(*value_type_id, &self.semantic) + } +} + +impl StringType { + pub fn location(&self) -> DataLocation { + let types::Type::String { location } = self.internal_type() else { + unreachable!("invalid string type"); + }; + *location + } +} + +impl StructType { + pub fn definition(&self) -> Definition { + let types::Type::Struct { definition_id, .. } = self.internal_type() else { + unreachable!("invalid struct type"); + }; + Definition::try_create(*definition_id, &self.semantic).expect("invalid struct definition") + } + pub fn location(&self) -> DataLocation { + let types::Type::Struct { location, .. } = self.internal_type() else { + unreachable!("invalid struct type"); + }; + *location + } +} + +impl TupleType { + pub fn types(&self) -> Vec { + let types::Type::Tuple { types } = self.internal_type() else { + unreachable!("invalid tuple type"); + }; + types + .iter() + .map(|type_id| Type::create(*type_id, &self.semantic)) + .collect() + } +} + +impl UserDefinedValueType { + pub fn definition(&self) -> Definition { + let types::Type::UserDefinedValue { definition_id } = self.internal_type() else { + unreachable!("invalid user defined value type"); + }; + Definition::try_create(*definition_id, &self.semantic) + .expect("invalid user defined value definition") + } +} + +impl VoidType {} diff --git a/crates/solidity/outputs/cargo/crate/src/backend/ir/ast/nodes.generated.rs b/crates/solidity/outputs/cargo/crate/src/backend/ir/ast/nodes.generated.rs index de6de060d6..50bf62fb3c 100644 --- a/crates/solidity/outputs/cargo/crate/src/backend/ir/ast/nodes.generated.rs +++ b/crates/solidity/outputs/cargo/crate/src/backend/ir/ast/nodes.generated.rs @@ -5,11 +5,11 @@ use std::rc::Rc; use paste::paste; -use super::input as input_ir; use super::node_extensions::{ create_identifier, create_yul_identifier, Identifier, IdentifierStruct, YulIdentifier, YulIdentifierStruct, }; +use super::{input as input_ir, Type}; use crate::backend::{binder, SemanticAnalysis}; use crate::cst::{NodeId, TerminalKind, TerminalNode, TextIndex}; @@ -48,6 +48,10 @@ impl SourceUnitStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type PragmaDirective = Rc; @@ -81,6 +85,10 @@ impl PragmaDirectiveStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type AbicoderPragma = Rc; @@ -114,6 +122,10 @@ impl AbicoderPragmaStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type ExperimentalPragma = Rc; @@ -147,6 +159,10 @@ impl ExperimentalPragmaStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type VersionPragma = Rc; @@ -180,6 +196,10 @@ impl VersionPragmaStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type VersionRange = Rc; @@ -217,6 +237,10 @@ impl VersionRangeStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type VersionTerm = Rc; @@ -257,6 +281,10 @@ impl VersionTermStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type PathImport = Rc; @@ -297,6 +325,10 @@ impl PathImportStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type ImportDeconstruction = Rc; @@ -334,6 +366,10 @@ impl ImportDeconstructionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type ImportDeconstructionSymbol = Rc; @@ -374,6 +410,10 @@ impl ImportDeconstructionSymbolStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type UsingDirective = Rc; @@ -415,6 +455,10 @@ impl UsingDirectiveStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type UsingDeconstruction = Rc; @@ -448,6 +492,10 @@ impl UsingDeconstructionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type UsingDeconstructionSymbol = Rc; @@ -488,6 +536,10 @@ impl UsingDeconstructionSymbolStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type ContractDefinition = Rc; @@ -540,6 +592,10 @@ impl ContractDefinitionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type InheritanceType = Rc; @@ -580,6 +636,10 @@ impl InheritanceTypeStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type InterfaceDefinition = Rc; @@ -624,6 +684,10 @@ impl InterfaceDefinitionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type LibraryDefinition = Rc; @@ -661,6 +725,10 @@ impl LibraryDefinitionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type StructDefinition = Rc; @@ -698,6 +766,10 @@ impl StructDefinitionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type StructMember = Rc; @@ -735,6 +807,10 @@ impl StructMemberStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type EnumDefinition = Rc; @@ -772,6 +848,10 @@ impl EnumDefinitionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type ConstantDefinition = Rc; @@ -823,6 +903,10 @@ impl ConstantDefinitionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type StateVariableDefinition = Rc; @@ -882,6 +966,10 @@ impl StateVariableDefinitionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type FunctionDefinition = Rc; @@ -963,6 +1051,10 @@ impl FunctionDefinitionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type Parameter = Rc; @@ -1014,6 +1106,10 @@ impl ParameterStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type OverrideSpecifier = Rc; @@ -1050,6 +1146,10 @@ impl OverrideSpecifierStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type ModifierInvocation = Rc; @@ -1090,6 +1190,10 @@ impl ModifierInvocationStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type EventDefinition = Rc; @@ -1131,6 +1235,10 @@ impl EventDefinitionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type UserDefinedValueTypeDefinition = Rc; @@ -1168,6 +1276,10 @@ impl UserDefinedValueTypeDefinitionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type ErrorDefinition = Rc; @@ -1205,6 +1317,10 @@ impl ErrorDefinitionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type ArrayTypeName = Rc; @@ -1245,6 +1361,10 @@ impl ArrayTypeNameStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type FunctionType = Rc; @@ -1293,6 +1413,10 @@ impl FunctionTypeStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type MappingType = Rc; @@ -1330,6 +1454,10 @@ impl MappingTypeStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type AddressType = Rc; @@ -1363,6 +1491,10 @@ impl AddressTypeStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type Block = Rc; @@ -1393,6 +1525,10 @@ impl BlockStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type UncheckedBlock = Rc; @@ -1426,6 +1562,10 @@ impl UncheckedBlockStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type ExpressionStatement = Rc; @@ -1459,6 +1599,10 @@ impl ExpressionStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type AssemblyStatement = Rc; @@ -1500,6 +1644,10 @@ impl AssemblyStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type TupleDeconstructionStatement = Rc; @@ -1537,6 +1685,10 @@ impl TupleDeconstructionStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type VariableDeclarationStatement = Rc; @@ -1591,6 +1743,10 @@ impl VariableDeclarationStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type IfStatement = Rc; @@ -1635,6 +1791,10 @@ impl IfStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type ForStatement = Rc; @@ -1683,6 +1843,10 @@ impl ForStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type WhileStatement = Rc; @@ -1720,6 +1884,10 @@ impl WhileStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type DoWhileStatement = Rc; @@ -1757,6 +1925,10 @@ impl DoWhileStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type ContinueStatement = Rc; @@ -1786,6 +1958,10 @@ impl ContinueStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type BreakStatement = Rc; @@ -1815,6 +1991,10 @@ impl BreakStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type ReturnStatement = Rc; @@ -1851,6 +2031,10 @@ impl ReturnStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type EmitStatement = Rc; @@ -1888,6 +2072,10 @@ impl EmitStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type TryStatement = Rc; @@ -1936,6 +2124,10 @@ impl TryStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type CatchClause = Rc; @@ -1976,6 +2168,10 @@ impl CatchClauseStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type CatchClauseError = Rc; @@ -2016,6 +2212,10 @@ impl CatchClauseErrorStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type RevertStatement = Rc; @@ -2053,6 +2253,10 @@ impl RevertStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type ThrowStatement = Rc; @@ -2082,6 +2286,10 @@ impl ThrowStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type AssignmentExpression = Rc; @@ -2123,6 +2331,10 @@ impl AssignmentExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type ConditionalExpression = Rc; @@ -2164,6 +2376,10 @@ impl ConditionalExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type OrExpression = Rc; @@ -2201,6 +2417,10 @@ impl OrExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type AndExpression = Rc; @@ -2238,6 +2458,10 @@ impl AndExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type EqualityExpression = Rc; @@ -2279,6 +2503,10 @@ impl EqualityExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type InequalityExpression = Rc; @@ -2320,6 +2548,10 @@ impl InequalityExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type BitwiseOrExpression = Rc; @@ -2357,6 +2589,10 @@ impl BitwiseOrExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type BitwiseXorExpression = Rc; @@ -2394,6 +2630,10 @@ impl BitwiseXorExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type BitwiseAndExpression = Rc; @@ -2431,6 +2671,10 @@ impl BitwiseAndExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type ShiftExpression = Rc; @@ -2472,6 +2716,10 @@ impl ShiftExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type AdditiveExpression = Rc; @@ -2513,6 +2761,10 @@ impl AdditiveExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type MultiplicativeExpression = Rc; @@ -2554,6 +2806,10 @@ impl MultiplicativeExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type ExponentiationExpression = Rc; @@ -2595,6 +2851,10 @@ impl ExponentiationExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type PostfixExpression = Rc; @@ -2632,6 +2892,10 @@ impl PostfixExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type PrefixExpression = Rc; @@ -2669,6 +2933,10 @@ impl PrefixExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type FunctionCallExpression = Rc; @@ -2706,6 +2974,10 @@ impl FunctionCallExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type CallOptionsExpression = Rc; @@ -2743,6 +3015,10 @@ impl CallOptionsExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type MemberAccessExpression = Rc; @@ -2780,6 +3056,10 @@ impl MemberAccessExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type IndexAccessExpression = Rc; @@ -2827,6 +3107,10 @@ impl IndexAccessExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type NamedArgument = Rc; @@ -2864,6 +3148,10 @@ impl NamedArgumentStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type TypeExpression = Rc; @@ -2897,6 +3185,10 @@ impl TypeExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type NewExpression = Rc; @@ -2930,6 +3222,10 @@ impl NewExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type TupleExpression = Rc; @@ -2963,6 +3259,10 @@ impl TupleExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type TupleValue = Rc; @@ -2999,6 +3299,10 @@ impl TupleValueStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type ArrayExpression = Rc; @@ -3032,6 +3336,10 @@ impl ArrayExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type HexNumberExpression = Rc; @@ -3072,6 +3380,10 @@ impl HexNumberExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type DecimalNumberExpression = Rc; @@ -3112,6 +3424,10 @@ impl DecimalNumberExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type YulBlock = Rc; @@ -3145,6 +3461,10 @@ impl YulBlockStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type YulFunctionDefinition = Rc; @@ -3193,6 +3513,10 @@ impl YulFunctionDefinitionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type YulVariableDeclarationStatement = Rc; @@ -3233,6 +3557,10 @@ impl YulVariableDeclarationStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type YulVariableDeclarationValue = Rc; @@ -3270,6 +3598,10 @@ impl YulVariableDeclarationValueStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type YulVariableAssignmentStatement = Rc; @@ -3311,6 +3643,10 @@ impl YulVariableAssignmentStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type YulColonAndEqual = Rc; @@ -3340,6 +3676,10 @@ impl YulColonAndEqualStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type YulStackAssignmentStatement = Rc; @@ -3377,6 +3717,10 @@ impl YulStackAssignmentStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type YulEqualAndColon = Rc; @@ -3406,6 +3750,10 @@ impl YulEqualAndColonStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type YulIfStatement = Rc; @@ -3443,6 +3791,10 @@ impl YulIfStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type YulForStatement = Rc; @@ -3488,6 +3840,10 @@ impl YulForStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type YulSwitchStatement = Rc; @@ -3525,6 +3881,10 @@ impl YulSwitchStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type YulDefaultCase = Rc; @@ -3558,6 +3918,10 @@ impl YulDefaultCaseStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type YulValueCase = Rc; @@ -3595,6 +3959,10 @@ impl YulValueCaseStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type YulLeaveStatement = Rc; @@ -3624,6 +3992,10 @@ impl YulLeaveStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type YulBreakStatement = Rc; @@ -3653,6 +4025,10 @@ impl YulBreakStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type YulContinueStatement = Rc; @@ -3682,6 +4058,10 @@ impl YulContinueStatementStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type YulLabel = Rc; @@ -3715,6 +4095,10 @@ impl YulLabelStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } pub type YulFunctionCallExpression = Rc; @@ -3752,6 +4136,10 @@ impl YulFunctionCallExpressionStruct { .get_text_offset_by_node_id(self.ir_node.node_id) .unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } // diff --git a/crates/solidity/outputs/cargo/crate/src/backend/ir/ast/nodes.rs.jinja2 b/crates/solidity/outputs/cargo/crate/src/backend/ir/ast/nodes.rs.jinja2 index 00c2df6fcf..7e09154b6a 100644 --- a/crates/solidity/outputs/cargo/crate/src/backend/ir/ast/nodes.rs.jinja2 +++ b/crates/solidity/outputs/cargo/crate/src/backend/ir/ast/nodes.rs.jinja2 @@ -11,6 +11,7 @@ use crate::backend::{binder, SemanticAnalysis}; use crate::cst::{NodeId, TerminalKind, TerminalNode, TextIndex}; use super::node_extensions::{Identifier, IdentifierStruct, YulIdentifier, YulIdentifierStruct}; use super::node_extensions::{create_identifier, create_yul_identifier}; +use super::Type; // // Sequences: @@ -99,6 +100,10 @@ use super::node_extensions::{create_identifier, create_yul_identifier}; pub fn text_offset(&self) -> TextIndex { self.semantic.get_text_offset_by_node_id(self.ir_node.node_id).unwrap() } + + pub fn get_type(&self) -> Option { + self.semantic.get_type_from_node_id(self.ir_node.node_id) + } } {% endfor %} diff --git a/crates/solidity/outputs/cargo/crate/src/backend/semantic/mod.rs b/crates/solidity/outputs/cargo/crate/src/backend/semantic/mod.rs index b3b7ea168f..c073daf33e 100644 --- a/crates/solidity/outputs/cargo/crate/src/backend/semantic/mod.rs +++ b/crates/solidity/outputs/cargo/crate/src/backend/semantic/mod.rs @@ -202,6 +202,13 @@ impl SemanticAnalysis { self.text_offsets.get(&node_id).copied() } + pub fn get_type_from_node_id(self: &Rc, node_id: NodeId) -> Option { + self.binder + .node_typing(node_id) + .as_type_id() + .map(|type_id| ast::Type::create(type_id, self)) + } + pub fn get_contracts_abi(self: &Rc) -> Vec { let mut contracts = Vec::new(); for file in self.files.values() { diff --git a/crates/solidity/outputs/cargo/crate/src/backend/types/mod.rs b/crates/solidity/outputs/cargo/crate/src/backend/types/mod.rs index 559e97016b..585b3e1902 100644 --- a/crates/solidity/outputs/cargo/crate/src/backend/types/mod.rs +++ b/crates/solidity/outputs/cargo/crate/src/backend/types/mod.rs @@ -8,6 +8,7 @@ pub use registry::TypeRegistry; #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct TypeId(usize); +// __SLANG_TYPE_TYPES__ keep in sync with AST types #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub enum Type { Address { diff --git a/crates/solidity/outputs/cargo/tests/src/backend/semantic/ast.rs b/crates/solidity/outputs/cargo/tests/src/backend/semantic/ast.rs index 7e245870a9..c02a1dea01 100644 --- a/crates/solidity/outputs/cargo/tests/src/backend/semantic/ast.rs +++ b/crates/solidity/outputs/cargo/tests/src/backend/semantic/ast.rs @@ -89,3 +89,77 @@ fn test_text_offsets() -> Result<()> { Ok(()) } + +#[test] +fn test_get_type() -> Result<()> { + let unit = fixtures::Counter::build_compilation_unit()?; + let semantic = unit.semantic_analysis(); + + let ownable = semantic + .find_contract_by_name("Ownable") + .expect("contract is found"); + + let state_variables = ownable + .members() + .iter() + .filter_map(|member| { + if let ast::ContractMember::StateVariableDefinition(definition) = member { + Some(definition) + } else { + None + } + }) + .collect::>(); + + assert_eq!(state_variables.len(), 1); + let owner = &state_variables[0]; + assert_eq!(owner.name().name(), "_owner"); + + let owner_type = owner + .get_type() + .expect("_owner state variable has resolved type"); + assert!(matches!(owner_type, ast::Type::Address(_))); + + Ok(()) +} + +#[test] +fn test_function_get_type() -> Result<()> { + let unit = fixtures::Counter::build_compilation_unit()?; + let semantic = unit.semantic_analysis(); + + let counter = semantic + .find_contract_by_name("Counter") + .expect("contract is found"); + + let increment = counter + .members() + .iter() + .find_map(|member| { + if let ast::ContractMember::FunctionDefinition(function_definition) = member { + if function_definition + .name() + .is_some_and(|name| name.name() == "increment") + { + Some(function_definition) + } else { + None + } + } else { + None + } + }) + .expect("increment method is found"); + + let increment_type = increment.get_type().expect("increment method has a type"); + let ast::Type::Function(function_type) = increment_type else { + panic!("method's type is expect to be a function"); + }; + assert!(function_type.external()); + assert!(matches!(function_type.return_type(), ast::Type::Integer(_))); + assert!(function_type + .associated_definition() + .is_some_and(|definition| matches!(definition, ast::Definition::Function(_)))); + + Ok(()) +}