Pārlūkot izejas kodu

Move AccountMeta and AccountInfo into builtin 'solana' import

Currently, AccountMeta and AccountInfo are reserved types on Solana. We
can avoid this sitation by putting the builtins into a builtin import
called solana. Using this mechanism, the builtins can be renamed, put
into an import object, or not imported at all.

Syntax shamelessly stolen from javascript (e.g. `import 'fs';`);

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 3 gadi atpakaļ
vecāks
revīzija
27899f1f25

+ 7 - 4
src/bin/languageserver/mod.rs

@@ -96,7 +96,7 @@ impl SolangServer {
             codegen(&mut ns, &Default::default());
 
             diags.extend(ns.diagnostics.iter().filter_map(|diag| {
-                if diag.pos.file_no() != 0 {
+                if diag.pos.file_no() != ns.top_file_no() {
                     // The first file is the one we wanted to parse; others are imported
                     return None;
                 }
@@ -121,14 +121,17 @@ impl SolangServer {
                                 location: Location {
                                     uri: Url::from_file_path(&ns.files[note.pos.file_no()].path)
                                         .unwrap(),
-                                    range: SolangServer::loc_to_range(&note.pos, &ns.files[0]),
+                                    range: SolangServer::loc_to_range(
+                                        &note.pos,
+                                        &ns.files[ns.top_file_no()],
+                                    ),
                                 },
                             })
                             .collect(),
                     )
                 };
 
-                let range = SolangServer::loc_to_range(&diag.pos, &ns.files[0]);
+                let range = SolangServer::loc_to_range(&diag.pos, &ns.files[ns.top_file_no()]);
 
                 Some(Diagnostic {
                     range,
@@ -151,7 +154,7 @@ impl SolangServer {
             self.files.lock().await.insert(
                 path,
                 Hovers {
-                    file: ns.files[0].clone(),
+                    file: ns.files[ns.top_file_no()].clone(),
                     lookup,
                 },
             );

+ 3 - 2
src/file_resolver.rs

@@ -244,10 +244,11 @@ impl FileResolver {
         } else {
             unreachable!();
         };
+        let cache_no = file.cache_no.unwrap();
         let (begin_line, mut begin_column) = file.offset_to_line_column(*start);
         let (end_line, mut end_column) = file.offset_to_line_column(*end);
 
-        let mut full_line = self.files[file.cache_no]
+        let mut full_line = self.files[cache_no]
             .lines()
             .nth(begin_line)
             .unwrap()
@@ -256,7 +257,7 @@ impl FileResolver {
         // If the loc spans across multiple lines, we concatenate them
         if begin_line != end_line {
             for i in begin_line + 1..=end_line {
-                let line = self.files[file.cache_no].lines().nth(i).unwrap();
+                let line = self.files[cache_no].lines().nth(i).unwrap();
                 if i == end_line {
                     end_column += full_line.len();
                 }

+ 2 - 2
src/sema/ast.rs

@@ -420,14 +420,14 @@ impl Symbol {
 }
 
 /// Any Solidity file, either the main file or anything that was imported
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub struct File {
     /// The on-disk filename
     pub path: PathBuf,
     /// Used for offset to line-column conversions
     pub line_starts: Vec<usize>,
     /// Indicates the file number in FileResolver.files
-    pub cache_no: usize,
+    pub cache_no: Option<usize>,
 }
 
 /// When resolving a Solidity file, this holds all the resolved items

+ 13 - 3
src/sema/builtin.rs

@@ -1,5 +1,6 @@
 use super::ast::{
-    Builtin, BuiltinStruct, Diagnostic, Expression, Namespace, Parameter, StructDecl, Symbol, Type,
+    Builtin, BuiltinStruct, Diagnostic, Expression, File, Namespace, Parameter, StructDecl, Symbol,
+    Type,
 };
 use super::eval::eval_const_number;
 use super::expression::{args_sanity_check, expression, ExprContext, ResolveTo};
@@ -11,6 +12,7 @@ use crate::Target;
 use num_bigint::BigInt;
 use num_traits::One;
 use once_cell::sync::Lazy;
+use std::path::PathBuf;
 
 pub struct Prototype {
     pub builtin: Builtin,
@@ -1389,6 +1391,14 @@ pub fn resolve_method_call(
 
 impl Namespace {
     pub fn add_solana_builtins(&mut self) {
+        let file_no = self.files.len();
+
+        self.files.push(File {
+            path: PathBuf::from("solana"),
+            line_starts: Vec::new(),
+            cache_no: None,
+        });
+
         let account_info_no = self.structs.len();
 
         let fields = vec![
@@ -1499,7 +1509,7 @@ impl Namespace {
         };
 
         assert!(self.add_symbol(
-            0,
+            file_no,
             None,
             &id,
             Symbol::Struct(pt::Loc::Builtin, account_info_no)
@@ -1560,7 +1570,7 @@ impl Namespace {
         };
 
         assert!(self.add_symbol(
-            0,
+            file_no,
             None,
             &id,
             Symbol::Struct(pt::Loc::Builtin, account_meta_no)

+ 19 - 11
src/sema/diagnostics.rs

@@ -4,10 +4,13 @@ use crate::parser::pt::Loc;
 use codespan_reporting::{diagnostic, files, term};
 use itertools::Itertools;
 use serde::Serialize;
-use std::slice::Iter;
-use std::{io, sync::Arc};
+use std::{
+    collections::HashMap,
+    slice::Iter,
+    {io, sync::Arc},
+};
 
-#[derive(Default)]
+#[derive(Default, Debug)]
 pub struct Diagnostics {
     contents: Vec<Diagnostic>,
     has_error: bool,
@@ -115,7 +118,10 @@ impl Diagnostics {
     }
 }
 
-fn convert_diagnostic(msg: &Diagnostic, file_id: &[usize]) -> diagnostic::Diagnostic<usize> {
+fn convert_diagnostic(
+    msg: &Diagnostic,
+    file_id: &HashMap<usize, usize>,
+) -> diagnostic::Diagnostic<usize> {
     let diagnostic = diagnostic::Diagnostic::new(match msg.level {
         Level::Debug => diagnostic::Severity::Help,
         Level::Info => diagnostic::Severity::Note,
@@ -127,13 +133,13 @@ fn convert_diagnostic(msg: &Diagnostic, file_id: &[usize]) -> diagnostic::Diagno
     let mut labels = Vec::new();
 
     if let Loc::File(file_no, start, end) = msg.pos {
-        labels.push(diagnostic::Label::primary(file_id[file_no], start..end));
+        labels.push(diagnostic::Label::primary(file_id[&file_no], start..end));
     }
 
     for note in &msg.notes {
         if let Loc::File(file_no, start, end) = note.pos {
             labels.push(
-                diagnostic::Label::secondary(file_id[file_no], start..end)
+                diagnostic::Label::secondary(file_id[&file_no], start..end)
                     .with_message(note.message.to_owned()),
             );
         } else {
@@ -234,13 +240,15 @@ impl Namespace {
     fn convert_files(
         &self,
         cache: &FileResolver,
-    ) -> (files::SimpleFiles<String, Arc<str>>, Vec<usize>) {
+    ) -> (files::SimpleFiles<String, Arc<str>>, HashMap<usize, usize>) {
         let mut files = files::SimpleFiles::new();
-        let mut file_id = Vec::new();
+        let mut file_id = HashMap::new();
 
-        for file in &self.files {
-            let (contents, _) = cache.get_file_contents_and_number(&file.path);
-            file_id.push(files.add(format!("{}", file), contents.to_owned()));
+        for (file_no, file) in self.files.iter().enumerate() {
+            if file.cache_no.is_some() {
+                let (contents, _) = cache.get_file_contents_and_number(&file.path);
+                file_id.insert(file_no, files.add(format!("{}", file), contents.to_owned()));
+            }
         }
 
         (files, file_id)

+ 1 - 1
src/sema/dotgraphviz.rs

@@ -2041,7 +2041,7 @@ impl Dot {
 impl Namespace {
     pub fn dotgraphviz(&self) -> String {
         let mut dot = Dot {
-            filename: format!("{}", self.files[0].path.display()),
+            filename: format!("{}", self.files[self.top_file_no()].path.display()),
             nodes: Vec::new(),
             edges: Vec::new(),
         };

+ 9 - 1
src/sema/file.rs

@@ -15,7 +15,7 @@ impl File {
         File {
             path,
             line_starts,
-            cache_no,
+            cache_no: Some(cache_no),
         }
     }
 
@@ -103,6 +103,14 @@ impl Namespace {
             Loc::CommandLine => String::from("commandline"),
         }
     }
+
+    /// File number of the top level source unit which was compiled
+    pub fn top_file_no(&self) -> usize {
+        self.files
+            .iter()
+            .position(|file| file.cache_no.is_some())
+            .unwrap()
+    }
 }
 
 /// Windows verbatim paths look like \\?\C:\foo\bar which not very human readable,

+ 28 - 17
src/sema/mod.rs

@@ -183,27 +183,38 @@ fn resolve_import(
         pt::Import::Rename(f, _, _) => f,
     };
 
-    let import_file_no = match resolver.resolve_file(parent, OsStr::new(&filename.string)) {
-        Err(message) => {
-            ns.diagnostics
-                .push(ast::Diagnostic::error(filename.loc, message));
+    let os_filename = OsStr::new(&filename.string);
+
+    let import_file_no = if let Some(builtin_file_no) = ns
+        .files
+        .iter()
+        .position(|file| file.cache_no.is_none() && file.path == os_filename)
+    {
+        // import "solana"
+        builtin_file_no
+    } else {
+        match resolver.resolve_file(parent, os_filename) {
+            Err(message) => {
+                ns.diagnostics
+                    .push(ast::Diagnostic::error(filename.loc, message));
 
-            return;
-        }
-        Ok(file) => {
-            if !ns.files.iter().any(|f| f.path == file.full_path) {
-                sema_file(&file, resolver, ns);
+                return;
+            }
+            Ok(file) => {
+                if !ns.files.iter().any(|f| f.path == file.full_path) {
+                    sema_file(&file, resolver, ns);
 
-                // give up if we failed
-                if ns.diagnostics.any_errors() {
-                    return;
+                    // give up if we failed
+                    if ns.diagnostics.any_errors() {
+                        return;
+                    }
                 }
-            }
 
-            ns.files
-                .iter()
-                .position(|f| f.path == file.full_path)
-                .expect("import should be loaded by now")
+                ns.files
+                    .iter()
+                    .position(|f| f.path == file.full_path)
+                    .expect("import should be loaded by now")
+            }
         }
     };
 

+ 6 - 4
tests/contract.rs

@@ -112,10 +112,12 @@ fn add_file(cache: &mut FileResolver, path: &Path, target: Target) -> io::Result
             let start = line.find('"').unwrap();
             let end = line.rfind('"').unwrap();
             let file = &line[start + 1..end];
-            let mut import_path = path.parent().unwrap().to_path_buf();
-            import_path.push(file);
-            println!("adding import {}", import_path.display());
-            add_file(cache, &import_path, target)?;
+            if file != "solana" {
+                let mut import_path = path.parent().unwrap().to_path_buf();
+                import_path.push(file);
+                println!("adding import {}", import_path.display());
+                add_file(cache, &import_path, target)?;
+            }
         }
     }
 

+ 11 - 11
tests/contract_testcases/solana/account_info.dot

@@ -1,17 +1,17 @@
 strict digraph "tests/contract_testcases/solana/account_info.sol" {
-	contract [label="contract c\ntests/contract_testcases/solana/account_info.sol:1:1-12"]
-	f [label="function f\ncontract: c\ntests/contract_testcases/solana/account_info.sol:6:2-21\nsignature f()\nvisibility public\nmutability nonpayable"]
-	f2 [label="function f2\ncontract: c\ntests/contract_testcases/solana/account_info.sol:11:2-22\nsignature f2()\nvisibility public\nmutability nonpayable"]
-	notpub [label="function notpub\ncontract: c\ntests/contract_testcases/solana/account_info.sol:16:2-60\nsignature notpub((bytes32,uint64,bytes,bytes32,uint64,bool,bool,bool))\nvisibility private\nmutability nonpayable"]
+	contract [label="contract c\ntests/contract_testcases/solana/account_info.sol:2:1-3:12"]
+	f [label="function f\ncontract: c\ntests/contract_testcases/solana/account_info.sol:8:2-21\nsignature f()\nvisibility public\nmutability nonpayable"]
+	f2 [label="function f2\ncontract: c\ntests/contract_testcases/solana/account_info.sol:13:2-22\nsignature f2()\nvisibility public\nmutability nonpayable"]
+	notpub [label="function notpub\ncontract: c\ntests/contract_testcases/solana/account_info.sol:18:2-60\nsignature notpub((bytes32,uint64,bytes,bytes32,uint64,bool,bool,bool))\nvisibility private\nmutability nonpayable"]
 	parameters [label="parameters\nstruct AccountInfo "]
 	returns [label="returns\nstruct AccountInfo "]
-	diagnostic [label="found contract 'c'\nlevel Debug\ntests/contract_testcases/solana/account_info.sol:1:1-12"]
-	diagnostic_10 [label="variable cannot be of builtin type 'struct AccountInfo'\nlevel Error\ntests/contract_testcases/solana/account_info.sol:2:2-13"]
-	diagnostic_11 [label="parameter of type 'struct AccountInfo' not alowed in public or external functions\nlevel Error\ntests/contract_testcases/solana/account_info.sol:4:15-26"]
-	diagnostic_12 [label="return type 'struct AccountInfo' not allowed in public or external functions\nlevel Error\ntests/contract_testcases/solana/account_info.sol:4:44-55"]
-	diagnostic_13 [label="builtin struct 'AccountInfo' cannot be created using struct literal\nlevel Error\ntests/contract_testcases/solana/account_info.sol:8:8-36"]
-	diagnostic_14 [label="builtin struct 'AccountInfo' cannot be created using struct literal\nlevel Error\ntests/contract_testcases/solana/account_info.sol:13:8-22"]
-	diagnostic_15 [label="struct 'AccountInfo' field 'key' is readonly\nlevel Error\ntests/contract_testcases/solana/account_info.sol:18:6-9"]
+	diagnostic [label="found contract 'c'\nlevel Debug\ntests/contract_testcases/solana/account_info.sol:2:1-3:12"]
+	diagnostic_10 [label="variable cannot be of builtin type 'struct AccountInfo'\nlevel Error\ntests/contract_testcases/solana/account_info.sol:4:2-13"]
+	diagnostic_11 [label="parameter of type 'struct AccountInfo' not alowed in public or external functions\nlevel Error\ntests/contract_testcases/solana/account_info.sol:6:15-26"]
+	diagnostic_12 [label="return type 'struct AccountInfo' not allowed in public or external functions\nlevel Error\ntests/contract_testcases/solana/account_info.sol:6:44-55"]
+	diagnostic_13 [label="builtin struct 'AccountInfo' cannot be created using struct literal\nlevel Error\ntests/contract_testcases/solana/account_info.sol:10:8-36"]
+	diagnostic_14 [label="builtin struct 'AccountInfo' cannot be created using struct literal\nlevel Error\ntests/contract_testcases/solana/account_info.sol:15:8-22"]
+	diagnostic_15 [label="struct 'AccountInfo' field 'key' is readonly\nlevel Error\ntests/contract_testcases/solana/account_info.sol:20:6-9"]
 	contracts -> contract
 	contract -> f [label="function"]
 	contract -> f2 [label="function"]

+ 2 - 0
tests/contract_testcases/solana/account_info.sol

@@ -1,3 +1,5 @@
+import "solana";
+
 contract c {
 	AccountInfo ai;
 

+ 47 - 47
tests/contract_testcases/solana/account_meta.dot

@@ -1,54 +1,54 @@
 strict digraph "tests/contract_testcases/solana/account_meta.sol" {
-	contract [label="contract spl\ntests/contract_testcases/solana/account_meta.sol:1:1-14"]
-	foo [label="function foo\ncontract: spl\ntests/contract_testcases/solana/account_meta.sol:2:2-47\nsignature foo()\nvisibility public\nmutability nonpayable"]
+	contract [label="contract spl\ntests/contract_testcases/solana/account_meta.sol:2:1-3:14"]
+	foo [label="function foo\ncontract: spl\ntests/contract_testcases/solana/account_meta.sol:4:2-47\nsignature foo()\nvisibility public\nmutability nonpayable"]
 	returns [label="returns\nbool \naddress "]
-	var_decl [label="variable decl struct AccountMeta meta\ntests/contract_testcases/solana/account_meta.sol:3:3-67"]
-	struct_literal [label="struct literal: struct AccountMeta\ntests/contract_testcases/solana/account_meta.sol:3:22-67"]
-	getref [label="getref address\ntests/contract_testcases/solana/account_meta.sol:3:22-67"]
-	cast [label="cast address\ntests/contract_testcases/solana/account_meta.sol:3:34-53"]
-	builtins [label="builtin Sender\ntests/contract_testcases/solana/account_meta.sol:3:42-52"]
-	bool_literal [label="bool literal: true\ntests/contract_testcases/solana/account_meta.sol:3:55-59"]
-	bool_literal_11 [label="bool literal: false\ntests/contract_testcases/solana/account_meta.sol:3:61-66"]
-	return [label="return\ntests/contract_testcases/solana/account_meta.sol:4:3-41"]
-	list [label="list\ntests/contract_testcases/solana/account_meta.sol:4:3-41"]
-	load [label="load bool\ntests/contract_testcases/solana/account_meta.sol:4:3-41"]
-	structmember [label="struct member #1 bool\ntests/contract_testcases/solana/account_meta.sol:4:16-27"]
-	variable [label="variable: meta\nstruct AccountMeta\ntests/contract_testcases/solana/account_meta.sol:4:11-15"]
-	load_17 [label="load address\ntests/contract_testcases/solana/account_meta.sol:4:3-41"]
-	load_18 [label="load address\ntests/contract_testcases/solana/account_meta.sol:4:3-41"]
-	structmember_19 [label="struct member #0 address\ntests/contract_testcases/solana/account_meta.sol:4:34-40"]
-	variable_20 [label="variable: meta\nstruct AccountMeta\ntests/contract_testcases/solana/account_meta.sol:4:29-33"]
-	bar [label="function bar\ncontract: spl\ntests/contract_testcases/solana/account_meta.sol:7:2-56\nsignature bar(bytes32)\nvisibility public\nmutability nonpayable"]
+	var_decl [label="variable decl struct AccountMeta meta\ntests/contract_testcases/solana/account_meta.sol:5:3-75"]
+	struct_literal [label="struct literal: struct AccountMeta\ntests/contract_testcases/solana/account_meta.sol:5:26-75"]
+	getref [label="getref address\ntests/contract_testcases/solana/account_meta.sol:5:26-75"]
+	cast [label="cast address\ntests/contract_testcases/solana/account_meta.sol:5:42-61"]
+	builtins [label="builtin Sender\ntests/contract_testcases/solana/account_meta.sol:5:50-60"]
+	bool_literal [label="bool literal: true\ntests/contract_testcases/solana/account_meta.sol:5:63-67"]
+	bool_literal_11 [label="bool literal: false\ntests/contract_testcases/solana/account_meta.sol:5:69-74"]
+	return [label="return\ntests/contract_testcases/solana/account_meta.sol:6:3-41"]
+	list [label="list\ntests/contract_testcases/solana/account_meta.sol:6:3-41"]
+	load [label="load bool\ntests/contract_testcases/solana/account_meta.sol:6:3-41"]
+	structmember [label="struct member #1 bool\ntests/contract_testcases/solana/account_meta.sol:6:16-27"]
+	variable [label="variable: meta\nstruct AccountMeta\ntests/contract_testcases/solana/account_meta.sol:6:11-15"]
+	load_17 [label="load address\ntests/contract_testcases/solana/account_meta.sol:6:3-41"]
+	load_18 [label="load address\ntests/contract_testcases/solana/account_meta.sol:6:3-41"]
+	structmember_19 [label="struct member #0 address\ntests/contract_testcases/solana/account_meta.sol:6:34-40"]
+	variable_20 [label="variable: meta\nstruct AccountMeta\ntests/contract_testcases/solana/account_meta.sol:6:29-33"]
+	bar [label="function bar\ncontract: spl\ntests/contract_testcases/solana/account_meta.sol:9:2-56\nsignature bar(bytes32)\nvisibility public\nmutability nonpayable"]
 	parameters [label="parameters\naddress x"]
 	returns_23 [label="returns\nbool \naddress "]
-	var_decl_24 [label="variable decl struct AccountMeta[2] meta\ntests/contract_testcases/solana/account_meta.sol:8:3-11:4"]
-	array_literal [label="array literal: struct AccountMeta[2]\ntests/contract_testcases/solana/account_meta.sol:8:25-11:4"]
-	struct_literal_26 [label="struct literal: struct AccountMeta\ntests/contract_testcases/solana/account_meta.sol:9:4-30"]
-	getref_27 [label="getref address\ntests/contract_testcases/solana/account_meta.sol:9:4-30"]
-	variable_28 [label="variable: x\naddress\ntests/contract_testcases/solana/account_meta.sol:9:16-17"]
-	bool_literal_29 [label="bool literal: true\ntests/contract_testcases/solana/account_meta.sol:9:19-23"]
-	bool_literal_30 [label="bool literal: true\ntests/contract_testcases/solana/account_meta.sol:9:25-29"]
-	struct_literal_31 [label="struct literal: struct AccountMeta\ntests/contract_testcases/solana/account_meta.sol:10:4-66"]
-	getref_32 [label="getref address\ntests/contract_testcases/solana/account_meta.sol:10:4-66"]
-	variable_33 [label="variable: x\naddress\ntests/contract_testcases/solana/account_meta.sol:10:25-26"]
-	bool_literal_34 [label="bool literal: false\ntests/contract_testcases/solana/account_meta.sol:10:41-46"]
-	bool_literal_35 [label="bool literal: false\ntests/contract_testcases/solana/account_meta.sol:10:59-64"]
-	return_36 [label="return\ntests/contract_testcases/solana/account_meta.sol:13:3-47"]
-	list_37 [label="list\ntests/contract_testcases/solana/account_meta.sol:13:3-47"]
-	load_38 [label="load bool\ntests/contract_testcases/solana/account_meta.sol:13:3-47"]
-	structmember_39 [label="struct member #1 bool\ntests/contract_testcases/solana/account_meta.sol:13:19-30"]
-	subscript [label="subscript struct AccountMeta[2]\ntests/contract_testcases/solana/account_meta.sol:13:11-18"]
-	variable_41 [label="variable: meta\nstruct AccountMeta[2]\ntests/contract_testcases/solana/account_meta.sol:13:11-15"]
-	number_literal [label="uint32 literal: 1\ntests/contract_testcases/solana/account_meta.sol:13:16-17"]
-	load_43 [label="load address\ntests/contract_testcases/solana/account_meta.sol:13:3-47"]
-	load_44 [label="load address\ntests/contract_testcases/solana/account_meta.sol:13:3-47"]
-	structmember_45 [label="struct member #0 address\ntests/contract_testcases/solana/account_meta.sol:13:40-46"]
-	subscript_46 [label="subscript struct AccountMeta[2]\ntests/contract_testcases/solana/account_meta.sol:13:32-39"]
-	variable_47 [label="variable: meta\nstruct AccountMeta[2]\ntests/contract_testcases/solana/account_meta.sol:13:32-36"]
-	number_literal_48 [label="uint32 literal: 0\ntests/contract_testcases/solana/account_meta.sol:13:37-38"]
-	diagnostic [label="found contract 'spl'\nlevel Debug\ntests/contract_testcases/solana/account_meta.sol:1:1-14"]
-	diagnostic_51 [label="function can be declared 'pure'\nlevel Warning\ntests/contract_testcases/solana/account_meta.sol:2:2-47"]
-	diagnostic_52 [label="function can be declared 'pure'\nlevel Warning\ntests/contract_testcases/solana/account_meta.sol:7:2-56"]
+	var_decl_24 [label="variable decl struct AccountMeta[2] meta\ntests/contract_testcases/solana/account_meta.sol:10:3-13:4"]
+	array_literal [label="array literal: struct AccountMeta[2]\ntests/contract_testcases/solana/account_meta.sol:10:29-13:4"]
+	struct_literal_26 [label="struct literal: struct AccountMeta\ntests/contract_testcases/solana/account_meta.sol:11:4-34"]
+	getref_27 [label="getref address\ntests/contract_testcases/solana/account_meta.sol:11:4-34"]
+	variable_28 [label="variable: x\naddress\ntests/contract_testcases/solana/account_meta.sol:11:20-21"]
+	bool_literal_29 [label="bool literal: true\ntests/contract_testcases/solana/account_meta.sol:11:23-27"]
+	bool_literal_30 [label="bool literal: true\ntests/contract_testcases/solana/account_meta.sol:11:29-33"]
+	struct_literal_31 [label="struct literal: struct AccountMeta\ntests/contract_testcases/solana/account_meta.sol:12:4-70"]
+	getref_32 [label="getref address\ntests/contract_testcases/solana/account_meta.sol:12:4-70"]
+	variable_33 [label="variable: x\naddress\ntests/contract_testcases/solana/account_meta.sol:12:29-30"]
+	bool_literal_34 [label="bool literal: false\ntests/contract_testcases/solana/account_meta.sol:12:45-50"]
+	bool_literal_35 [label="bool literal: false\ntests/contract_testcases/solana/account_meta.sol:12:63-68"]
+	return_36 [label="return\ntests/contract_testcases/solana/account_meta.sol:15:3-47"]
+	list_37 [label="list\ntests/contract_testcases/solana/account_meta.sol:15:3-47"]
+	load_38 [label="load bool\ntests/contract_testcases/solana/account_meta.sol:15:3-47"]
+	structmember_39 [label="struct member #1 bool\ntests/contract_testcases/solana/account_meta.sol:15:19-30"]
+	subscript [label="subscript struct AccountMeta[2]\ntests/contract_testcases/solana/account_meta.sol:15:11-18"]
+	variable_41 [label="variable: meta\nstruct AccountMeta[2]\ntests/contract_testcases/solana/account_meta.sol:15:11-15"]
+	number_literal [label="uint32 literal: 1\ntests/contract_testcases/solana/account_meta.sol:15:16-17"]
+	load_43 [label="load address\ntests/contract_testcases/solana/account_meta.sol:15:3-47"]
+	load_44 [label="load address\ntests/contract_testcases/solana/account_meta.sol:15:3-47"]
+	structmember_45 [label="struct member #0 address\ntests/contract_testcases/solana/account_meta.sol:15:40-46"]
+	subscript_46 [label="subscript struct AccountMeta[2]\ntests/contract_testcases/solana/account_meta.sol:15:32-39"]
+	variable_47 [label="variable: meta\nstruct AccountMeta[2]\ntests/contract_testcases/solana/account_meta.sol:15:32-36"]
+	number_literal_48 [label="uint32 literal: 0\ntests/contract_testcases/solana/account_meta.sol:15:37-38"]
+	diagnostic [label="found contract 'spl'\nlevel Debug\ntests/contract_testcases/solana/account_meta.sol:2:1-3:14"]
+	diagnostic_51 [label="function can be declared 'pure'\nlevel Warning\ntests/contract_testcases/solana/account_meta.sol:4:2-47"]
+	diagnostic_52 [label="function can be declared 'pure'\nlevel Warning\ntests/contract_testcases/solana/account_meta.sol:9:2-56"]
 	contracts -> contract
 	contract -> foo [label="function"]
 	foo -> returns [label="returns"]

+ 6 - 4
tests/contract_testcases/solana/account_meta.sol

@@ -1,13 +1,15 @@
+import "solana" as sol;
+
 contract spl {
 	function foo() public returns (bool, address) {
-		AccountMeta meta = AccountMeta(address(msg.sender), true, false);
+		sol.AccountMeta meta = sol.AccountMeta(address(msg.sender), true, false);
 		return (meta.is_writable, meta.pubkey);
 	}
 
 	function bar(address x) public returns (bool, address) {
-		AccountMeta[2] meta = [
-			AccountMeta(x, true, true),
-			AccountMeta({pubkey: x, is_writable: false, is_signer: false})
+		sol.AccountMeta[2] meta = [
+			sol.AccountMeta(x, true, true),
+			sol.AccountMeta({pubkey: x, is_writable: false, is_signer: false})
 		];
 
 		return (meta[1].is_writable, meta[0].pubkey);

+ 3 - 0
tests/solana_tests/account_info.rs

@@ -5,6 +5,7 @@ use ethabi::{ethereum_types::U256, Token};
 fn lamports() {
     let mut vm = build_solidity(
         r#"
+        import 'solana';
         contract c {
             function test() public payable returns (uint64) {
                 for (uint32 i = 0; i < tx.accounts.length; i++) {
@@ -37,6 +38,7 @@ fn lamports() {
 fn owner() {
     let mut vm = build_solidity(
         r#"
+        import 'solana';
         contract c {
             function test() public payable returns (address) {
                 for (uint32 i = 0; i < tx.accounts.length; i++) {
@@ -65,6 +67,7 @@ fn owner() {
 fn data() {
     let mut vm = build_solidity(
         r#"
+        import 'solana';
         contract c {
             function test(uint32 index) public payable returns (uint8) {
                 for (uint32 i = 0; i < tx.accounts.length; i++) {

+ 2 - 0
tests/solana_tests/call.rs

@@ -343,6 +343,8 @@ fn internal_function_storage() {
 fn raw_call_accounts() {
     let mut vm = build_solidity(
         r#"
+        import {AccountMeta} from 'solana';
+
         contract SplToken {
             address constant tokenProgramId = address"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
             address constant SYSVAR_RENT_PUBKEY = address"SysvarRent111111111111111111111111111111111";