// Part of the Carbon Language project, under the Apache License v2.0 with LLVM // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include #include #include "common/ostream.h" #include "common/raw_string_ostream.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/VirtualFileSystem.h" #include "testing/base/global_exe_path.h" #include "toolchain/driver/driver.h" #include "toolchain/testing/yaml_test_helpers.h" namespace Carbon::SemIR { namespace { using ::testing::_; using ::testing::AllOf; using ::testing::Contains; using ::testing::Each; using ::testing::ElementsAre; using ::testing::IsEmpty; using ::testing::MatchesRegex; using ::testing::Pair; using ::testing::SizeIs; namespace Yaml = ::Carbon::Testing::Yaml; TEST(SemIRTest, Yaml) { llvm::IntrusiveRefCntPtr fs = new llvm::vfs::InMemoryFileSystem; CARBON_CHECK(fs->addFile( "test.carbon", /*ModificationTime=*/0, llvm::MemoryBuffer::getMemBuffer("fn F() { let x: () = (); return; }"))); const auto install_paths = InstallPaths::MakeForBazelRunfiles(Testing::GetExePath()); RawStringOstream print_stream; Driver driver(fs, &install_paths, /*input_stream=*/nullptr, &print_stream, &llvm::errs()); auto run_result = driver.RunCommand({"compile", "--no-prelude-import", "--phase=check", "--dump-raw-sem-ir", "test.carbon"}); EXPECT_TRUE(run_result.success); // Matches the ID of an instruction. Instruction counts may change as various // support changes, so this code is only doing loose structural checks. auto inst_id = Yaml::Scalar(MatchesRegex(R"(inst[0-9A-F]+)")); auto inst_block_id = Yaml::Scalar(MatchesRegex(R"(inst_block([0-9A-F]+|_empty))")); auto inst_block = Pair(inst_block_id, Yaml::Mapping(Each(Pair(_, inst_id)))); auto constant_id = Yaml::Scalar(MatchesRegex(R"(concrete_constant\(inst[0-9A-F]+\))")); auto type_id = Yaml::Scalar(MatchesRegex(R"(type\((\w+|inst\(\w+\)|inst[0-9A-F]+)\))")); auto type_builtin = Pair(type_id, Yaml::Mapping(_)); auto file = Yaml::Mapping(ElementsAre( Pair("names", Yaml::Mapping(SizeIs(2))), Pair("import_irs", Yaml::Mapping(SizeIs(2))), Pair("import_ir_insts", Yaml::Mapping(SizeIs(0))), Pair("clang_decls", Yaml::Mapping(SizeIs(0))), Pair("name_scopes", Yaml::Mapping(SizeIs(1))), Pair("entity_names", Yaml::Mapping(SizeIs(1))), Pair("cpp_global_vars", Yaml::Mapping(SizeIs(0))), Pair("functions", Yaml::Mapping(SizeIs(1))), Pair("classes", Yaml::Mapping(SizeIs(0))), Pair("interfaces", Yaml::Mapping(SizeIs(0))), Pair("associated_constants", Yaml::Mapping(SizeIs(0))), Pair("impls", Yaml::Mapping(SizeIs(0))), Pair("generics", Yaml::Mapping(SizeIs(0))), Pair("specifics", Yaml::Mapping(SizeIs(0))), Pair("specific_interfaces", Yaml::Mapping(SizeIs(0))), Pair("struct_type_fields", Yaml::Mapping(SizeIs(1))), Pair("types", Yaml::Mapping(Each(type_builtin))), Pair("facet_types", Yaml::Mapping(SizeIs(0))), Pair("insts", Yaml::Mapping(AllOf( Each(Key(inst_id)), // kind is required, other parts are optional. Each(Pair(_, Yaml::Mapping(Contains(Pair("kind", _))))), // A 0-arg instruction. Contains( Pair(_, Yaml::Mapping(ElementsAre(Pair("kind", "Return"))))), // A 1-arg instruction. Contains(Pair(_, Yaml::Mapping(ElementsAre( Pair("kind", "TupleType"), Pair("arg0", inst_block_id), Pair("type", "type(TypeType)"))))), // A 2-arg instruction. Contains(Pair(_, Yaml::Mapping(ElementsAre( Pair("kind", "FunctionDecl"), Pair("arg0", Yaml::Scalar(MatchesRegex( "function[0-9A-F]+"))), Pair("arg1", "inst_block_empty"), Pair("type", type_id)))))))), Pair("constant_values", Yaml::Mapping(ElementsAre( Pair("values", Yaml::Mapping(AllOf(Each(Pair(inst_id, constant_id))))), Pair("symbolic_constants", Yaml::Mapping(SizeIs(0)))))), Pair("inst_blocks", Yaml::Mapping(ElementsAre( Pair("inst_block_empty", Yaml::Mapping(IsEmpty())), Pair("exports", Yaml::Mapping(Each(Pair(_, inst_id)))), Pair("generated", Yaml::Mapping(IsEmpty())), Pair("imports", Yaml::Mapping(IsEmpty())), Pair("global_init", Yaml::Mapping(IsEmpty())), // There are 5 non-reserved inst blocks. inst_block, inst_block, inst_block, inst_block, inst_block))), Pair("value_stores", Yaml::Mapping(ElementsAre( Pair("shared_values", Yaml::Mapping(ElementsAre( Pair("ints", Yaml::Mapping(SizeIs(0))), Pair("reals", Yaml::Mapping(SizeIs(0))), Pair("floats", Yaml::Mapping(SizeIs(0))), Pair("identifiers", Yaml::Mapping(SizeIs(2))), Pair("strings", Yaml::Mapping(SizeIs(0))))))))))); auto root = Yaml::Sequence(ElementsAre(Yaml::Mapping( ElementsAre(Pair("filename", "test.carbon"), Pair("sem_ir", file))))); std::string print_text = print_stream.TakeStr(); EXPECT_THAT(Yaml::Value::FromText(print_text), IsYaml(root)) << "Actual text:\n" << print_text; } } // namespace } // namespace Carbon::SemIR