Add check for nested records; fix codegen for circuit nested in record

This commit is contained in:
Pranav Gaddamadugu 2022-08-10 14:56:41 -07:00
parent a26c452de2
commit da7ff48b11
8 changed files with 95 additions and 2 deletions

View File

@ -111,7 +111,7 @@ impl fmt::Display for Type {
Type::I32 => write!(f, "i32"),
Type::I64 => write!(f, "i64"),
Type::I128 => write!(f, "i128"),
Type::Identifier(ref variable) => write!(f, "circuit {}", variable),
Type::Identifier(ref variable) => write!(f, "{}", variable),
Type::Scalar => write!(f, "scalar"),
Type::String => write!(f, "string"),
Type::U8 => write!(f, "u8"),

View File

@ -149,7 +149,7 @@ impl<'a> CodeGenerator<'a> {
writeln!(
output_string,
" {} as {}.private;", // todo: CAUTION private record variables only.
name, type_,
name, type_.to_string().to_lowercase(),
)
.expect("failed to write to string");
}

View File

@ -121,6 +121,21 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
};
check_has_field(sym::owner, Type::Address);
check_has_field(sym::gates, Type::U64);
// Check that the record does not contain another record.
for member in input.members.iter() {
if let CircuitMember::CircuitVariable(_, Type::Identifier(identifier)) = member {
if let Some(circuit) = self.symbol_table.borrow().lookup_circuit(identifier.name) {
if circuit.is_record {
self.emit_err(TypeCheckerError::record_cannot_contain_record(
input.identifier.name,
identifier.name,
input.span(),
));
}
}
}
}
}
// Ensure there are no tuple typed members.

View File

@ -288,4 +288,11 @@ create_messages!(
msg: format!("Helper functions cannot have modes associated with their inputs."),
help: Some("Consider removing the mode or adding a `@program` annotation to the function.".to_string()),
}
@formatted
record_cannot_contain_record {
args: (parent_record: impl Display, child_record: impl Display),
msg: format!("A record cannot contain another record."),
help: Some(format!("Remove the record `{child_record} from `{parent_record}`.")),
}
);

View File

@ -0,0 +1,35 @@
/*
namespace: Compile
expectation: Pass
*/
circuit Amount {
amount: u64,
amt: u64,
}
record Token {
// The token owner.
owner: address,
// The Aleo balance (in gates).
gates: u64,
// The token amount.
amount: Amount,
}
@program
function mint(r0: address, r1: u64) -> Token {
return Token {
owner: r0,
gates: 0u64,
amount: Amount { amount: r1, amt: r1 },
};
}
@program
function main(x: address) -> u64 {
const c: u64 = 1u64;
let t: Token = Token { owner: x, gates: 0u64, amount: Amount { amount: c, amt: c } };
return t.gates;
}

View File

@ -0,0 +1,22 @@
/*
namespace: Compile
expectation: Fail
*/
record Foo {
// The token owner.
owner: address,
// The Aleo balance (in gates).
gates: u64,
// The token amount.
amount: u64,
}
record Token {
// The token owner.
owner: address,
// The Aleo balance (in gates).
gates: u64,
// The token amount.
foo: Foo,
}

View File

@ -0,0 +1,9 @@
---
namespace: Compile
expectation: Pass
outputs:
- output:
- initial_input_ast: no input
initial_ast: e781700aae47b3e3e6fabae4bc8620588ce4a91c8ed500cd1bfb0005ba92f9a0
unrolled_ast: e781700aae47b3e3e6fabae4bc8620588ce4a91c8ed500cd1bfb0005ba92f9a0
ssa_ast: fdd24be71c71d34367fdd00465fa80391d89776c49e62ad13bea07385dfeb8f8

View File

@ -0,0 +1,5 @@
---
namespace: Compile
expectation: Fail
outputs:
- "Error [ETYC0372030]: A record cannot contain another record.\n --> compiler-test:12:1\n |\n 12 | record Token {\n 13 | // The token owner.\n 14 | owner: address,\n 15 | // The Aleo balance (in gates).\n 16 | gates: u64,\n 17 | // The token amount.\n 18 | foo: Foo,\n 19 | }\n | ^\n |\n = Remove the record `Foo from `Token`.\n"