cairo-lang-semantic 2.18.0

Cairo semantic model.
Documentation
use cairo_lang_debug::DebugWithDb;
use cairo_lang_defs::ids::{FunctionWithBodyId, ModuleItemId};
use cairo_lang_filesystem::ids::SmolStrId;
use cairo_lang_test_utils::test;
use cairo_lang_utils::extract_matches;
use pretty_assertions::assert_eq;

use crate::expr::fmt::ExprFormatter;
use crate::items::function_with_body::{FunctionWithBodySemantic, SemanticExprLookup};
use crate::items::module::ModuleSemantic;
use crate::test_utils::{SemanticDatabaseForTesting, setup_test_module};

#[test]
fn test_expr_lookup() {
    let db_val = SemanticDatabaseForTesting::default();
    let db = &db_val;
    let test_module = setup_test_module(
        db,
        indoc::indoc! {"
            // `inline` is used just to have an allowed attribute.
            #[inline]
            fn foo<A, B>(_a: felt252) -> felt252 {
                let _x = 5 + 5;
                match 1 * (1) {
                    0 => {5},
                    _ => {6}
                }
            }
        "},
    )
    .unwrap();
    let module_id = test_module.module_id;

    let function_id = FunctionWithBodyId::Free(extract_matches!(
        db.module_item_by_name(module_id, SmolStrId::from(db, "foo")).unwrap().unwrap(),
        ModuleItemId::FreeFunction
    ));
    let expr_formatter = ExprFormatter { db, function_id };
    let mut expr_debugs = Vec::new();
    for (expr_id, expr) in &db.function_body(function_id).unwrap().arenas.exprs {
        assert_eq!(db.lookup_expr_by_ptr(function_id, expr.stable_ptr()), Ok(expr_id));
        expr_debugs.push(format!("{:?}", expr.debug(&expr_formatter)));
    }
    expr_debugs.sort();
    assert_eq!(
        expr_debugs,
        [
            "Block(ExprBlock { statements: [Let(StatementLet { pattern: Variable(_x), expr: \
             FunctionCall(ExprFunctionCall { function: core::Felt252Add::add, args: \
             [Value(Literal(ExprNumericLiteral { value: 5, ty: core::felt252 })), \
             Value(Literal(ExprNumericLiteral { value: 5, ty: core::felt252 }))], coupon_arg: \
             None, ty: core::felt252 }), else_clause: None })], tail: Some(Match(ExprMatch { \
             matched_expr: FunctionCall(ExprFunctionCall { function: core::Felt252Mul::mul, args: \
             [Value(Literal(ExprNumericLiteral { value: 1, ty: core::felt252 })), \
             Value(Literal(ExprNumericLiteral { value: 1, ty: core::felt252 }))], coupon_arg: \
             None, ty: core::felt252 }), arms: [MatchArm { patterns: [Literal(PatternLiteral { \
             literal: ExprNumericLiteral { value: 0, ty: core::felt252 } })], expression: \
             Block(ExprBlock { statements: [], tail: Some(Literal(ExprNumericLiteral { value: 5, \
             ty: core::felt252 })), ty: core::felt252 }) }, MatchArm { patterns: \
             [Otherwise(PatternOtherwise { ty: core::felt252 })], expression: Block(ExprBlock { \
             statements: [], tail: Some(Literal(ExprNumericLiteral { value: 6, ty: core::felt252 \
             })), ty: core::felt252 }) }], ty: core::felt252 })), ty: core::felt252 })",
            "Block(ExprBlock { statements: [], tail: Some(Literal(ExprNumericLiteral { value: 5, \
             ty: core::felt252 })), ty: core::felt252 })",
            "Block(ExprBlock { statements: [], tail: Some(Literal(ExprNumericLiteral { value: 6, \
             ty: core::felt252 })), ty: core::felt252 })",
            "FunctionCall(ExprFunctionCall { function: core::Felt252Add::add, args: \
             [Value(Literal(ExprNumericLiteral { value: 5, ty: core::felt252 })), \
             Value(Literal(ExprNumericLiteral { value: 5, ty: core::felt252 }))], coupon_arg: \
             None, ty: core::felt252 })",
            "FunctionCall(ExprFunctionCall { function: core::Felt252Mul::mul, args: \
             [Value(Literal(ExprNumericLiteral { value: 1, ty: core::felt252 })), \
             Value(Literal(ExprNumericLiteral { value: 1, ty: core::felt252 }))], coupon_arg: \
             None, ty: core::felt252 })",
            "Literal(ExprNumericLiteral { value: 1, ty: core::felt252 })",
            "Literal(ExprNumericLiteral { value: 1, ty: core::felt252 })",
            "Literal(ExprNumericLiteral { value: 5, ty: core::felt252 })",
            "Literal(ExprNumericLiteral { value: 5, ty: core::felt252 })",
            "Literal(ExprNumericLiteral { value: 5, ty: core::felt252 })",
            "Literal(ExprNumericLiteral { value: 6, ty: core::felt252 })",
            "Match(ExprMatch { matched_expr: FunctionCall(ExprFunctionCall { function: \
             core::Felt252Mul::mul, args: [Value(Literal(ExprNumericLiteral { value: 1, ty: \
             core::felt252 })), Value(Literal(ExprNumericLiteral { value: 1, ty: core::felt252 \
             }))], coupon_arg: None, ty: core::felt252 }), arms: [MatchArm { patterns: \
             [Literal(PatternLiteral { literal: ExprNumericLiteral { value: 0, ty: core::felt252 \
             } })], expression: Block(ExprBlock { statements: [], tail: \
             Some(Literal(ExprNumericLiteral { value: 5, ty: core::felt252 })), ty: core::felt252 \
             }) }, MatchArm { patterns: [Otherwise(PatternOtherwise { ty: core::felt252 })], \
             expression: Block(ExprBlock { statements: [], tail: Some(Literal(ExprNumericLiteral \
             { value: 6, ty: core::felt252 })), ty: core::felt252 }) }], ty: core::felt252 })",
        ]
    );

    let attributes = db.function_with_body_attributes(function_id).unwrap();
    assert_eq!(format!("{:?}", attributes.to_vec().debug(db)), "[Attribute { id: \"inline\" }]");
}