Bläddra i källkod

Load readonly members in codegen (#1325)

Signed-off-by: Lucas Steuernagel <lucas.tnagel@gmail.com>
Lucas Steuernagel 2 år sedan
förälder
incheckning
c9b6a73331

+ 33 - 8
src/codegen/expression.rs

@@ -659,12 +659,37 @@ pub fn expression(
             ty,
             expr: var,
             field: member,
-        } => Expression::StructMember {
-            loc: *loc,
-            ty: ty.clone(),
-            expr: Box::new(expression(var, cfg, contract_no, func, ns, vartab, opt)),
-            member: *member,
-        },
+        } => {
+            let readonly = if let Type::Struct(struct_type) = var.ty().deref_memory() {
+                let definition = struct_type.definition(ns);
+                definition.fields[*member].readonly
+            } else {
+                false
+            };
+
+            let member_ty = if readonly {
+                Type::Ref(Box::new(ty.clone()))
+            } else {
+                ty.clone()
+            };
+
+            let member_ptr = Expression::StructMember {
+                loc: *loc,
+                ty: member_ty,
+                expr: Box::new(expression(var, cfg, contract_no, func, ns, vartab, opt)),
+                member: *member,
+            };
+
+            if readonly {
+                Expression::Load {
+                    loc: *loc,
+                    ty: ty.clone(),
+                    expr: Box::new(member_ptr),
+                }
+            } else {
+                member_ptr
+            }
+        }
         ast::Expression::StringCompare { loc, left, right } => Expression::StringCompare {
             loc: *loc,
             left: string_location(left, cfg, contract_no, func, ns, vartab, opt),
@@ -3136,7 +3161,7 @@ fn array_subscript(
                 expression(&ast_big_int, cfg, contract_no, func, ns, vartab, opt)
             }
         },
-        Type::DynamicBytes => Expression::Builtin {
+        Type::DynamicBytes | Type::Slice(_) => Expression::Builtin {
             loc: *loc,
             tys: vec![Type::Uint(32)],
             kind: Builtin::ArrayLength,
@@ -3382,7 +3407,7 @@ fn array_subscript(
         }
     } else {
         match array_ty.deref_memory() {
-            Type::DynamicBytes | Type::Array(..) => Expression::Subscript {
+            Type::DynamicBytes | Type::Array(..) | Type::Slice(_) => Expression::Subscript {
                 loc: *loc,
                 ty: elem_ty.clone(),
                 array_ty: array_ty.clone(),

+ 13 - 6
src/codegen/solana_deploy.rs

@@ -116,17 +116,24 @@ pub(super) fn solana_deploy(
         .into(),
     };
 
+    let loaded_item = Expression::Load {
+        loc: Loc::Codegen,
+        ty: Type::Slice(Box::new(Type::Bytes(1))),
+        expr: Expression::StructMember {
+            loc: Loc::Codegen,
+            ty: Type::Ref(Box::new(Type::Slice(Box::new(Type::Bytes(1))))),
+            expr: tx_account_0.into(),
+            member: 2,
+        }
+        .into(),
+    };
+
     // .data.length
     let account_length = Expression::Builtin {
         loc: Loc::Codegen,
         tys: vec![Type::Uint(32)],
         kind: Builtin::ArrayLength,
-        args: vec![Expression::StructMember {
-            loc: Loc::Codegen,
-            ty: Type::DynamicBytes,
-            expr: tx_account_0.into(),
-            member: 2,
-        }],
+        args: vec![loaded_item],
     };
 
     let account_data_var = vartab.temp_name("data_length", &Type::Uint(32));

+ 21 - 99
src/emit/solana/mod.rs

@@ -4,12 +4,15 @@ pub(super) mod target;
 
 use crate::sema::ast;
 use crate::Target;
+use std::cmp::Ordering;
 
 use crate::codegen::{cfg::ReturnCode, Options};
 use crate::sema::ast::Type;
 use inkwell::module::{Linkage, Module};
 use inkwell::types::BasicType;
-use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, UnnamedAddress};
+use inkwell::values::{
+    BasicValue, BasicValueEnum, FunctionValue, IntValue, PointerValue, UnnamedAddress,
+};
 use inkwell::{context::Context, types::BasicTypeEnum};
 use inkwell::{AddressSpace, IntPredicate};
 use num_traits::ToPrimitive;
@@ -978,40 +981,12 @@ impl SolanaTarget {
             .module
             .get_struct_type("struct.SolAccountInfo")
             .unwrap();
-        match member {
-            // key
-            0 => {
-                let key = binary
-                    .builder
-                    .build_load(
-                        binary
-                            .module
-                            .get_struct_type("struct.SolPubkey")
-                            .unwrap()
-                            .ptr_type(AddressSpace::default()),
-                        binary
-                            .builder
-                            .build_struct_gep(account_info_ty, account_info, 0, "key")
-                            .unwrap(),
-                        "key",
-                    )
-                    .into_pointer_value();
 
-                binary
-                    .builder
-                    .build_load(binary.address_type(ns), key, "key")
-            }
-            // lamports
-            1 => binary.builder.build_load(
-                binary.context.i64_type().ptr_type(AddressSpace::default()),
-                binary
-                    .builder
-                    .build_struct_gep(account_info_ty, account_info, 1, "lamports")
-                    .unwrap(),
-                "lamports",
-            ),
-            // data
-            2 => {
+        let gep_no = match member.cmp(&2) {
+            Ordering::Less => member as u32,
+            Ordering::Greater => (member + 1) as u32,
+            Ordering::Equal => {
+                // The data field is transformed into a slice, so we do not return it directly.
                 let data_len = binary
                     .builder
                     .build_load(
@@ -1059,73 +1034,20 @@ impl SolanaTarget {
                     .unwrap();
                 binary.builder.build_store(data_len_elem, data_len);
 
-                binary.builder.build_load(
-                    binary.llvm_type(&ast::Type::Slice(Box::new(Type::Bytes(1))), ns),
-                    slice_alloca,
-                    "data_slice",
-                )
+                return slice_alloca.as_basic_value_enum();
             }
-            // owner
-            3 => {
-                let owner = binary
-                    .builder
-                    .build_load(
-                        binary
-                            .module
-                            .get_struct_type("struct.SolPubkey")
-                            .unwrap()
-                            .ptr_type(AddressSpace::default()),
-                        binary
-                            .builder
-                            .build_struct_gep(account_info_ty, account_info, 4, "owner")
-                            .unwrap(),
-                        "owner",
-                    )
-                    .into_pointer_value();
-
-                binary
-                    .builder
-                    .build_load(binary.address_type(ns), owner, "owner")
-            }
-            // rent epoch
-            4 => {
-                let rent_epoch = binary
-                    .builder
-                    .build_struct_gep(account_info_ty, account_info, 5, "rent_epoch")
-                    .unwrap();
-
-                binary
-                    .builder
-                    .build_load(binary.context.i64_type(), rent_epoch, "rent_epoch")
-            }
-            // remaining fields are bool
-            _ => {
-                let bool_field = binary
-                    .builder
-                    .build_struct_gep(
-                        account_info_ty,
-                        account_info,
-                        member as u32 + 1,
-                        "bool_field",
-                    )
-                    .unwrap();
-
-                let value = binary
-                    .builder
-                    .build_load(binary.context.i8_type(), bool_field, "bool_field")
-                    .into_int_value();
+        };
 
-                binary
-                    .builder
-                    .build_int_compare(
-                        IntPredicate::NE,
-                        value,
-                        value.get_type().const_zero(),
-                        "is_non_zero",
-                    )
-                    .into()
-            }
-        }
+        binary
+            .builder
+            .build_struct_gep(
+                account_info_ty,
+                account_info,
+                gep_no,
+                format!("AccountInfo_member_{}", member).as_str(),
+            )
+            .unwrap()
+            .as_basic_value_enum()
     }
 
     /// Construct the LLVM-IR to call 'external_call' from solana.c

+ 74 - 74
src/sema/builtin.rs

@@ -21,7 +21,7 @@ use std::path::PathBuf;
 pub struct Prototype {
     pub builtin: Builtin,
     pub namespace: Option<&'static str>,
-    pub method: Option<Type>,
+    pub method: Vec<Type>,
     pub name: &'static str,
     pub params: Vec<Type>,
     pub ret: Vec<Type>,
@@ -37,7 +37,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Assert,
             namespace: None,
-            method: None,
+            method: vec![],
             name: "assert",
             params: vec![Type::Bool],
             ret: vec![Type::Void],
@@ -48,7 +48,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Print,
             namespace: None,
-            method: None,
+            method: vec![],
             name: "print",
             params: vec![Type::String],
             ret: vec![Type::Void],
@@ -59,7 +59,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Require,
             namespace: None,
-            method: None,
+            method: vec![],
             name: "require",
             params: vec![Type::Bool],
             ret: vec![Type::Void],
@@ -70,7 +70,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Require,
             namespace: None,
-            method: None,
+            method: vec![],
             name: "require",
             params: vec![Type::Bool, Type::String],
             ret: vec![Type::Void],
@@ -81,7 +81,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::SelfDestruct,
             namespace: None,
-            method: None,
+            method: vec![],
             name: "selfdestruct",
             params: vec![Type::Address(true)],
             ret: vec![Type::Unreachable],
@@ -92,7 +92,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Keccak256,
             namespace: None,
-            method: None,
+            method: vec![],
             name: "keccak256",
             params: vec![Type::DynamicBytes],
             ret: vec![Type::Bytes(32)],
@@ -103,7 +103,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Ripemd160,
             namespace: None,
-            method: None,
+            method: vec![],
             name: "ripemd160",
             params: vec![Type::DynamicBytes],
             ret: vec![Type::Bytes(20)],
@@ -114,7 +114,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Sha256,
             namespace: None,
-            method: None,
+            method: vec![],
             name: "sha256",
             params: vec![Type::DynamicBytes],
             ret: vec![Type::Bytes(32)],
@@ -125,7 +125,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Blake2_128,
             namespace: None,
-            method: None,
+            method: vec![],
             name: "blake2_128",
             params: vec![Type::DynamicBytes],
             ret: vec![Type::Bytes(16)],
@@ -136,7 +136,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Blake2_256,
             namespace: None,
-            method: None,
+            method: vec![],
             name: "blake2_256",
             params: vec![Type::DynamicBytes],
             ret: vec![Type::Bytes(32)],
@@ -147,7 +147,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Gasleft,
             namespace: None,
-            method: None,
+            method: vec![],
             name: "gasleft",
             params: vec![],
             ret: vec![Type::Uint(64)],
@@ -158,7 +158,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::BlockHash,
             namespace: None,
-            method: None,
+            method: vec![],
             name: "blockhash",
             params: vec![Type::Uint(64)],
             ret: vec![Type::Bytes(32)],
@@ -169,7 +169,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::AbiDecode,
             namespace: Some("abi"),
-            method: None,
+            method: vec![],
             name: "decode",
             params: vec![Type::DynamicBytes],
             ret: vec![],
@@ -180,7 +180,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::AbiEncode,
             namespace: Some("abi"),
-            method: None,
+            method: vec![],
             name: "encode",
             params: vec![],
             ret: vec![],
@@ -192,7 +192,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::AbiEncodePacked,
             namespace: Some("abi"),
-            method: None,
+            method: vec![],
             name: "encodePacked",
             params: vec![],
             ret: vec![],
@@ -204,7 +204,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::AbiEncodeWithSelector,
             namespace: Some("abi"),
-            method: None,
+            method: vec![],
             name: "encodeWithSelector",
             params: vec![Type::FunctionSelector],
             ret: vec![],
@@ -216,7 +216,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::AbiEncodeWithSignature,
             namespace: Some("abi"),
-            method: None,
+            method: vec![],
             name: "encodeWithSignature",
             params: vec![Type::String],
             ret: vec![],
@@ -228,7 +228,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::AbiEncodeCall,
             namespace: Some("abi"),
-            method: None,
+            method: vec![],
             name: "encodeCall",
             params: vec![],
             ret: vec![],
@@ -240,7 +240,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Gasprice,
             namespace: Some("tx"),
-            method: None,
+            method: vec![],
             name: "gasprice",
             params: vec![Type::Uint(64)],
             ret: vec![Type::Value],
@@ -251,7 +251,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::MulMod,
             namespace: None,
-            method: None,
+            method: vec![],
             name: "mulmod",
             params: vec![Type::Uint(256), Type::Uint(256), Type::Uint(256)],
             ret: vec![Type::Uint(256)],
@@ -263,7 +263,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::AddMod,
             namespace: None,
-            method: None,
+            method: vec![],
             name: "addmod",
             params: vec![Type::Uint(256), Type::Uint(256), Type::Uint(256)],
             ret: vec![Type::Uint(256)],
@@ -275,7 +275,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::SignatureVerify,
             namespace: None,
-            method: None,
+            method: vec![],
             name: "signatureVerify",
             params: vec![Type::Address(false), Type::DynamicBytes, Type::DynamicBytes],
             ret: vec![Type::Bool],
@@ -286,7 +286,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::UserTypeWrap,
             namespace: None,
-            method: Some(Type::UserType(0)),
+            method: vec![Type::UserType(0)],
             name: "wrap",
             params: vec![],
             ret: vec![Type::UserType(0)],
@@ -297,7 +297,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::UserTypeUnwrap,
             namespace: None,
-            method: Some(Type::UserType(0)),
+            method: vec![Type::UserType(0)],
             name: "unwrap",
             params: vec![Type::UserType(0)],
             ret: vec![],
@@ -314,7 +314,7 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::BlockCoinbase,
             namespace: Some("block"),
-            method: None,
+            method: vec![],
             name: "coinbase",
             params: vec![],
             ret: vec![Type::Address(true)],
@@ -325,7 +325,7 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::BlockDifficulty,
             namespace: Some("block"),
-            method: None,
+            method: vec![],
             name: "difficulty",
             params: vec![],
             ret: vec![Type::Uint(256)],
@@ -336,7 +336,7 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::GasLimit,
             namespace: Some("block"),
-            method: None,
+            method: vec![],
             name: "gaslimit",
             params: vec![],
             ret: vec![Type::Uint(64)],
@@ -347,7 +347,7 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::BlockNumber,
             namespace: Some("block"),
-            method: None,
+            method: vec![],
             name: "number",
             params: vec![],
             ret: vec![Type::Uint(64)],
@@ -358,7 +358,7 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Slot,
             namespace: Some("block"),
-            method: None,
+            method: vec![],
             name: "slot",
             params: vec![],
             ret: vec![Type::Uint(64)],
@@ -369,7 +369,7 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::ProgramId,
             namespace: Some("tx"),
-            method: None,
+            method: vec![],
             name: "program_id",
             params: vec![],
             ret: vec![Type::Address(false)],
@@ -380,7 +380,7 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Timestamp,
             namespace: Some("block"),
-            method: None,
+            method: vec![],
             name: "timestamp",
             params: vec![],
             ret: vec![Type::Uint(64)],
@@ -391,7 +391,7 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::MinimumBalance,
             namespace: Some("block"),
-            method: None,
+            method: vec![],
             name: "minimum_balance",
             params: vec![],
             ret: vec![Type::Value],
@@ -402,7 +402,7 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::ChainId,
             namespace: Some("block"),
-            method: None,
+            method: vec![],
             name: "chainid",
             params: vec![],
             ret: vec![Type::Uint(256)],
@@ -413,7 +413,7 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::BaseFee,
             namespace: Some("block"),
-            method: None,
+            method: vec![],
             name: "basefee",
             params: vec![],
             ret: vec![Type::Uint(256)],
@@ -424,7 +424,7 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::PrevRandao,
             namespace: Some("block"),
-            method: None,
+            method: vec![],
             name: "prevrandao",
             params: vec![],
             ret: vec![Type::Uint(256)],
@@ -435,7 +435,7 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Calldata,
             namespace: Some("msg"),
-            method: None,
+            method: vec![],
             name: "data",
             params: vec![],
             ret: vec![Type::DynamicBytes],
@@ -446,7 +446,7 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Sender,
             namespace: Some("msg"),
-            method: None,
+            method: vec![],
             name: "sender",
             params: vec![],
             ret: vec![Type::Address(true)],
@@ -457,7 +457,7 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Signature,
             namespace: Some("msg"),
-            method: None,
+            method: vec![],
             name: "sig",
             params: vec![],
             ret: vec![Type::FunctionSelector],
@@ -468,7 +468,7 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Value,
             namespace: Some("msg"),
-            method: None,
+            method: vec![],
             name: "value",
             params: vec![],
             ret: vec![Type::Value],
@@ -479,7 +479,7 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Gasprice,
             namespace: Some("tx"),
-            method: None,
+            method: vec![],
             name: "gasprice",
             params: vec![],
             ret: vec![Type::Value],
@@ -490,7 +490,7 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Origin,
             namespace: Some("tx"),
-            method: None,
+            method: vec![],
             name: "origin",
             params: vec![],
             ret: vec![Type::Address(false)],
@@ -501,7 +501,7 @@ static BUILTIN_VARIABLE: Lazy<[Prototype; 18]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::Accounts,
             namespace: Some("tx"),
-            method: None,
+            method: vec![],
             name: "accounts",
             params: vec![],
             ret: vec![Type::Array(
@@ -521,7 +521,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::ReadInt8,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes, Type::Slice(Box::new(Type::Bytes(1)))],
             name: "readInt8",
             params: vec![Type::Uint(32)],
             ret: vec![Type::Int(8)],
@@ -532,7 +532,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::ReadInt16LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes, Type::Slice(Box::new(Type::Bytes(1)))],
             name: "readInt16LE",
             params: vec![Type::Uint(32)],
             ret: vec![Type::Int(16)],
@@ -543,7 +543,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::ReadInt32LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes, Type::Slice(Box::new(Type::Bytes(1)))],
             name: "readInt32LE",
             params: vec![Type::Uint(32)],
             ret: vec![Type::Int(32)],
@@ -554,7 +554,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::ReadInt64LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes, Type::Slice(Box::new(Type::Bytes(1)))],
             name: "readInt64LE",
             params: vec![Type::Uint(32)],
             ret: vec![Type::Int(64)],
@@ -565,7 +565,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::ReadInt128LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes, Type::Slice(Box::new(Type::Bytes(1)))],
             name: "readInt128LE",
             params: vec![Type::Uint(32)],
             ret: vec![Type::Int(128)],
@@ -576,7 +576,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::ReadInt256LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes, Type::Slice(Box::new(Type::Bytes(1)))],
             name: "readInt256LE",
             params: vec![Type::Uint(32)],
             ret: vec![Type::Int(256)],
@@ -587,7 +587,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::ReadUint8,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes, Type::Slice(Box::new(Type::Bytes(1)))],
             name: "readUint8",
             params: vec![Type::Uint(32)],
             ret: vec![Type::Uint(8)],
@@ -598,7 +598,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::ReadUint16LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes, Type::Slice(Box::new(Type::Bytes(1)))],
             name: "readUint16LE",
             params: vec![Type::Uint(32)],
             ret: vec![Type::Uint(16)],
@@ -609,7 +609,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::ReadUint32LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes, Type::Slice(Box::new(Type::Bytes(1)))],
             name: "readUint32LE",
             params: vec![Type::Uint(32)],
             ret: vec![Type::Uint(32)],
@@ -620,7 +620,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::ReadUint64LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes, Type::Slice(Box::new(Type::Bytes(1)))],
             name: "readUint64LE",
             params: vec![Type::Uint(32)],
             ret: vec![Type::Uint(64)],
@@ -631,7 +631,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::ReadUint128LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes, Type::Slice(Box::new(Type::Bytes(1)))],
             name: "readUint128LE",
             params: vec![Type::Uint(32)],
             ret: vec![Type::Uint(128)],
@@ -642,7 +642,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::ReadUint256LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes, Type::Slice(Box::new(Type::Bytes(1)))],
             name: "readUint256LE",
             params: vec![Type::Uint(32)],
             ret: vec![Type::Uint(256)],
@@ -653,7 +653,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::ReadAddress,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes, Type::Slice(Box::new(Type::Bytes(1)))],
             name: "readAddress",
             params: vec![Type::Uint(32)],
             ret: vec![Type::Address(false)],
@@ -664,7 +664,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::WriteInt8,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes],
             name: "writeInt8",
             params: vec![Type::Int(8), Type::Uint(32)],
             ret: vec![],
@@ -675,7 +675,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::WriteInt16LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes],
             name: "writeInt16LE",
             params: vec![Type::Int(16), Type::Uint(32)],
             ret: vec![],
@@ -686,7 +686,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::WriteInt32LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes],
             name: "writeInt32LE",
             params: vec![Type::Int(32), Type::Uint(32)],
             ret: vec![],
@@ -697,7 +697,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::WriteInt64LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes],
             name: "writeInt64LE",
             params: vec![Type::Int(64), Type::Uint(32)],
             ret: vec![],
@@ -708,7 +708,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::WriteInt128LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes],
             name: "writeInt128LE",
             params: vec![Type::Int(128), Type::Uint(32)],
             ret: vec![],
@@ -719,7 +719,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::WriteInt256LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes],
             name: "writeInt256LE",
             params: vec![Type::Int(256), Type::Uint(32)],
             ret: vec![],
@@ -730,7 +730,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::WriteUint16LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes],
             name: "writeUint16LE",
             params: vec![Type::Uint(16), Type::Uint(32)],
             ret: vec![],
@@ -741,7 +741,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::WriteUint32LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes],
             name: "writeUint32LE",
             params: vec![Type::Uint(32), Type::Uint(32)],
             ret: vec![],
@@ -752,7 +752,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::WriteUint64LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes],
             name: "writeUint64LE",
             params: vec![Type::Uint(64), Type::Uint(32)],
             ret: vec![],
@@ -763,7 +763,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::WriteUint128LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes],
             name: "writeUint128LE",
             params: vec![Type::Uint(128), Type::Uint(32)],
             ret: vec![],
@@ -774,7 +774,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::WriteUint256LE,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes],
             name: "writeUint256LE",
             params: vec![Type::Uint(256), Type::Uint(32)],
             ret: vec![],
@@ -785,7 +785,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::WriteAddress,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes],
             name: "writeAddress",
             params: vec![Type::Address(false), Type::Uint(32)],
             ret: vec![],
@@ -796,7 +796,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::WriteString,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes],
             name: "writeString",
             params: vec![Type::String, Type::Uint(32)],
             ret: vec![],
@@ -807,7 +807,7 @@ static BUILTIN_METHODS: Lazy<[Prototype; 27]> = Lazy::new(|| {
         Prototype {
             builtin: Builtin::WriteBytes,
             namespace: None,
-            method: Some(Type::DynamicBytes),
+            method: vec![Type::DynamicBytes],
             name: "writeBytes",
             params: vec![Type::DynamicBytes, Type::Uint(32)],
             ret: vec![],
@@ -895,7 +895,7 @@ pub fn is_reserved(fname: &str) -> bool {
     }
 
     let is_builtin_function = BUILTIN_FUNCTIONS.iter().any(|p| {
-        (p.name == fname && p.namespace.is_none() && p.method.is_none())
+        (p.name == fname && p.namespace.is_none() && p.method.is_empty())
             || (p.namespace == Some(fname))
     });
 
@@ -904,7 +904,7 @@ pub fn is_reserved(fname: &str) -> bool {
     }
 
     BUILTIN_VARIABLE.iter().any(|p| {
-        (p.name == fname && p.namespace.is_none() && p.method.is_none())
+        (p.name == fname && p.namespace.is_none() && p.method.is_empty())
             || (p.namespace == Some(fname))
     })
 }
@@ -922,7 +922,7 @@ pub(super) fn resolve_call(
 ) -> Result<Expression, ()> {
     let funcs = BUILTIN_FUNCTIONS
         .iter()
-        .filter(|p| p.name == id && p.namespace == namespace && p.method.is_none())
+        .filter(|p| p.name == id && p.namespace == namespace && p.method.is_empty())
         .collect::<Vec<&Prototype>>();
     let mut errors: Diagnostics = Diagnostics::default();
 
@@ -1352,7 +1352,7 @@ pub(super) fn resolve_method_call(
     let expr_ty = expr.ty();
     let funcs: Vec<_> = BUILTIN_METHODS
         .iter()
-        .filter(|func| func.name == id.name && func.method.as_ref() == Some(&expr_ty))
+        .filter(|func| func.name == id.name && func.method.contains(&expr_ty))
         .collect();
     let mut errors = Diagnostics::default();
 

+ 4 - 4
src/sema/builtin_structs.rs

@@ -18,7 +18,7 @@ static BUILTIN_STRUCTS: Lazy<[StructDecl; 3]> = Lazy::new(|| {
                         name: String::from("key"),
                         loc: pt::Loc::Builtin,
                     }),
-                    ty: Type::Address(false),
+                    ty: Type::Ref(Box::new(Type::Address(false))),
                     ty_loc: None,
                     indexed: false,
                     readonly: true,
@@ -31,7 +31,7 @@ static BUILTIN_STRUCTS: Lazy<[StructDecl; 3]> = Lazy::new(|| {
                         name: String::from("lamports"),
                         loc: pt::Loc::Builtin,
                     }),
-                    ty: Type::Uint(64),
+                    ty: Type::Ref(Box::new(Type::Uint(64))),
                     ty_loc: None,
                     indexed: false,
                     readonly: false,
@@ -44,7 +44,7 @@ static BUILTIN_STRUCTS: Lazy<[StructDecl; 3]> = Lazy::new(|| {
                         name: String::from("data"),
                         loc: pt::Loc::Builtin,
                     }),
-                    ty: Type::DynamicBytes,
+                    ty: Type::Slice(Box::new(Type::Bytes(1))),
                     ty_loc: None,
                     indexed: false,
                     readonly: true,
@@ -57,7 +57,7 @@ static BUILTIN_STRUCTS: Lazy<[StructDecl; 3]> = Lazy::new(|| {
                         name: String::from("owner"),
                         loc: pt::Loc::Builtin,
                     }),
-                    ty: Type::Address(false),
+                    ty: Type::Ref(Box::new(Type::Address(false))),
                     ty_loc: None,
                     indexed: false,
                     readonly: true,

+ 1 - 1
src/sema/expression/member_access.rs

@@ -244,7 +244,7 @@ pub(super) fn member_access(
                 };
             }
         }
-        Type::String | Type::DynamicBytes => {
+        Type::String | Type::DynamicBytes | Type::Slice(_) => {
             if id.name == "length" {
                 return Ok(Expression::Builtin {
                     loc: *loc,

+ 3 - 0
src/sema/expression/mod.rs

@@ -377,6 +377,9 @@ impl Expression {
                     expr: Box::new(self.clone()),
                 })
             }
+            (Type::Bytes(1), Type::Enum(_)) if !implicit => {
+                self.cast_types(loc, &Type::Uint(8), to, implicit, ns, diagnostics)
+            }
             (Type::Uint(from_width), Type::Enum(enum_no))
             | (Type::Int(from_width), Type::Enum(enum_no)) => {
                 if implicit {

+ 1 - 1
src/sema/expression/subscript.rs

@@ -83,7 +83,7 @@ pub(super) fn array_subscript(
 
     let deref_ty = array_ty.deref_any();
     match deref_ty {
-        Type::Bytes(_) | Type::Array(..) | Type::DynamicBytes => {
+        Type::Bytes(_) | Type::Array(..) | Type::DynamicBytes | Type::Slice(_) => {
             if array_ty.is_contract_storage() {
                 let elem_ty = array_ty.storage_array_elem();
 

+ 2 - 0
src/sema/types.rs

@@ -1357,6 +1357,7 @@ impl Type {
             ))),
             Type::Array(ty, dim) if dim.len() == 1 => Type::Ref(ty.clone()),
             Type::Bytes(_) => Type::Bytes(1),
+            Type::Slice(ty) => Type::Ref(Box::new(*ty.clone())),
             _ => panic!("deref on non-array"),
         }
     }
@@ -1480,6 +1481,7 @@ impl Type {
                 .sum::<BigInt>(),
             Type::String
             | Type::DynamicBytes
+            | Type::Slice(_)
             | Type::InternalFunction { .. }
             | Type::Ref(_)
             | Type::StorageRef(..) => BigInt::from(ns.target.ptr_size() / 8),

+ 35 - 0
tests/codegen_testcases/solidity/load_account_info_members.sol

@@ -0,0 +1,35 @@
+// RUN: --target solana --emit cfg
+
+import 'solana';
+
+contract MyTest {
+    // BEGIN-CHECK: MyTest::MyTest::function::test_this__uint32_address
+    function test_this(uint32 i, address addr) public view returns (uint32) {
+        AccountInfo info = tx.accounts[i];
+        if (info.key == addr) {
+            // CHECK: branchcond ((load (load (struct %info field 0))) == (arg #1)), block3, block4
+            return 0;
+        } else if (info.lamports == 90) {
+            // CHECK: branchcond ((load (load (struct %info field 1))) == uint64 90), block6, block7
+            return 1;
+        } else if (info.data.length == 5) {
+            // CHECK: branchcond ((builtin ArrayLength ((load (struct %info field 2)))) == uint32 5), block9, block10
+            return info.data.readUint32LE(4);
+        } else if (info.owner == addr) {
+            // CHECK: ((load (load (struct %info field 3))) == (arg #1)), block14, block15
+            return 3;
+        } else if (info.rent_epoch == 45) {
+            // CHECK: branchcond ((load (struct %info field 4)) == uint64 45), block17, block18
+            return 4;
+        } else if (info.is_signer) {
+            // CHECK: branchcond (load (struct %info field 5)), block20, block21
+            return 5;
+        } else if (info.is_writable) {
+            // CHECK: branchcond (load (struct %info field 6)), block23, block24
+            return 6;
+        } else if (info.executable) {
+            // CHECK: branchcond (load (struct %info field 7)), block26, block27
+            return 7;
+        }
+    }
+}

+ 12 - 6
tests/solana_tests/account_info.rs

@@ -91,12 +91,12 @@ fn data() {
                 revert("account not found");
             }
 
-            function test2() public payable returns (uint32) {
+            function test2() public payable returns (uint32, uint32) {
                 for (uint32 i = 0; i < tx.accounts.length; i++) {
                     AccountInfo ai = tx.accounts[i];
 
                     if (ai.key == address(this)) {
-                        return ai.data.readUint32LE(1);
+                        return (ai.data.readUint32LE(1), ai.data.length);
                     }
                 }
 
@@ -139,9 +139,15 @@ fn data() {
 
     assert_eq!(
         returns,
-        BorshToken::Uint {
-            width: 32,
-            value: BigInt::from(val),
-        }
+        BorshToken::Tuple(vec![
+            BorshToken::Uint {
+                width: 32,
+                value: BigInt::from(val),
+            },
+            BorshToken::Uint {
+                width: 32,
+                value: BigInt::from(4096),
+            }
+        ]),
     );
 }