fn lower_generic_member_access(
expr: &Expression,
inner: &Expression,
member: &Identifier,
ctx: &mut LoweringContext,
instructions: &mut Vec<Instruction>,
) -> bool {
fn is_namespace_identifier(name: &str, ctx: &LoweringContext) -> bool {
!ctx.param_index_map.contains_key(name)
&& ctx.resolve_local(name).is_none()
&& !ctx.state_index_map.contains_key(name)
}
if let Expression::Variable(base) = inner {
if let Some(variants) = ctx.enum_variant_map.get(&base.name) {
if let Some(value) = variants.get(&member.name) {
instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
BigInt::from(*value),
)));
return true;
}
}
}
if let Expression::MemberAccess(_, namespace_expr, enum_type) = inner {
if let Expression::Variable(namespace_id) = namespace_expr.as_ref() {
if is_namespace_identifier(&namespace_id.name, ctx)
&& ctx.is_contract_type_name(&namespace_id.name)
{
if let Some(variants) = ctx.enum_variant_map.get(&enum_type.name) {
if let Some(value) = variants.get(&member.name) {
instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
BigInt::from(*value),
)));
return true;
}
}
}
}
}
if let Expression::Variable(namespace_id) = inner {
if is_namespace_identifier(&namespace_id.name, ctx)
&& ctx.is_contract_type_name(&namespace_id.name)
{
if let Some(state_index) = ctx.state_index_map.get(&member.name).copied() {
let state_type = ctx.state_type(state_index).cloned();
let const_initializer = ctx.state_metadata(state_index).and_then(|meta| {
if meta.is_constant {
meta.initializer.clone()
} else {
None
}
});
if let Some(initializer) = const_initializer {
if ctx.is_resolving_constant(state_index) {
instructions.push(Instruction::LoadState(state_index));
return true;
}
if matches!(state_type.as_ref(), Some(ValueType::Address)) {
if let Some(bytes) = address_bytes_le_from_expression(&initializer) {
instructions.push(Instruction::PushLiteral(LiteralValue::Address(bytes)));
return true;
}
}
ctx.push_resolving_constant(state_index);
let result = lower_expression(&initializer, ctx, instructions);
ctx.pop_resolving_constant();
return result;
}
instructions.push(Instruction::LoadState(state_index));
return true;
}
}
}
if let Some(reference) = resolve_storage_reference(expr, ctx) {
return emit_storage_load(&reference, ctx, instructions);
}
if let Some(ValueType::Struct { fields, .. }) = infer_type_from_expression(inner, ctx) {
if let Some(field_index) = fields
.iter()
.position(|field| field.name == member.name)
{
if !lower_expression(inner, ctx, instructions) {
return false;
}
instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
BigInt::from(field_index as u64),
)));
instructions.push(Instruction::ArrayGet);
return true;
}
}
load_expression(inner, ctx, instructions);
instructions.push(Instruction::Drop(ValueType::Any));
instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
BigInt::zero(),
)));
true
}