<commit_before>use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::ty::query::Providers;
use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_span::symbol::Symbol;

// When adding features to the below lists
// check whether they're named already elsewhere in rust
// e.g. in stdarch and whether the given name matches LLVM's
// if it doesn't, to_llvm_feature in llvm_util in rustc_codegen_llvm needs to be adapted

const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
    ("aclass", Some(sym::arm_target_feature)),
    ("mclass", Some(sym::arm_target_feature)),
    ("rclass", Some(sym::arm_target_feature)),
    ("dsp", Some(sym::arm_target_feature)),
    ("neon", Some(sym::arm_target_feature)),
    ("crc", Some(sym::arm_target_feature)),
    ("crypto", Some(sym::arm_target_feature)),
    ("aes", Some(sym::arm_target_feature)),
    ("sha2", Some(sym::arm_target_feature)),
    ("v5te", Some(sym::arm_target_feature)),
    ("v6", Some(sym::arm_target_feature)),
    ("v6k", Some(sym::arm_target_feature)),
    ("v6t2", Some(sym::arm_target_feature)),
    ("v7", Some(sym::arm_target_feature)),
    ("v8", Some(sym::arm_target_feature)),
    ("vfp2", Some(sym::arm_target_feature)),
    ("vfp3", Some(sym::arm_target_feature)),
    ("vfp4", Some(sym::arm_target_feature)),
    ("fp-armv8", Some(sym::arm_target_feature)),
    // This is needed for inline assembly, but shouldn't be stabilized as-is
    // since it should be enabled per-function using #[instruction_set], not
    // #[target_feature].
    ("thumb-mode", Some(sym::arm_target_feature)),
];

// Commented features are not available in LLVM 10.0, or have since been renamed
const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
    // FEAT_AdvSimd
    ("neon", Some(sym::aarch64_target_feature)),
    // FEAT_FP
    ("fp", Some(sym::aarch64_target_feature)),
    // FEAT_FP16
    ("fp16", Some(sym::aarch64_target_feature)),
    // FEAT_SVE
    ("sve", Some(sym::aarch64_target_feature)),
    // FEAT_CRC
    ("crc", Some(sym::aarch64_target_feature)),
    // FEAT_RAS
    ("ras", Some(sym::aarch64_target_feature)),
    // FEAT_LSE
    ("lse", Some(sym::aarch64_target_feature)),
    // FEAT_RDM
    ("rdm", Some(sym::aarch64_target_feature)),
    // FEAT_RCPC
    ("rcpc", Some(sym::aarch64_target_feature)),
    // FEAT_RCPC2
    ("rcpc2", Some(sym::aarch64_target_feature)),
    // FEAT_DotProd
    ("dotprod", Some(sym::aarch64_target_feature)),
    // FEAT_TME
    ("tme", Some(sym::aarch64_target_feature)),
    // FEAT_FHM
    ("fhm", Some(sym::aarch64_target_feature)),
    // FEAT_DIT
    ("dit", Some(sym::aarch64_target_feature)),
    // FEAT_FLAGM
    // ("flagm", Some(sym::aarch64_target_feature)),
    // FEAT_SSBS
    ("ssbs", Some(sym::aarch64_target_feature)),
    // FEAT_SB
    ("sb", Some(sym::aarch64_target_feature)),
    // FEAT_PAUTH
    // ("pauth", Some(sym::aarch64_target_feature)),
    // FEAT_DPB
    ("dpb", Some(sym::aarch64_target_feature)),
    // FEAT_DPB2
    ("dpb2", Some(sym::aarch64_target_feature)),
    // FEAT_SVE2
    ("sve2", Some(sym::aarch64_target_feature)),
    // FEAT_SVE2_AES
    ("sve2-aes", Some(sym::aarch64_target_feature)),
    // FEAT_SVE2_SM4
    ("sve2-sm4", Some(sym::aarch64_target_feature)),
    // FEAT_SVE2_SHA3
    ("sve2-sha3", Some(sym::aarch64_target_feature)),
    // FEAT_SVE2_BitPerm
    ("sve2-bitperm", Some(sym::aarch64_target_feature)),
    // FEAT_FRINTTS
    ("frintts", Some(sym::aarch64_target_feature)),
    // FEAT_I8MM
    // ("i8mm", Some(sym::aarch64_target_feature)),
    // FEAT_F32MM
    // ("f32mm", Some(sym::aarch64_target_feature)),
    // FEAT_F64MM
    // ("f64mm", Some(sym::aarch64_target_feature)),
    // FEAT_BF16
    // ("bf16", Some(sym::aarch64_target_feature)),
    // FEAT_RAND
    ("rand", Some(sym::aarch64_target_feature)),
    // FEAT_BTI
    ("bti", Some(sym::aarch64_target_feature)),
    // FEAT_MTE
    ("mte", Some(sym::aarch64_target_feature)),
    // FEAT_JSCVT
    ("jsconv", Some(sym::aarch64_target_feature)),
    // FEAT_FCMA
    ("fcma", Some(sym::aarch64_target_feature)),
    // FEAT_AES
    ("aes", Some(sym::aarch64_target_feature)),
    // FEAT_SHA1 & FEAT_SHA256
    ("sha2", Some(sym::aarch64_target_feature)),
    // FEAT_SHA512 & FEAT_SHA3
    ("sha3", Some(sym::aarch64_target_feature)),
    // FEAT_SM3 & FEAT_SM4
    ("sm4", Some(sym::aarch64_target_feature)),
    ("v8.1a", Some(sym::aarch64_target_feature)),
    ("v8.2a", Some(sym::aarch64_target_feature)),
    ("v8.3a", Some(sym::aarch64_target_feature)),
    ("v8.4a", Some(sym::aarch64_target_feature)),
    ("v8.5a", Some(sym::aarch64_target_feature)),
    // ("v8.6a", Some(sym::aarch64_target_feature)),
    // ("v8.7a", Some(sym::aarch64_target_feature)),
];

const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
    ("adx", Some(sym::adx_target_feature)),
    ("aes", None),
    ("avx", None),
    ("avx2", None),
    ("avx512bf16", Some(sym::avx512_target_feature)),
    ("avx512bitalg", Some(sym::avx512_target_feature)),
    ("avx512bw", Some(sym::avx512_target_feature)),
    ("avx512cd", Some(sym::avx512_target_feature)),
    ("avx512dq", Some(sym::avx512_target_feature)),
    ("avx512er", Some(sym::avx512_target_feature)),
    ("avx512f", Some(sym::avx512_target_feature)),
    ("avx512gfni", Some(sym::avx512_target_feature)),
    ("avx512ifma", Some(sym::avx512_target_feature)),
    ("avx512pf", Some(sym::avx512_target_feature)),
    ("avx512vaes", Some(sym::avx512_target_feature)),
    ("avx512vbmi", Some(sym::avx512_target_feature)),
    ("avx512vbmi2", Some(sym::avx512_target_feature)),
    ("avx512vl", Some(sym::avx512_target_feature)),
    ("avx512vnni", Some(sym::avx512_target_feature)),
    ("avx512vp2intersect", Some(sym::avx512_target_feature)),
    ("avx512vpclmulqdq", Some(sym::avx512_target_feature)),
    ("avx512vpopcntdq", Some(sym::avx512_target_feature)),
    ("bmi1", None),
    ("bmi2", None),
    ("cmpxchg16b", Some(sym::cmpxchg16b_target_feature)),
    ("ermsb", Some(sym::ermsb_target_feature)),
    ("f16c", Some(sym::f16c_target_feature)),
    ("fma", None),
    ("fxsr", None),
    ("lzcnt", None),
    ("movbe", Some(sym::movbe_target_feature)),
    ("pclmulqdq", None),
    ("popcnt", None),
    ("rdrand", None),
    ("rdseed", None),
    ("rtm", Some(sym::rtm_target_feature)),
    ("sha", None),
    ("sse", None),
    ("sse2", None),
    ("sse3", None),
    ("sse4.1", None),
    ("sse4.2", None),
    ("sse4a", Some(sym::sse4a_target_feature)),
    ("ssse3", None),
    ("tbm", Some(sym::tbm_target_feature)),
    ("xsave", None),
    ("xsavec", None),
    ("xsaveopt", None),
    ("xsaves", None),
];

const HEXAGON_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
    ("hvx", Some(sym::hexagon_target_feature)),
    ("hvx-length128b", Some(sym::hexagon_target_feature)),
];

const POWERPC_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
    ("altivec", Some(sym::powerpc_target_feature)),
    ("power8-altivec", Some(sym::powerpc_target_feature)),
    ("power9-altivec", Some(sym::powerpc_target_feature)),
    ("power8-vector", Some(sym::powerpc_target_feature)),
    ("power9-vector", Some(sym::powerpc_target_feature)),
    ("vsx", Some(sym::powerpc_target_feature)),
];

const MIPS_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] =
    &[("fp64", Some(sym::mips_target_feature)), ("msa", Some(sym::mips_target_feature))];

const RISCV_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
    ("m", Some(sym::riscv_target_feature)),
    ("a", Some(sym::riscv_target_feature)),
    ("c", Some(sym::riscv_target_feature)),
    ("f", Some(sym::riscv_target_feature)),
    ("d", Some(sym::riscv_target_feature)),
    ("e", Some(sym::riscv_target_feature)),
];

const WASM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
    ("simd128", None),
    ("atomics", Some(sym::wasm_target_feature)),
    ("nontrapping-fptoint", Some(sym::wasm_target_feature)),
];

const BPF_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[("alu32", Some(sym::bpf_target_feature))];

/// When rustdoc is running, provide a list of all known features so that all their respective
/// primitives may be documented.
///
/// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator!
pub fn all_known_features() -> impl Iterator<Item = (&'static str, Option<Symbol>)> {
    std::iter::empty()
        .chain(ARM_ALLOWED_FEATURES.iter())
        .chain(AARCH64_ALLOWED_FEATURES.iter())
        .chain(X86_ALLOWED_FEATURES.iter())
        .chain(HEXAGON_ALLOWED_FEATURES.iter())
        .chain(POWERPC_ALLOWED_FEATURES.iter())
        .chain(MIPS_ALLOWED_FEATURES.iter())
        .chain(RISCV_ALLOWED_FEATURES.iter())
        .chain(WASM_ALLOWED_FEATURES.iter())
        .chain(BPF_ALLOWED_FEATURES.iter())
        .cloned()
}

pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Option<Symbol>)] {
    match &*sess.target.arch {
        "arm" => ARM_ALLOWED_FEATURES,
        "aarch64" => AARCH64_ALLOWED_FEATURES,
        "x86" | "x86_64" => X86_ALLOWED_FEATURES,
        "hexagon" => HEXAGON_ALLOWED_FEATURES,
        "mips" | "mips64" => MIPS_ALLOWED_FEATURES,
        "powerpc" | "powerpc64" => POWERPC_ALLOWED_FEATURES,
        "riscv32" | "riscv64" => RISCV_ALLOWED_FEATURES,
        "wasm32" | "wasm64" => WASM_ALLOWED_FEATURES,
        "bpf" => BPF_ALLOWED_FEATURES,
        _ => &[],
    }
}

pub(crate) fn provide(providers: &mut Providers) {
    providers.supported_target_features = |tcx, cnum| {
        assert_eq!(cnum, LOCAL_CRATE);
        if tcx.sess.opts.actually_rustdoc {
            // rustdoc needs to be able to document functions that use all the features, so
            // whitelist them all
            all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
        } else {
            supported_target_features(tcx.sess).iter().map(|&(a, b)| (a.to_string(), b)).collect()
        }
    };
}
<commit_msg>Rollup merge of #90079 - SparrowLii:i8mm, r=Amanieu<commit_after>use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::ty::query::Providers;
use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_span::symbol::Symbol;

// When adding features to the below lists
// check whether they're named already elsewhere in rust
// e.g. in stdarch and whether the given name matches LLVM's
// if it doesn't, to_llvm_feature in llvm_util in rustc_codegen_llvm needs to be adapted

const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
    ("aclass", Some(sym::arm_target_feature)),
    ("mclass", Some(sym::arm_target_feature)),
    ("rclass", Some(sym::arm_target_feature)),
    ("dsp", Some(sym::arm_target_feature)),
    ("neon", Some(sym::arm_target_feature)),
    ("crc", Some(sym::arm_target_feature)),
    ("crypto", Some(sym::arm_target_feature)),
    ("aes", Some(sym::arm_target_feature)),
    ("sha2", Some(sym::arm_target_feature)),
    ("i8mm", Some(sym::arm_target_feature)),
    ("v5te", Some(sym::arm_target_feature)),
    ("v6", Some(sym::arm_target_feature)),
    ("v6k", Some(sym::arm_target_feature)),
    ("v6t2", Some(sym::arm_target_feature)),
    ("v7", Some(sym::arm_target_feature)),
    ("v8", Some(sym::arm_target_feature)),
    ("vfp2", Some(sym::arm_target_feature)),
    ("vfp3", Some(sym::arm_target_feature)),
    ("vfp4", Some(sym::arm_target_feature)),
    ("fp-armv8", Some(sym::arm_target_feature)),
    // This is needed for inline assembly, but shouldn't be stabilized as-is
    // since it should be enabled per-function using #[instruction_set], not
    // #[target_feature].
    ("thumb-mode", Some(sym::arm_target_feature)),
];

// Commented features are not available in LLVM 10.0, or have since been renamed
const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
    // FEAT_AdvSimd
    ("neon", Some(sym::aarch64_target_feature)),
    // FEAT_FP
    ("fp", Some(sym::aarch64_target_feature)),
    // FEAT_FP16
    ("fp16", Some(sym::aarch64_target_feature)),
    // FEAT_SVE
    ("sve", Some(sym::aarch64_target_feature)),
    // FEAT_CRC
    ("crc", Some(sym::aarch64_target_feature)),
    // FEAT_RAS
    ("ras", Some(sym::aarch64_target_feature)),
    // FEAT_LSE
    ("lse", Some(sym::aarch64_target_feature)),
    // FEAT_RDM
    ("rdm", Some(sym::aarch64_target_feature)),
    // FEAT_RCPC
    ("rcpc", Some(sym::aarch64_target_feature)),
    // FEAT_RCPC2
    ("rcpc2", Some(sym::aarch64_target_feature)),
    // FEAT_DotProd
    ("dotprod", Some(sym::aarch64_target_feature)),
    // FEAT_TME
    ("tme", Some(sym::aarch64_target_feature)),
    // FEAT_FHM
    ("fhm", Some(sym::aarch64_target_feature)),
    // FEAT_DIT
    ("dit", Some(sym::aarch64_target_feature)),
    // FEAT_FLAGM
    // ("flagm", Some(sym::aarch64_target_feature)),
    // FEAT_SSBS
    ("ssbs", Some(sym::aarch64_target_feature)),
    // FEAT_SB
    ("sb", Some(sym::aarch64_target_feature)),
    // FEAT_PAUTH
    // ("pauth", Some(sym::aarch64_target_feature)),
    // FEAT_DPB
    ("dpb", Some(sym::aarch64_target_feature)),
    // FEAT_DPB2
    ("dpb2", Some(sym::aarch64_target_feature)),
    // FEAT_SVE2
    ("sve2", Some(sym::aarch64_target_feature)),
    // FEAT_SVE2_AES
    ("sve2-aes", Some(sym::aarch64_target_feature)),
    // FEAT_SVE2_SM4
    ("sve2-sm4", Some(sym::aarch64_target_feature)),
    // FEAT_SVE2_SHA3
    ("sve2-sha3", Some(sym::aarch64_target_feature)),
    // FEAT_SVE2_BitPerm
    ("sve2-bitperm", Some(sym::aarch64_target_feature)),
    // FEAT_FRINTTS
    ("frintts", Some(sym::aarch64_target_feature)),
    // FEAT_I8MM
    ("i8mm", Some(sym::aarch64_target_feature)),
    // FEAT_F32MM
    // ("f32mm", Some(sym::aarch64_target_feature)),
    // FEAT_F64MM
    // ("f64mm", Some(sym::aarch64_target_feature)),
    // FEAT_BF16
    // ("bf16", Some(sym::aarch64_target_feature)),
    // FEAT_RAND
    ("rand", Some(sym::aarch64_target_feature)),
    // FEAT_BTI
    ("bti", Some(sym::aarch64_target_feature)),
    // FEAT_MTE
    ("mte", Some(sym::aarch64_target_feature)),
    // FEAT_JSCVT
    ("jsconv", Some(sym::aarch64_target_feature)),
    // FEAT_FCMA
    ("fcma", Some(sym::aarch64_target_feature)),
    // FEAT_AES
    ("aes", Some(sym::aarch64_target_feature)),
    // FEAT_SHA1 & FEAT_SHA256
    ("sha2", Some(sym::aarch64_target_feature)),
    // FEAT_SHA512 & FEAT_SHA3
    ("sha3", Some(sym::aarch64_target_feature)),
    // FEAT_SM3 & FEAT_SM4
    ("sm4", Some(sym::aarch64_target_feature)),
    ("v8.1a", Some(sym::aarch64_target_feature)),
    ("v8.2a", Some(sym::aarch64_target_feature)),
    ("v8.3a", Some(sym::aarch64_target_feature)),
    ("v8.4a", Some(sym::aarch64_target_feature)),
    ("v8.5a", Some(sym::aarch64_target_feature)),
    // ("v8.6a", Some(sym::aarch64_target_feature)),
    // ("v8.7a", Some(sym::aarch64_target_feature)),
];

const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
    ("adx", Some(sym::adx_target_feature)),
    ("aes", None),
    ("avx", None),
    ("avx2", None),
    ("avx512bf16", Some(sym::avx512_target_feature)),
    ("avx512bitalg", Some(sym::avx512_target_feature)),
    ("avx512bw", Some(sym::avx512_target_feature)),
    ("avx512cd", Some(sym::avx512_target_feature)),
    ("avx512dq", Some(sym::avx512_target_feature)),
    ("avx512er", Some(sym::avx512_target_feature)),
    ("avx512f", Some(sym::avx512_target_feature)),
    ("avx512gfni", Some(sym::avx512_target_feature)),
    ("avx512ifma", Some(sym::avx512_target_feature)),
    ("avx512pf", Some(sym::avx512_target_feature)),
    ("avx512vaes", Some(sym::avx512_target_feature)),
    ("avx512vbmi", Some(sym::avx512_target_feature)),
    ("avx512vbmi2", Some(sym::avx512_target_feature)),
    ("avx512vl", Some(sym::avx512_target_feature)),
    ("avx512vnni", Some(sym::avx512_target_feature)),
    ("avx512vp2intersect", Some(sym::avx512_target_feature)),
    ("avx512vpclmulqdq", Some(sym::avx512_target_feature)),
    ("avx512vpopcntdq", Some(sym::avx512_target_feature)),
    ("bmi1", None),
    ("bmi2", None),
    ("cmpxchg16b", Some(sym::cmpxchg16b_target_feature)),
    ("ermsb", Some(sym::ermsb_target_feature)),
    ("f16c", Some(sym::f16c_target_feature)),
    ("fma", None),
    ("fxsr", None),
    ("lzcnt", None),
    ("movbe", Some(sym::movbe_target_feature)),
    ("pclmulqdq", None),
    ("popcnt", None),
    ("rdrand", None),
    ("rdseed", None),
    ("rtm", Some(sym::rtm_target_feature)),
    ("sha", None),
    ("sse", None),
    ("sse2", None),
    ("sse3", None),
    ("sse4.1", None),
    ("sse4.2", None),
    ("sse4a", Some(sym::sse4a_target_feature)),
    ("ssse3", None),
    ("tbm", Some(sym::tbm_target_feature)),
    ("xsave", None),
    ("xsavec", None),
    ("xsaveopt", None),
    ("xsaves", None),
];

const HEXAGON_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
    ("hvx", Some(sym::hexagon_target_feature)),
    ("hvx-length128b", Some(sym::hexagon_target_feature)),
];

const POWERPC_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
    ("altivec", Some(sym::powerpc_target_feature)),
    ("power8-altivec", Some(sym::powerpc_target_feature)),
    ("power9-altivec", Some(sym::powerpc_target_feature)),
    ("power8-vector", Some(sym::powerpc_target_feature)),
    ("power9-vector", Some(sym::powerpc_target_feature)),
    ("vsx", Some(sym::powerpc_target_feature)),
];

const MIPS_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] =
    &[("fp64", Some(sym::mips_target_feature)), ("msa", Some(sym::mips_target_feature))];

const RISCV_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
    ("m", Some(sym::riscv_target_feature)),
    ("a", Some(sym::riscv_target_feature)),
    ("c", Some(sym::riscv_target_feature)),
    ("f", Some(sym::riscv_target_feature)),
    ("d", Some(sym::riscv_target_feature)),
    ("e", Some(sym::riscv_target_feature)),
];

const WASM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
    ("simd128", None),
    ("atomics", Some(sym::wasm_target_feature)),
    ("nontrapping-fptoint", Some(sym::wasm_target_feature)),
];

const BPF_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[("alu32", Some(sym::bpf_target_feature))];

/// When rustdoc is running, provide a list of all known features so that all their respective
/// primitives may be documented.
///
/// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator!
pub fn all_known_features() -> impl Iterator<Item = (&'static str, Option<Symbol>)> {
    std::iter::empty()
        .chain(ARM_ALLOWED_FEATURES.iter())
        .chain(AARCH64_ALLOWED_FEATURES.iter())
        .chain(X86_ALLOWED_FEATURES.iter())
        .chain(HEXAGON_ALLOWED_FEATURES.iter())
        .chain(POWERPC_ALLOWED_FEATURES.iter())
        .chain(MIPS_ALLOWED_FEATURES.iter())
        .chain(RISCV_ALLOWED_FEATURES.iter())
        .chain(WASM_ALLOWED_FEATURES.iter())
        .chain(BPF_ALLOWED_FEATURES.iter())
        .cloned()
}

pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Option<Symbol>)] {
    match &*sess.target.arch {
        "arm" => ARM_ALLOWED_FEATURES,
        "aarch64" => AARCH64_ALLOWED_FEATURES,
        "x86" | "x86_64" => X86_ALLOWED_FEATURES,
        "hexagon" => HEXAGON_ALLOWED_FEATURES,
        "mips" | "mips64" => MIPS_ALLOWED_FEATURES,
        "powerpc" | "powerpc64" => POWERPC_ALLOWED_FEATURES,
        "riscv32" | "riscv64" => RISCV_ALLOWED_FEATURES,
        "wasm32" | "wasm64" => WASM_ALLOWED_FEATURES,
        "bpf" => BPF_ALLOWED_FEATURES,
        _ => &[],
    }
}

pub(crate) fn provide(providers: &mut Providers) {
    providers.supported_target_features = |tcx, cnum| {
        assert_eq!(cnum, LOCAL_CRATE);
        if tcx.sess.opts.actually_rustdoc {
            // rustdoc needs to be able to document functions that use all the features, so
            // whitelist them all
            all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
        } else {
            supported_target_features(tcx.sess).iter().map(|&(a, b)| (a.to_string(), b)).collect()
        }
    };
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::ffi::OsStr;
use std::path::PathBuf;
use semver::Version;

use core::{PackageId, Package, Target};
use util::{self, CargoResult, Config, ProcessBuilder, process, join_paths};

/// A structure returning the result of a compilation.
pub struct Compilation<'cfg> {
    /// All libraries which were built for a package.
    ///
    /// This is currently used for passing --extern flags to rustdoc tests later
    /// on.
    pub libraries: HashMap<PackageId, Vec<(Target, PathBuf)>>,

    /// An array of all tests created during this compilation.
    pub tests: Vec<(Package, String, PathBuf)>,

    /// An array of all binaries created.
    pub binaries: Vec<PathBuf>,

    /// All directires for the output of native build commands.
    ///
    /// This is currently used to drive some entries which are added to the
    /// LD_LIBRARY_PATH as appropriate.
    // TODO: deprecated, remove
    pub native_dirs: HashSet<PathBuf>,

    /// Root output directory (for the local package's artifacts)
    pub root_output: PathBuf,

    /// Output directory for rust dependencies
    pub deps_output: PathBuf,

    /// Library search path for compiler plugins and build scripts
    /// which have dynamic dependencies.
    pub plugins_dylib_path: PathBuf,

    /// Extra environment variables that were passed to compilations and should
    /// be passed to future invocations of programs.
    pub extra_env: HashMap<PackageId, Vec<(String, String)>>,

    pub to_doc_test: Vec<Package>,

    /// Features enabled during this compilation.
    pub cfgs: HashSet<String>,

    pub target: String,

    config: &'cfg Config,
}

impl<'cfg> Compilation<'cfg> {
    pub fn new(config: &'cfg Config) -> Compilation<'cfg> {
        Compilation {
            libraries: HashMap::new(),
            native_dirs: HashSet::new(),  // TODO: deprecated, remove
            root_output: PathBuf::from("/"),
            deps_output: PathBuf::from("/"),
            plugins_dylib_path: PathBuf::from("/"),
            tests: Vec::new(),
            binaries: Vec::new(),
            extra_env: HashMap::new(),
            to_doc_test: Vec::new(),
            cfgs: HashSet::new(),
            config: config,
            target: String::new(),
        }
    }

    /// See `process`.
    pub fn rustc_process(&self, pkg: &Package) -> CargoResult<ProcessBuilder> {
        self.fill_env(try!(self.config.rustc()).process(), pkg, true)
    }

    /// See `process`.
    pub fn rustdoc_process(&self, pkg: &Package) -> CargoResult<ProcessBuilder> {
        self.fill_env(process(&*try!(self.config.rustdoc())), pkg, true)
    }

    /// See `process`.
    pub fn host_process<T: AsRef<OsStr>>(&self, cmd: T, pkg: &Package)
                                         -> CargoResult<ProcessBuilder> {
        self.fill_env(process(cmd), pkg, true)
    }

    /// See `process`.
    pub fn target_process<T: AsRef<OsStr>>(&self, cmd: T, pkg: &Package)
                                           -> CargoResult<ProcessBuilder> {
        self.fill_env(process(cmd), pkg, false)
    }

    /// Prepares a new process with an appropriate environment to run against
    /// the artifacts produced by the build process.
    ///
    /// The package argument is also used to configure environment variables as
    /// well as the working directory of the child process.
    fn fill_env(&self, mut cmd: ProcessBuilder, pkg: &Package, is_host: bool)
                -> CargoResult<ProcessBuilder> {

        let mut search_path = if is_host {
            vec![self.plugins_dylib_path.clone()]
        } else {
            let mut search_path = vec![];

            // Add -L arguments, after stripping off prefixes like "native=" or "framework=".
            for dir in self.native_dirs.iter() {
                let dir = match dir.to_str() {
                    Some(s) => {
                        let mut parts = s.splitn(2, '=');
                        match (parts.next(), parts.next()) {
                            (Some("native"), Some(path)) |
                            (Some("crate"), Some(path)) |
                            (Some("dependency"), Some(path)) |
                            (Some("framework"), Some(path)) |
                            (Some("all"), Some(path)) => path.into(),
                            _ => dir.clone(),
                        }
                    }
                    None => dir.clone(),
                };
                search_path.push(dir);
            }
            search_path.push(self.root_output.clone());
            search_path.push(self.deps_output.clone());
            search_path
        };

        search_path.extend(util::dylib_path().into_iter());
        let search_path = try!(join_paths(&search_path, util::dylib_path_envvar()));

        cmd.env(util::dylib_path_envvar(), &search_path);
        if let Some(env) = self.extra_env.get(pkg.package_id()) {
            for &(ref k, ref v) in env {
                cmd.env(k, v);
            }
        }

        let metadata = pkg.manifest().metadata();

        cmd.env("CARGO_MANIFEST_DIR", pkg.root())
           .env("CARGO_PKG_VERSION_MAJOR", &pkg.version().major.to_string())
           .env("CARGO_PKG_VERSION_MINOR", &pkg.version().minor.to_string())
           .env("CARGO_PKG_VERSION_PATCH", &pkg.version().patch.to_string())
           .env("CARGO_PKG_VERSION_PRE", &pre_version_component(pkg.version()))
           .env("CARGO_PKG_VERSION", &pkg.version().to_string())
           .env("CARGO_PKG_NAME", &pkg.name())
           .env("CARGO_PKG_DESCRIPTION", metadata.description.as_ref().unwrap_or(&String::new()))
           .env("CARGO_PKG_HOMEPAGE", metadata.homepage.as_ref().unwrap_or(&String::new()))
           .env("CARGO_PKG_AUTHORS", &pkg.authors().join(":"))
           .cwd(pkg.root());
        Ok(cmd)
    }
}

fn pre_version_component(v: &Version) -> String {
    if v.pre.is_empty() {
        return String::new();
    }

    let mut ret = String::new();

    for (i, x) in v.pre.iter().enumerate() {
        if i != 0 { ret.push('.') };
        ret.push_str(&x.to_string());
    }

    ret
}
<commit_msg>Auto merge of #3205 - matklad:fix-rustdoc-ld-path, r=alexcrichton<commit_after>use std::collections::{HashMap, HashSet};
use std::ffi::OsStr;
use std::path::PathBuf;
use semver::Version;

use core::{PackageId, Package, Target};
use util::{self, CargoResult, Config, ProcessBuilder, process, join_paths};

/// A structure returning the result of a compilation.
pub struct Compilation<'cfg> {
    /// All libraries which were built for a package.
    ///
    /// This is currently used for passing --extern flags to rustdoc tests later
    /// on.
    pub libraries: HashMap<PackageId, Vec<(Target, PathBuf)>>,

    /// An array of all tests created during this compilation.
    pub tests: Vec<(Package, String, PathBuf)>,

    /// An array of all binaries created.
    pub binaries: Vec<PathBuf>,

    /// All directires for the output of native build commands.
    ///
    /// This is currently used to drive some entries which are added to the
    /// LD_LIBRARY_PATH as appropriate.
    // TODO: deprecated, remove
    pub native_dirs: HashSet<PathBuf>,

    /// Root output directory (for the local package's artifacts)
    pub root_output: PathBuf,

    /// Output directory for rust dependencies
    pub deps_output: PathBuf,

    /// Library search path for compiler plugins and build scripts
    /// which have dynamic dependencies.
    pub plugins_dylib_path: PathBuf,

    /// Extra environment variables that were passed to compilations and should
    /// be passed to future invocations of programs.
    pub extra_env: HashMap<PackageId, Vec<(String, String)>>,

    pub to_doc_test: Vec<Package>,

    /// Features enabled during this compilation.
    pub cfgs: HashSet<String>,

    pub target: String,

    config: &'cfg Config,
}

impl<'cfg> Compilation<'cfg> {
    pub fn new(config: &'cfg Config) -> Compilation<'cfg> {
        Compilation {
            libraries: HashMap::new(),
            native_dirs: HashSet::new(),  // TODO: deprecated, remove
            root_output: PathBuf::from("/"),
            deps_output: PathBuf::from("/"),
            plugins_dylib_path: PathBuf::from("/"),
            tests: Vec::new(),
            binaries: Vec::new(),
            extra_env: HashMap::new(),
            to_doc_test: Vec::new(),
            cfgs: HashSet::new(),
            config: config,
            target: String::new(),
        }
    }

    /// See `process`.
    pub fn rustc_process(&self, pkg: &Package) -> CargoResult<ProcessBuilder> {
        self.fill_env(try!(self.config.rustc()).process(), pkg, true)
    }

    /// See `process`.
    pub fn rustdoc_process(&self, pkg: &Package) -> CargoResult<ProcessBuilder> {
        self.fill_env(process(&*try!(self.config.rustdoc())), pkg, false)
    }

    /// See `process`.
    pub fn host_process<T: AsRef<OsStr>>(&self, cmd: T, pkg: &Package)
                                         -> CargoResult<ProcessBuilder> {
        self.fill_env(process(cmd), pkg, true)
    }

    /// See `process`.
    pub fn target_process<T: AsRef<OsStr>>(&self, cmd: T, pkg: &Package)
                                           -> CargoResult<ProcessBuilder> {
        self.fill_env(process(cmd), pkg, false)
    }

    /// Prepares a new process with an appropriate environment to run against
    /// the artifacts produced by the build process.
    ///
    /// The package argument is also used to configure environment variables as
    /// well as the working directory of the child process.
    fn fill_env(&self, mut cmd: ProcessBuilder, pkg: &Package, is_host: bool)
                -> CargoResult<ProcessBuilder> {

        let mut search_path = if is_host {
            vec![self.plugins_dylib_path.clone()]
        } else {
            let mut search_path = vec![];

            // Add -L arguments, after stripping off prefixes like "native=" or "framework=".
            for dir in self.native_dirs.iter() {
                let dir = match dir.to_str() {
                    Some(s) => {
                        let mut parts = s.splitn(2, '=');
                        match (parts.next(), parts.next()) {
                            (Some("native"), Some(path)) |
                            (Some("crate"), Some(path)) |
                            (Some("dependency"), Some(path)) |
                            (Some("framework"), Some(path)) |
                            (Some("all"), Some(path)) => path.into(),
                            _ => dir.clone(),
                        }
                    }
                    None => dir.clone(),
                };
                search_path.push(dir);
            }
            search_path.push(self.root_output.clone());
            search_path.push(self.deps_output.clone());
            search_path
        };

        search_path.extend(util::dylib_path().into_iter());
        let search_path = try!(join_paths(&search_path, util::dylib_path_envvar()));

        cmd.env(util::dylib_path_envvar(), &search_path);
        if let Some(env) = self.extra_env.get(pkg.package_id()) {
            for &(ref k, ref v) in env {
                cmd.env(k, v);
            }
        }

        let metadata = pkg.manifest().metadata();

        cmd.env("CARGO_MANIFEST_DIR", pkg.root())
           .env("CARGO_PKG_VERSION_MAJOR", &pkg.version().major.to_string())
           .env("CARGO_PKG_VERSION_MINOR", &pkg.version().minor.to_string())
           .env("CARGO_PKG_VERSION_PATCH", &pkg.version().patch.to_string())
           .env("CARGO_PKG_VERSION_PRE", &pre_version_component(pkg.version()))
           .env("CARGO_PKG_VERSION", &pkg.version().to_string())
           .env("CARGO_PKG_NAME", &pkg.name())
           .env("CARGO_PKG_DESCRIPTION", metadata.description.as_ref().unwrap_or(&String::new()))
           .env("CARGO_PKG_HOMEPAGE", metadata.homepage.as_ref().unwrap_or(&String::new()))
           .env("CARGO_PKG_AUTHORS", &pkg.authors().join(":"))
           .cwd(pkg.root());
        Ok(cmd)
    }
}

fn pre_version_component(v: &Version) -> String {
    if v.pre.is_empty() {
        return String::new();
    }

    let mut ret = String::new();

    for (i, x) in v.pre.iter().enumerate() {
        if i != 0 { ret.push('.') };
        ret.push_str(&x.to_string());
    }

    ret
}
<|endoftext|>


<commit_before>#![no_main]
#[macro_use] extern crate libfuzzer_sys;
extern crate image;

fuzz_target!(|data: &[u8]| {
    let _ = image::load_from_memory_with_format(data, image::ImageFormat::Tga);
});
<commit_msg>Update fuzzer script with upper size bound<commit_after>#![no_main]
#[macro_use] extern crate libfuzzer_sys;
extern crate image;

fuzz_target!(|data: &[u8]| {
    let _ = decode(data);
});

fn decode(data: &[u8]) -> Result<(), image::ImageError> {
    use image::ImageDecoder;
    let decoder = image::codecs::tga::TgaDecoder::new(std::io::Cursor::new(data))?;
    if decoder.total_bytes() > 4_000_000 {
        return Ok(());
    }
    let mut buffer = vec![0; decoder.total_bytes() as usize];
    decoder.read_image(&mut buffer)?;
    Ok(())
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]
use std::{cmp::min, env};

use crate::{
    cluster::Cluster,
    experiments::{
        CompatiblityTestParams, CpuFlamegraphParams, Experiment, ExperimentParam,
        PerformanceBenchmarkParams, PerformanceBenchmarkThreeRegionSimulationParams,
        RebootRandomValidatorsParams, RecoveryTimeParams, TwinValidatorsParams,
    },
};
use anyhow::{format_err, Result};

pub struct ExperimentSuite {
    pub experiments: Vec<Box<dyn Experiment>>,
}

impl ExperimentSuite {
    fn new_pre_release(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        if env::var("RECOVERY_EXP").is_ok() {
            experiments.push(Box::new(
                RecoveryTimeParams {
                    num_accounts_to_mint: 100_000,
                }
                .build(cluster),
            ));
        }
        let count = min(3, cluster.validator_instances().len() / 3);
        // Reboot different sets of 3 validators *100 times
        for _ in 0..10 {
            let b = Box::new(RebootRandomValidatorsParams::new(count, 0).build(cluster));
            experiments.push(b);
        }
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0)
                .enable_db_backup()
                .build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(10)
                .enable_db_backup()
                .build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkThreeRegionSimulationParams {}.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_fixed_tps(0, 10)
                .enable_db_backup()
                .build(cluster),
        ));
        experiments.push(Box::new(TwinValidatorsParams { pair: 1 }.build(cluster)));
        experiments.push(Box::new(
            CpuFlamegraphParams { duration_secs: 60 }.build(cluster),
        ));
        Self { experiments }
    }

    fn new_twin_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(TwinValidatorsParams { pair: 1 }.build(cluster)));
        experiments.push(Box::new(
            CpuFlamegraphParams { duration_secs: 60 }.build(cluster),
        ));
        Self { experiments }
    }

    fn new_perf_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0).build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(10).build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkThreeRegionSimulationParams {}.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_fixed_tps(0, 10).build(cluster),
        ));
        Self { experiments }
    }

    fn new_land_blocking_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0).build(cluster),
        ));
        Self { experiments }
    }

    fn new_land_blocking_compat_suite(cluster: &Cluster) -> Result<Self> {
        let count: usize = match env::var("BATCH_SIZE") {
            Ok(val) => val
                .parse()
                .map_err(|e| format_err!("Failed to parse BATCH_SIZE {}: {}", val, e))?,
            Err(_) => cluster.validator_instances().len() / 2,
        };
        let updated_image_tag = env::var("UPDATE_TO_TAG")
            .map_err(|_| format_err!("Expected environment variable UPDATE_TO_TAG"))?;
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            CompatiblityTestParams {
                count,
                updated_image_tag,
            }
            .build(cluster),
        ));
        experiments.extend(Self::new_land_blocking_suite(cluster).experiments);
        Ok(Self { experiments })
    }

    pub fn new_by_name(cluster: &Cluster, name: &str) -> Result<Self> {
        match name {
            "perf" => Ok(Self::new_perf_suite(cluster)),
            "pre_release" => Ok(Self::new_pre_release(cluster)),
            "twin" => Ok(Self::new_twin_suite(cluster)),
            "land_blocking" => Ok(Self::new_land_blocking_suite(cluster)),
            "land_blocking_compat" => Self::new_land_blocking_compat_suite(cluster),
            other => Err(format_err!("Unknown suite: {}", other)),
        }
    }
}
<commit_msg>[cluster test] add reconfig to the pre release suite<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]
use std::{cmp::min, env};

use crate::{
    cluster::Cluster,
    experiments::{
        CompatiblityTestParams, CpuFlamegraphParams, Experiment, ExperimentParam,
        PerformanceBenchmarkParams, PerformanceBenchmarkThreeRegionSimulationParams,
        RebootRandomValidatorsParams, ReconfigurationParams, RecoveryTimeParams,
        TwinValidatorsParams,
    },
};
use anyhow::{format_err, Result};

pub struct ExperimentSuite {
    pub experiments: Vec<Box<dyn Experiment>>,
}

impl ExperimentSuite {
    fn new_pre_release(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        if env::var("RECOVERY_EXP").is_ok() {
            experiments.push(Box::new(
                RecoveryTimeParams {
                    num_accounts_to_mint: 100_000,
                }
                .build(cluster),
            ));
        }
        let count = min(3, cluster.validator_instances().len() / 3);
        // Reboot different sets of 3 validators *100 times
        for _ in 0..10 {
            let b = Box::new(RebootRandomValidatorsParams::new(count, 0).build(cluster));
            experiments.push(b);
        }
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0)
                .enable_db_backup()
                .build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(10)
                .enable_db_backup()
                .build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkThreeRegionSimulationParams {}.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_fixed_tps(0, 10)
                .enable_db_backup()
                .build(cluster),
        ));
        experiments.push(Box::new(TwinValidatorsParams { pair: 1 }.build(cluster)));
        // This can't be run before any experiment that requires clean_data.
        experiments.push(Box::new(
            ReconfigurationParams {
                count: 101,
                emit_txn: false,
            }
            .build(cluster),
        ));
        experiments.push(Box::new(
            CpuFlamegraphParams { duration_secs: 60 }.build(cluster),
        ));
        Self { experiments }
    }

    fn new_twin_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(TwinValidatorsParams { pair: 1 }.build(cluster)));
        experiments.push(Box::new(
            CpuFlamegraphParams { duration_secs: 60 }.build(cluster),
        ));
        Self { experiments }
    }

    fn new_perf_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0).build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(10).build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkThreeRegionSimulationParams {}.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_fixed_tps(0, 10).build(cluster),
        ));
        Self { experiments }
    }

    fn new_land_blocking_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0).build(cluster),
        ));
        Self { experiments }
    }

    fn new_land_blocking_compat_suite(cluster: &Cluster) -> Result<Self> {
        let count: usize = match env::var("BATCH_SIZE") {
            Ok(val) => val
                .parse()
                .map_err(|e| format_err!("Failed to parse BATCH_SIZE {}: {}", val, e))?,
            Err(_) => cluster.validator_instances().len() / 2,
        };
        let updated_image_tag = env::var("UPDATE_TO_TAG")
            .map_err(|_| format_err!("Expected environment variable UPDATE_TO_TAG"))?;
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            CompatiblityTestParams {
                count,
                updated_image_tag,
            }
            .build(cluster),
        ));
        experiments.extend(Self::new_land_blocking_suite(cluster).experiments);
        Ok(Self { experiments })
    }

    pub fn new_by_name(cluster: &Cluster, name: &str) -> Result<Self> {
        match name {
            "perf" => Ok(Self::new_perf_suite(cluster)),
            "pre_release" => Ok(Self::new_pre_release(cluster)),
            "twin" => Ok(Self::new_twin_suite(cluster)),
            "land_blocking" => Ok(Self::new_land_blocking_suite(cluster)),
            "land_blocking_compat" => Self::new_land_blocking_compat_suite(cluster),
            other => Err(format_err!("Unknown suite: {}", other)),
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::build_project::{build_project, build_schema, check_project, commit_project};
use crate::compiler_state::{ArtifactMapKind, CompilerState, ProjectName};
use crate::config::Config;
use crate::errors::{BuildProjectError, Error, Result};
use crate::graphql_asts::GraphQLAsts;
use crate::watchman::{source_for_location, FileSource};
use common::{PerfLogEvent, PerfLogger};
use futures::future::join_all;
use graphql_ir::ValidationError;
use log::{error, info};
use rayon::prelude::*;
use schema::Schema;
use std::fmt::Write;
use std::{collections::HashMap, sync::Arc};
use tokio::task;

pub struct Compiler<TPerfLogger>
where
    TPerfLogger: PerfLogger + 'static,
{
    config: Arc<Config>,
    perf_logger: Arc<TPerfLogger>,
}

impl<TPerfLogger: PerfLogger> Compiler<TPerfLogger> {
    pub fn new(config: Config, perf_logger: Arc<TPerfLogger>) -> Self {
        Self {
            config: Arc::new(config),
            perf_logger,
        }
    }

    pub async fn compile(&self) -> Result<CompilerState> {
        let setup_event = self.perf_logger.create_event("compiler_setup");

        let file_source = FileSource::connect(&self.config, &setup_event).await?;
        let mut compiler_state = file_source
            .query(&setup_event, self.perf_logger.as_ref())
            .await?;
        self.build_projects(&mut compiler_state, &setup_event)
            .await?;

        self.perf_logger.complete_event(setup_event);

        Ok(compiler_state)
    }

    pub fn build_schemas(
        &self,
        compiler_state: &CompilerState,
        setup_event: &impl PerfLogEvent,
    ) -> HashMap<ProjectName, Arc<Schema>> {
        let timer = setup_event.start("build_schemas");
        let mut schemas = HashMap::new();
        for project_config in self.config.enabled_projects() {
            let schema = build_schema(compiler_state, project_config);
            schemas.insert(project_config.name, Arc::new(schema));
        }
        setup_event.stop(timer);
        schemas
    }

    pub async fn watch_with_callback<F>(&self, mut callback: F) -> Result<()>
    where
        F: FnMut(Result<()>),
    {
        let setup_event = self.perf_logger.create_event("compiler_setup");

        let file_source = FileSource::connect(&self.config, &setup_event).await?;
        let (mut compiler_state, mut subscription) = file_source
            .subscribe(&setup_event, self.perf_logger.as_ref())
            .await?;
        let schemas = self.build_schemas(&compiler_state, &setup_event);
        callback(
            self.check_projects(&mut compiler_state, &schemas, &setup_event)
                .await,
        );

        self.perf_logger.complete_event(setup_event);

        loop {
            if let Some(file_source_changes) = subscription.next_change().await? {
                let incremental_check_event =
                    self.perf_logger.create_event("incremental_check_event");
                let incremental_check_time =
                    incremental_check_event.start("incremental_check_time");

                // TODO Single change to file in VSCode sometimes produces
                // 2 watchman change events for the same file
                let had_new_changes = compiler_state.merge_file_source_changes(
                    &self.config,
                    &file_source_changes,
                    &incremental_check_event,
                    self.perf_logger.as_ref(),
                )?;
                if had_new_changes {
                    // Clear out existing errors
                    callback(Ok(()));
                    // Report any new errors
                    callback(
                        self.check_projects(
                            &mut compiler_state,
                            &schemas,
                            &incremental_check_event,
                        )
                        .await,
                    );
                } else {
                    info!("[watch-mode] No re-compilation required");
                }
                incremental_check_event.stop(incremental_check_time);
                self.perf_logger.complete_event(incremental_check_event);
                // We probably don't want the messages queue to grow indefinitely
                // and we need to flush then, as the check/build is completed
                self.perf_logger.flush();
            }
        }
    }

    pub async fn watch(&self) -> Result<()> {
        let setup_event = self.perf_logger.create_event("compiler_setup");

        let file_source = FileSource::connect(&self.config, &setup_event).await?;

        let (mut compiler_state, mut subscription) = file_source
            .subscribe(&setup_event, self.perf_logger.as_ref())
            .await?;

        if let Err(errors) = self.build_projects(&mut compiler_state, &setup_event).await {
            // TODO correctly print errors
            error!("Errors: {:#?}", errors)
        }
        self.perf_logger.complete_event(setup_event);

        loop {
            if let Some(file_source_changes) = subscription.next_change().await? {
                let incremental_build_event =
                    self.perf_logger.create_event("incremental_build_event");
                let incremental_build_time =
                    incremental_build_event.start("incremental_build_time");

                // TODO Single change to file in VSCode sometimes produces
                // 2 watchman change events for the same file

                info!("\n\n[watch-mode] Change detected");
                let had_new_changes = compiler_state.merge_file_source_changes(
                    &self.config,
                    &file_source_changes,
                    &incremental_build_event,
                    self.perf_logger.as_ref(),
                )?;

                if had_new_changes {
                    if let Err(errors) = self
                        .build_projects(&mut compiler_state, &incremental_build_event)
                        .await
                    {
                        // TODO correctly print errors
                        error!("Errors: {:#?}", errors)
                    }
                } else {
                    info!("[watch-mode] No re-compilation required");
                }
                incremental_build_event.stop(incremental_build_time);
                self.perf_logger.complete_event(incremental_build_event);
                // We probably don't want the messages queue to grow indefinitely
                // and we need to flush then, as the check/build is completed
                self.perf_logger.flush();
            }
        }
    }

    async fn check_projects(
        &self,
        compiler_state: &mut CompilerState,
        schemas: &HashMap<ProjectName, Arc<Schema>>,
        setup_event: &impl PerfLogEvent,
    ) -> Result<()> {
        let graphql_asts = setup_event.time("parse_sources_time", || {
            compiler_state
                .graphql_sources
                .iter()
                .map(|(&source_set_name, sources)| {
                    let asts = GraphQLAsts::from_graphql_sources(sources)?;
                    Ok((source_set_name, asts))
                })
                .collect::<Result<_>>()
        })?;

        let mut build_project_errors = vec![];

        for project_config in self.config.enabled_projects() {
            if compiler_state.project_has_pending_changes(project_config.name) {
                let schema = Arc::clone(schemas.get(&project_config.name).unwrap());
                // TODO: consider running all projects in parallel
                check_project(
                    project_config,
                    compiler_state,
                    &graphql_asts,
                    schema,
                    Arc::clone(&self.perf_logger),
                )
                .map_err(|err| {
                    build_project_errors.push(err);
                })
                .ok();
            }
        }

        if build_project_errors.is_empty() {
            Ok(())
        } else {
            Err(Error::BuildProjectsErrors {
                errors: build_project_errors,
            })
        }
    }

    async fn build_projects(
        &self,
        compiler_state: &mut CompilerState,
        setup_event: &impl PerfLogEvent,
    ) -> Result<()> {
        let result = build_projects(
            Arc::clone(&self.config),
            Arc::clone(&self.perf_logger),
            setup_event,
            compiler_state,
        )
        .await;
        match result {
            Ok(()) => {
                compiler_state.complete_compilation();
                Ok(())
            }
            Err(error) => {
                if let Error::BuildProjectsErrors { errors } = &error {
                    for error in errors {
                        self.print_project_error(error);
                    }
                }
                Err(error)
            }
        }
    }

    fn print_project_error(&self, error: &BuildProjectError) {
        if let BuildProjectError::ValidationErrors { errors } = error {
            for ValidationError { message, locations } in errors {
                let locations_and_source: Vec<_> = locations
                    .iter()
                    .map(|&location| {
                        let source = source_for_location(&self.config.root_dir, location);
                        (location, source)
                    })
                    .collect();
                let mut error_message = format!("{}", message);
                for (location, source) in locations_and_source {
                    if let Some(source) = source {
                        write!(
                            error_message,
                            "\n{}",
                            location.print(&source.text, source.line_index, source.column_index)
                        )
                        .unwrap();
                    } else {
                        write!(error_message, "\n{:?}", location).unwrap();
                    }
                }
                error!("{}", error_message);
            }
        };
    }
}

async fn build_projects<TPerfLogger: PerfLogger + 'static>(
    config: Arc<Config>,
    perf_logger: Arc<TPerfLogger>,
    setup_event: &impl PerfLogEvent,
    compiler_state: &mut CompilerState,
) -> Result<()> {
    let mut graphql_asts = setup_event.time("parse_sources_time", || {
        GraphQLAsts::from_graphql_sources_map(&compiler_state.graphql_sources)
    })?;

    let build_results: Vec<_> = config
        .par_enabled_projects()
        .filter(|project_config| compiler_state.project_has_pending_changes(project_config.name))
        .map(|project_config| {
            build_project(
                project_config,
                compiler_state,
                &graphql_asts,
                Arc::clone(&perf_logger),
            )
        })
        .collect();
    let mut results = Vec::new();
    let mut errors = Vec::new();
    for result in build_results {
        match result {
            Ok(result) => results.push(result),
            Err(error) => errors.push(error),
        }
    }

    if errors.is_empty() {
        let mut handles = Vec::new();
        for (project_name, schema, programs, artifacts) in results {
            let config = Arc::clone(&config);
            let perf_logger = Arc::clone(&perf_logger);
            let artifact_map = compiler_state
                .artifacts
                .get(&project_name)
                .cloned()
                .unwrap_or_else(|| Arc::new(ArtifactMapKind::Unconnected(Default::default())));
            let removed_definition_names = graphql_asts
                .remove(&project_name)
                .expect("Expect GraphQLAsts to exist.")
                .removed_definition_names;
            handles.push(task::spawn(async move {
                let project_config = &config.projects[&project_name];
                Ok((
                    project_name,
                    commit_project(
                        &config,
                        project_config,
                        perf_logger,
                        &schema,
                        programs,
                        artifacts,
                        artifact_map,
                        removed_definition_names,
                    )
                    .await?,
                ))
            }));
        }
        for commit_result in join_all(handles).await {
            match commit_result.unwrap() {
                Ok((project_name, next_artifact_map)) => {
                    let next_artifact_map = Arc::new(ArtifactMapKind::Mapping(next_artifact_map));
                    compiler_state
                        .artifacts
                        .insert(project_name, next_artifact_map);
                }
                Err(error) => {
                    errors.push(error);
                }
            }
        }
    };

    if errors.is_empty() {
        Ok(())
    } else {
        Err(Error::BuildProjectsErrors { errors })
    }
}
<commit_msg>cleanup printing of error messages<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::build_project::{build_project, build_schema, check_project, commit_project};
use crate::compiler_state::{ArtifactMapKind, CompilerState, ProjectName};
use crate::config::Config;
use crate::errors::{BuildProjectError, Error, Result};
use crate::graphql_asts::GraphQLAsts;
use crate::watchman::{source_for_location, FileSource};
use common::{PerfLogEvent, PerfLogger};
use futures::future::join_all;
use graphql_ir::ValidationError;
use log::{error, info};
use rayon::prelude::*;
use schema::Schema;
use std::fmt::Write;
use std::{collections::HashMap, sync::Arc};
use tokio::task;

pub struct Compiler<TPerfLogger>
where
    TPerfLogger: PerfLogger + 'static,
{
    config: Arc<Config>,
    perf_logger: Arc<TPerfLogger>,
}

impl<TPerfLogger: PerfLogger> Compiler<TPerfLogger> {
    pub fn new(config: Config, perf_logger: Arc<TPerfLogger>) -> Self {
        Self {
            config: Arc::new(config),
            perf_logger,
        }
    }

    pub async fn compile(&self) -> Result<CompilerState> {
        let setup_event = self.perf_logger.create_event("compiler_setup");

        let file_source = FileSource::connect(&self.config, &setup_event).await?;
        let mut compiler_state = file_source
            .query(&setup_event, self.perf_logger.as_ref())
            .await?;
        self.build_projects(&mut compiler_state, &setup_event)
            .await?;

        self.perf_logger.complete_event(setup_event);

        Ok(compiler_state)
    }

    pub fn build_schemas(
        &self,
        compiler_state: &CompilerState,
        setup_event: &impl PerfLogEvent,
    ) -> HashMap<ProjectName, Arc<Schema>> {
        let timer = setup_event.start("build_schemas");
        let mut schemas = HashMap::new();
        for project_config in self.config.enabled_projects() {
            let schema = build_schema(compiler_state, project_config);
            schemas.insert(project_config.name, Arc::new(schema));
        }
        setup_event.stop(timer);
        schemas
    }

    pub async fn watch_with_callback<F>(&self, mut callback: F) -> Result<()>
    where
        F: FnMut(Result<()>),
    {
        let setup_event = self.perf_logger.create_event("compiler_setup");

        let file_source = FileSource::connect(&self.config, &setup_event).await?;
        let (mut compiler_state, mut subscription) = file_source
            .subscribe(&setup_event, self.perf_logger.as_ref())
            .await?;
        let schemas = self.build_schemas(&compiler_state, &setup_event);
        callback(
            self.check_projects(&mut compiler_state, &schemas, &setup_event)
                .await,
        );

        self.perf_logger.complete_event(setup_event);

        loop {
            if let Some(file_source_changes) = subscription.next_change().await? {
                let incremental_check_event =
                    self.perf_logger.create_event("incremental_check_event");
                let incremental_check_time =
                    incremental_check_event.start("incremental_check_time");

                // TODO Single change to file in VSCode sometimes produces
                // 2 watchman change events for the same file
                let had_new_changes = compiler_state.merge_file_source_changes(
                    &self.config,
                    &file_source_changes,
                    &incremental_check_event,
                    self.perf_logger.as_ref(),
                )?;
                if had_new_changes {
                    // Clear out existing errors
                    callback(Ok(()));
                    // Report any new errors
                    callback(
                        self.check_projects(
                            &mut compiler_state,
                            &schemas,
                            &incremental_check_event,
                        )
                        .await,
                    );
                } else {
                    info!("[watch-mode] No re-compilation required");
                }
                incremental_check_event.stop(incremental_check_time);
                self.perf_logger.complete_event(incremental_check_event);
                // We probably don't want the messages queue to grow indefinitely
                // and we need to flush then, as the check/build is completed
                self.perf_logger.flush();
            }
        }
    }

    pub async fn watch(&self) -> Result<()> {
        let setup_event = self.perf_logger.create_event("compiler_setup");

        let file_source = FileSource::connect(&self.config, &setup_event).await?;

        let (mut compiler_state, mut subscription) = file_source
            .subscribe(&setup_event, self.perf_logger.as_ref())
            .await?;

        if let Err(err) = self.build_projects(&mut compiler_state, &setup_event).await {
            if let Error::BuildProjectsErrors { .. } = err {
                error!("Compilation failed, see errors above.");
            } else {
                error!("{}", err);
            }
        }
        self.perf_logger.complete_event(setup_event);

        loop {
            if let Some(file_source_changes) = subscription.next_change().await? {
                let incremental_build_event =
                    self.perf_logger.create_event("incremental_build_event");
                let incremental_build_time =
                    incremental_build_event.start("incremental_build_time");

                // TODO Single change to file in VSCode sometimes produces
                // 2 watchman change events for the same file

                info!("\n\n[watch-mode] Change detected");
                let had_new_changes = compiler_state.merge_file_source_changes(
                    &self.config,
                    &file_source_changes,
                    &incremental_build_event,
                    self.perf_logger.as_ref(),
                )?;

                if had_new_changes {
                    if let Err(err) = self
                        .build_projects(&mut compiler_state, &incremental_build_event)
                        .await
                    {
                        if let Error::BuildProjectsErrors { .. } = err {
                            error!("Compilation failed, see errors above.");
                        } else {
                            error!("{}", err);
                        }
                    }
                } else {
                    info!("[watch-mode] No re-compilation required");
                }
                incremental_build_event.stop(incremental_build_time);
                self.perf_logger.complete_event(incremental_build_event);
                // We probably don't want the messages queue to grow indefinitely
                // and we need to flush then, as the check/build is completed
                self.perf_logger.flush();
            }
        }
    }

    async fn check_projects(
        &self,
        compiler_state: &mut CompilerState,
        schemas: &HashMap<ProjectName, Arc<Schema>>,
        setup_event: &impl PerfLogEvent,
    ) -> Result<()> {
        let graphql_asts = setup_event.time("parse_sources_time", || {
            compiler_state
                .graphql_sources
                .iter()
                .map(|(&source_set_name, sources)| {
                    let asts = GraphQLAsts::from_graphql_sources(sources)?;
                    Ok((source_set_name, asts))
                })
                .collect::<Result<_>>()
        })?;

        let mut build_project_errors = vec![];

        for project_config in self.config.enabled_projects() {
            if compiler_state.project_has_pending_changes(project_config.name) {
                let schema = Arc::clone(schemas.get(&project_config.name).unwrap());
                // TODO: consider running all projects in parallel
                check_project(
                    project_config,
                    compiler_state,
                    &graphql_asts,
                    schema,
                    Arc::clone(&self.perf_logger),
                )
                .map_err(|err| {
                    build_project_errors.push(err);
                })
                .ok();
            }
        }

        if build_project_errors.is_empty() {
            Ok(())
        } else {
            Err(Error::BuildProjectsErrors {
                errors: build_project_errors,
            })
        }
    }

    async fn build_projects(
        &self,
        compiler_state: &mut CompilerState,
        setup_event: &impl PerfLogEvent,
    ) -> Result<()> {
        let result = build_projects(
            Arc::clone(&self.config),
            Arc::clone(&self.perf_logger),
            setup_event,
            compiler_state,
        )
        .await;
        match result {
            Ok(()) => {
                compiler_state.complete_compilation();
                Ok(())
            }
            Err(error) => {
                if let Error::BuildProjectsErrors { errors } = &error {
                    for error in errors {
                        self.print_project_error(error);
                    }
                }
                Err(error)
            }
        }
    }

    fn print_project_error(&self, error: &BuildProjectError) {
        if let BuildProjectError::ValidationErrors { errors } = error {
            for ValidationError { message, locations } in errors {
                let locations_and_source: Vec<_> = locations
                    .iter()
                    .map(|&location| {
                        let source = source_for_location(&self.config.root_dir, location);
                        (location, source)
                    })
                    .collect();
                let mut error_message = format!("{}", message);
                for (location, source) in locations_and_source {
                    if let Some(source) = source {
                        write!(
                            error_message,
                            "\n{}",
                            location.print(&source.text, source.line_index, source.column_index)
                        )
                        .unwrap();
                    } else {
                        write!(error_message, "\n{:?}", location).unwrap();
                    }
                }
                error!("{}", error_message);
            }
        };
    }
}

async fn build_projects<TPerfLogger: PerfLogger + 'static>(
    config: Arc<Config>,
    perf_logger: Arc<TPerfLogger>,
    setup_event: &impl PerfLogEvent,
    compiler_state: &mut CompilerState,
) -> Result<()> {
    let mut graphql_asts = setup_event.time("parse_sources_time", || {
        GraphQLAsts::from_graphql_sources_map(&compiler_state.graphql_sources)
    })?;

    let build_results: Vec<_> = config
        .par_enabled_projects()
        .filter(|project_config| compiler_state.project_has_pending_changes(project_config.name))
        .map(|project_config| {
            build_project(
                project_config,
                compiler_state,
                &graphql_asts,
                Arc::clone(&perf_logger),
            )
        })
        .collect();
    let mut results = Vec::new();
    let mut errors = Vec::new();
    for result in build_results {
        match result {
            Ok(result) => results.push(result),
            Err(error) => errors.push(error),
        }
    }

    if errors.is_empty() {
        let mut handles = Vec::new();
        for (project_name, schema, programs, artifacts) in results {
            let config = Arc::clone(&config);
            let perf_logger = Arc::clone(&perf_logger);
            let artifact_map = compiler_state
                .artifacts
                .get(&project_name)
                .cloned()
                .unwrap_or_else(|| Arc::new(ArtifactMapKind::Unconnected(Default::default())));
            let removed_definition_names = graphql_asts
                .remove(&project_name)
                .expect("Expect GraphQLAsts to exist.")
                .removed_definition_names;
            handles.push(task::spawn(async move {
                let project_config = &config.projects[&project_name];
                Ok((
                    project_name,
                    commit_project(
                        &config,
                        project_config,
                        perf_logger,
                        &schema,
                        programs,
                        artifacts,
                        artifact_map,
                        removed_definition_names,
                    )
                    .await?,
                ))
            }));
        }
        for commit_result in join_all(handles).await {
            match commit_result.unwrap() {
                Ok((project_name, next_artifact_map)) => {
                    let next_artifact_map = Arc::new(ArtifactMapKind::Mapping(next_artifact_map));
                    compiler_state
                        .artifacts
                        .insert(project_name, next_artifact_map);
                }
                Err(error) => {
                    errors.push(error);
                }
            }
        }
    };

    if errors.is_empty() {
        Ok(())
    } else {
        Err(Error::BuildProjectsErrors { errors })
    }
}
<|endoftext|>