Skip to content

Commit

Permalink
wip debugging: globals are always comptime, remove global type, add h…
Browse files Browse the repository at this point in the history
…andling for Value -> Type::Constant, wip cleanup
  • Loading branch information
michaeljklein committed Nov 14, 2024
1 parent 14ca3ee commit c155d33
Show file tree
Hide file tree
Showing 10 changed files with 341 additions and 416 deletions.
25 changes: 17 additions & 8 deletions compiler/noirc_frontend/src/elaborator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -912,8 +912,9 @@ impl<'context> Elaborator<'context> {
| Type::TraitAsType(..)
| Type::TypeVariable(..)
| Type::NamedGeneric(..)
// TODO cleanup
// TODO always marked as used?
| Type::Global(..)
// | Type::Global(..)
| Type::Function(..)
| Type::Forall(..)
| Type::Error => (),
Expand Down Expand Up @@ -1531,8 +1532,9 @@ impl<'context> Elaborator<'context> {
| Type::TraitAsType(..)
| Type::Constant(..)
| Type::NamedGeneric(..)
// TODO cleanup
// TODO no items unless comptime, right?
| Type::Global(..)
// | Type::Global(..)
| Type::Error => (),
}
}
Expand Down Expand Up @@ -1661,16 +1663,23 @@ impl<'context> Elaborator<'context> {
self.push_err(ResolverError::MutableGlobal { span });
}

let (let_statement, _typ) = if comptime {
self.elaborate_in_comptime_context(|this| this.elaborate_let(let_stmt, Some(global_id)))
} else {
self.elaborate_let(let_stmt, Some(global_id))
};
// TODO: throw error if !comptime and evaluates function?

// TODO cleanup
// let (let_statement, _typ) = if comptime {
// self.elaborate_in_comptime_context(|this| this.elaborate_let(let_stmt, Some(global_id)))
// } else {
// self.elaborate_let(let_stmt, Some(global_id))
// };
let (let_statement, _typ) =
self.elaborate_in_comptime_context(|this| this.elaborate_let(let_stmt, Some(global_id)));

let statement_id = self.interner.get_global(global_id).let_statement;
self.interner.replace_statement(statement_id, let_statement);

if comptime {
// TODO cleanup
// if comptime {
if true {
self.elaborate_comptime_global(global_id);
}

Expand Down
7 changes: 7 additions & 0 deletions compiler/noirc_frontend/src/elaborator/statements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,15 @@ impl<'context> Elaborator<'context> {
) -> (HirStatement, Type) {
let expr_span = let_stmt.expression.span;
let (expression, expr_type) = self.elaborate_expression(let_stmt.expression);

// TODO cleanup
let let_stmt_type = let_stmt.r#type.clone();

let annotated_type = self.resolve_inferred_type(let_stmt.r#type);

// TODO cleanup
dbg!("elaborate_let", &let_stmt_type, &annotated_type, &expr_type, &self.errors);

let definition = match global_id {
None => DefinitionKind::Local(Some(expression)),
Some(id) => DefinitionKind::Global(id),
Expand Down
260 changes: 42 additions & 218 deletions compiler/noirc_frontend/src/elaborator/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,9 +417,6 @@ impl<'context> Elaborator<'context> {
.map(|let_statement| Kind::numeric(let_statement.r#type))
.unwrap_or(Kind::u32());

// TODO cleanup
dbg!("lookup_generic_or_global_type: kind unifying", &kind);

// TODO: close issue after test passes
// // TODO(https://github.com/noir-lang/noir/issues/6238):
// // support non-u32 generics here
Expand Down Expand Up @@ -447,120 +444,54 @@ impl<'context> Elaborator<'context> {
let rhs = stmt.expression;
let span = self.interner.expr_span(&rhs);

let Some(global_value) = &self.interner.get_global(id).value else {
// TODO: new error (i.e. comptime didn't evaluate)
let path = path.clone();
self.push_err(ResolverError::NoSuchNumericTypeVariable { path });
return None;
};

// TODO propagate error
let result = self.interner.get_global_as_type(rhs, kind, span);

// TODO cleanup
dbg!("lookup_generic_or_global_type: reached result", &result);
// TODO: fix kind of global: may need to bring back a version of the cast from
// before
let global_type = global_value.get_type().into_owned();
let global_value_kind = if global_type == Type::FieldElement {
Kind::IntegerOrField
} else {
Kind::Numeric(Box::new(global_type))
};

result.ok()
if !kind.unifies(&global_value_kind) {
panic!("global evaluates to invalid type for its kind: {:?} {:?}", &kind, &global_value);
}
dbg!("lookup_generic_or_global_type", &kind, &global_value_kind);

// TODO error instead of panic
let Some(global_value) = global_value.to_field_element() else {
if global_value.is_integral() {
panic!("negative global as type is unsupported")
} else {
panic!("non-integral global unsupported in a type position")
}
};

let global_value = match kind.ensure_value_fits(global_value, span) {
Ok(global_value) => global_value,
Err(_err) => {
// TODO: error instead of panic
// self.push_err(err);
panic!("evaluated global exceeds the size of its kind: {:?} ; {:?}", &global_value, &kind);

return None;
}
};

Some(Type::Constant(global_value, kind))

}
_ => None,
}
}

// TODO cleanup
// "TODO_move_to_interner.resolve_global_definition_to_type"
// fn resolve_global_to_type(&mut self, rhs: ExprId, kind: Kind, span: Span) -> Option<Type> {
// match self.interner.expression(&rhs) {
// HirExpression::Literal(HirLiteral::Integer(int, false)) => {
// // int.try_into_u128().ok_or(Some(ResolverError::IntegerTooLarge { span }))
// Some(Type::Constant(int, kind))
// }
// HirExpression::Ident(ident, _) => {
// if let Some(definition) = self.interner.try_definition(ident.id) {
// match definition.kind {
// DefinitionKind::Global(global_id) => {
// // nested case: return a Type::Global instead of recursing
// Some(Type::Global(global_id, definition.name.clone().into(), kind))
//
// // TODO cleanup
// // let let_statement = interner.get_global_let_statement(global_id);
// // if let Some(let_statement) = let_statement {
// // let expression = let_statement.expression;
// // try_eval_array_length_id_with_fuel(interner, expression, span, fuel - 1)
// // } else {
// // Err(Some(ResolverError::InvalidArrayLengthExpr { span }))
// // }
// }
// _ => {
// // TODO: new error
// let err = ResolverError::InvalidArrayLengthExpr { span };
// self.push_err(err);
// None
// },
// }
// } else {
// // TODO: new error
// let err = ResolverError::InvalidArrayLengthExpr { span };
// self.push_err(err);
// None
// }
//
// }
// HirExpression::Infix(infix) => {
// // let lhs = try_eval_array_length_id_with_fuel(interner, infix.lhs, span, fuel - 1)?;
// // let rhs = try_eval_array_length_id_with_fuel(interner, infix.rhs, span, fuel - 1)?;
// let lhs = Box::new(self.resolve_global_to_type(infix.lhs, kind.clone(), span)?);
// let rhs = Box::new(self.resolve_global_to_type(infix.rhs, kind.clone(), span)?);
//
// let op = match infix.operator.kind {
// BinaryOpKind::Add => Some(BinaryTypeOperator::Addition),
// BinaryOpKind::Subtract => Some(BinaryTypeOperator::Subtraction),
// BinaryOpKind::Multiply => Some(BinaryTypeOperator::Multiplication),
// BinaryOpKind::Divide => Some(BinaryTypeOperator::Division),
// BinaryOpKind::Modulo => Some(BinaryTypeOperator::Modulo),
//
// // TODO: support in InfixExpr?
// // BinaryOpKind::Equal => Ok((lhs == rhs) as u128),
// // BinaryOpKind::NotEqual => Ok((lhs != rhs) as u128),
// // BinaryOpKind::Less => Ok((lhs < rhs) as u128),
// // BinaryOpKind::LessEqual => Ok((lhs <= rhs) as u128),
// // BinaryOpKind::Greater => Ok((lhs > rhs) as u128),
// // BinaryOpKind::GreaterEqual => Ok((lhs >= rhs) as u128),
// // BinaryOpKind::And => Ok(lhs & rhs),
// // BinaryOpKind::Or => Ok(lhs | rhs),
// // BinaryOpKind::Xor => Ok(lhs ^ rhs),
// // BinaryOpKind::ShiftRight => Ok(lhs >> rhs),
// // BinaryOpKind::ShiftLeft => Ok(lhs << rhs),
//
// _ => {
// // TODO: new error
// let err = ResolverError::InvalidArrayLengthExpr { span };
// self.push_err(err);
// None
// }
// }?;
//
// Some(Type::InfixExpr(lhs, op, rhs))
// }
//
// // TODO: comptime only?
// // HirExpression::Cast(cast) => {
// // let lhs = try_eval_array_length_id_with_fuel(interner, cast.lhs, span, fuel - 1)?;
// // let lhs_value = Value::Field(lhs.into());
// // let evaluated_value =
// // Interpreter::evaluate_cast_one_step(&cast, rhs, lhs_value, interner)
// // .map_err(|error| Some(ResolverError::ArrayLengthInterpreter { error }))?;
// //
// // evaluated_value
// // .to_u128()
// // .ok_or_else(|| Some(ResolverError::InvalidArrayLengthExpr { span }))
// // }
//
// _other => {
// // TODO: new error
// let err = ResolverError::InvalidArrayLengthExpr { span };
// self.push_err(err);
// None
// },
// }
//
// }


pub(super) fn convert_expression_type(
&mut self,
length: UnresolvedTypeExpression,
Expand Down Expand Up @@ -763,32 +694,6 @@ impl<'context> Elaborator<'context> {
.or_else(|| self.resolve_trait_method_by_named_generic(path))
}

// // TODO remove
// fn eval_global_as_array_length(&mut self, global_id: GlobalId, path: &Path) -> u32 {
// let Some(stmt) = self.interner.get_global_let_statement(global_id) else {
// if let Some(global) = self.unresolved_globals.remove(&global_id) {
// self.elaborate_global(global);
// return self.eval_global_as_array_length(global_id, path);
// } else {
// let path = path.clone();
// self.push_err(ResolverError::NoSuchNumericTypeVariable { path });
// return 0;
// }
// };
//
// let length = stmt.expression;
// let span = self.interner.expr_span(&length);
// let result = try_eval_array_length_id(self.interner, length, span);
//
// match result.map(|length| length.try_into()) {
// Ok(Ok(length_value)) => return length_value,
// Ok(Err(_cast_err)) => self.push_err(ResolverError::IntegerTooLarge { span }),
// Err(Some(error)) => self.push_err(error),
// Err(None) => (),
// }
// 0
// }

pub(super) fn unify(
&mut self,
actual: &Type,
Expand Down Expand Up @@ -1876,7 +1781,8 @@ impl<'context> Elaborator<'context> {
| Type::TypeVariable(_)
| Type::Constant(..)
| Type::NamedGeneric(_, _)
| Type::Global(..)
// TODO cleanup
// | Type::Global(..)
| Type::Quoted(_)
| Type::Forall(_, _) => (),

Expand Down Expand Up @@ -2058,88 +1964,6 @@ fn bind_generic(param: &ResolvedGeneric, arg: &Type, bindings: &mut TypeBindings
}
}

pub fn try_eval_array_length_id(
interner: &NodeInterner,
rhs: ExprId,
span: Span,
) -> Result<u128, Option<ResolverError>> {
// Arbitrary amount of recursive calls to try before giving up
let fuel = 100;
try_eval_array_length_id_with_fuel(interner, rhs, span, fuel)
}

fn try_eval_array_length_id_with_fuel(
interner: &NodeInterner,
rhs: ExprId,
span: Span,
fuel: u32,
) -> Result<u128, Option<ResolverError>> {
if fuel == 0 {
// If we reach here, it is likely from evaluating cyclic globals. We expect an error to
// be issued for them after name resolution so issue no error now.
return Err(None);
}

match interner.expression(&rhs) {
HirExpression::Literal(HirLiteral::Integer(int, false)) => {
int.try_into_u128().ok_or(Some(ResolverError::IntegerTooLarge { span }))
}
HirExpression::Ident(ident, _) => {
if let Some(definition) = interner.try_definition(ident.id) {
match definition.kind {
DefinitionKind::Global(global_id) => {
let let_statement = interner.get_global_let_statement(global_id);
if let Some(let_statement) = let_statement {
let expression = let_statement.expression;
try_eval_array_length_id_with_fuel(interner, expression, span, fuel - 1)
} else {
Err(Some(ResolverError::InvalidArrayLengthExpr { span }))
}
}
_ => Err(Some(ResolverError::InvalidArrayLengthExpr { span })),
}
} else {
Err(Some(ResolverError::InvalidArrayLengthExpr { span }))
}
}
HirExpression::Infix(infix) => {
let lhs = try_eval_array_length_id_with_fuel(interner, infix.lhs, span, fuel - 1)?;
let rhs = try_eval_array_length_id_with_fuel(interner, infix.rhs, span, fuel - 1)?;

match infix.operator.kind {
BinaryOpKind::Add => Ok(lhs + rhs),
BinaryOpKind::Subtract => Ok(lhs - rhs),
BinaryOpKind::Multiply => Ok(lhs * rhs),
BinaryOpKind::Divide => Ok(lhs / rhs),
BinaryOpKind::Equal => Ok((lhs == rhs) as u128),
BinaryOpKind::NotEqual => Ok((lhs != rhs) as u128),
BinaryOpKind::Less => Ok((lhs < rhs) as u128),
BinaryOpKind::LessEqual => Ok((lhs <= rhs) as u128),
BinaryOpKind::Greater => Ok((lhs > rhs) as u128),
BinaryOpKind::GreaterEqual => Ok((lhs >= rhs) as u128),
BinaryOpKind::And => Ok(lhs & rhs),
BinaryOpKind::Or => Ok(lhs | rhs),
BinaryOpKind::Xor => Ok(lhs ^ rhs),
BinaryOpKind::ShiftRight => Ok(lhs >> rhs),
BinaryOpKind::ShiftLeft => Ok(lhs << rhs),
BinaryOpKind::Modulo => Ok(lhs % rhs),
}
}
HirExpression::Cast(cast) => {
let lhs = try_eval_array_length_id_with_fuel(interner, cast.lhs, span, fuel - 1)?;
let lhs_value = Value::Field(lhs.into());
let evaluated_value =
Interpreter::evaluate_cast_one_step(&cast, rhs, lhs_value, interner)
.map_err(|error| Some(ResolverError::ArrayLengthInterpreter { error }))?;

evaluated_value
.to_u128()
.ok_or_else(|| Some(ResolverError::InvalidArrayLengthExpr { span }))
}
_other => Err(Some(ResolverError::InvalidArrayLengthExpr { span })),
}
}

/// Gives an error if a user tries to create a mutable reference
/// to an immutable variable.
fn verify_mutable_reference(interner: &NodeInterner, rhs: ExprId) -> Result<(), ResolverError> {
Expand Down
11 changes: 6 additions & 5 deletions compiler/noirc_frontend/src/hir/comptime/hir_to_display_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,11 +340,12 @@ impl Type {
let name = Path::from_single(name.as_ref().clone(), Span::default());
UnresolvedTypeData::Named(name, GenericTypeArgs::default(), true)
}
Type::Global(_global_id, name, _kind) => {
// TODO: currently emitting globals as Named types for printing
let name = Path::from_single(name.as_ref().clone(), Span::default());
UnresolvedTypeData::Named(name, GenericTypeArgs::default(), true)
}
// TODO cleanup
// Type::Global(_global_id, name, _kind) => {
// // TODO: currently emitting globals as Named types for printing
// let name = Path::from_single(name.as_ref().clone(), Span::default());
// UnresolvedTypeData::Named(name, GenericTypeArgs::default(), true)
// }
Type::CheckedCast { to, .. } => to.to_display_ast().typ,
Type::Function(args, ret, env, unconstrained) => {
let args = vecmap(args, |arg| arg.to_display_ast());
Expand Down
Loading

0 comments on commit c155d33

Please sign in to comment.