Skip to content

Commit

Permalink
Various small changes while preparing to improve type checking (#192)
Browse files Browse the repository at this point in the history
* Remove an unecessary `clone` and add comment
* Add some methods for asg::IndexOperator
* Rename some functions for consistency.
* Corrections in comments.
* Make some improvements in methods in types.rs
  Some of these methods are not completed yet.
  But this brings it a bit closer.
* Add `equal_up_to_shape`. Try to make this and
  `equal_up_to_dims` do the correct things
  • Loading branch information
jlapeyre committed Mar 25, 2024
1 parent 3396068 commit 8b7a788
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 13 deletions.
17 changes: 17 additions & 0 deletions crates/oq3_semantics/src/asg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,15 @@ pub enum IndexOperator {
ExpressionList(ExpressionList),
}

impl IndexOperator {
pub fn num_dims(&self) -> usize {
match self {
IndexOperator::SetExpression(_) => 1,
IndexOperator::ExpressionList(elist) => elist.len(),
}
}
}

#[derive(Clone, Debug, PartialEq)]
pub struct ExpressionList {
pub expressions: Vec<TExpr>,
Expand Down Expand Up @@ -372,6 +381,14 @@ impl ExpressionList {
pub fn new(expressions: Vec<TExpr>) -> ExpressionList {
ExpressionList { expressions }
}

pub fn len(&self) -> usize {
self.expressions.len()
}

pub fn is_empty(&self) -> bool {
self.expressions.is_empty()
}
}

#[derive(Clone, Debug, PartialEq)]
Expand Down
1 change: 1 addition & 0 deletions crates/oq3_semantics/src/semantic_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub enum SemanticErrorKind {
ConstIntegerError, // need a better way to organize this kind of type error
IncompatibleTypesError,
IncompatibleDimensionError,
TooManyIndexes,
CastError,
MutateConstError,
IncludeNotInGlobalScopeError,
Expand Down
37 changes: 27 additions & 10 deletions crates/oq3_semantics/src/syntax_to_semantics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ fn from_expr(expr_maybe: Option<synast::Expr>, context: &mut Context) -> Option<
let left_syn = bin_expr.lhs();
let right_syn = bin_expr.rhs();

let op = from_binary_op(synast_op);
let op = ast_from_binary_op(synast_op);
let left = from_expr(left_syn, context).unwrap();
let right = from_expr(right_syn, context).unwrap();
// There are no binary ops that accept quantum operands.
Expand Down Expand Up @@ -648,7 +648,7 @@ fn from_expr(expr_maybe: Option<synast::Expr>, context: &mut Context) -> Option<

synast::Expr::IndexExpr(index_expr) => {
let expr = from_expr(index_expr.expr(), context);
let index = from_index_operator(index_expr.index_operator().unwrap(), context);
let index = ast_from_index_operator(index_expr.index_operator().unwrap(), context);
Some(asg::IndexExpression::new(expr.unwrap(), index).to_texpr())
}

Expand Down Expand Up @@ -799,7 +799,7 @@ fn from_gate_operand(gate_operand: synast::GateOperand, context: &mut Context) -
}
}

fn from_index_operator(
fn ast_from_index_operator(
index_op: synast::IndexOperator,
context: &mut Context,
) -> asg::IndexOperator {
Expand Down Expand Up @@ -832,7 +832,7 @@ fn inner_expression_list(
.collect()
}

fn from_binary_op(synast_op: synast::BinaryOp) -> asg::BinaryOp {
fn ast_from_binary_op(synast_op: synast::BinaryOp) -> asg::BinaryOp {
match synast_op {
synast::BinaryOp::ArithOp(arith_op) => {
use asg::BinaryOp::ArithOp;
Expand Down Expand Up @@ -1013,6 +1013,7 @@ fn from_assignment_stmt(
if expr_type.equal_up_to_dims(&symbol_type) {
context.insert_error(IncompatibleDimensionError, assignment_stmt);
} else if let asg::Expr::Literal(asg::Literal::Int(intlit)) = expr.expression() {
// Cast positive integer literal to UInt
if matches!(symbol_type, Type::UInt(..)) {
if *intlit.sign() {
// FIXME: We are casting to unsigned if the int literal is positive.
Expand All @@ -1029,7 +1030,7 @@ fn from_assignment_stmt(
} else {
let promoted_type = types::promote_types(&symbol_type, expr_type);
if promoted_type == symbol_type {
expr = asg::Cast::new(expr, promoted_type.clone()).to_texpr()
expr = asg::Cast::new(expr, promoted_type).to_texpr()
} else {
context.insert_error(IncompatibleTypesError, assignment_stmt);
}
Expand All @@ -1042,9 +1043,25 @@ fn from_assignment_stmt(
return stmt_asg;
}
// LHS is *not* an identifier, rather an indexed identifier
let indexed_identifier_ast = assignment_stmt.indexed_identifier();
let (indexed_identifier, _typ) =
ast_indexed_identifier(&indexed_identifier_ast.unwrap(), context);
let indexed_identifier_ast = assignment_stmt.indexed_identifier().unwrap();
let (indexed_identifier, typ) = ast_indexed_identifier(&indexed_identifier_ast, context);
// Examine number of indexing operators. Eg. `d[1][2]` has two operations.
// We only check expressions with a single indexing op for now.
if indexed_identifier.indexes().len() == 1 {
let index = &indexed_identifier.indexes()[0];
if index.num_dims() > typ.num_dims() {
context.insert_error(TooManyIndexes, &indexed_identifier_ast);
}
// let mut num_out_dims = typ.num_dims();
// match index {
// asg::IndexOperator::SetExpression(_) => { num_out_dims = 1;}
// asg::IndexOperator::ExpressionList(elist) => {
// for expr in &elist.expressions {
// dbg!(expr);
// }
// }
// }
}
let expr = from_expr(assignment_stmt.rhs(), context).unwrap(); // rhs of `=` operator
let lvalue = asg::LValue::IndexedIdentifier(indexed_identifier);
Some(asg::Assignment::new(lvalue, expr).to_stmt())
Expand All @@ -1054,7 +1071,7 @@ fn from_assignment_stmt(
// These functions (fn ast_ ...) convert oq3_syntax::ast (alias synast) structs to ast structs.
// These ast structs are not yet wrapped in `enum Stmt` or `enum Expr`, etc.
// These functions exist because some of these ast structs will be wrapped into the
// ast tree in different ways. So their construction is abstracted out.
// ast tree in different ways. So their construction is factored out.
//
// It seems like it would be a good idea to use these functions as much as possible. However,
// Sometimes construction of the object on the one hand and wrapping it in a type and in an
Expand Down Expand Up @@ -1086,7 +1103,7 @@ fn ast_indexed_identifier(
.as_tuple();
let indexes = indexed_identifier
.index_operators()
.map(|index| from_index_operator(index, context))
.map(|index| ast_from_index_operator(index, context))
.collect();
(asg::IndexedIdentifier::new(symbol_id, indexes), typ)
}
Expand Down
33 changes: 30 additions & 3 deletions crates/oq3_semantics/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ pub enum ArrayDims {
}

impl ArrayDims {
pub fn num_dims(&self) -> i32 {
pub fn num_dims(&self) -> usize {
match self {
ArrayDims::D1(..) => 1,
ArrayDims::D2(..) => 2,
Expand Down Expand Up @@ -180,21 +180,48 @@ impl Type {
pub fn dims(&self) -> Option<Vec<usize>> {
use Type::*;
match self {
QubitArray(dims) | IntArray(dims) => Some(dims.dims()),
QubitArray(dims) | IntArray(dims) | BitArray(dims, _) => Some(dims.dims()),
_ => None,
}
}

pub fn equal_up_to_dims(&self, other: &Type) -> bool {
pub fn num_dims(&self) -> usize {
use Type::*;
match self {
QubitArray(dims) | IntArray(dims) | BitArray(dims, _) => dims.num_dims(),
_ => 0,
}
}

// FIXME: Not finished
/// Return `true` if the types have the same base type.
/// The number of dimensions and dimensions may differ.
pub fn equal_up_to_shape(&self, other: &Type) -> bool {
use Type::*;
if self == other {
return true;
}
if matches!(self, BitArray(_, _)) && matches!(other, BitArray(_, _)) {
return true;
}
if matches!(self, QubitArray(_)) && matches!(other, QubitArray(_)) {
return true;
}
false
}

// FIXME: Not finished
/// Return `true` if the types have the same base type and the same shape.
/// The dimensions of each axis may differ.
pub fn equal_up_to_dims(&self, other: &Type) -> bool {
if self == other {
return true;
}
if self.num_dims() != other.num_dims() {
return false;
}
self.equal_up_to_shape(other)
}
}

#[test]
Expand Down

0 comments on commit 8b7a788

Please sign in to comment.