diff --git a/crates/cairo-lang-language-server/src/ide/completion/completions.rs b/crates/cairo-lang-language-server/src/ide/completion/completions.rs index 7e238f261d9..9f5e4e277d3 100644 --- a/crates/cairo-lang-language-server/src/ide/completion/completions.rs +++ b/crates/cairo-lang-language-server/src/ide/completion/completions.rs @@ -95,7 +95,7 @@ pub fn generic_completions( fn resolved_generic_item_completion_kind(item: ResolvedGenericItem) -> CompletionItemKind { match item { - ResolvedGenericItem::Constant(_) => CompletionItemKind::CONSTANT, + ResolvedGenericItem::GenericConstant(_) => CompletionItemKind::CONSTANT, ResolvedGenericItem::Module(_) => CompletionItemKind::MODULE, ResolvedGenericItem::GenericFunction(_) | ResolvedGenericItem::TraitFunction(_) => { CompletionItemKind::FUNCTION diff --git a/crates/cairo-lang-language-server/src/ide/semantic_highlighting/token_kind.rs b/crates/cairo-lang-language-server/src/ide/semantic_highlighting/token_kind.rs index 5946d9da87b..24bdc61fce9 100644 --- a/crates/cairo-lang-language-server/src/ide/semantic_highlighting/token_kind.rs +++ b/crates/cairo-lang-language-server/src/ide/semantic_highlighting/token_kind.rs @@ -141,7 +141,7 @@ impl SemanticTokenKind { db.lookup_resolved_generic_item_by_ptr(lookup_item_id, identifier.stable_ptr()) { return Some(match item { - ResolvedGenericItem::Constant(_) => SemanticTokenKind::EnumMember, + ResolvedGenericItem::GenericConstant(_) => SemanticTokenKind::EnumMember, ResolvedGenericItem::Module(_) => SemanticTokenKind::Namespace, ResolvedGenericItem::GenericFunction(_) | ResolvedGenericItem::TraitFunction(_) => SemanticTokenKind::Function, @@ -163,8 +163,7 @@ impl SemanticTokenKind { ResolvedConcreteItem::Module(_) => SemanticTokenKind::Namespace, ResolvedConcreteItem::Function(_) | ResolvedConcreteItem::TraitFunction(_) => SemanticTokenKind::Function, - ResolvedConcreteItem::Type(_) - | ResolvedConcreteItem::ConstGenericParameter(_) => SemanticTokenKind::Type, + ResolvedConcreteItem::Type(_) => SemanticTokenKind::Type, ResolvedConcreteItem::Variant(_) => SemanticTokenKind::EnumMember, ResolvedConcreteItem::Trait(_) => SemanticTokenKind::Interface, ResolvedConcreteItem::Impl(_) => SemanticTokenKind::Class, diff --git a/crates/cairo-lang-language-server/src/lib.rs b/crates/cairo-lang-language-server/src/lib.rs index 0668899276a..c6d4907aaa8 100644 --- a/crates/cairo-lang-language-server/src/lib.rs +++ b/crates/cairo-lang-language-server/src/lib.rs @@ -939,7 +939,7 @@ fn resolved_generic_item_def( ) -> SyntaxStablePtrId { let defs_db = db.upcast(); match item { - ResolvedGenericItem::Constant(item) => item.untyped_stable_ptr(defs_db), + ResolvedGenericItem::GenericConstant(item) => item.untyped_stable_ptr(defs_db), ResolvedGenericItem::Module(module_id) => { // Check if the module is an inline submodule. if let ModuleId::Submodule(submodule_id) = module_id { diff --git a/crates/cairo-lang-lowering/src/add_withdraw_gas/mod.rs b/crates/cairo-lang-lowering/src/add_withdraw_gas/mod.rs index 344dd2a9f4b..8420e0db440 100644 --- a/crates/cairo-lang-lowering/src/add_withdraw_gas/mod.rs +++ b/crates/cairo-lang-lowering/src/add_withdraw_gas/mod.rs @@ -136,7 +136,10 @@ fn create_panic_block( location, }), Statement::Const(StatementConst { - value: ConstValue::Int(BigInt::from_bytes_be(Sign::Plus, "Out of gas".as_bytes())), + value: ConstValue::Int( + BigInt::from_bytes_be(Sign::Plus, "Out of gas".as_bytes()), + core_felt252_ty(db.upcast()), + ), output: out_of_gas_err_var, }), Statement::Call(StatementCall { diff --git a/crates/cairo-lang-lowering/src/db.rs b/crates/cairo-lang-lowering/src/db.rs index b177616803e..62cf3240610 100644 --- a/crates/cairo-lang-lowering/src/db.rs +++ b/crates/cairo-lang-lowering/src/db.rs @@ -11,11 +11,10 @@ use cairo_lang_semantic::{self as semantic, corelib, ConcreteTypeId, TypeId, Typ use cairo_lang_utils::ordered_hash_set::OrderedHashSet; use cairo_lang_utils::unordered_hash_map::UnorderedHashMap; use cairo_lang_utils::unordered_hash_set::UnorderedHashSet; -use cairo_lang_utils::{extract_matches, Intern, LookupIntern, Upcast}; +use cairo_lang_utils::{Intern, LookupIntern, Upcast}; use defs::ids::NamedLanguageElementId; use itertools::Itertools; use num_traits::ToPrimitive; -use semantic::items::constant::ConstValue; use crate::add_withdraw_gas::add_withdraw_gas; use crate::borrow_check::{borrow_check, PotentialDestructCalls}; @@ -760,7 +759,12 @@ fn type_size(db: &dyn LoweringGroup, ty: TypeId) -> usize { TypeLongId::Snapshot(ty) => db.type_size(ty), TypeLongId::FixedSizeArray { type_id, size } => { db.type_size(type_id) - * extract_matches!(size.lookup_intern(db), ConstValue::Int).to_usize().unwrap() + * size + .lookup_intern(db) + .into_int() + .expect("Expected ConstValue::Int for size") + .to_usize() + .unwrap() } TypeLongId::Coupon(_) => 0, TypeLongId::GenericParameter(_) diff --git a/crates/cairo-lang-lowering/src/lower/generators.rs b/crates/cairo-lang-lowering/src/lower/generators.rs index ca93d41a6ea..b47fb6e7dc2 100644 --- a/crates/cairo-lang-lowering/src/lower/generators.rs +++ b/crates/cairo-lang-lowering/src/lower/generators.rs @@ -32,6 +32,7 @@ impl StatementsBuilder { pub struct Const { pub value: ConstValue, pub location: LocationId, + // TODO(TomerStarkware): Remove this field and use the type from value. pub ty: semantic::TypeId, } impl Const { diff --git a/crates/cairo-lang-lowering/src/lower/mod.rs b/crates/cairo-lang-lowering/src/lower/mod.rs index 184edec2fc2..067332e3d49 100644 --- a/crates/cairo-lang-lowering/src/lower/mod.rs +++ b/crates/cairo-lang-lowering/src/lower/mod.rs @@ -663,7 +663,10 @@ fn lower_tuple_like_pattern_helper( let tys = match long_type_id { TypeLongId::Tuple(tys) => tys, TypeLongId::FixedSizeArray { type_id, size } => { - let size = extract_matches!(size.lookup_intern(ctx.db), ConstValue::Int) + let size = size + .lookup_intern(ctx.db) + .into_int() + .expect("Expected ConstValue::Int for size") .to_usize() .unwrap(); vec![type_id; size] @@ -874,7 +877,7 @@ fn add_chunks_to_data_array<'a>( let remainder = chunks.remainder(); for chunk in chunks { let chunk_usage = generators::Const { - value: ConstValue::Int(BigInt::from_bytes_be(Sign::Plus, chunk)), + value: ConstValue::Int(BigInt::from_bytes_be(Sign::Plus, chunk), bytes31_ty), ty: bytes31_ty, location: ctx.get_location(expr_stable_ptr), } @@ -908,7 +911,7 @@ fn add_pending_word( let felt252_ty = core_felt252_ty(ctx.db.upcast()); let pending_word_usage = generators::Const { - value: ConstValue::Int(BigInt::from_bytes_be(Sign::Plus, pending_word_bytes)), + value: ConstValue::Int(BigInt::from_bytes_be(Sign::Plus, pending_word_bytes), felt252_ty), ty: felt252_ty, location: ctx.get_location(expr_stable_ptr), } @@ -916,7 +919,7 @@ fn add_pending_word( let pending_word_len = expr.value.len() % 31; let pending_word_len_usage = generators::Const { - value: ConstValue::Int(pending_word_len.into()), + value: ConstValue::Int(pending_word_len.into(), u32_ty), ty: u32_ty, location: ctx.get_location(expr_stable_ptr), } @@ -971,8 +974,12 @@ fn lower_expr_fixed_size_array( semantic::FixedSizeArrayItems::ValueAndSize(value, size) => { let lowered_value = lower_expr(ctx, builder, *value)?; let var_usage = lowered_value.as_var_usage(ctx, builder)?; - let size = - extract_matches!(size.lookup_intern(ctx.db), ConstValue::Int).to_usize().unwrap(); + let size = size + .lookup_intern(ctx.db) + .into_int() + .expect("Expected ConstValue::Int for size") + .to_usize() + .unwrap(); if size == 0 { return Err(LoweringFlowError::Failed( ctx.diagnostics diff --git a/crates/cairo-lang-lowering/src/optimizations/const_folding.rs b/crates/cairo-lang-lowering/src/optimizations/const_folding.rs index 446c49ad735..d99dd2ee623 100644 --- a/crates/cairo-lang-lowering/src/optimizations/const_folding.rs +++ b/crates/cairo-lang-lowering/src/optimizations/const_folding.rs @@ -3,11 +3,11 @@ mod test; use cairo_lang_defs::ids::ModuleItemId; -use cairo_lang_semantic::corelib; +use cairo_lang_semantic::corelib::{self}; use cairo_lang_semantic::items::constant::ConstValue; use cairo_lang_utils::unordered_hash_map::UnorderedHashMap; use cairo_lang_utils::unordered_hash_set::UnorderedHashSet; -use cairo_lang_utils::{extract_matches, Intern}; +use cairo_lang_utils::Intern; use itertools::{chain, zip_eq}; use num_traits::Zero; @@ -89,6 +89,7 @@ pub fn const_folding(db: &dyn LoweringGroup, lowered: &mut FlatLowered) { Statement::Snapshot(stmt) => { if let Some(VarInfo::Const(val)) = var_info.get(&stmt.input.var_id) { let val = val.clone(); + // TODO(Tomerstarkware): add snapshot to value type. var_info.insert(stmt.original(), VarInfo::Const(val.clone())); var_info.insert(stmt.snapshot(), VarInfo::Const(val)); } @@ -96,13 +97,14 @@ pub fn const_folding(db: &dyn LoweringGroup, lowered: &mut FlatLowered) { Statement::Desnap(StatementDesnap { input, output }) => { if let Some(VarInfo::Const(val)) = var_info.get(&input.var_id) { let val = val.clone(); + // TODO(Tomerstarkware): remove snapshot from value type. var_info.insert(*output, VarInfo::Const(val)); } } Statement::Call(StatementCall { function, ref mut inputs, outputs, .. }) => { // (a - 0) can be replaced by a. if function == &felt_sub { - if let Some(VarInfo::Const(ConstValue::Int(val))) = + if let Some(VarInfo::Const(ConstValue::Int(val, _))) = var_info.get(&inputs[1].var_id) { if val.is_zero() { @@ -112,10 +114,7 @@ pub fn const_folding(db: &dyn LoweringGroup, lowered: &mut FlatLowered) { } else if let Some(extrn) = function.get_extern(db) { if extrn == into_box { if let Some(VarInfo::Const(val)) = var_info.get(&inputs[0].var_id) { - let value = ConstValue::Boxed( - lowered.variables[inputs[0].var_id].ty, - val.clone().into(), - ); + let value = ConstValue::Boxed(val.clone().into()); // Not inserting the value into the `var_info` map because the // resulting box isn't an actual const at the Sierra level. *stmt = @@ -123,7 +122,11 @@ pub fn const_folding(db: &dyn LoweringGroup, lowered: &mut FlatLowered) { } } else if extrn == upcast { if let Some(VarInfo::Const(value)) = var_info.get(&inputs[0].var_id) { - let value = value.clone(); + let value = ConstValue::Int( + value.clone().into_int().unwrap(), + lowered.variables[outputs[0]].ty, + ); + var_info.insert(outputs[0], VarInfo::Const(value.clone())); *stmt = Statement::Const(StatementConst { value, output: outputs[0] }); @@ -136,22 +139,22 @@ pub fn const_folding(db: &dyn LoweringGroup, lowered: &mut FlatLowered) { .iter() .map(|input| { if let Some(VarInfo::Const(val)) = var_info.get(&input.var_id) { - Some((lowered.variables[input.var_id].ty, val.clone())) + Some(val.clone()) } else { None } }) .collect::>>() { - let value = ConstValue::Struct(args); - var_info.insert(*output, VarInfo::Const(value.clone())); + let value = ConstValue::Struct(args, lowered.variables[*output].ty); + var_info.insert(*output, VarInfo::Const(value)); } } Statement::StructDestructure(StatementStructDestructure { input, outputs }) => { - if let Some(VarInfo::Const(ConstValue::Struct(args))) = + if let Some(VarInfo::Const(ConstValue::Struct(args, _))) = var_info.get(&input.var_id) { - for (output, (_, val)) in zip_eq(outputs, args.clone()) { + for (output, val) in zip_eq(outputs, args.clone()) { var_info.insert(*output, VarInfo::Const(val)); } } @@ -189,9 +192,12 @@ pub fn const_folding(db: &dyn LoweringGroup, lowered: &mut FlatLowered) { let input_var = inputs[0].var_id; if let Some(VarInfo::Const(val)) = var_info.get(&input_var) { let is_zero = match val { - ConstValue::Int(v) => v.is_zero(), - ConstValue::Struct(s) => s.iter().all(|(_, v)| { - extract_matches!(v, ConstValue::Int).is_zero() + ConstValue::Int(v, _) => v.is_zero(), + ConstValue::Struct(s, _) => s.iter().all(|v| { + v.clone() + .into_int() + .expect("Expected ConstValue::Int for size") + .is_zero() }), _ => unreachable!(), }; @@ -201,10 +207,7 @@ pub fn const_folding(db: &dyn LoweringGroup, lowered: &mut FlatLowered) { } else { let arm = &arms[1]; let nz_var = arm.var_ids[0]; - let nz_val = ConstValue::NonZero( - lowered.variables[input_var].ty, - Box::new(val.clone()), - ); + let nz_val = ConstValue::NonZero(Box::new(val.clone())); var_info.insert(nz_var, VarInfo::Const(nz_val.clone())); block.statements.push(Statement::Const(StatementConst { value: nz_val, diff --git a/crates/cairo-lang-semantic/src/corelib.rs b/crates/cairo-lang-semantic/src/corelib.rs index 7e80aa0156b..ed77c7cc6fd 100644 --- a/crates/cairo-lang-semantic/src/corelib.rs +++ b/crates/cairo-lang-semantic/src/corelib.rs @@ -73,8 +73,9 @@ pub fn core_felt252_ty(db: &dyn SemanticGroup) -> TypeId { /// Returns the concrete type of a bounded int type with a given min and max. pub fn bounded_int_ty(db: &dyn SemanticGroup, min: BigInt, max: BigInt) -> TypeId { let internal = core_submodule(db, "internal"); - let lower_id = ConstValue::Int(min).intern(db); - let upper_id = ConstValue::Int(max).intern(db); + let size_ty = core_felt252_ty(db); + let lower_id = ConstValue::Int(min, size_ty).intern(db); + let upper_id = ConstValue::Int(max, size_ty).intern(db); try_get_ty_by_name( db, internal, @@ -111,6 +112,15 @@ pub fn core_option_ty(db: &dyn SemanticGroup, some_type: TypeId) -> TypeId { ) } +pub fn core_box_ty(db: &dyn SemanticGroup, inner_type: TypeId) -> TypeId { + get_ty_by_name( + db, + core_submodule(db, "box"), + "Box".into(), + vec![GenericArgumentId::Type(inner_type)], + ) +} + pub fn core_array_felt252_ty(db: &dyn SemanticGroup) -> TypeId { get_core_ty_by_name(db, "Array".into(), vec![GenericArgumentId::Type(core_felt252_ty(db))]) } @@ -831,6 +841,7 @@ fn try_extract_bounded_int_type_ranges( else { return None; }; - let to_int = |id| try_extract_matches!(db.lookup_intern_const_value(id), ConstValue::Int); + let to_int = |id| db.lookup_intern_const_value(id).into_int(); + Some((to_int(min)?, to_int(max)?)) } diff --git a/crates/cairo-lang-semantic/src/diagnostic.rs b/crates/cairo-lang-semantic/src/diagnostic.rs index 0074eaf45d0..17c62604357 100644 --- a/crates/cairo-lang-semantic/src/diagnostic.rs +++ b/crates/cairo-lang-semantic/src/diagnostic.rs @@ -1158,7 +1158,6 @@ impl From<&ResolvedConcreteItem> for ElementKind { fn from(val: &ResolvedConcreteItem) -> Self { match val { ResolvedConcreteItem::Constant(_) => ElementKind::Constant, - ResolvedConcreteItem::ConstGenericParameter(_) => ElementKind::Constant, ResolvedConcreteItem::Module(_) => ElementKind::Module, ResolvedConcreteItem::Function(_) => ElementKind::Function, ResolvedConcreteItem::TraitFunction(_) => ElementKind::TraitFunction, diff --git a/crates/cairo-lang-semantic/src/expr/compute.rs b/crates/cairo-lang-semantic/src/expr/compute.rs index 1ead20323eb..2ed10ba71a1 100644 --- a/crates/cairo-lang-semantic/src/expr/compute.rs +++ b/crates/cairo-lang-semantic/src/expr/compute.rs @@ -2,6 +2,7 @@ //! the code, while type checking. //! It is invoked by queries for function bodies and other code blocks. +use core::panic; use std::ops::Deref; use std::sync::Arc; @@ -45,8 +46,8 @@ use super::pattern::{ }; use crate::corelib::{ core_binary_operator, core_bool_ty, core_unary_operator, false_literal_expr, get_core_trait, - never_ty, numeric_literal_trait, true_literal_expr, try_get_core_ty_by_name, unit_expr, - unit_ty, unwrap_error_propagation_type, CoreTraitContext, + get_usize_ty, never_ty, numeric_literal_trait, true_literal_expr, try_get_core_ty_by_name, + unit_expr, unit_ty, unwrap_error_propagation_type, CoreTraitContext, }; use crate::db::SemanticGroup; use crate::diagnostic::SemanticDiagnosticKind::{self, *}; @@ -71,8 +72,8 @@ use crate::types::{ ConcreteTypeId, }; use crate::{ - ConcreteEnumId, GenericArgumentId, GenericParam, Member, Mutability, Parameter, - PatternStringLiteral, PatternStruct, Signature, + ConcreteEnumId, GenericArgumentId, Member, Mutability, Parameter, PatternStringLiteral, + PatternStruct, Signature, }; /// Expression with its id. @@ -650,6 +651,7 @@ fn compute_expr_fixed_size_array_semantic( let db = ctx.db; let syntax_db = db.upcast(); let exprs = syntax.exprs(syntax_db).elements(syntax_db); + let size_ty = get_usize_ty(db); let (items, type_id, size) = if let Some(size_const_id) = extract_fixed_size_array_size(db, ctx.diagnostics, syntax, &ctx.resolver)? { @@ -658,7 +660,9 @@ fn compute_expr_fixed_size_array_semantic( return Err(ctx.diagnostics.report(syntax, FixedSizeArrayNonSingleValue)); }; let expr_semantic = compute_expr_semantic(ctx, expr); - let size = try_extract_matches!(size_const_id.lookup_intern(db), ConstValue::Int) + let size = size_const_id + .lookup_intern(db) + .into_int() .ok_or_else(|| ctx.diagnostics.report(syntax, FixedSizeArrayNonNumericSize))? .to_usize() .unwrap(); @@ -669,7 +673,7 @@ fn compute_expr_fixed_size_array_semantic( size_const_id, ) } else if let Some((first_expr, tail_exprs)) = exprs.split_first() { - let size = ConstValue::Int((tail_exprs.len() + 1).into()).intern(db); + let size = ConstValue::Int((tail_exprs.len() + 1).into(), size_ty).intern(db); let first_expr_semantic = compute_expr_semantic(ctx, first_expr); let mut items: Vec = vec![first_expr_semantic.id]; // The type of the first expression is the type of the array. All other expressions must @@ -694,7 +698,7 @@ fn compute_expr_fixed_size_array_semantic( ( FixedSizeArrayItems::Items(vec![]), ctx.resolver.inference().new_type_var(Some(syntax.into())), - ConstValue::Int(0.into()).intern(db), + ConstValue::Int(0.into(), size_ty).intern(db), ) }; Ok(Expr::FixedSizeArray(ExprFixedSizeArray { @@ -1781,8 +1785,12 @@ fn maybe_compute_tuple_like_pattern_semantic( let inner_tys = match long_ty { TypeLongId::Tuple(inner_tys) => inner_tys, TypeLongId::FixedSizeArray { type_id: inner_ty, size } => { - let size = - extract_matches!(size.lookup_intern(ctx.db), ConstValue::Int).to_usize().unwrap(); + let size = size + .lookup_intern(ctx.db) + .into_int() + .expect("Expected ConstValue::Int for size") + .to_usize() + .unwrap(); [inner_ty].repeat(size) } _ => unreachable!(), @@ -2393,22 +2401,12 @@ fn resolve_expr_path(ctx: &mut ComputationContext<'_>, path: &ast::ExprPath) -> ctx.resolver.resolve_concrete_path(ctx.diagnostics, path, NotFoundItemType::Identifier)?; match resolved_item { - ResolvedConcreteItem::Constant(constant_id) => Ok(Expr::Constant(ExprConstant { - const_value_id: db.constant_const_value(constant_id)?.intern(db), - ty: db.constant_const_type(constant_id)?, + ResolvedConcreteItem::Constant(const_value_id) => Ok(Expr::Constant(ExprConstant { + const_value_id, + ty: const_value_id.ty(db)?, stable_ptr: path.stable_ptr().into(), })), - ResolvedConcreteItem::ConstGenericParameter(generic_param_id) => { - Ok(Expr::Constant(ExprConstant { - const_value_id: ConstValue::Generic(generic_param_id).intern(db), - ty: extract_matches!( - db.generic_param_semantic(generic_param_id)?, - GenericParam::Const - ) - .ty, - stable_ptr: path.stable_ptr().into(), - })) - } + ResolvedConcreteItem::Variant(variant) if variant.ty == unit_ty(db) => { let stable_ptr = path.stable_ptr().into(); let concrete_enum_id = variant.concrete_enum_id; diff --git a/crates/cairo-lang-semantic/src/expr/inference.rs b/crates/cairo-lang-semantic/src/expr/inference.rs index ef63fa11068..d943b8ee16f 100644 --- a/crates/cairo-lang-semantic/src/expr/inference.rs +++ b/crates/cairo-lang-semantic/src/expr/inference.rs @@ -470,9 +470,13 @@ impl<'db> Inference<'db> { /// Allocates a new [ConstVar] for an unknown consts that needs to be inferred. /// Returns a wrapping [ConstValueId]. - pub fn new_const_var(&mut self, stable_ptr: Option) -> ConstValueId { + pub fn new_const_var( + &mut self, + stable_ptr: Option, + ty: TypeId, + ) -> ConstValueId { let var = self.new_const_var_raw(stable_ptr); - ConstValue::Var(var).intern(self.db) + ConstValue::Var(var, ty).intern(self.db) } /// Allocates a new [ConstVar] for an unknown type that needs to be inferred. @@ -753,7 +757,8 @@ impl<'db> Inference<'db> { fn assign_const(&mut self, var: ConstVar, id: ConstValueId) -> InferenceResult { if var.inference_id != self.inference_id { return Err(self.set_error(InferenceError::ConstKindMismatch { - const0: ConstValue::Var(var).intern(self.db), + const0: ConstValue::Var(var, TypeId::missing(self.db, skip_diagnostic())) + .intern(self.db), const1: id, })); } @@ -806,7 +811,7 @@ impl<'db> Inference<'db> { return Ok(SolutionSet::Ambiguous(Ambiguity::WillNotInfer(concrete_trait_id))); } Some(GenericArgumentId::Constant(const_value)) => { - if let ConstValue::Var(_) = const_value.lookup_intern(self.db) { + if let ConstValue::Var(_, _) = const_value.lookup_intern(self.db) { // Don't try to infer such impls. return Ok(SolutionSet::Ambiguous(Ambiguity::WillNotInfer(concrete_trait_id))); } @@ -1079,7 +1084,7 @@ impl<'a> SemanticRewriter for Inference<'a> { } impl<'a> SemanticRewriter for Inference<'a> { fn internal_rewrite(&mut self, value: &mut ConstValue) -> Result { - if let ConstValue::Var(var) = value { + if let ConstValue::Var(var, _) = value { if let Some(const_value_id) = self.const_assignment.get(&var.id) { let mut const_value = const_value_id.lookup_intern(self.db); if let RewriteResult::Modified = self.internal_rewrite(&mut const_value)? { diff --git a/crates/cairo-lang-semantic/src/expr/inference/canonic.rs b/crates/cairo-lang-semantic/src/expr/inference/canonic.rs index d8adee49f03..3abe7ff8114 100644 --- a/crates/cairo-lang-semantic/src/expr/inference/canonic.rs +++ b/crates/cairo-lang-semantic/src/expr/inference/canonic.rs @@ -204,17 +204,20 @@ impl<'a> SemanticRewriter for Canonicalizer<'a> { } impl<'a> SemanticRewriter for Canonicalizer<'a> { fn internal_rewrite(&mut self, value: &mut ConstValue) -> Result { - let ConstValue::Var(var) = value else { + let ConstValue::Var(var, ty) = value else { return value.default_rewrite(self); }; if var.inference_id != self.to_canonic.source_inference_id { return value.default_rewrite(self); } let next_id = LocalConstVarId(self.to_canonic.const_var_mapping.len()); - *value = ConstValue::Var(ConstVar { - id: *self.to_canonic.const_var_mapping.entry(var.id).or_insert(next_id), - inference_id: InferenceId::Canonical, - }); + *value = ConstValue::Var( + ConstVar { + id: *self.to_canonic.const_var_mapping.entry(var.id).or_insert(next_id), + inference_id: InferenceId::Canonical, + }, + *ty, + ); Ok(RewriteResult::Modified) } } @@ -363,7 +366,7 @@ impl<'db> SemanticRewriter for Mapper<'db> { } impl<'db> SemanticRewriter for Mapper<'db> { fn internal_rewrite(&mut self, value: &mut ConstValue) -> Result { - let ConstValue::Var(var) = value else { + let ConstValue::Var(var, ty) = value else { return value.default_rewrite(self); }; let id = self @@ -372,7 +375,8 @@ impl<'db> SemanticRewriter for Mapper<'db> { .get(&var.id) .copied() .ok_or(MapperError(InferenceVar::Const(var.id)))?; - *value = ConstValue::Var(ConstVar { id, inference_id: self.mapping.target_inference_id }); + *value = + ConstValue::Var(ConstVar { id, inference_id: self.mapping.target_inference_id }, *ty); Ok(RewriteResult::Modified) } } diff --git a/crates/cairo-lang-semantic/src/expr/inference/conform.rs b/crates/cairo-lang-semantic/src/expr/inference/conform.rs index eb4f6b59fe5..f5f9dda0f84 100644 --- a/crates/cairo-lang-semantic/src/expr/inference/conform.rs +++ b/crates/cairo-lang-semantic/src/expr/inference/conform.rs @@ -216,11 +216,11 @@ impl<'db> InferenceConform for Inference<'db> { } match id1.lookup_intern(self.db) { ConstValue::Missing(_) => return Ok(id1), - ConstValue::Var(var) => return self.assign_const(var, id0), + ConstValue::Var(var, _) => return self.assign_const(var, id0), _ => {} } match const_value0 { - ConstValue::Var(var) => Ok(self.assign_const(var, id1)?), + ConstValue::Var(var, _) => Ok(self.assign_const(var, id1)?), _ => { Err(self.set_error(InferenceError::ConstKindMismatch { const0: id0, const1: id1 })) } diff --git a/crates/cairo-lang-semantic/src/expr/inference/infers.rs b/crates/cairo-lang-semantic/src/expr/inference/infers.rs index 516a95f75b8..f9520e0e56e 100644 --- a/crates/cairo-lang-semantic/src/expr/inference/infers.rs +++ b/crates/cairo-lang-semantic/src/expr/inference/infers.rs @@ -7,6 +7,7 @@ use super::canonic::ResultNoErrEx; use super::conform::InferenceConform; use super::{Inference, InferenceError, InferenceResult}; use crate::items::functions::{GenericFunctionId, ImplGenericFunctionId}; +use crate::items::generics::GenericParamConst; use crate::items::imp::{ImplId, ImplLookupContext, UninferredImpl}; use crate::items::trt::{ConcreteTraitGenericFunctionId, ConcreteTraitTypeId}; use crate::substitution::{GenericSubstitution, SemanticRewriter, SubstitutionRewriter}; @@ -341,8 +342,8 @@ impl<'db> InferenceEmbeddings for Inference<'db> { lookup_context, )?)) } - GenericParam::Const(_) => { - Ok(GenericArgumentId::Constant(self.new_const_var(stable_ptr))) + GenericParam::Const(GenericParamConst { ty, .. }) => { + Ok(GenericArgumentId::Constant(self.new_const_var(stable_ptr, *ty))) } GenericParam::NegImpl(_) => Ok(GenericArgumentId::NegImpl), } diff --git a/crates/cairo-lang-semantic/src/items/constant.rs b/crates/cairo-lang-semantic/src/items/constant.rs index 0ad7fb2d47a..8b076bc96ef 100644 --- a/crates/cairo-lang-semantic/src/items/constant.rs +++ b/crates/cairo-lang-semantic/src/items/constant.rs @@ -10,7 +10,9 @@ use cairo_lang_proc_macros::{DebugWithDb, SemanticObject}; use cairo_lang_syntax::node::ast::ItemConstant; use cairo_lang_syntax::node::ids::SyntaxStablePtrId; use cairo_lang_syntax::node::{TypedStablePtr, TypedSyntaxNode}; -use cairo_lang_utils::{define_short_id, extract_matches, try_extract_matches, LookupIntern}; +use cairo_lang_utils::{ + define_short_id, extract_matches, try_extract_matches, Intern, LookupIntern, +}; use id_arena::Arena; use itertools::Itertools; use num_bigint::BigInt; @@ -19,8 +21,8 @@ use num_traits::{Num, ToPrimitive, Zero}; use super::functions::{GenericFunctionId, GenericFunctionWithBodyId}; use super::structure::SemanticStructEx; use crate::corelib::{ - core_felt252_ty, get_core_trait, get_core_ty_by_name, try_extract_nz_wrapped_type, - validate_literal, CoreTraitContext, LiteralError, + core_box_ty, core_felt252_ty, core_nonzero_ty, get_core_trait, get_core_ty_by_name, + try_extract_nz_wrapped_type, validate_literal, CoreTraitContext, LiteralError, }; use crate::db::SemanticGroup; use crate::diagnostic::{SemanticDiagnosticKind, SemanticDiagnostics, SemanticDiagnosticsBuilder}; @@ -31,9 +33,9 @@ use crate::literals::try_extract_minus_literal; use crate::resolve::{Resolver, ResolverData}; use crate::types::resolve_type; use crate::{ - semantic_object_for_id, ConcreteVariant, Expr, ExprBlock, ExprConstant, ExprFunctionCall, - ExprFunctionCallArg, ExprId, ExprMemberAccess, ExprStructCtor, FunctionId, SemanticDiagnostic, - TypeId, + semantic_object_for_id, ConcreteTypeId, ConcreteVariant, Expr, ExprBlock, ExprConstant, + ExprFunctionCall, ExprFunctionCallArg, ExprId, ExprMemberAccess, ExprStructCtor, FunctionId, + GenericParam, SemanticDiagnostic, TypeId, TypeLongId, }; #[derive(Clone, Debug, PartialEq, Eq, DebugWithDb)] @@ -44,6 +46,7 @@ pub struct Constant { /// The arena of all the expressions for the const calculation. pub exprs: Arc>, } + impl Constant { pub fn ty(&self) -> TypeId { self.exprs[self.value].ty() @@ -59,7 +62,6 @@ pub struct ConstantData { pub diagnostics: Diagnostics, pub constant: Maybe, pub const_value: ConstValue, - pub ty: TypeId, pub resolver_data: Arc, } @@ -85,18 +87,23 @@ impl ConstValueId { pub fn is_var_free(&self, db: &dyn SemanticGroup) -> bool { self.lookup_intern(db).is_var_free() } + + /// Returns the type of the const. + pub fn ty(&self, db: &dyn SemanticGroup) -> Maybe { + self.lookup_intern(db).ty(db) + } } /// A constant value. #[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject)] pub enum ConstValue { - Int(#[dont_rewrite] BigInt), - Struct(Vec<(TypeId, ConstValue)>), + Int(#[dont_rewrite] BigInt, TypeId), + Struct(Vec, TypeId), Enum(ConcreteVariant, Box), - NonZero(TypeId, Box), - Boxed(TypeId, Box), + NonZero(Box), + Boxed(Box), Generic(#[dont_rewrite] GenericParamId), - Var(ConstVar), + Var(ConstVar, TypeId), /// A missing value, used in cases where the value is not known due to diagnostics. Missing(#[dont_rewrite] DiagnosticAdded), } @@ -104,26 +111,52 @@ impl ConstValue { /// Returns true if the const does not depend on any generics. pub fn is_fully_concrete(&self) -> bool { match self { - ConstValue::Int(_) => true, - ConstValue::Struct(members) => { - members.iter().all(|(_, member)| member.is_fully_concrete()) + ConstValue::Int(_, _) => true, + ConstValue::Struct(members, _) => { + members.iter().all(|member| member.is_fully_concrete()) } - ConstValue::Enum(_, value) - | ConstValue::NonZero(_, value) - | ConstValue::Boxed(_, value) => value.is_fully_concrete(), - ConstValue::Generic(_) | ConstValue::Var(_) | ConstValue::Missing(_) => false, + ConstValue::Enum(_, value) | ConstValue::NonZero(value) | ConstValue::Boxed(value) => { + value.is_fully_concrete() + } + ConstValue::Generic(_) | ConstValue::Var(_, _) | ConstValue::Missing(_) => false, } } /// Returns true if the const does not contain any inference variables. pub fn is_var_free(&self) -> bool { match self { - ConstValue::Int(_) | ConstValue::Generic(_) | ConstValue::Missing(_) => true, - ConstValue::Struct(members) => members.iter().all(|(_, member)| member.is_var_free()), - ConstValue::Enum(_, value) - | ConstValue::NonZero(_, value) - | ConstValue::Boxed(_, value) => value.is_var_free(), - ConstValue::Var(_) => false, + ConstValue::Int(_, _) | ConstValue::Generic(_) | ConstValue::Missing(_) => true, + ConstValue::Struct(members, _) => members.iter().all(|member| member.is_var_free()), + ConstValue::Enum(_, value) | ConstValue::NonZero(value) | ConstValue::Boxed(value) => { + value.is_var_free() + } + ConstValue::Var(_, _) => false, + } + } + + /// Returns the type of the const. + pub fn ty(&self, db: &dyn SemanticGroup) -> Maybe { + Ok(match self { + ConstValue::Int(_, ty) => *ty, + ConstValue::Struct(_, ty) => *ty, + ConstValue::Enum(variant, _) => { + TypeLongId::Concrete(ConcreteTypeId::Enum(variant.concrete_enum_id)).intern(db) + } + ConstValue::NonZero(value) => core_nonzero_ty(db, value.ty(db)?), + ConstValue::Boxed(value) => core_box_ty(db, value.ty(db)?), + ConstValue::Generic(param) => { + extract_matches!(db.generic_param_semantic(*param)?, GenericParam::Const).ty + } + ConstValue::Var(_var, ty) => *ty, + ConstValue::Missing(_) => TypeId::missing(db, skip_diagnostic()), + }) + } + + /// Returns the value of an int const as a BigInt. + pub fn into_int(self) -> Option { + match self { + ConstValue::Int(value, _) => Some(value), + _ => None, } } } @@ -194,7 +227,7 @@ pub fn constant_semantic_data_helper( let mut ctx = ComputationContext::new(db, &mut diagnostics, resolver, None, environment); let value = compute_expr_semantic(&mut ctx, &constant_ast.value(syntax_db)); - let (ty, const_value) = resolve_const_expr_and_evaluate( + let const_value = resolve_const_expr_and_evaluate( db, &mut ctx, &value, @@ -211,7 +244,6 @@ pub fn constant_semantic_data_helper( Ok(ConstantData { diagnostics: diagnostics.build(), const_value, - ty, constant: Ok(constant), resolver_data, }) @@ -242,7 +274,6 @@ pub fn constant_semantic_data_cycle_helper( Ok(ConstantData { constant: Err(diagnostic_added), const_value: ConstValue::Missing(diagnostic_added), - ty: TypeId::missing(db, diagnostic_added), diagnostics: diagnostics.build(), resolver_data, }) @@ -255,7 +286,7 @@ pub fn resolve_const_expr_and_evaluate( value: &ExprAndId, const_stable_ptr: SyntaxStablePtrId, target_type: TypeId, -) -> (TypeId, ConstValue) { +) -> ConstValue { let inference = &mut ctx.resolver.inference(); if let Err(err_set) = inference.conform_ty(value.ty(), target_type) { inference.report_on_pending_error(err_set, ctx.diagnostics, const_stable_ptr); @@ -268,9 +299,7 @@ pub fn resolve_const_expr_and_evaluate( ctx.apply_inference_rewriter_to_exprs(); match &value.expr { - Expr::Constant(ExprConstant { const_value_id, ty, .. }) => { - (*ty, const_value_id.lookup_intern(db)) - } + Expr::Constant(ExprConstant { const_value_id, .. }) => const_value_id.lookup_intern(db), // Check that the expression is a valid constant. _ => evaluate_constant_expr(db, &ctx.exprs, value.id, ctx.diagnostics), } @@ -287,21 +316,21 @@ pub fn value_as_const_value( let u256_ty = get_core_ty_by_name(db.upcast(), "u256".into(), vec![]); if ty != u256_ty { - ConstValue::Int(value.clone()) + ConstValue::Int(value.clone(), ty) } else { let u128_ty = get_core_ty_by_name(db.upcast(), "u128".into(), vec![]); let mask128 = BigInt::from(u128::MAX); let low = value & mask128; let high = value >> 128; - ConstValue::Struct(vec![ - (u128_ty, ConstValue::Int(low)), - (u128_ty, ConstValue::Int(high)), - ]) + ConstValue::Struct( + vec![(ConstValue::Int(low, u128_ty)), (ConstValue::Int(high, u128_ty))], + ty, + ) } }; if let Some(inner) = try_extract_nz_wrapped_type(db.upcast(), ty) { - Ok(ConstValue::NonZero(inner, Box::new(get_basic_const_value(inner)))) + Ok(ConstValue::NonZero(Box::new(get_basic_const_value(inner)))) } else { Ok(get_basic_const_value(ty)) } @@ -313,72 +342,65 @@ pub fn evaluate_constant_expr( exprs: &Arena, expr_id: ExprId, diagnostics: &mut SemanticDiagnostics, -) -> (TypeId, ConstValue) { +) -> ConstValue { let expr = &exprs[expr_id]; - ( - expr.ty(), - match expr { - Expr::Constant(expr) => expr.const_value_id.lookup_intern(db), - Expr::Block(ExprBlock { statements, tail: Some(inner), .. }) - if statements.is_empty() => - { - evaluate_constant_expr(db, exprs, *inner, diagnostics).1 - } - Expr::FunctionCall(expr) => evaluate_const_function_call(db, exprs, expr, diagnostics) - .map(|value| { - value_as_const_value(db, expr.ty, &value) - .map_err(|err| { - diagnostics.report( - expr.stable_ptr.untyped(), - SemanticDiagnosticKind::LiteralError(err), - ) - }) - .unwrap_or_else(ConstValue::Missing) - }) - .unwrap_or_else(ConstValue::Missing), - Expr::Literal(expr) => value_as_const_value(db, expr.ty, &expr.value) - .map_err(|err| { - diagnostics.report( - expr.stable_ptr.untyped(), - SemanticDiagnosticKind::LiteralError(err), - ) - }) - .unwrap_or_else(ConstValue::Missing), - Expr::Tuple(expr) => ConstValue::Struct( - expr.items + + match expr { + Expr::Constant(expr) => expr.const_value_id.lookup_intern(db), + Expr::Block(ExprBlock { statements, tail: Some(inner), .. }) if statements.is_empty() => { + evaluate_constant_expr(db, exprs, *inner, diagnostics) + } + Expr::FunctionCall(expr) => evaluate_const_function_call(db, exprs, expr, diagnostics) + .map(|value| { + value_as_const_value(db, expr.ty, &value) + .map_err(|err| { + diagnostics.report( + expr.stable_ptr.untyped(), + SemanticDiagnosticKind::LiteralError(err), + ) + }) + .unwrap_or_else(ConstValue::Missing) + }) + .unwrap_or_else(ConstValue::Missing), + Expr::Literal(expr) => value_as_const_value(db, expr.ty, &expr.value) + .map_err(|err| { + diagnostics + .report(expr.stable_ptr.untyped(), SemanticDiagnosticKind::LiteralError(err)) + }) + .unwrap_or_else(ConstValue::Missing), + Expr::Tuple(expr) => ConstValue::Struct( + expr.items + .iter() + .map(|expr_id| evaluate_constant_expr(db, exprs, *expr_id, diagnostics)) + .collect(), + expr.ty, + ), + Expr::StructCtor(ExprStructCtor { members, base_struct: None, ty, .. }) => { + ConstValue::Struct( + members .iter() - .map(|expr_id| evaluate_constant_expr(db, exprs, *expr_id, diagnostics)) + .map(|(_, expr_id)| evaluate_constant_expr(db, exprs, *expr_id, diagnostics)) .collect(), - ), - Expr::StructCtor(ExprStructCtor { members, base_struct: None, .. }) => { - ConstValue::Struct( - members - .iter() - .map(|(_, expr_id)| { - evaluate_constant_expr(db, exprs, *expr_id, diagnostics) - }) - .collect(), - ) - } - Expr::EnumVariantCtor(expr) => ConstValue::Enum( - expr.variant.clone(), - Box::new(evaluate_constant_expr(db, exprs, expr.value_expr, diagnostics).1), - ), - Expr::MemberAccess(expr) => extract_const_member_access(db, exprs, expr, diagnostics) - .unwrap_or_else(ConstValue::Missing), - Expr::FixedSizeArray(expr) => ConstValue::Struct(match &expr.items { + *ty, + ) + } + Expr::EnumVariantCtor(expr) => ConstValue::Enum( + expr.variant.clone(), + Box::new(evaluate_constant_expr(db, exprs, expr.value_expr, diagnostics)), + ), + Expr::MemberAccess(expr) => extract_const_member_access(db, exprs, expr, diagnostics) + .unwrap_or_else(ConstValue::Missing), + Expr::FixedSizeArray(expr) => ConstValue::Struct( + match &expr.items { crate::FixedSizeArrayItems::Items(items) => items .iter() .map(|expr_id| evaluate_constant_expr(db, exprs, *expr_id, diagnostics)) .collect(), crate::FixedSizeArrayItems::ValueAndSize(value, count) => { - let value = evaluate_constant_expr(db, exprs, *value, diagnostics).1; + let value = evaluate_constant_expr(db, exprs, *value, diagnostics); let count = count.lookup_intern(db); - if let ConstValue::Int(count) = count { - (0..count.to_usize().unwrap()) - .map(|_| value.clone()) - .map(|value| (expr.ty, value)) - .collect() + if let Some(count) = count.into_int() { + (0..count.to_usize().unwrap()).map(|_| value.clone()).collect() } else { diagnostics.report( expr.stable_ptr.untyped(), @@ -387,16 +409,15 @@ pub fn evaluate_constant_expr( vec![] } } - }), - _ if diagnostics.error_count == 0 => { - ConstValue::Missing(diagnostics.report( - expr.stable_ptr().untyped(), - SemanticDiagnosticKind::UnsupportedConstant, - )) - } - _ => ConstValue::Missing(skip_diagnostic()), - }, - ) + }, + expr.ty, + ), + _ if diagnostics.error_count == 0 => ConstValue::Missing( + diagnostics + .report(expr.stable_ptr().untyped(), SemanticDiagnosticKind::UnsupportedConstant), + ), + _ => ConstValue::Missing(skip_diagnostic()), + } } /// Returns true if the given function is allowed to be called in constant context. @@ -441,11 +462,11 @@ fn evaluate_const_function_call( .iter() .filter_map(|arg| try_extract_matches!(arg, ExprFunctionCallArg::Value)) .map(|arg| { - match evaluate_constant_expr(db, exprs, *arg, diagnostics).1 { - ConstValue::Int(v) => Ok(v), + match evaluate_constant_expr(db, exprs, *arg, diagnostics) { + ConstValue::Int(v, _ty) => Ok(v), // Handling u256 constants to enable const evaluation of them. - ConstValue::Struct(v) => { - if let [(_, ConstValue::Int(low)), (_, ConstValue::Int(high))] = &v[..] { + ConstValue::Struct(v, _) => { + if let [ConstValue::Int(low, _), ConstValue::Int(high, _)] = &v[..] { Ok(low + (high << 128)) } else { Err(diagnostics.report( @@ -509,8 +530,8 @@ fn extract_const_member_access( expr: &ExprMemberAccess, diagnostics: &mut SemanticDiagnostics, ) -> Maybe { - let full_struct = evaluate_constant_expr(db, exprs, expr.expr, diagnostics).1; - let ConstValue::Struct(mut values) = full_struct else { + let full_struct = evaluate_constant_expr(db, exprs, expr.expr, diagnostics); + let ConstValue::Struct(mut values, _) = full_struct else { return Err(diagnostics.report( exprs[expr.expr].stable_ptr().untyped(), SemanticDiagnosticKind::UnsupportedConstant, @@ -523,7 +544,7 @@ fn extract_const_member_access( SemanticDiagnosticKind::UnsupportedConstant, )); }; - Ok(values.swap_remove(member_idx).1) + Ok(values.swap_remove(member_idx)) } /// Query implementation of [SemanticGroup::constant_semantic_diagnostics]. @@ -583,7 +604,7 @@ pub fn constant_const_value_cycle( /// Query implementation of [crate::db::SemanticGroup::constant_const_type]. pub fn constant_const_type(db: &dyn SemanticGroup, const_id: ConstantId) -> Maybe { - Ok(db.priv_constant_semantic_data(const_id)?.ty) + db.priv_constant_semantic_data(const_id)?.const_value.ty(db) } /// Cycle handling for [crate::db::SemanticGroup::constant_const_type]. @@ -593,5 +614,5 @@ pub fn constant_const_type_cycle( const_id: &ConstantId, ) -> Maybe { // Forwarding cycle handling to `priv_constant_semantic_data` handler. - Ok(db.priv_constant_semantic_data(*const_id)?.ty) + db.priv_constant_semantic_data(*const_id)?.const_value.ty(db) } diff --git a/crates/cairo-lang-semantic/src/items/fmt.rs b/crates/cairo-lang-semantic/src/items/fmt.rs index 91d64bcc542..f23655773dc 100644 --- a/crates/cairo-lang-semantic/src/items/fmt.rs +++ b/crates/cairo-lang-semantic/src/items/fmt.rs @@ -10,15 +10,15 @@ impl> DebugWithDb for Const fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &Db) -> std::fmt::Result { let db = db.upcast(); match self { - ConstValue::Int(value) => write!(f, "{}", value), - ConstValue::Struct(inner) => { + ConstValue::Int(value, _ty) => write!(f, "{}", value), + ConstValue::Struct(inner, _) => { write!(f, "{{")?; let mut inner = inner.iter().peekable(); - while let Some((ty, value)) = inner.next() { + while let Some(value) = inner.next() { write!(f, " ")?; value.fmt(f, db)?; write!(f, ": ")?; - ty.fmt(f, db.elongate())?; + value.ty(db).unwrap().fmt(f, db.elongate())?; if inner.peek().is_some() { write!(f, ",")?; } else { @@ -33,13 +33,13 @@ impl> DebugWithDb for Const inner.fmt(f, db)?; write!(f, ")") } - ConstValue::NonZero(_, value) => value.fmt(f, db), - ConstValue::Boxed(_, value) => { + ConstValue::NonZero(value) => value.fmt(f, db), + ConstValue::Boxed(value) => { value.fmt(f, db)?; write!(f, ".into_box()") } ConstValue::Generic(param) => write!(f, "{}", param.debug_name(db.upcast())), - ConstValue::Var(var) => write!(f, "?{}", var.id.0), + ConstValue::Var(var, _) => write!(f, "?{}", var.id.0), ConstValue::Missing(_) => write!(f, "missing"), } } diff --git a/crates/cairo-lang-semantic/src/resolve/item.rs b/crates/cairo-lang-semantic/src/resolve/item.rs index 6d59e4c9d62..d66bed0382f 100644 --- a/crates/cairo-lang-semantic/src/resolve/item.rs +++ b/crates/cairo-lang-semantic/src/resolve/item.rs @@ -1,12 +1,13 @@ use cairo_lang_defs::ids::{ - ConstantId, GenericParamId, GenericTypeId, ImplAliasId, ImplDefId, ModuleId, ModuleItemId, - ModuleTypeAliasId, TopLevelLanguageElementId, TraitFunctionId, TraitId, VarId, + ConstantId, GenericTypeId, ImplAliasId, ImplDefId, ModuleId, ModuleItemId, ModuleTypeAliasId, + TopLevelLanguageElementId, TraitFunctionId, TraitId, VarId, }; use cairo_lang_diagnostics::Maybe; use cairo_lang_proc_macros::DebugWithDb; use cairo_lang_utils::LookupIntern; use crate::db::SemanticGroup; +use crate::items::constant::ConstValueId; use crate::items::functions::GenericFunctionId; use crate::items::imp::ImplId; use crate::items::trt::ConcreteTraitGenericFunctionId; @@ -20,7 +21,7 @@ use crate::{ConcreteTraitId, ConcreteVariant, FunctionId, TypeId, TypeLongId, Va #[derive(Clone, PartialEq, Eq, Debug, DebugWithDb)] #[debug_db(dyn SemanticGroup + 'static)] pub enum ResolvedGenericItem { - Constant(ConstantId), + GenericConstant(ConstantId), Module(ModuleId), GenericFunction(GenericFunctionId), TraitFunction(TraitFunctionId), @@ -39,7 +40,7 @@ impl ResolvedGenericItem { module_item: ModuleItemId, ) -> Maybe { Ok(match module_item { - ModuleItemId::Constant(id) => ResolvedGenericItem::Constant(id), + ModuleItemId::Constant(id) => ResolvedGenericItem::GenericConstant(id), ModuleItemId::Submodule(id) => ResolvedGenericItem::Module(ModuleId::Submodule(id)), ModuleItemId::Use(id) => { // Note that `use_resolved_item` needs to be called before @@ -67,7 +68,7 @@ impl ResolvedGenericItem { pub fn full_path(&self, db: &dyn SemanticGroup) -> String { let defs_db = db.upcast(); match self { - ResolvedGenericItem::Constant(id) => id.full_path(defs_db), + ResolvedGenericItem::GenericConstant(_) => "".into(), ResolvedGenericItem::Module(id) => id.full_path(defs_db), ResolvedGenericItem::GenericFunction(id) => id.format(db), ResolvedGenericItem::TraitFunction(id) => id.full_path(defs_db), @@ -85,8 +86,7 @@ impl ResolvedGenericItem { #[derive(Clone, PartialEq, Eq, Debug, DebugWithDb)] #[debug_db(dyn SemanticGroup + 'static)] pub enum ResolvedConcreteItem { - Constant(ConstantId), - ConstGenericParameter(GenericParamId), + Constant(ConstValueId), Module(ModuleId), Function(FunctionId), TraitFunction(ConcreteTraitGenericFunctionId), @@ -99,8 +99,7 @@ pub enum ResolvedConcreteItem { impl ResolvedConcreteItem { pub fn generic(&self, db: &dyn SemanticGroup) -> Option { Some(match self { - ResolvedConcreteItem::Constant(id) => ResolvedGenericItem::Constant(*id), - ResolvedConcreteItem::ConstGenericParameter(_) => return None, + ResolvedConcreteItem::Constant(_) => return None, ResolvedConcreteItem::Module(item) => ResolvedGenericItem::Module(*item), ResolvedConcreteItem::Function(function) => ResolvedGenericItem::GenericFunction( function.lookup_intern(db).function.generic_function, diff --git a/crates/cairo-lang-semantic/src/resolve/mod.rs b/crates/cairo-lang-semantic/src/resolve/mod.rs index 95694714fd8..fd52b29661f 100644 --- a/crates/cairo-lang-semantic/src/resolve/mod.rs +++ b/crates/cairo-lang-semantic/src/resolve/mod.rs @@ -728,7 +728,9 @@ impl<'db> Resolver<'db> { generic_args_syntax: Option>, ) -> Maybe { Ok(match generic_item { - ResolvedGenericItem::Constant(id) => ResolvedConcreteItem::Constant(id), + ResolvedGenericItem::GenericConstant(id) => { + ResolvedConcreteItem::Constant(self.db.constant_const_value(id)?.intern(self.db)) + } ResolvedGenericItem::Module(module_id) => { if generic_args_syntax.is_some() { return Err(diagnostics.report(identifier, UnexpectedGenericArgs)); @@ -850,9 +852,9 @@ impl<'db> Resolver<'db> { GenericKind::Type => ResolvedConcreteItem::Type( TypeLongId::GenericParameter(*generic_param_id).intern(self.db), ), - GenericKind::Const => { - ResolvedConcreteItem::ConstGenericParameter(*generic_param_id) - } + GenericKind::Const => ResolvedConcreteItem::Constant( + ConstValue::Generic(*generic_param_id).intern(self.db), + ), GenericKind::Impl => { ResolvedConcreteItem::Impl(ImplId::GenericParameter(*generic_param_id)) } @@ -1123,7 +1125,7 @@ impl<'db> Resolver<'db> { ); let value = compute_expr_semantic(&mut ctx, generic_arg_syntax); - let (_, const_value) = resolve_const_expr_and_evaluate( + let const_value = resolve_const_expr_and_evaluate( self.db, &mut ctx, &value, @@ -1135,8 +1137,8 @@ impl<'db> Resolver<'db> { std::mem::swap(&mut ctx.resolver.data, &mut self.data); match const_value { - ConstValue::Int(value) => { - GenericArgumentId::Constant(ConstValue::Int(value).intern(self.db)) + ConstValue::Int(value, ty) => { + GenericArgumentId::Constant(ConstValue::Int(value, ty).intern(self.db)) } ConstValue::Generic(generic_param_id) => GenericArgumentId::Constant( ConstValue::Generic(generic_param_id).intern(self.db), diff --git a/crates/cairo-lang-semantic/src/types.rs b/crates/cairo-lang-semantic/src/types.rs index afa610e1ba5..6e98e4c70dd 100644 --- a/crates/cairo-lang-semantic/src/types.rs +++ b/crates/cairo-lang-semantic/src/types.rs @@ -522,18 +522,17 @@ pub fn extract_fixed_size_array_size( let mut ctx = ComputationContext::new(db, diagnostics, resolver, None, environment); let size_expr_syntax = size_clause.size(syntax_db); let size = compute_expr_semantic(&mut ctx, &size_expr_syntax); - let (_, const_value) = resolve_const_expr_and_evaluate( + let const_value = resolve_const_expr_and_evaluate( db, &mut ctx, &size, size_expr_syntax.stable_ptr().untyped(), get_usize_ty(db), ); - match &const_value { - ConstValue::Int(_) => Ok(Some(const_value.intern(db))), - ConstValue::Generic(_) => Ok(Some(const_value.intern(db))), - - _ => Err(diagnostics.report(syntax, FixedSizeArrayNonNumericSize)), + if matches!(const_value, ConstValue::Int(_, _) | ConstValue::Generic(_)) { + Ok(Some(const_value.intern(db))) + } else { + Err(diagnostics.report(syntax, FixedSizeArrayNonNumericSize)) } } ast::OptionFixedSizeArraySize::Empty(_) => Ok(None), @@ -640,7 +639,7 @@ pub fn single_value_type(db: &dyn SemanticGroup, ty: TypeId) -> Maybe { TypeLongId::FixedSizeArray { type_id, size } => { db.single_value_type(type_id)? || matches!(size.lookup_intern(db), - ConstValue::Int(value) if value.is_zero()) + ConstValue::Int(value, _) if value.is_zero()) } }) } @@ -725,7 +724,7 @@ pub fn type_size_info(db: &dyn SemanticGroup, ty: TypeId) -> Maybe {} TypeLongId::FixedSizeArray { type_id, size } => { - if matches!(size.lookup_intern(db), ConstValue::Int(value) if value.is_zero()) + if matches!(size.lookup_intern(db), ConstValue::Int(value,_) if value.is_zero()) || db.type_size_info(type_id)? == TypeSizeInformation::ZeroSized { return Ok(TypeSizeInformation::ZeroSized); diff --git a/crates/cairo-lang-sierra-generator/src/block_generator.rs b/crates/cairo-lang-sierra-generator/src/block_generator.rs index 59c7e540a88..18569b934d2 100644 --- a/crates/cairo-lang-sierra-generator/src/block_generator.rs +++ b/crates/cairo-lang-sierra-generator/src/block_generator.rs @@ -280,11 +280,7 @@ fn generate_statement_const_code( ) -> Maybe<()> { let output_var = context.get_sierra_variable(statement.output); context.push_statement(simple_basic_statement( - const_libfunc_id_by_type( - context.get_db(), - context.get_var_type(statement.output), - &statement.value, - ), + const_libfunc_id_by_type(context.get_db(), &statement.value), &[], &[output_var], )); diff --git a/crates/cairo-lang-sierra-generator/src/expr_generator_context.rs b/crates/cairo-lang-sierra-generator/src/expr_generator_context.rs index 86f1b1d8de0..75822f97973 100644 --- a/crates/cairo-lang-sierra-generator/src/expr_generator_context.rs +++ b/crates/cairo-lang-sierra-generator/src/expr_generator_context.rs @@ -1,7 +1,6 @@ use cairo_lang_defs::diagnostic_utils::StableLocation; use cairo_lang_diagnostics::Maybe; use cairo_lang_lowering as lowering; -use cairo_lang_semantic::TypeId; use cairo_lang_sierra::extensions::uninitialized::UninitializedType; use cairo_lang_sierra::extensions::NamedType; use cairo_lang_sierra::program::{ConcreteTypeLongId, GenericArg}; @@ -9,7 +8,7 @@ use cairo_lang_utils::ordered_hash_map::OrderedHashMap; use cairo_lang_utils::unordered_hash_map::UnorderedHashMap; use cairo_lang_utils::Intern; use lowering::ids::ConcreteFunctionWithBodyId; -use lowering::{BlockId, FlatLowered, VariableId}; +use lowering::{BlockId, FlatLowered}; use crate::ap_tracking::ApTrackingConfiguration; use crate::db::SierraGenGroup; @@ -160,11 +159,6 @@ impl<'a> ExprGeneratorContext<'a> { self.lifetime.last_use.contains(use_location) } - /// Returns the type of the variable given by `var_id`. - pub fn get_var_type(&self, var_id: VariableId) -> TypeId { - self.lowered.variables[var_id].ty - } - /// Gets the current ap tracking state. pub fn get_ap_tracking(&self) -> bool { self.ap_tracking_enabled diff --git a/crates/cairo-lang-sierra-generator/src/types.rs b/crates/cairo-lang-sierra-generator/src/types.rs index e7c8b80dd88..3d77c59de1c 100644 --- a/crates/cairo-lang-sierra-generator/src/types.rs +++ b/crates/cairo-lang-sierra-generator/src/types.rs @@ -10,10 +10,9 @@ use cairo_lang_semantic::items::structure::SemanticStructEx; use cairo_lang_sierra::extensions::snapshot::snapshot_ty; use cairo_lang_sierra::ids::UserTypeId; use cairo_lang_sierra::program::{ConcreteTypeLongId, GenericArg as SierraGenericArg}; -use cairo_lang_utils::{extract_matches, try_extract_matches, Intern, LookupIntern}; +use cairo_lang_utils::{try_extract_matches, Intern, LookupIntern}; use itertools::chain; use num_traits::ToPrimitive; -use semantic::items::constant::ConstValue; use semantic::items::imp::ImplLookupContext; use semantic::TypeId; @@ -105,11 +104,12 @@ pub fn get_concrete_long_type_id( SierraGenericArg::Type(db.get_concrete_type_id(ty).unwrap()) } semantic::GenericArgumentId::Constant(value_id) => { - SierraGenericArg::Value(extract_matches!( - value_id.lookup_intern(db), - ConstValue::Int, - "Only integer constants are supported." - )) + let value = value_id + .lookup_intern(db) + .into_int() + .expect("Expected ConstValue::Int for size"); + + SierraGenericArg::Value(value) } semantic::GenericArgumentId::Impl(_) => { panic!("Extern function with impl generics are not supported.") @@ -203,8 +203,12 @@ pub fn type_dependencies( semantic::TypeLongId::Snapshot(ty) => vec![ty], semantic::TypeLongId::Coupon(_) => vec![], semantic::TypeLongId::FixedSizeArray { type_id, size } => { - let size = - extract_matches!(size.lookup_intern(db), ConstValue::Int).to_usize().unwrap(); + let size = size + .lookup_intern(db) + .into_int() + .expect("Expected ConstValue::Int for size") + .to_usize() + .unwrap(); [type_id].repeat(size) } semantic::TypeLongId::GenericParameter(_) diff --git a/crates/cairo-lang-sierra-generator/src/utils.rs b/crates/cairo-lang-sierra-generator/src/utils.rs index dbcd85e967a..275d9ce8796 100644 --- a/crates/cairo-lang-sierra-generator/src/utils.rs +++ b/crates/cairo-lang-sierra-generator/src/utils.rs @@ -163,16 +163,15 @@ fn get_libfunc_id_without_generics( pub fn const_libfunc_id_by_type( db: &dyn SierraGenGroup, - ty: semantic::TypeId, value: &ConstValue, ) -> cairo_lang_sierra::ids::ConcreteLibfuncId { - if let ConstValue::Boxed(ty, inner_value) = value { + if let ConstValue::Boxed(inner_value) = value { cairo_lang_sierra::program::ConcreteLibfuncLongId { generic_id: cairo_lang_sierra::ids::GenericLibfuncId::from_string( ConstAsBoxLibfunc::STR_ID, ), generic_args: vec![ - GenericArg::Type(const_type_id(db, *ty, inner_value)), + GenericArg::Type(const_type_id(db, inner_value)), GenericArg::Value(0.into()), ], } @@ -182,28 +181,28 @@ pub fn const_libfunc_id_by_type( generic_id: cairo_lang_sierra::ids::GenericLibfuncId::from_string( ConstAsImmediateLibfunc::STR_ID, ), - generic_args: vec![GenericArg::Type(const_type_id(db, ty, value))], + generic_args: vec![GenericArg::Type(const_type_id(db, value))], } .intern(db) } } -/// Returns the [cairo_lang_sierra::ids::ConcreteTypeId] for the given `ty` and `value`. +/// Returns the [cairo_lang_sierra::ids::ConcreteTypeId] for the given `value`. fn const_type_id( db: &dyn SierraGenGroup, - ty: semantic::TypeId, value: &ConstValue, ) -> cairo_lang_sierra::ids::ConcreteTypeId { + let ty = value.ty(db.upcast()).unwrap(); let first_arg = GenericArg::Type(db.get_concrete_type_id(ty).unwrap()); SierraGeneratorTypeLongId::Regular( cairo_lang_sierra::program::ConcreteTypeLongId { generic_id: ConstType::ID, generic_args: match value { - ConstValue::Int(v) => vec![first_arg, GenericArg::Value(v.clone())], - ConstValue::Struct(tys) => { + ConstValue::Int(v, _) => vec![first_arg, GenericArg::Value(v.clone())], + ConstValue::Struct(tys, _) => { let mut args = vec![first_arg]; - for (ty, value) in tys { - args.push(GenericArg::Type(const_type_id(db, *ty, value))); + for value in tys { + args.push(GenericArg::Type(const_type_id(db, value))); } args } @@ -211,16 +210,16 @@ fn const_type_id( vec![ first_arg, GenericArg::Value(variant.idx.into()), - GenericArg::Type(const_type_id(db, variant.ty, inner)), + GenericArg::Type(const_type_id(db, inner)), ] } - ConstValue::NonZero(ty, value) => { - vec![first_arg, GenericArg::Type(const_type_id(db, *ty, value))] + ConstValue::NonZero(value) => { + vec![first_arg, GenericArg::Type(const_type_id(db, value))] } - ConstValue::Boxed(_, _) => { + ConstValue::Boxed(_) => { unreachable!("Should be handled by `const_libfunc_id_by_type`.") } - ConstValue::Generic(_) | ConstValue::Var(_) | ConstValue::Missing(_) => { + ConstValue::Generic(_) | ConstValue::Var(_, _) | ConstValue::Missing(_) => { unreachable!("Should be caught by the lowering.") } }, @@ -404,11 +403,12 @@ pub fn get_concrete_libfunc_id( generic_args.push(GenericArg::Type(db.get_concrete_type_id(*ty).unwrap())) } semantic::GenericArgumentId::Constant(value_id) => { - generic_args.push(GenericArg::Value(extract_matches!( - value_id.lookup_intern(db), - ConstValue::Int, - "Only integer constants are supported." - ))) + let size = value_id + .lookup_intern(db) + .into_int() + .expect("Expected ConstValue::Int for size"); + + generic_args.push(GenericArg::Value(size)) } semantic::GenericArgumentId::Impl(_) | semantic::GenericArgumentId::NegImpl => { // Everything after an impl generic is ignored as it does not exist in Sierra.