Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ impl<'a> Context<'a> {
self.current_module.map(|cur| cur == m).unwrap_or(false)
}

fn struct_field_access_allowed(&self) -> bool {
self.env.test_mode() || self.env.verify_mode()
}

//**********************************************************************************************
// Dependency item building
//**********************************************************************************************
Expand Down Expand Up @@ -264,7 +268,7 @@ impl<'a> Context<'a> {

pub fn struct_definition_name(&self, m: &ModuleIdent, s: DatatypeName) -> IR::DatatypeName {
assert!(
self.is_current_module(m),
self.is_current_module(m) || self.struct_field_access_allowed(),
"ICE invalid struct definition lookup"
);
Self::translate_datatype_name(s)
Expand Down
4 changes: 4 additions & 0 deletions external-crates/move/crates/move-compiler/src/typing/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,10 @@ impl<'env, 'outer> Context<'env, 'outer> {
self.reporter.pop_warning_filter_scope()
}

pub fn struct_field_access_allowed(&self) -> bool {
self.env().test_mode() || self.env().verify_mode()
}

pub fn emit_warning_if_deprecated(
&mut self,
mident: &ModuleIdent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2966,7 +2966,7 @@ fn resolve_field(context: &mut Context, loc: Loc, ty: Type, field: &Field) -> Ty
context.error_type(loc)
}
sp!(_, Apply(_, sp!(_, ModuleType(m, n)), targs)) => {
if !context.is_current_module(&m) {
if !context.is_current_module(&m) && !context.struct_field_access_allowed() {
let msg = format!(
"Invalid access of field '{field}' on the struct '{m}::{n}'. The field '{field}' can only \
be accessed within the module '{m}' since it defines '{n}'"
Expand Down
10 changes: 2 additions & 8 deletions external-crates/move/crates/move-ir-to-bytecode/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1896,10 +1896,7 @@ fn compile_bytecode(
Bytecode::ImmBorrowLoc(function_frame.get_local(&v_)?)
}
IRBytecode_::MutBorrowField(name, tys, sp!(_, field_)) => {
let qualified_struct_name = QualifiedDatatypeIdent {
module: ModuleName::module_self(),
name,
};
let qualified_struct_name = context.resolve_datatype_name(&name)?;
let sh_idx = context.datatype_handle_index(qualified_struct_name)?;
let (def_idx, _, field_offset) = context.field(sh_idx, field_)?;

Expand All @@ -1918,10 +1915,7 @@ fn compile_bytecode(
}
}
IRBytecode_::ImmBorrowField(name, tys, sp!(_, field_)) => {
let qualified_struct_name = QualifiedDatatypeIdent {
module: ModuleName::module_self(),
name,
};
let qualified_struct_name = context.resolve_datatype_name(&name)?;
let sh_idx = context.datatype_handle_index(qualified_struct_name)?;
let (def_idx, _, field_offset) = context.field(sh_idx, field_)?;

Expand Down
110 changes: 104 additions & 6 deletions external-crates/move/crates/move-ir-to-bytecode/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use move_binary_format::{
IdentifierIndex, ModuleHandle, ModuleHandleIndex, Signature, SignatureIndex,
SignatureToken, StructDefInstantiation, StructDefInstantiationIndex, StructDefinitionIndex,
TableIndex, VariantHandle, VariantHandleIndex, VariantInstantiationHandle,
VariantInstantiationHandleIndex,
VariantInstantiationHandleIndex, TypeSignature,
},
};
use move_bytecode_source_map::source_map::SourceMap;
Expand All @@ -29,6 +29,7 @@ use move_ir_types::{
},
location::Loc,
};
use core::str;
use std::{clone::Clone, collections::HashMap, hash::Hash};

macro_rules! get_or_add_item_macro {
Expand Down Expand Up @@ -75,13 +76,17 @@ pub struct CompiledDependencyView<'a> {
identifiers: &'a [Identifier],
address_identifiers: &'a [AccountAddress],
signature_pool: &'a [Signature],

field_pool: HashMap<(&'a IdentStr, &'a IdentStr, &'a IdentStr), (StructDefinitionIndex, IdentifierIndex, TypeSignature, usize)>,
}

impl<'a> CompiledDependencyView<'a> {
pub fn new(dep: &'a CompiledModule) -> Result<Self> {
let mut structs = HashMap::new();
let mut functions = HashMap::new();

let mut field_pool = HashMap::new();

let self_handle = dep.self_handle_idx();

for shandle in dep.datatype_handles() {
Expand All @@ -93,6 +98,27 @@ impl<'a> CompiledDependencyView<'a> {
get_or_add_item(&mut structs, (mname, sname))?;
}

// ISSUE: struct_defs is empty in this moment :(
for (sdef_idx, sdef) in dep.struct_defs().iter().enumerate() {
let sh = dep.datatype_handle_at(sdef.struct_handle);
let mhandle = dep.module_handle_at(sh.module);
let mname = dep.identifier_at(mhandle.name);
let sname = dep.identifier_at(sh.name);

for (i, field) in sdef.fields().unwrap().iter().enumerate() {
let field_name = field.name;
let field_signature = field.signature.clone();
let field_idx = i;

let fname = dep.identifier_at(field.name);

let key = (mname, sname, fname);
let value = (StructDefinitionIndex(sdef_idx as u16), field_name, field_signature, field_idx);

field_pool.insert(key, value);
}
}

// keep only functions defined in the current module
// with module handle 0
let defined_function_handles = dep
Expand All @@ -108,6 +134,7 @@ impl<'a> CompiledDependencyView<'a> {
Ok(Self {
structs,
functions,
field_pool,
module_pool: dep.module_handles(),
datatype_pool: dep.datatype_handles(),
function_pool: dep.function_handles(),
Expand Down Expand Up @@ -156,6 +183,20 @@ impl<'a> CompiledDependencyView<'a> {
.and_then(|idx| self.datatype_pool.get(*idx as usize))
}

fn field_handle(
&self,
module: &ModuleName,
datatype: &DatatypeName,
field: &Field_,
) -> Option<(StructDefinitionIndex, IdentifierIndex, TypeSignature, usize)> {
self.field_pool
.get(&(
ident_str(module.0.as_str()).ok()?,
ident_str(datatype.0.as_str()).ok()?,
ident_str(field.0.as_str()).ok()?,
)).cloned()
}

fn function_signature(&self, name: &FunctionName) -> Option<FunctionSignature> {
self.functions
.get(ident_str(name.0.as_str()).ok()?)
Expand Down Expand Up @@ -594,17 +635,58 @@ impl<'a> Context<'a> {
}

/// Get the field index, fails if it is not bound.
/// Now supports looking up fields from dependency modules.
pub fn field(
&self,
&mut self,
s: DatatypeHandleIndex,
f: Field_,
) -> Result<(StructDefinitionIndex, SignatureToken, usize)> {
match self.fields.get(&(s, f.clone())) {
None => bail!("Unbound field {}", f),
Some((sd_idx, token, decl_order)) => Ok((*sd_idx, token.clone(), *decl_order)),
None => {
self.populate_dependency_field_info(s, &f)?;
match self.fields.get(&(s, f.clone())) {
Some((sd_idx, token, decl_order)) => Ok((*sd_idx, token.clone(), *decl_order)),
None => bail!("Unbound field {}", f),
}
}
}
}

fn populate_dependency_field_info(&mut self, s: DatatypeHandleIndex, f: &Field_) -> Result<()> {
let qualified_struct = self.find_struct_by_handle_index(s);

if let Some(qualified_struct) = qualified_struct {
if qualified_struct.module == ModuleName::module_self() {
bail!("Field '{}' not found in current module struct", f);
}

let module_ident = *self.module_ident(&qualified_struct.module)?;
let dep = self.dependency(&module_ident)?;

let fh = dep.field_handle(&module_ident.name, &qualified_struct.name, f) ;
if let Some((sd_idx, _, sig, order)) = fh {
self.declare_field(s, sd_idx, f.clone(), sig.0, order);
} else {
bail!("Field '{}' not found in dependency struct '{}::{}'", f, module_ident.name, qualified_struct.name);
}
}

Ok(())
}

/// Helper method to find the qualified struct name by its handle index
fn find_struct_by_handle_index(&self, s: DatatypeHandleIndex) -> Option<QualifiedDatatypeIdent> {
for (qualified_name, handle) in &self.structs {
if let Some(&index) = self.datatype_handles.get(handle) {
if index == s.0 as u16 {
return Some(qualified_name.clone());
}
}
}
None
}

pub fn variant(
&self,
s: DatatypeHandleIndex,
Expand Down Expand Up @@ -862,9 +944,25 @@ impl<'a> Context<'a> {
}
}

/// Given an identifier, find the struct handle index.
/// Creates the handle and adds it to the pool if it it is the *first* time it looks
/// up the struct in a dependency.
/// Resolves a DatatypeName to a QualifiedDatatypeIdent by checking current module first,
/// then looking through properly imported modules (those with registered aliases)
pub fn resolve_datatype_name(&self, name: &DatatypeName) -> Result<QualifiedDatatypeIdent> {
if self.struct_defs.contains_key(name) {
return Ok(QualifiedDatatypeIdent {
module: ModuleName::module_self(),
name: name.clone(),
});
}

for skey in self.structs.keys() {
if &skey.name == name {
return Ok(skey.clone());
}
}

bail!("Unbound struct {}", name)
}

pub fn datatype_handle_index(
&mut self,
s: QualifiedDatatypeIdent,
Expand Down
Loading