Skip to content

Commit 24ecf61

Browse files
authored
Expose typing information through the AST API (#1514)
This PR adds a `get_type()` method to AST node types to expose the typing information obtained during the binding passes through a public `Type` interface. Similar to the AST nodes and the definitions, this `Type` is a façade to the underlying `binder::Type` and the `SemanticAnalysis` object, which allows navigation to nested types and related definitions.
1 parent de0c541 commit 24ecf61

File tree

8 files changed

+832
-2
lines changed

8 files changed

+832
-2
lines changed

crates/solidity/outputs/cargo/crate/src/backend/ir/ast/node_extensions/identifiers.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::rc::Rc;
22

33
use super::super::IdentifierPathStruct;
4-
use super::Definition;
4+
use super::{Definition, Type};
55
use crate::backend::SemanticAnalysis;
66
use crate::cst::{NodeId, TerminalKind, TerminalNode, TextIndex};
77

@@ -88,6 +88,10 @@ impl IdentifierStruct {
8888
self.semantic.references_binding_to(self.ir_node.id())
8989
}
9090

91+
pub fn get_type(&self) -> Option<Type> {
92+
self.semantic.get_type_from_node_id(self.ir_node.id())
93+
}
94+
9195
pub fn text_offset(&self) -> TextIndex {
9296
self.semantic
9397
.get_text_offset_by_node_id(self.ir_node.id())

crates/solidity/outputs/cargo/crate/src/backend/ir/ast/node_extensions/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ pub use identifiers::{
1212
Identifier, IdentifierStruct, Reference, YulIdentifier, YulIdentifierStruct,
1313
};
1414

15+
mod types;
16+
pub use types::Type;
17+
1518
impl SourceUnitStruct {
1619
pub fn file_id(&self) -> String {
1720
self.semantic
Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
use std::rc::Rc;
2+
3+
use paste::paste;
4+
5+
use super::Definition;
6+
use crate::backend::types::{self, DataLocation, FunctionTypeKind, TypeId};
7+
use crate::backend::SemanticAnalysis;
8+
9+
// __SLANG_TYPE_TYPES__ keep in sync with binder types
10+
#[derive(Clone)]
11+
pub enum Type {
12+
Address(AddressType),
13+
Array(ArrayType),
14+
Boolean(BooleanType),
15+
ByteArray(ByteArrayType),
16+
Bytes(BytesType),
17+
Contract(ContractType),
18+
Enum(EnumType),
19+
FixedPointNumber(FixedPointNumberType),
20+
Function(FunctionType),
21+
Integer(IntegerType),
22+
Interface(InterfaceType),
23+
Literal(LiteralType),
24+
Mapping(MappingType),
25+
String(StringType),
26+
Struct(StructType),
27+
Tuple(TupleType),
28+
UserDefinedValue(UserDefinedValueType),
29+
Void(VoidType),
30+
}
31+
32+
macro_rules! define_type_variant {
33+
($type:ident) => {
34+
paste! {
35+
#[derive(Clone)]
36+
pub struct [<$type Type>] {
37+
type_id: TypeId,
38+
semantic: Rc<SemanticAnalysis>,
39+
}
40+
41+
impl [<$type Type>] {
42+
#[allow(unused)]
43+
fn internal_type(&self) -> &types::Type {
44+
self.semantic.types.get_type_by_id(self.type_id)
45+
}
46+
}
47+
}
48+
};
49+
}
50+
51+
define_type_variant!(Address);
52+
define_type_variant!(Array);
53+
define_type_variant!(Boolean);
54+
define_type_variant!(ByteArray);
55+
define_type_variant!(Bytes);
56+
define_type_variant!(Contract);
57+
define_type_variant!(Enum);
58+
define_type_variant!(FixedPointNumber);
59+
define_type_variant!(Function);
60+
define_type_variant!(Integer);
61+
define_type_variant!(Interface);
62+
define_type_variant!(Literal);
63+
define_type_variant!(Mapping);
64+
define_type_variant!(String);
65+
define_type_variant!(Struct);
66+
define_type_variant!(Tuple);
67+
define_type_variant!(UserDefinedValue);
68+
define_type_variant!(Void);
69+
70+
impl Type {
71+
pub fn create(type_id: TypeId, semantic: &Rc<SemanticAnalysis>) -> Self {
72+
let type_ = semantic.types().get_type_by_id(type_id);
73+
let semantic = Rc::clone(semantic);
74+
match type_ {
75+
types::Type::Address { .. } => Self::Address(AddressType { type_id, semantic }),
76+
types::Type::Array { .. } => Self::Array(ArrayType { type_id, semantic }),
77+
types::Type::Boolean => Self::Boolean(BooleanType { type_id, semantic }),
78+
types::Type::ByteArray { .. } => Self::ByteArray(ByteArrayType { type_id, semantic }),
79+
types::Type::Bytes { .. } => Self::Bytes(BytesType { type_id, semantic }),
80+
types::Type::Contract { .. } => Self::Contract(ContractType { type_id, semantic }),
81+
types::Type::Enum { .. } => Self::Enum(EnumType { type_id, semantic }),
82+
types::Type::FixedPointNumber { .. } => {
83+
Self::FixedPointNumber(FixedPointNumberType { type_id, semantic })
84+
}
85+
types::Type::Function(_) => Self::Function(FunctionType { type_id, semantic }),
86+
types::Type::Integer { .. } => Self::Integer(IntegerType { type_id, semantic }),
87+
types::Type::Interface { .. } => Self::Interface(InterfaceType { type_id, semantic }),
88+
types::Type::Literal(_) => Self::Literal(LiteralType { type_id, semantic }),
89+
types::Type::Mapping { .. } => Self::Mapping(MappingType { type_id, semantic }),
90+
types::Type::String { .. } => Self::String(StringType { type_id, semantic }),
91+
types::Type::Struct { .. } => Self::Struct(StructType { type_id, semantic }),
92+
types::Type::Tuple { .. } => Self::Tuple(TupleType { type_id, semantic }),
93+
types::Type::UserDefinedValue { .. } => {
94+
Self::UserDefinedValue(UserDefinedValueType { type_id, semantic })
95+
}
96+
types::Type::Void => Self::Void(VoidType { type_id, semantic }),
97+
}
98+
}
99+
100+
pub fn type_id(&self) -> TypeId {
101+
match self {
102+
Type::Address(details) => details.type_id,
103+
Type::Array(details) => details.type_id,
104+
Type::Boolean(details) => details.type_id,
105+
Type::ByteArray(details) => details.type_id,
106+
Type::Bytes(details) => details.type_id,
107+
Type::Contract(details) => details.type_id,
108+
Type::Enum(details) => details.type_id,
109+
Type::FixedPointNumber(details) => details.type_id,
110+
Type::Function(details) => details.type_id,
111+
Type::Integer(details) => details.type_id,
112+
Type::Interface(details) => details.type_id,
113+
Type::Literal(details) => details.type_id,
114+
Type::Mapping(details) => details.type_id,
115+
Type::String(details) => details.type_id,
116+
Type::Struct(details) => details.type_id,
117+
Type::Tuple(details) => details.type_id,
118+
Type::UserDefinedValue(details) => details.type_id,
119+
Type::Void(details) => details.type_id,
120+
}
121+
}
122+
}
123+
124+
impl AddressType {
125+
pub fn payable(&self) -> bool {
126+
let types::Type::Address { payable } = self.internal_type() else {
127+
unreachable!("invalid address type");
128+
};
129+
*payable
130+
}
131+
}
132+
133+
impl ArrayType {
134+
pub fn element_type(&self) -> Type {
135+
let types::Type::Array { element_type, .. } = self.internal_type() else {
136+
unreachable!("invalid array type");
137+
};
138+
Type::create(*element_type, &self.semantic)
139+
}
140+
pub fn location(&self) -> DataLocation {
141+
let types::Type::Array { location, .. } = self.internal_type() else {
142+
unreachable!("invalid array type");
143+
};
144+
*location
145+
}
146+
}
147+
148+
impl BooleanType {}
149+
150+
impl ByteArrayType {
151+
pub fn width(&self) -> u32 {
152+
let types::Type::ByteArray { width } = self.internal_type() else {
153+
unreachable!("invalid byte array type");
154+
};
155+
*width
156+
}
157+
}
158+
159+
impl BytesType {
160+
pub fn location(&self) -> DataLocation {
161+
let types::Type::Bytes { location } = self.internal_type() else {
162+
unreachable!("invalid bytes type");
163+
};
164+
*location
165+
}
166+
}
167+
168+
impl ContractType {
169+
pub fn definition(&self) -> Definition {
170+
let types::Type::Contract { definition_id } = self.internal_type() else {
171+
unreachable!("invalid contract type");
172+
};
173+
Definition::try_create(*definition_id, &self.semantic).expect("invalid contract definition")
174+
}
175+
}
176+
177+
impl EnumType {
178+
pub fn definition(&self) -> Definition {
179+
let types::Type::Enum { definition_id } = self.internal_type() else {
180+
unreachable!("invalid enum type");
181+
};
182+
Definition::try_create(*definition_id, &self.semantic).expect("invalid enum definition")
183+
}
184+
}
185+
186+
impl FixedPointNumberType {
187+
pub fn signed(&self) -> bool {
188+
let types::Type::FixedPointNumber { signed, .. } = self.internal_type() else {
189+
unreachable!("invalid fixed point number type");
190+
};
191+
*signed
192+
}
193+
pub fn bits(&self) -> u32 {
194+
let types::Type::FixedPointNumber { bits, .. } = self.internal_type() else {
195+
unreachable!("invalid fixed point number type");
196+
};
197+
*bits
198+
}
199+
pub fn precision_bits(&self) -> u32 {
200+
let types::Type::FixedPointNumber { precision_bits, .. } = self.internal_type() else {
201+
unreachable!("invalid fixed point number type");
202+
};
203+
*precision_bits
204+
}
205+
}
206+
207+
impl FunctionType {
208+
pub fn associated_definition(&self) -> Option<Definition> {
209+
let types::Type::Function(function_type) = self.internal_type() else {
210+
unreachable!("invalid function type");
211+
};
212+
function_type.definition_id.map(|definition_id| {
213+
Definition::try_create(definition_id, &self.semantic)
214+
.expect("invalid function definition")
215+
})
216+
}
217+
218+
pub fn implicit_receiver_type(&self) -> Option<Type> {
219+
let types::Type::Function(function_type) = self.internal_type() else {
220+
unreachable!("invalid function type");
221+
};
222+
function_type
223+
.implicit_receiver_type
224+
.map(|type_id| Type::create(type_id, &self.semantic))
225+
}
226+
227+
pub fn parameter_types(&self) -> Vec<Type> {
228+
let types::Type::Function(function_type) = self.internal_type() else {
229+
unreachable!("invalid function type");
230+
};
231+
function_type
232+
.parameter_types
233+
.iter()
234+
.map(|type_id| Type::create(*type_id, &self.semantic))
235+
.collect()
236+
}
237+
238+
pub fn return_type(&self) -> Type {
239+
let types::Type::Function(function_type) = self.internal_type() else {
240+
unreachable!("invalid function type");
241+
};
242+
Type::create(function_type.return_type, &self.semantic)
243+
}
244+
245+
pub fn external(&self) -> bool {
246+
let types::Type::Function(function_type) = self.internal_type() else {
247+
unreachable!("invalid function type");
248+
};
249+
function_type.external
250+
}
251+
252+
pub fn kind(&self) -> FunctionTypeKind {
253+
let types::Type::Function(function_type) = self.internal_type() else {
254+
unreachable!("invalid function type");
255+
};
256+
function_type.kind
257+
}
258+
}
259+
260+
impl IntegerType {
261+
pub fn signed(&self) -> bool {
262+
let types::Type::Integer { signed, .. } = self.internal_type() else {
263+
unreachable!("invalid integer type");
264+
};
265+
*signed
266+
}
267+
pub fn bits(&self) -> u32 {
268+
let types::Type::Integer { bits, .. } = self.internal_type() else {
269+
unreachable!("invalid integer type");
270+
};
271+
*bits
272+
}
273+
}
274+
275+
impl InterfaceType {
276+
pub fn definition(&self) -> Definition {
277+
let types::Type::Interface { definition_id } = self.internal_type() else {
278+
unreachable!("invalid interface type");
279+
};
280+
Definition::try_create(*definition_id, &self.semantic)
281+
.expect("invalid interface definition")
282+
}
283+
}
284+
285+
impl LiteralType {}
286+
287+
impl MappingType {
288+
pub fn key_type(&self) -> Type {
289+
let types::Type::Mapping { key_type_id, .. } = self.internal_type() else {
290+
unreachable!("invalid mapping type");
291+
};
292+
Type::create(*key_type_id, &self.semantic)
293+
}
294+
pub fn value_type(&self) -> Type {
295+
let types::Type::Mapping { value_type_id, .. } = self.internal_type() else {
296+
unreachable!("invalid mapping type");
297+
};
298+
Type::create(*value_type_id, &self.semantic)
299+
}
300+
}
301+
302+
impl StringType {
303+
pub fn location(&self) -> DataLocation {
304+
let types::Type::String { location } = self.internal_type() else {
305+
unreachable!("invalid string type");
306+
};
307+
*location
308+
}
309+
}
310+
311+
impl StructType {
312+
pub fn definition(&self) -> Definition {
313+
let types::Type::Struct { definition_id, .. } = self.internal_type() else {
314+
unreachable!("invalid struct type");
315+
};
316+
Definition::try_create(*definition_id, &self.semantic).expect("invalid struct definition")
317+
}
318+
pub fn location(&self) -> DataLocation {
319+
let types::Type::Struct { location, .. } = self.internal_type() else {
320+
unreachable!("invalid struct type");
321+
};
322+
*location
323+
}
324+
}
325+
326+
impl TupleType {
327+
pub fn types(&self) -> Vec<Type> {
328+
let types::Type::Tuple { types } = self.internal_type() else {
329+
unreachable!("invalid tuple type");
330+
};
331+
types
332+
.iter()
333+
.map(|type_id| Type::create(*type_id, &self.semantic))
334+
.collect()
335+
}
336+
}
337+
338+
impl UserDefinedValueType {
339+
pub fn definition(&self) -> Definition {
340+
let types::Type::UserDefinedValue { definition_id } = self.internal_type() else {
341+
unreachable!("invalid user defined value type");
342+
};
343+
Definition::try_create(*definition_id, &self.semantic)
344+
.expect("invalid user defined value definition")
345+
}
346+
}
347+
348+
impl VoidType {}

0 commit comments

Comments
 (0)